LlamaIndex RAG评估实战:从原理到可落地流程

发布时间:2026/10/20 12:54:39
LlamaIndex RAG评估实战:从原理到可落地流程 做RAG应用的人应该都有过这种体验demo阶段跑得挺欢一上生产就开始翻车。检索回来的片段和问题驴唇不对马嘴模型明明看到了正确答案却在回答里胡编乱造更气人的是它在不知道答案的时候还一本正经地编故事。这种时候你需要的不是盲调prompt而是一个能把效果好不好从主观感觉变成可量化指标的评估模块。最近我在复盘 LlamaIndex 里评估相关的实践从最底层的评估器原理到一套可落地的构建流程都过了一遍这篇就系统拆一下评估模块怎么搭、怎么用、有哪些坑。这篇文章适合正在用 LlamaIndex 搭建 RAG 应用的人尤其是刚接触评估、只听说过RAG评估但不知道从哪下手的开发者。读完你至少能搞明白三件事评估到底在评估什么、LlamaIndex 提供了哪些现成的评估器、以及怎么把评估流程接到自己的项目里并以此驱动优化迭代。1. 为什么 RAG 应用离不开评估模块1.1 RAG 让人又爱又恨的地方RAG 看起来是很美的方案——把外部知识接到大模型上不微调、不蒸馏、也不需要重新训练。但问题恰恰藏在看起来很美里。一个典型的 RAG 链路包含检索、重排、上下文拼装、答案生成几个环节任何一个环节出错都会导致最终回答崩掉。更麻烦的是这种崩掉不是显式的报错而是很隐蔽的质量劣化只有仔细看回答内容才能发现。我之前接手过一个内部知识库问答系统当时系统已经把 ChatGPT 的 prompt 调得很顺手了生成的回答读起来通顺、结构也好但一问到具体操作步骤就频繁出错。后来把错误回答逐一比对原始文档发现根因有两个一是检索模块把不相关的片段排进了上下文二是模型被这些噪声干扰后抛弃了正确信息。这种问题在 demo 阶段很难发现因为没有人在 demo 时拿一百个问题去对照文档查准确率。这就是为什么需要一个独立的评估模块——它能告诉你系统在哪些问题上答错了、答偏了、或者压根没答出来。1.2 评估到底在评估什么很多人一提评估就想到准确率但在 RAG 场景里单看一个数字远远不够。业内习惯把 RAG 评估拆成检索质量和生成质量两个维度对应链路中两个独立的模块。检索质量衡量的是系统有没有把正确答案所在的片段找回来。常用指标包括命中率、MRR平均倒数排名、NDCG 之类这些指标关心的是正确答案在检索结果里的位置和排序。检索质量不好后面生成阶段再强也白搭毕竟上下文里根本没有正确答案。生成质量衡量的是模型拿到的上下文之后回答得好不好。这比检索质量更微妙一个回答可能有四个子维度忠实度是否严格基于给定上下文没有编造、相关性是否紧扣用户问题、正确性事实层面是否和参考答案一致、以及完整性是否覆盖了用户所有诉求。如果你连要评估什么都没想清楚直接用一个评估器跑结果那得到的数字基本没有指导意义。1.3 评估模块的两种形态评估按照使用时机可以分成离线评估和在线评估两种形态。离线评估是主流做法先准备一批带参考答案的问题集定期跑一遍全流程得出指标分数用来度量系统改动前后的质量差异。在线评估则是生产环境里的旁路监控常见做法是给每轮回答加个点赞/点踩按钮或者用规则去抓明显的失败模式比如超时、空回答、答非所问。LlamaIndex 的评估模块侧重离线评估这一侧。它本身不强制你用什么指标而是提供一套统一的评估器接口让你挂在 RAG 链路的任意节点上采集需要的数据然后输出结构化评估结果。这就像给系统装了一块仪表盘你开着车能看到实时的时速、油量、水温而不是等车坏了才找人检查。2. LlamaIndex 评估模块的核心组件拆解2.1 评估器的基本构成prompt 解析LlamaIndex 里所有的评估器都遵循同一个抽象模式。每个评估器有一个内置的评估 prompt把待评估的内容比如用户问题、系统回答、参考答案、检索片段填进去送给一个大模型称为 judge 模型也就是裁判然后对模型输出的文本做解析最终产出一个 EvaluationResult 对象。用一句话概括评估器就是用大模型去当裁判给另一个大模型的回答打分并给出理由。这个设计有它的必然性。传统的信息检索评估靠字符串匹配或标准答案比对但生成式回答的表达方式千变万化同一个知识点可以有完全不同的表述字符串匹配根本兜不住。而大模型天然理解语义可以充当语义层面的裁判这是过去用规则和启发式方法做不到的。理解了这个原理你就会明白为什么评估器的选择和 judge 模型的选择都极其重要。评估 prompt 决定裁判按照什么标准打分judge 模型决定裁判能不能把这个标准执行到位。两者任何一个不给力评估结果都会失真。2.2 常用的内置评估器及适用场景LlamaIndex 内置了一批评估器覆盖了 RAG 场景里大部分评估需求。下面是我实际用过的几个给你拆开讲CorrectnessEvaluator把系统回答和参考答案放一起让 judge 模型判断两者内容是否一致并打分。适合有标准答案的场景比如客服FAQ、法律咨询这类事实边界明确的问答。FaithfulnessEvaluator只给系统回答和检索回来的上下文让 judge 模型逐句判断回答里的每个信息点是否能从上下文中找到依据。这是我最常用的评估器也是防止模型编造的第一道防线。RelevancyEvaluator给用户问题和系统回答判断回答是否切题。它不关心回答内容是否真实只关心有没有答到点子上。SemanticSimilarityEvaluator计算系统回答和参考答案的语义相似度基于嵌入模型实现不依赖 LLM 裁判速度和成本会低一些。GuidelineEvaluator可以自定义一组评估规则比如回答必须包含操作步骤不能在回答中出现模糊表述等让 judge 模型按规则逐条核查。适合有具体业务约束的场景。这几个评估器对应的评估维度和输入差异我用一张表整理了一下方便你快速对号入座评估器评估维度核心输入judge 模型依赖CorrectnessEvaluator事实正确性用户问题、系统回答、参考答案高FaithfulnessEvaluator忠实度/防幻觉系统回答、检索上下文高RelevancyEvaluator回答相关性用户问题、系统回答高SemanticSimilarityEvaluator语义相似度系统回答、参考答案低靠嵌入模型GuidelineEvaluator业务规则符合度用户问题、系统回答、规则集高2.3 批量评估与结果聚合单个评估器一次只能评估一条回答但在实际项目中一次回归测试动辄要跑上百个问题。LlamaIndex 提供了两个批量评估工具一个是基于多线程并发跑多个评估器的 BatchEvalRunner另一个是针对评估器本身需要更细致打分的场景设计的 ProcessEvaluator。我用得最多的是 BatchEvalRunner。BatchEvalRunner 做的事情很简单把一堆 query 和 response 分发到多个 worker 里并行跑多个评估器最后把结果按评估器汇总。它还有个重要的能力——让你一次性跑多个不同维度的评估器。比如我把 correctness、faithfulness、relevancy 三个评估器塞进同一个 BatchEvalRunner一条回答跑完就能拿到三个分数不用来回重算。使用 BatchEvalRunner 时还有个容易被忽略的细节不同的评估器需要不同的输入字段。CorrectnessEvaluator 需要 referenceFaithfulnessEvaluator 需要 contextsRelevancyEvaluator 仅需要 query 和 response。你把它们塞进同一个 runner 时所有数据集字段会被合并传入但评估器只会挑自己需要的字段所以数据集里字段不足不会报错只会导致对应评估器无法正常工作。我一开始就在这上面踩过坑字段缺失时跑出的分数全是默认值还浑然不觉。3. 从零搭建一个评估模块3.1 准备环境与模型动手之前先把环境装好。以目前常见的 Python 版本为例你需要安装 LlamaIndex 的核心库和至少一个 LLM 接入包。我日常用的是pip install llama-index-core pip install llama-index-llms-openai如果你用的不是 OpenAI 的模型也可以换成别的厂商对应的包比如llama-index-llms-ollama或llama-index-llms-azure-openai。接口上差异不大核心就是创建一个 LLM 对象传给评估器。评估模块对 judge 模型的质量要求比较高。实践中我建议把生成回答的模型和做评判的模型分开。原因很朴素如果让同一个模型既当运动员又当裁判它很容易对自己的产出偏心。实测下来用高一档次的模型做 judge评估结果更稳定。在 judge 模型上省的钱最终会在错误的评估结论上加倍还回来。3.2 构建基础评估流程最简单的评估流程只需要三步创建 judge 模型、实例化评估器、传入数据。下面是一段可以直接跑的示例代码from llama_index.core.evaluation import ( CorrectnessEvaluator, FaithfulnessEvaluator, RelevancyEvaluator, EvaluationResult, ) from llama_index.llms.openai import OpenAI # 1. 创建 judge 模型 judge_llm OpenAI(modelgpt-4o, temperature0) # 2. 实例化评估器 correctness CorrectnessEvaluator(llmjudge_llm) faithfulness FaithfulnessEvaluator(llmjudge_llm) relevancy RelevancyEvaluator(llmjudge_llm)接着构造一条评估样本。这里我有两条经验值得单独强调一下第一FaithfulnessEvaluator 的输入里不需要 query只需要 response 和 contexts但如果你传了 query它会顺带在 prompt 里提示裁判结合问题判断忠实度效果会好一些。第二CorrectnessEvaluator 的 reference 是必需的在没有参考答案的场景下不要硬凑换个评估器更合适。评估调用可以这样写from typing import Optional from llama_index.core.schema import NodeWithScore, Document # 模拟检索上下文 contexts [ 产品支持退款退款申请需要在购买后30天内提交。, 退款到账时间通常为3-5个工作日节假日顺延。, ] # 模拟LLM的回答 response 用户可以在购买后30天内申请退款到账时间为3-5个工作日。 # 参考答案用于 correctness 评估 reference 产品支持30天内申请退款退款通常在3-5个工作日内到账节假日顺延。 # 逐项评估 res_correct correctness.evaluate_response( query退款政策是什么, responseresponse, referencereference, ) print(fcorrectness score: {res_correct.score}) print(fcorrectness feedback: {res_correct.feedback}) print(fpassing: {res_correct.passing}) res_faithful faithfulness.evaluate_response( query退款政策是什么, responseresponse, contextscontexts, ) print(ffaithfulness score: {res_faithful.score}) print(ffaithfulness feedback: {res_faithful.feedback})输出结果里score是 judge 模型给出的分数通常是0到1或0到5的浮点数passing是布尔值表示是否通过阈值feedback是 judge 给出的文字理由。不要小看 feedback 这个字段它才是评估里最有价值的部分——分数告诉你差feedback 告诉你差在哪。迭代优化时我几乎全靠读 feedback 来定位问题。3.3 批量评估与数据集设计单条样本的意义有限评估必须站在数据集层面才有说服力。一个实用的做法是把测试样本整理成 JSONL 文件每行一条记录包含 query、reference、contexts 三个核心字段。response 字段则需要先跑一遍完整的 RAG 流程去生成再和上述字段一起喂给评估器。批量评估的代码骨架长这样import json import asyncio from llama_index.core.evaluation import BatchEvalRunner async def run_batch_eval(samples): queries [s[query] for s in samples] responses [s[response] for s in samples] references [s.get(reference) for s in samples] contexts_list [s.get(contexts, []) for s in samples] runner BatchEvalRunner( evaluators{ correctness: correctness, faithfulness: faithfulness, relevancy: relevancy, }, workers4, show_progressTrue, ) eval_results await runner.aevaluate_queries( queriesqueries, responsesresponses, referencesreferences, contexts_listcontexts_list, ) for eval_name, results in eval_results.items(): passing sum(1 for r in results if r.passing) avg_score sum(r.score for r in results) / len(results) print(f{eval_name}: passing{passing}/{len(results)}, avg_score{avg_score:.3f}) # 运行 samples [ {query: 退款时效是多久, response: ..., reference: ..., contexts: [...]}, # ...更多样本 ] asyncio.run(run_batch_eval(samples))这里需要注意workers的取值。它控制评估的并发线程数。如果你用的 judge 模型有速率限制workers 开得太大很容易触发限流报错。我个人的经验值是免费的模型开2付费且没有并发限制的模型开4到8具体根据自己的预算和体验来。show_progressTrue建议打开跑上百条样本时你不会想干等的。数据集的设计直接决定评估的有效性。我的原则是宁少毋偏。与其贪多求全搞两百条模板化的简单问题不如挑三十条有代表性的边缘 case。至少应当覆盖这样几类有明确标准答案的事实型问题、上下文里存在干扰信息的问题、问题表述模糊需要追问澄清的问题、以及文档里完全没有答案的越界问题。最后那一类尤其重要它能检验系统在不知道的时候会不会诚实承认还是硬着头皮胡说。3.4 自定义评估标准内置评估器覆盖的是通用维度但真实项目里总有一些业务特有的规则需要约束。比如你的业务规定回答必须引用来源文档编号或者回答不能暴露内部系统名称这些用通用评估器是测不出来的就得自己写一个评估器。LlamaIndex 允许你继承 BaseEvaluator 来写自定义评估器。核心要做的就两件事设计评估 prompt以及解析 judge 的输出。下面我给出一个简化的自定义评估器示例它的逻辑是判断回答是否引用了文档来源from llama_index.core.evaluation import BaseEvaluator, EvaluationResult from llama_index.core.prompts import PromptTemplate from typing import Optional, Any, List class CitationEvaluator(BaseEvaluator): def __init__(self, llm): self._llm llm self._template PromptTemplate( 你是一个严格的评估员。给定用户问题、AI回答和参考上下文判断AI回答 是否明确引用了上下文中存在的文档来源。\n 回答中必须出现类似『根据某文档』『来源: 某文档』的表述。\n 请用以下格式输出\n 引用正确: 是/否\n 原因: (给出简要判断理由)\n ----\n 用户问题: {query}\n AI回答: {response}\n 参考上下文: {contexts}\n ) async def aevaluate( self, query: str, response: str, contexts: Optional[List[str]] None, **kwargs: Any, ) - EvaluationResult: prompt self._template.format( queryquery, responseresponse, contexts\n.join(contexts or []), ) output str(await self._llm.acomplete(prompt)) lines output.strip().split(\n) is_cited lines[0].replace(引用正确:, ).strip() 是 if lines else False feedback \n.join(lines[1:]).strip() if len(lines) 1 else output return EvaluationResult( queryquery, responseresponse, passingis_cited, score1.0 if is_cited else 0.0, feedbackfeedback, )写自定义评估器时最容易出错的地方是输出解析。大模型不一定会严格按照你的格式输出偶尔会在前面多一句好的下面我来评估或者把是/否写成是的。我建议在评估 prompt 里加上不要输出额外内容的约束同时在解析逻辑里做关键词容错比如包含是就判定为真。如果你的 judge 模型有 function calling 能力用它做结构化输出更靠谱LlamaIndex 也支持定义 Pydantic 对象做输出格式化这个进阶玩法后面可以单独写一篇。4. 案例分析知识问答系统评估实战4.1 案例背景与评估目标为了把这套流程讲透我用一个模拟场景来做完整演示。假设某团队在做一个内部产品问答助手知识库里有产品说明书和运维手册两类文档用户群体是内部客服他们需要快速查询产品功能、参数、故障排查步骤等信息。这个系统的目标很清晰回答必须完全来自知识库不能编造回答必须能直接解决客服的问题不能答非所问。基于这两个目标我选了两个评估器FaithfulnessEvaluator 用来抓编造回答RelevancyEvaluator 用来抓偏题回答。因为客服问题通常有一个标准答案可以参考所以我额外加了一个 CorrectnessEvaluator 来比对回答和标准答案的一致性。judge 模型我选了一个比线上生成模型更强的款temperature 设为 0确保裁判的标准稳定。生成回答的模型则保持线上配置不变因为评估的就是线上真实表现。4.2 构造评估数据集我构造了一个二十条的验证集刻意加入了五类问题正常事实型问题例如产品的最大并发连接数是多少多文档综合问题需要参考多篇文档才能答全干扰信息问题检索结果里混入了看似相关实则错误的内容模糊表述问题问题里用的术语和文档里的术语不完全一致知识库外问题文档里根本没有答案每一类都对应一种典型的线上翻车模式这样评估出来的结果才有区分度。之后每条问题跑一遍线上 RAG 链路拿到 response和 query、reference、contexts 一起拼成评估数据集。这一步里我会把 contexts 原样存下来因为后面分析忠实度问题时需要对照检索结果排查问题到底出在检索还是生成。4.3 评估结果解读与优化迭代跑完批量评估后我汇总出的结果大致如下为了方便展示我挑几条代表性的问题忠实度相关性正确性问题类型产品的最大并发连接数是多少5.05.05.0正常事实型宕机后如何恢复服务并做数据校验2.05.03.0多文档综合7x24小时运行的设备推荐5.05.04.0干扰信息服务器连接不上怎么办5.01.05.0模糊表述知识库外的问题A4.02.02.0知识库外最典型的失败案例是宕机后如何恢复服务并做数据校验。忠实度只有 2 分feedback 里 judge 明确写着一句回答中出现了上下文中不存在的步骤。我去翻了原始上下文发现检索模块只召回了一篇文档的恢复步骤另一篇讲数据校验的章节根本没有进入上下文。原因是我当时 top_k 设得偏小并且查询改写没有把数据校验这个隐含诉求扩展出来。另一个值得注意的案例是服务器连接不上怎么办。这个问题的本质是模糊文档里其实有多个章节对应不同的连接不上场景系统检索到了一个章节就直接生成了答案但从相关性判断来看回答没有覆盖用户可能真正的意图。这个问题靠调整检索参数解决不了需要在系统上加入澄清追问逻辑或者至少让 RAG 在不确定时主动说明有几种可能原因请确认具体场景。根据这些反馈我做了三轮优化一是调大 top_k让更多候选片段进上下文二是给检索前加了一道查询改写把用户问法映射到文档里更标准的术语三是把文档分块策略从固定长度改为按标题层级切分减少一个片段里混杂多个主题的情况。每轮优化后都重跑同一套评估数据集忠实度平均分从最初的 3.4 逐步拉到了 4.7这是因为评估提供了可对比的基线才让每一次改动都有了明确的验证依据——没有评估的话这三轮优化完全靠感觉根本分不清哪步有用哪步没用。5. 常见问题与排查技巧实录5.1 评估结果不稳定同一数据跑出不同分数这是最常遇到的问题尤其是在 judge 模型使用随机采样的时候。解决方案有三个一是把 judge 模型的 temperature 设成 0。严格来说即便有很多模型在 temperature0 的时候也不是完全确定性的但绝大多数情况下这已经足够稳定了。二是多次采样取平均或投票。如果评估成本允许可以对同一条样本跑三次取分数的中位数或者按照多数投票决定 passing。实测下来这个做法能明显洗掉单次采样的噪声。三是排查是不是上下文顺序导致的不稳定。有时候 judge 模型对上下文里片段的先后顺序敏感同样的片段换了个排列分数就变了。如果你的评估结果对顺序特别敏感说明 judge 模型的推理能力不够强建议换更强的模型。5.2 评估器与场景不匹配这个坑非常隐蔽而且特别容易出现在偷懒复用的时候。之前我把 CorrectnessEvaluator 用在一个开放型提问场景问题是你怎么看这个设计方案参考答案是我手写的一段分析。结果分数忽高忽低完全不可信因为参考答案本身是主观观点CorrectnessEvaluator 根本没法客观判断两个主观观点的一致性。后来我意识到评估器的选择必须和问题的确定性匹配事实型问题用 CorrectnessEvaluator约束型问题用 GuidelineEvaluator开放性生成问题用 SemanticSimilarityEvaluator 或者干脆人工抽样评估。没有万能的评估器每多用一个维度你得到的信息就多一层但误判的风险也对应增加。5.3 成本与速度的平衡评估是很烧钱的。每条样本跑三个评估器每个评估器调一次 judge 模型一百条样本就是三百次调用量大的时候账单唰唰涨。我现在的做法是先在二十到三十条的小样本集上快速跑定位到明确问题后再扩大到全量回归集。这个过程能省掉大量无效调用。速度也一样BatchEvalRunner 开并发能提速但并发开得太高会触发限流。还有一个偏方是把评估数据缓存下来。LlamaIndex 的评估结果可以序列化成 JSON 保存下次再跑同样的数据时直接读缓存不做重复调用。这样至少可以让回归测试变得便宜很多。5.4 版本兼容性踩坑记录LlamaIndex 的迭代速度很快API 变动也比较频繁这确实是很多用户头疼的地方。比如早期版本里评估器是通过from llama_index.evaluation import ...导入的后来核心评估逻辑迁移到了llama_index.core.evaluation连带一些方法签名也变了。如果你的项目里同时用了多个版本的 LlamaIndex 包很容易出现评估器导入路径查不到、或者evaluate_response和aevaluate混用后行为不一致的情况。我自己的建议是锁定版本、读对应版本的文档、升级后先跑一遍小样本回归。具体做法是把核心依赖写在 requirements.txt 里固定版本号。评估模块这种基础设施一旦跑通没有必要追新版本稳定才是第一位的。再补一个细节如果你用的是 OpenAI 兼容的接入方案注意确认 judge 模型支持你用的接口协议有些模型的/chat/completions和/completions接口行为差异很大很可能导致输出解析失败。另外有些本地模型的输出里喜欢附带解释性前缀比如我认为答案是...这种输出格式变化会在解析阶段直接搞崩评估器。遇到这种情况最好写一个输出清洗函数把答案部分截取出来再进入解析逻辑。5.5 上下文窗口限制评估 prompt 里如果塞入很长的 contexts比如多篇文档拼接很容易撑爆 judge 模型的上下文窗口。我的处理方式是对传入评估器的 contexts 做截断只保留每个片段的前几百个字符。这个截断会影响忠实度评估的准确度但考虑到评估本身关注的是信息点是否存在截断后依然能覆盖大部分情况。如果确实需要评估超长文档场景考虑换用更大上下文窗口的 judge 模型同时做好预算管理。在我实际使用中还有一个小技巧把评估结果结构化存成一个 JSONL 文件至少包含 query、response、contexts、score、passing、feedback、模型名称、评估时间这几个字段。迭代多了以后你手头就有了一个可以追溯的历史库哪天改坏了什么东西直接查历史对比就能知道是哪次改动引入的问题。这个习惯帮我省掉了大量排查时间算是评估模块落地里最被低估的一个操作。做评估这件事不需要一开始就追求全面。先挑一个 FaithfulnessEvaluator 跑起来哪怕只有十来个测试问题只要它能在你改动系统时给出稳定的升降趋势就比什么都强了。之后再逐步加相关性、正确性、自定义规则让评估体系随着项目一起长出来。成熟的 RAG 系统从来不是一次搭好的而是靠一次次可量化的反馈慢慢磨出来的。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询