LlamaIndex 是一个专门为 RAG(检索增强生成)应用而生的开发框架。简单来说,它的核心作用是帮你把私有的、不在大模型训练数据里的数据(如 PDF、API、SQL 数据库等)连接给大模型,让模型能基于这些数据回答问题和执行任务
工作流程图:
一、使用Llamalndex快速实现RAG应用
通过Agent智能体构建大模型应用的方式,在很多业务场景中,都是非常有效的。不过,Agent却并不是Llamalndex的重点。
一方面,现在业界有LangChain框架,更适合构建Agelnt智能体。另一方面,除了Agent,业界还有大语言模型更重要的使用场景RAG。
RAG全称Retrieval Augmented Generation,检索增强生成。这是一种大模型应用落地最成熟的方式。RAG的核心思想是在询问大语言大语言模型时,给大语言模型提供更多的本地信息作为参考,从而让大语言模型能够更好的理解用户的问题,给出更有针对性的答案。
回到之前的案例,我们希望大语言模型回答"怎么还款"这个问题时,其实最需要的,还不是提供Agent,而是希望给大语言模型提供我们自己业务平台的业务规则,这样大语言模型才能根据业务规则,给出更符合业务场景的答案。
Llamalndex简单案例:
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings
from langchain_community.chat_models import ChatTongyi
from llama_index.embeddings.dashscope import (
DashScopeEmbedding,
DashScopeTextEmbeddingModels,
DashScopeTextEmbeddingType
)
from dotenv import load_dotenv
import os
load_dotenv()
Settings.embed_model = DashScopeEmbedding(
model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V2,
text_type=DashScopeTextEmbeddingType.TEXT_TYPE_DOCUMENT,
api_key=os.getenv("BAILIAN_API_KEY")
)
Settings.llm = ChatTongyi(
model="qwen-plus",
api_key=os.getenv("BAILIAN_API_KEY")
)
# 导入文档,只需提供文件夹名称即可,会自动读取该文件夹下的文档
documents = SimpleDirectoryReader("data").load_data()
# 为文档建立索引
index = VectorStoreIndex.from_documents(documents)
# 创建查询引擎
query_engine = index.as_query_engine()
# 输入查询问题,打印结果
response = query_engine.query("烟花爆竹零售店外部最小距离有什么要求")
print(response)
代码解读:
1、设置「向量化(Embedding)模型」
Settings.embed_model = DashScopeEmbedding(
model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V2, # 模型版本
text_type=DashScopeTextEmbeddingType.TEXT_TYPE_DOCUMENT, # 文档级向量
api_key=os.getenv("BAILIAN_API_KEY") # 你的 DashScope 密钥
)
- 作用:把文本变成 1536 维向量,供后续
VectorStoreIndex做相似度检索。 - 模型:
text-embedding-v2是 DashScope 免费模型,支持中英、8192 token,效果 ≈ OpenAI ada-002。 - text_type 选
DOCUMENT表示「一整段文本」级别;如果后续要嵌入用户问题,LlamaIndex 会自动切换为QUERY类型(DashScope 接口区分)。 - DashScope:DashScope(中文名“模型服务灵积”)是阿里云推出的 **Model-as-a-Service(MaaS)一站式模型服务平台。**它把「通义千问、CLIP、Paraformer、StableDiffusion」等 400+ 大模型/小模型做成 标准化 HTTP API,开发者无需本地 GPU 即可调用、微调、部署。
2、设置「大语言模型(LLM)」
Settings.llm = ChatTongyi(
model="qwen-plus", # 通义千问 Plus 版本(对标 GPT-3.5)
api_key=os.getenv("BAILIAN_API_KEY")
)
- 作用:负责「理解问题 → 生成答案」;RAG 场景里会拿到检索到的上下文再回答。
- 模型:
qwen-plus价格比qwen-turbo贵 2×,但推理能力更强;与 DeepSeek/GPT 一样走 OpenAI-Compatible 格式。 - ChatTongyi 是 LlamaIndex 官方封装的 Tongyi 驱动,内部帮你把消息格式、温度、top_p 等转成 DashScope 所需字段。
二、LlamaIndex基础组件
在具体实现时,Lamalndex采用组件化的方式,将大语言模型、向量数据库、索引、数据源等组件进行组合,实现大语言模型与数据源的交互。通过组件化的方式,可以像拼积木一样,将不同的组件进行组合,实现更好的可扩展性。这里就介绍Lamalndex中几个重要的组件。
1、Prompts 构建提示词
在和大语言模型交互的过程中,提示词是最为重要的工具。将对提示词的设计和处理封装成几个重要的参数,这也是构建AI应用最简单 的一种方式。Llamalndex提供了很方便的组件,可以用来构建提示词。
2、Models 大语言模型
Llamalndex通过抽象出LLM和Embedding类型,来实现与不同大语言模型以及向量化模型的兼容性。而针对不同大语言模型的具体实现都被封装到单独的依赖库中。具体参见官网: https:/docs.lamaindex.ai/en/stable/module_guides/models/lms/modules/ 这些不同的依赖库用法大都差不多。以阿里云百炼的Dashscop为例。需要引入对应的依赖库
#引入dashscope的依赖库
pip install llama-index-llms-dashscope
pip install dashscope
# 向量化模型库(文本转成向量)
pip install llama-index-embeddings-dashscope
3、Loading 文档加载组件
Llamalndex处理本地数据最基本的方式就是把本地档加载成Document,再把文档内容拆分成Node。这些Node就是Llamaindex处理本地数据的基本单位。Llamalndex中的Document可以代表一个本地的资源文件。并且不光是文本文件,图片、音频、视频等资源文件都可以作为Document。
一个Document代表的是一个本地资源文件。在对信息做处理时,则需要把Document拆分成Node,Node就是Llamalndex处理本地数据的基本单位。 这时候,如何把Document拆分成Node呢?Llamaindex提供了多种NodeParser的具体实现类,用来按照不同的规则拆分Document。
为了简化Document和Node的加载过程,Lamalndex提供了一个非常简单易用的工具类**SimpleDirectorvReader。用于从本地目录加载文档。SimpleDirectoryReader**能够处理非常多常见的文档,包括csv、docx、md、pdf、png、pptx等多种文档内容。
from llama_index.core import SimpleDirectoryReader
reader = SimpleDirectoryReader(input_dir="./resource" ,required_exts=[".txt"])
documents = reader.load data()
documents
大部分常用的文档,比如txt、pdf、docx等,都可以通过SimpleDirectoryReader加载。SimpleDirectoryReader还提供了很多扩展属性可以加载非常多的文件。但是如果遇到一些特殊的文档,也可以通过Llamalndex的设计扩展出来。例如对于常用的JSON文件,或者JSONL文件,SimpleDirectoryReader只能加载出一个文档。但是使用**JSONReader**可以解析JSON文件,按照指定的格式加载出多个文档。
#加载扩展依赖 pip install llama-index-readers-json
from llama_index.readers.json import JSONReader
reader = JSONReader(is_jsonl=True)
documents = reader.load_data(input_file="./jsonl/encyclopedia.jsonl", extra_info={})
4、Indexing 索引组件
Indexing是一种数据结构,允许用户从Indexing中快速检索感兴趣的数据。在Llamalndex中,Index通常可以由一系列的Document构建出来,然后再构建出一个Query Engine或者Chat Eingine。用户就可以基于这些Engine快速检索出感兴趣的数据。在Index内部,则会以Node的形式保存数据。Node则是Document拆出来的一个片段。另外,Index也会暴露出一个Retriever接口,进一步支持文件检索。
通常用得做多的是**VectorStorelndex**,存储自然语言处理后的向量数据。
5、Storing 数据存储组件
把数据检索出来之后,当然就是需要存储了。llamalndex提供了非常多的数据存储组件,允许用户定制外部数据存储。
- Document stores:用来存储Document和Node.
- Index stores: 用来存储index相关的元数据。
Vector stores: 用来存储向量数据。- Chat stores:用来存储聊天记录。
- Property stores: 用来存储知识图谱相关的数据
其中,用的最多的,通常就是**Vector stores**向量存储了。
在Llamalndex中,支持多种外部向量数据库来存储向量。具体参见官网https://docs.llamaindex.ai/en/stable/module_guides/storing/vector_stores/
这里以常见的Redis为例。需要注意的是,Redis需要stack插件支持,才能作为向量数据库使用。stack在Redis7版本中需要额外安装,在Redis8中则默认集成了stack,Llamalndex中要使用Redis作为向量存储,需要先添加对应的依赖库。
6、Querying 查询引擎
查询引擎是Llamalndex中最为核心的组件,因为他是直接暴露给用户的,用户可以基于查询引擎进行查询。 Llamalndex中同样也提供了非常多的Querying组件,用来支持不同的查询场景。 例如之前使用的Retriever就是一种Querying查询引擎。他的作用主要是检索出和问题最相关的文档。但是Retriever并不直接回答问题。如果需要回答问题,就可以进一步的封装成Query Ergine。
7、Settings 全局设置
Settings是Llamalndlx中的全局设置管理器。它允许用户设置全局的配置,如LLM、索引、查询引擎、Chat Engine等,有了Settings,用户就不用在每个组价中单独配置这些参数了。 例如Lamalndex默认都是使用的OpenAI相关的组件,在之前的示例中,我们想要使用阿里云百炼的组件就可以使用Settings进行全局设置。
三、RAG应用的评估
1、建立自动化评测机制
如果我们发现了RAG应用某一个具体问题回答效果不佳,那么我们可以逐步去排查RAG应用在哪个环节出现了问题,并逐步去优化。但通常构建RAG应用时,我们要面临的问题是无穷无尽的。我们不可能穷尽所有问题进行分析。在测试价段就无法对RAG应用形成一个比较正确的评估。测试不充分,自然就无法形成比较靠谱的应用。 因此,对整个RAG应用进行效果评测的第一步,是需要构建一个自动化的评测体系。通过自动化的评通常则体系进行大量样本的综合分析,这样才能对RAG应用的整体效果进行合理的评估。
2、使用Ragas评估RAG应用表现
这类测试框架有很多,主流的有Ragas\DeepEval\Trulens等。Llamalndex框架自己也提供了检测功能。甚至按照Llamalndex的设计模式,还提供了和其他主流评测框架集成的实现。
这里就以Ragas为例,来介绍一下如何来评估RAG应用的准确性。Ragas是这个领域里非常著名的一个框架
官网地址:https://docs.ragas.io/en/stable/getstarted/
他的核心思想和我们之前的简单应用差不多,也是让大模型来帮助你评估RAG系统,更重要的是,Ragas设计的评估指标非常契合RAG系统的特点。Ragas提供的评测指标有很多,对于RAG应用,主要关注以下几个指标:
- Answer Correctness, 用于评估 RAG 应用生成答案的准确度。
- Context Precision, 用于评估 contexts 中与正确答案相关的条目是否排名靠前、占比高(信噪比)。
- Context Recall, 用于评估有多少相关参考资料被检索到。
- Answer Relevancy, 用于评估 RAG 应用生成的答案是否与问题相关。
- Faithfulness, 用于评估 RAG 应用生成的答案和检索到的参考资料是否一致。
评估RAG应用回答质量:
Ragas提供了Answer Correctness指标,用于评估RAG应用的整体回答质量。使用这个指标时,需要准备以下数据
- question:输入给RAG应用的样本问题
- groud_truth:样本问题的正确答案
- answer:RAG应用给出的回答
评估RAG应用检索召回的效果:
检索召回阶段,主要使用Context precision和Cantext recall两个指标来评估RAG应用的召回效果。
- Context precision: precision表示检索出来条目有多少是正确的,或者说相关的。Ragas在评估这个指标时,还会计算与正确答案相关的条目是否靠前、是否占比高。更加则重于相关性。
- Context recall:Recall有多少正确的条目被检索出来。主要是评估contexts与groud_truth的一致性,侧重于事实准确度。
计算这些指标时,需要准备以下数据:
- question:输入给RAG应用的样本问题
- contexts:RAG应用返回的答案片段
- ground_truth:问题对应的真实答案
- answer:RAG应用给出的回答
Ragas核心提示词分析:
Ragas的许多评测指标也是基于大模型实现的。用户可以直接看到Ragas的很多核心提示词,也同样可以替换他的核心提示词。比如把Ragas默认的英文提示词翻译成中文,这样可以让评测结果更符合中文问答场景。
其实,如果你认真分析这些提示词,也大概能够猜想到Ragas一些核心指标的计算过程。 对于answer_crrectness,他的打分过程需要用到LLM大语言模型和Embedding向量化模型。在打分时,会综合计算answer和ground_truth的语义相似度和事实准确度。
语义相似度主要是通过Embedding模型得到answel和ground_truth的文本向量,然后计算两个文本向量的相似度。向量相似度的计算方法有很多种,比如余弦相似度、欧式距离、曼哈顿距离等。Ragas使用的是最常用的余弦相似度。 事实准确度会衡量answer和ground_truth在事实描述上的一些差异。在计算指标时,会把answer和ground_truth拆分成一些相对独立的观点列表,然后综合比较answer和ground_truth的这些观点列表的匹配程度,统计F1指标。 在计算context_recall和context_precision时,也会采用计算 answe_correctness 相似的方法。拆分成一些观点,再来计算匹配程度。如果你对ragas的具体实现感兴趣,可以尝试去研读Ragas的源码。
总结:
对大模型的能力进行合理的评估,这是深度使用大模型必须要走的一个过程。这一章节介绍了针对RAG应用,构建自动化评测体系的基础思路,也演示了如何通过Ragas构建更专业的评测体系,这些评测的经验都是行业内不可多得的宝贵财富。
对于这些评测框架,我们也只介绍了一些简单的实现。实际上,Ragas除了构建RAG的相关指标外,针对其他大模型的应用场景也构建了非常多的指标。比如针对机器翻译、文本摘要、NI2SQL(自然语言转换成SQL)、Agent等场景,也有非常多的指标。
另外像Llamalndex、Trulens、Deepeval等其他的大模型评测框架也都从同样的角度提供了对大模型进行评则的思路和实现。
四、优化RAG应用提升回答准确度
1、文档准备阶段
对RAG应用来说,文档的质量可以说直接决定了整个RAG应用的质量。因此,我们需要针对文档进行持续的优化。比如引入专家验证提升文档质量。跟踪用户反遗,不断调整文档内容。查漏补缺,同时定期剔除无关的或过时的内容,都是必要的措施。
2、文档解析与切片阶段
在使用Llamalndex构建RAG应用时,他是会自动挥析文档内容并进行切片的。这对于大部分的场景是够的。但是,实际工作中,当文档变得更复杂时,对文档进行合理的解析和切片就变得非常重要了。
比如,在Llamalndex中,通常使用SimpleDirectdryReader加载本地文件,实际上,Llamalndex同样提供了一些扩展插件,可以加载Notion、Slack、Discord、Google Docs等外部自文档。具体可以参见:https://docs.llamaindex.ai/en/stable/module guides/loading/connector/modules/
当文档多了之后,如果文档来源不统一,文档形式又五花八门,这是不利于统一进行解析的。我们上面就演示了把PDF格式的文档转换成为结构规整的Markdown格式,这样是可以提高RAG应用的效率的。对于docx、xlsx等格式的文档,如果结果过于复杂,把他们统一转换成为Markdown格式也是一个不错的选择。在做格式转换时,有些比较麻烦的问题,也可以借助大模型来进行深度调整。比如将转换的Markdown文本用大模型进行润色、修正目录层级、补充缺失信息等。当文档被正确加载成Document后,接下来Llamalndex也会完成对Document的切片工作,将Document切分成为多个相关联的Node。Llamalndex中也提供了非常多的文档切分工具可以作为参考,当然,如果这些工具不够用时,也可以自己实现。
- TokenTextSpliter:按照Token进行拆分。比较适合对Token数量有严格要求的场景。比如使用上下文长度比较小的模型时,
- SentenceSplitter:这是Llamalndexm默认的切片策略,切片时会尽量保持句子的完整性。
- SentenceWindowNodeParser:基于句子进行切分。不过在切分时,每个Node会包含周围的句子作为上下文窗口,这样可以更好的保持句子的完整性。
- SemanticSplitterNodeParser:根据语义相关新自适应进行切片。
- MarkdownNodeParser;基于Markdown格式进行切分。Llamalndex提供的实现会根据Markdown文档的标题层级进行智能切分。
3、文本向量化与存储阶段
文档切片后,我们就需要对其建立索引,以便后续检查。最常见的方案就是使用EmbeddingModel向量作模型将切片转成向量,然后存储到向量数据库当中。
首先,你要清楚,向量本质上是把不精确的自然语转成计算能够理解的精确的数字化的表达。转换出来的向量,主要包含的是自然语言的语义相似度信息。
这里需要注意的是,向量的本质是自然语言,而自然语言其实是一种非常不精确的表达方式。不同的人对语言的理解是不一样的,同样,不同的Embedding向量化模型对相同的文字计算,得到的向量也可能是完全不同的。例如上面的案例,可以分别使用阿里云提供的text-embedding-v2和test-embedding-v3模型,分别进行计算,得到的结果也是完全不同的。不过,一个通常的经验是,越新的Embedding模型,其表现通常越好。
然后,如何选择向量数据库?
向量数据库,通常要做的事情就两件,一是把向量诸起来,二是根据向量进行相似度检索。而实现这两个功能,其实并不一定需要额存外的数据库产品。Llamalndex内置的向量存储就是使用内存完成。这样的有点是快速上手,适合开发测试。但是缺点也很明显,数据量受限于内存的大小。
当数据量增大时,可以使用开源的向量数据库,如MiIvus、Qdrant等。这些数据库提供了数据持久化和高速检索的能力。很多传统的数据存储产品,也可以作为向量数据库使用。比如Redis、Elasticsearch等。这些本地数据库的优势是功能完整、可控性强。但是缺点是需要自行部署维护。
这时,也可以选择一些云服务提供的向量存储能力。例如阿里云上提供过的各种数据服务。像Redis也提供Redis Cloud云上服务,可以直接使用。
这些不同的向量数据库虽然具体的实现方式是天差地别的,但是他们的核心功能其实是差不多的。选择不同的向量数据库,通常不会对RAG应用的准确性产生太大的影响。
4、检索召回阶段
检索阶段会遇到的主要问题是,很难从众多的文档切片中,找到和用户问题最相关、且包含正确答案信息的片段。所以这个阶段的优化过程,更多需要考虑如何提升检索的性能。
要优化检索召回的效果,通常要分为两个不同的思路:
- 在执行检索前,需要更多关注用户的问题。减少用户问题中描述不完整、甚至有歧义的地方,更好的还原用户的真实意图。
- 在执行检索后,可能会出现很多和用户问题无关的信息。这时需要想办法减少无关信息,避免干扰下一步生成答案的质量。
常见的策略有以下几种:
- 用户提问前,对问题进行扩展 例如,将"找王芳"主动改写成"王芳是哪个部门的?他的联系方式、职责范围、工作目标是什么",这样能让目标更清晰。例如,在用户询问"工作注意事项有哪些"时,主动根据用户的个人信息进行改写,扩展成"项目经理的工作注意事项有哪些"。对问题进行适当扩写,可以极大的提升检索的准确度。当然,在具体实现过程中,扩展的规则会有很多,你甚至可以引入大模型,让大模型来帮助进行问题扩写。
- 将用户的单一查询,改写成多步问题 Llamalndex中就提供了两个强大的工具来实现这个功能:
- StepDecomposeQueryTransform:这个工具可以帮你把一个复杂问题分解成多个子问题。比如对于"王芳是哪个部门的”,他就可以分解成”公司里有几个叫王芳的员工?"和"这些王芳分别在哪些部门?"两个问题,这样可以更全面地获取所有王芳的信息。
- MultiStepQueryEngine:这个查询引擎会按顺序处理这些子问题。它会先获取公司所有王芳的信息,然后依次查询每个王芳的部门信息,最终答案聚合成一个完整回应。
把大问题拆解成小问题往往更容易得到准确的答案。不过需要注意的是,Lamalndex的实现过程是通过多次调用大语言模型完成的,所以会消耗更多的Token。另外,也会带来过程的不确定性。 - 使用假设文档HyDE进行增强 这种方法的基础思路是先让大模型基于问题编写一个"假象的答案文档”,然后用这个假象的文档来检索真实文档。最后用检索到的真实文档来生成实际答案。
5、重排序Rank
想象一下,如果是一个人来回答RAG最终的问题,他会希望参考信息怎么组织呢?是不是希望参考信息尽量简单,不要包含多余的信息而且重要参考信息排在最前面。这样才能更方便的找到答案。 这个事情,其实也可以让大语言模型来处理。例如阿里云百炼上提供了文本重排序模型(gte-rerank-v2),我们可以直接调用这个模型来对检索出的文本做一下处理。
6、生成答案阶段
现在,大模型会根据你的问题和检索召回的内容,生成最终答案。这个过程更多的是由大模型进行处理,考验的是大模型的理解与总结能力。不过,你也可以从以下几个方面着手优化。
- 选择合适的大模型 通常在这个阶段,大模型只需要做简单的信息总结,所以可以选择一些参数量比较小的模型就可以了。但是,如果你构建的RAG应用面向一些非通用领域,比如法律领域,那还是建议使用面向特定领域训练或者微调的模型。比如阿里云提供的通义法睿。
- 充分优化提示词模板 最终召回的信息和用户的问题,是需要整理成一个完整的提示词提供给大语言模型的。Llamalndex提供了默认的模板,将这些信息进行整合。但是,如果你希望大语言模型更理解你的要求,也可以自行修改模板。例如将默认的英文模板修改成中文。或者使用Llamalndex的refine模式,让大模型对输出结果再做一次整理。
- 调整大模型的参数 可以根据具体应用场景,适当调整大语言模型的参数。例如,如果你希望查询实时性的内容,可以适当降低temperature或top-p的值。如果是査询创造性的内容,可以适当增加他们的值。如果希望大模型在回答问题时不要总是用重复的句子,可以适当调presence_penalty值。如果希望限制字数,控制成本或减少响应时间,可以适当降低max tokens的值等。
- 调优大模型 如果试了很多方法后,仍然不及预期,或者希望更进一步提升效果,这时也可以尝试面向当前的业务场景单独微调一个新的模型。当然,这样难度比较高,成本通常也比较大,可以适当关注。