RAG评估秘籍:用真实代码与诚实权衡打造顶级AI应用
本文深入探讨了如何通过实际代码和诚实权衡来评估RAG(检索增强生成)流程中的关键因素。作者以一个RAG应用上线后出现答案错误为例,指出缺乏评估层、可见性和预警的问题。文章详细阐述了RAG评估的三个难点:输出开放式、存在两种失败模式和幻觉不可见,并提出了无需参考答案的四种评估指标:正确性、相关性、真实性依据和检索相关性。作者建议使用LangSmith或RAGAS等工具,通过构建评估数据集和评估器函数,持续追踪和改进RAG应用。最后,文章强调了评估的可见性和系统性,以及结合自动化评估和人类审核的重要性。

img
如何通过真实的代码和诚实的权衡来衡量 RAG 流程中真正重要的因素。
你构建了一个 RAG 应用。
它能够检索文档,将它们发送给 LLM,然后返回答案。
你手动测试了几个问题,效果看起来不错。
于是你上线了。
三周之后,用户开始反馈答案错误。
你深入排查,发现 Retriever 在某些查询类型下一直获取了不相关的 chunks。
LLM 则一直在生成一些听起来合理、但实际上没有任何检索上下文支持的幻觉信息。
没有评估层(evaluation layer)。
没有可见性(visibility)。
没有预警。
我知道评估很无聊,但它正是区分顶级 AI 工程师和只是在构建原型的人之间的关键因素。
本指南将通过一个包含代码的具体工作流程,介绍如何解决这个问题。
为什么 RAG 评估比看起来更困难
评估一个标准的 ML 分类器是比较直接的。
你有标签(labels)、预测结果(predictions),以及像 accuracy 或 F1 这样的指标。
真实答案(ground truth)是明确且固定的。
RAG 评估更加复杂,主要有三个原因:
输出是开放式的。
对于大多数问题,不存在唯一正确答案。两个不同的正确答案,在字符串形式上可能完全不同,因此简单的字符串比较会立即失效。
存在两种失败模式,而不是一种。
你的 RAG 系统可能在检索阶段失败(获取了错误的文档),也可能在生成阶段失败(即使获取了正确文档,仍然生成错误答案)。
你需要分别衡量这两个部分,否则你无法判断应该修复哪个组件。
没有参考依据时,幻觉是不可见的。
LLM 可以生成一个自信、表达良好的答案,但这个答案可能完全违背检索到的文档。
如果没有明确的 groundedness(基于事实依据程度)检查,这种失败是无法被发现的。
传统指标,例如 BLEU 和 ROUGE,是为机器翻译设计的。
它们衡量的是表层字符串重叠程度。
一个语义正确、但使用了不同表达方式的 RAG 答案,如果与参考答案的措辞不同,也会得到较低的评分。
它们并不是适合这个任务的工具。
实际需要评估什么
一个 RAG 系统包含两个组件:Retriever 和 Generator。
一个完整的评估框架需要覆盖这两个部分。
可以把每一次评估看作一个元组:评估的对象是什么,以及它与什么进行比较。

四个指标中,有三个完全不需要参考答案。
这一点在实际应用中非常重要。
为大型数据集收集真实答案(ground truth)成本很高。
那些只需要问题、检索到的 chunks,以及生成答案的评估方式,可以持续运行在生产流量上,而不需要任何人工标注。
可视化架构:每个指标位于哪里
理解每个指标应该应用于 pipeline 中的哪个位置,是理解整个体系的关键思维模型。
下面是 RAG pipeline,以及每个 evaluator(评估器)触发的位置:

诊断矩阵
当评估分数返回后,在修改任何内容之前,使用这个矩阵来定位根本原因:
LangSmith 评估流程
LangSmith 是完成这项工作的一个工具,但不是唯一选择。
RAGAS 也实现了相同概念的指标(faithfulness、answer relevance、context precision、context recall),只是使用了不同的 API。
无论你使用哪种工具,本文中的方法论都适用。
整个流程包含三个步骤:
-
- 构建一个包含问题以及可选参考答案的数据集
-
- 使用该数据集运行你的 RAG 应用
-
- 使用 evaluator 函数对每个输出进行评分
每当你对应用进行修改时,都应该执行评估。
在上线之前运行它。
针对生产环境中的 traces 运行它。
每次修改 prompt 后运行它。
评估实践本身就是这个循环,而不是某一次单独的执行。
步骤一:备你的 RAG 应用
本文不是关于如何构建 RAG 应用的。
它假设你已经拥有一个 RAG 应用。
对于评估来说,重要的是你的应用需要满足两个契约(contracts)。
契约 1:它必须支持追踪(traceable)。
添加 LangSmith 的 @traceable(),这样每一次调用都会被记录,包括完整的 prompt、检索到的文档,以及生成的答案。
契约 2:它必须在返回答案的同时返回文档。
四个评估器(evaluators)中,有三个需要的是检索到的 chunks,而不仅仅是最终答案。
from langsmith import traceable @traceable() def rag_bot(question: str) -> dict: docs = retriever.invoke(question) answer = llm.invoke(build_prompt(question, docs)) # Return BOTH - evaluators need the documents return {"answer": answer, "documents": docs}
这就是唯一的配置要求。
Retriever、向量存储(vector store)以及 LLM 的具体实现细节,评估器(evaluators)并不关心。
步骤二:构建评估数据集
你的评估效果取决于你的数据集质量。
一个最小的数据条目,需要将一个问题与一个参考答案(reference answer)配对:
from langsmith import Clientclient = Client() examples = [ { "inputs": {"question": "How does the ReAct agent use self-reflection?"}, "outputs": {"answer": "ReAct integrates reasoning and acting, using tools and then observing the outputs to reason about next steps."}, }, # Add more examples... ] dataset = client.create_dataset("RAG Evaluation Dataset") client.create_examples(dataset_id=dataset.id, examples=examples)
inputs 这个 key 保存的是你的 RAG 函数所需要的输入内容,在这里就是一个问题。
outputs 这个 key 保存的是你手动编写的参考答案。
在评估时,LangSmith 会将 inputs 传递给你的函数,然后将函数返回结果与 outputs(你的参考答案)一起传递给 correctness evaluator(正确性评估器),这样它就可以对两者进行比较。
一些看起来简单,但实际上非常重要的事项:
- • 使用真实用户查询,而不是你自己编写的问题。
自己编写的问题通常更加干净、结构完整。而真实查询会暴露歧义、拼写错误,以及你的 Retriever 难以处理的意图不匹配问题。 - • 至少准备 20–50 个示例。
少于 20 个时,一次异常运行就可能让整体评分产生偏差,而这种偏差在统计意义上并不可靠。 - • 参考答案只用于正确性评估(correctness)。
另外三个评估器不需要 ground truth(真实答案)。你可以持续在生产环境中的实时 traces 上运行它们。
步骤三:四个评估器
每个评估器都遵循相同的模式:
一个 TypedDict schema,一个评分 prompt,以及一个接收 inputs/outputs 并返回分数的函数。
其中的关键设计决策,对所有评估器都同样适用。
所有 grader LLM 都使用 temperature=0。
确定性的评分(Deterministic scoring)是不可妥协的。
同一个答案必须在每次运行中获得相同的分数,否则你的实验比较就失去了意义。
使用结构化输出(structured output)。
它会强制模型直接返回符合类型定义的 schema。
不需要字符串解析,不需要正则表达式,也不会因为模型输出了“是的,看起来正确”(“Yes, it looks correct”)而不是一个布尔值,导致评估失败。
将 explanation 字段放在 score 字段之前。
这会迫使模型在给出最终判断之前先进行推理。
在答案之前进行思考,有助于提升评判模型(judge)的准确性。
正确性:响应 vs 真实答案
这是唯一一个需要参考答案(reference answer)的评估器。
其他所有评估器都可以在没有标注数据(labeled data)的情况下运行。
from typing_extensions import Annotated, TypedDict from langchain_openai import ChatOpenAIclass CorrectnessGrade(TypedDict): explanation: Annotated[str, ..., "Reasoning for the score"] correct: Annotated[bool, ..., "True if factually accurate vs ground truth"] correctness_instructions = """You are grading a student's answer against a ground truth. Grade on factual accuracy only. Extra correct information is fine. Conflicting statements are not. Explain your reasoning step by step before giving a final verdict.""" grader_llm = ChatOpenAI(model="gpt-4.1", temperature=0).with_structured_output( CorrectnessGrade, method="json_schema", strict=True ) def correctness(inputs: dict, outputs: dict, reference_outputs: dict) -> bool: prompt = f"""QUESTION: {inputs['question']} GROUND TRUTH: {reference_outputs['answer']} STUDENT ANSWER: {outputs['answer']}""" grade = grader_llm.invoke([ {"role": "system", "content": correctness_instructions}, {"role": "user", "content": prompt} ]) return grade["correct"]
函数签名(function signature)是 LangSmith 判断应该传入哪些数据的依据。
如果函数接收 reference_outputs,那么 LangSmith 会从你的数据集中传入真实答案(ground truth)。
如果函数只接收 inputs 和 outputs,那么 LangSmith 会完全跳过参考答案。
这就是为什么另外三个不需要参考答案的评估器,可以知道自己不需要标注数据(labelled data)。
另外三个评估器
相关性(Relevance)、真实性依据(Groundedness)以及检索相关性(Retrieval Relevance)都遵循相同的结构。
不同之处在于,每个评估器接收的输入不同,以及它向评判模型(judge)提出的问题不同:
# --- ANSWER RELEVANCE: Does the response address the question? --- # Inputs: question + answer (no reference needed) def relevance(inputs: dict, outputs: dict) -> bool: prompt = f"QUESTION: {inputs['question']}\nANSWER: {outputs['answer']}" # Judge asks: does this answer actually address what was asked? grade = relevance_llm.invoke([ {"role": "system", "content": relevance_instructions}, {"role": "user", "content": prompt} ]) return grade["relevant"] # --- GROUNDEDNESS: Is the answer supported by retrieved documents? --- # Inputs: retrieved documents + answer (no reference needed) def groundedness(inputs: dict, outputs: dict) -> bool: docs = "\n\n".join(doc.page_content for doc in outputs["documents"]) prompt = f"FACTS:\n{docs}\n\nANSWER: {outputs['answer']}" # Judge asks: is every claim in the answer present in the documents? grade = grounded_llm.invoke([ {"role": "system", "content": grounded_instructions}, {"role": "user", "content": prompt} ]) return grade["grounded"] # --- RETRIEVAL RELEVANCE: Did the retriever fetch useful chunks? --- # Inputs: question + retrieved documents (no reference needed) def retrieval_relevance(inputs: dict, outputs: dict) -> bool: docs = "\n\n".join(doc.page_content for doc in outputs["documents"]) prompt = f"QUESTION: {inputs['question']}\n\nFACTS:\n{docs}" # Judge asks: are these documents relevant to the question at all? grade = retrieval_relevance_llm.invoke([ {"role": "system", "content": retrieval_relevance_instructions}, {"role": "user", "content": prompt} ]) return grade["relevant"]
注意,groundedness 和 retrieval relevance 都会通过:
"\n\n".join(doc.page_content for doc in outputs["documents"])
来提取文档内容。
这也是为什么你的 RAG 函数必须返回文档的重要原因。
如果没有返回这些文档,这两个评估器就没有任何内容可以处理,并且会在运行时失败。
每个 grader LLM 都使用与上面的 grader_llm 相同的配置:
temperature=0、with_structured_output,以及一个要求模型先进行推理再给出评分的 prompt。
每个评估器的指令都遵循相同的模板,只是在检查的内容上有所不同。
如果你想进行调整,可以在 LangSmith 文档中找到完整的 prompt 模板。
步骤 4:运行评估(Running the Evaluation)
将目标函数(target function)和评估器(evaluators)连接起来:
def target(inputs: dict) -> dict: return rag_bot(inputs["question"]) experiment_results = client.evaluate( target, data=dataset_name, evaluators=[correctness, groundedness, relevance, retrieval_relevance], experiment_prefix="rag-evaluation-v1", metadata={"version": "gpt-4.1, chunk_size=250"}, )
运行这个流程时,LangSmith 会针对你的数据集中的每个示例调用一次 target。
对于每一次调用,它会记录 inputs、outputs,然后将这两者传递给列表中的每一个 evaluator。
结果会以表格形式显示在 LangSmith UI 中:
每个示例对应一行,每个 evaluator 对应一列,其中包含通过/失败评分,以及 judge 生成的解释。
metadata 字段并不是装饰性的。
每当你修改某些内容(模型、prompt、chunk size)时,都应该给新的运行添加对应的标签,说明发生了什么变化。
否则,两周之后,你可能会面对一堆实验运行记录,却无法判断到底是什么因素导致评分上升或下降。
工程师常犯的错误
使用开发阶段相同的问题进行评估。
你已经在这些问题上调试过 prompt。
当然它们会得到很好的评分。
应该使用一个独立保留的测试集(held-out test set)。
只运行一次评估,并把结果当作永久有效。
评估结果只对你测试过的配置有效。
如果你修改了模型、prompt、chunk size 或 embedding model,那么之前的评分就不再适用。
使用同一个模型进行生成和评估。
如果 GPT-4 生成答案,同时 GPT-4 负责评估,那么评估器会倾向于接受符合它自身生成风格的答案。
应该使用不同的模型,或者为评估器配置不同的 temperature。
完全跳过检索评估。
大多数团队只评估最终答案。
当质量下降时,他们会修改 prompt。
但有时候,真正的问题一直都在 retriever 上,而修改 prompt 根本不会产生任何效果。
认为布尔值通过/失败已经足够。
True/False 分数只能告诉你某个结果是否通过。
每个 evaluator 中的 explanation 字段会告诉你为什么。
记录并检查这些解释,尤其是失败案例。
推理过程中的模式,通常比单纯查看总体评分,更快地暴露系统性问题。
自动化评估的优缺点
自动化的 LLM-as-judge 评估并不完美。
了解它适用的场景以及不适用的场景,与了解如何实现它同样重要。
优点:
- • 可以在没有人工成本的情况下扩展到数千个示例
- • 当 temperature 设置为 0 时,可以在不同运行之间保持一致的评分标准
- • 可以持续运行在生产环境的 traces 上,而无需人工审核
- • 足够快速,可以在 CI/CD pipeline 中作为部署门禁使用
缺点:
- • LLM judge 可能会与人工评分者产生分歧,尤其是在复杂、细微差异的答案上
- • 评估器质量高度依赖评估 prompt 的质量
- • 存在与被评估模型相同的失败模式(幻觉、偏差、不一致)
- • Correctness 评估仍然需要人工编写的参考答案来提供依据
正确的评估体系应该结合:
用于规模化评估的自动评分,
以及定期的人类审核,
从而发现系统性的评估器错误。
其他值得了解的框架
LangSmith 并不是这里唯一的选择。
本文中的四个指标与具体框架无关(framework-agnostic)。
RAGAS 使用简洁的 Python API 实现了 faithfulness、answer relevance、context precision 和 context recall。
它不依赖 LangChain。
如果你的技术栈不属于 LangChain 生态,RAGAS 通常会是更简单的集成选择。
DeepEval 覆盖了比 RAG 更广泛的指标:
- • 幻觉检测(hallucination detection)
- • 毒性检测(toxicity)
- • 摘要质量(summarization quality)
当你需要从同一个 pipeline 中评估多种类型的输出时,它会很有用。
Arize Phoenix 更关注模型版本之间的可观测性(observability)和漂移检测(drift detection)。
相比离线评估工具,它更适合作为生产环境监控层。
先学习方法论。
然后选择适合你技术栈的工具。
实用最佳实践
在构建应用之前,先构建评估数据集。
真实用户问题会迫使你提前考虑边界情况,并且从一开始就带来更好的设计决策。
记录解释(explanation),而不仅仅是分数。
这里的每个评估器都会在评分之前生成推理过程。
保存它。
解释内容能够比整体评分更快地暴露系统性的失败模式。
在 CI 中运行评估。
将评估结果作为部署门禁(deployment gate)。
如果修改 prompt 或模型之后,correctness 下降到阈值以下,就阻止部署。
这就是在代码评审阶段发现回归问题,与在生产环境发现问题之间的区别。
在报告中分离检索指标和生成指标。
单一的综合评分会隐藏诊断信息。
应该长期独立追踪四个指标。
对所有内容进行版本管理。
每个实验都应该标记:
- • 使用的模型
- • chunk size
- • overlap
- • embedding model
- • prompt 版本
否则你无法解释为什么评分发生变化。
01
什么是AI大模型应用开发工程师?
如果说AI大模型是蕴藏着巨大能量的“后台超级能力”,那么AI大模型应用开发工程师就是将这种能量转化为实用工具的执行者。
AI大模型应用开发工程师是基于AI大模型,设计开发落地业务的应用工程师。
这个职业的核心价值,在于打破技术与用户之间的壁垒,把普通人难以理解的算法逻辑、模型参数,转化为人人都能轻松操作的产品形态。
无论是日常写作时用到的AI文案生成器、修图软件里的智能美化功能,还是办公场景中的自动记账工具、会议记录用的语音转文字APP,这些看似简单的应用背后,都是应用开发工程师在默默搭建技术与需求之间的桥梁。
他们不追求创造全新的大模型,而是专注于让已有的大模型“听懂”业务需求,“学会”解决具体问题,最终形成可落地、可使用的产品。
CSDN粉丝独家福利
给大家整理了一份AI大模型全套学习资料,这份完整版的 AI 大模型学习资料已经上传CSDN,朋友们如果需要可以扫描下方二维码&点击下方CSDN官方认证链接免费领取 【保证100%免费】

02
AI大模型应用开发工程师的核心职责
需求分析与拆解是工作的起点,也是确保开发不偏离方向的关键。
应用开发工程师需要直接对接业务方,深入理解其核心诉求——不仅要明确“要做什么”,更要厘清“为什么要做”以及“做到什么程度算合格”。
在此基础上,他们会将模糊的业务需求拆解为具体的技术任务,明确每个环节的执行标准,并评估技术实现的可行性,同时定义清晰的核心指标,为后续开发、测试提供依据。
这一步就像建筑前的图纸设计,若出现偏差,后续所有工作都可能白费。
技术选型与适配是衔接需求与开发的核心环节。
工程师需要根据业务场景的特点,选择合适的基础大模型、开发框架和工具——不同的业务对模型的响应速度、精度、成本要求不同,选型的合理性直接影响最终产品的表现。
同时,他们还要对行业相关数据进行预处理,通过提示词工程优化模型输出,或在必要时进行轻量化微调,让基础模型更好地适配具体业务。
此外,设计合理的上下文管理规则确保模型理解连贯需求,建立敏感信息过滤机制保障数据安全,也是这一环节的重要内容。
应用开发与对接则是将方案转化为产品的实操阶段。
工程师会利用选定的开发框架构建应用的核心功能,同时联动各类外部系统——比如将AI模型与企业现有的客户管理系统、数据存储系统打通,确保数据流转顺畅。
在这一过程中,他们还需要配合设计团队打磨前端交互界面,让技术功能以简洁易懂的方式呈现给用户,实现从技术方案到产品形态的转化。
测试与优化是保障产品质量的关键步骤。
工程师会开展全面的功能测试,找出并修复开发过程中出现的漏洞,同时针对模型的响应速度、稳定性等性能指标进行优化。
安全合规性也是测试的重点,需要确保应用符合数据保护、隐私安全等相关规定。
此外,他们还会收集用户反馈,通过调整模型参数、优化提示词等方式持续提升产品体验,让应用更贴合用户实际使用需求。
部署运维与迭代则贯穿产品的整个生命周期。
工程师会通过云服务器或私有服务器将应用部署上线,并实时监控运行状态,及时处理突发故障,确保应用稳定运行。
随着业务需求的变化,他们还需要对应用功能进行迭代更新,同时编写完善的开发文档和使用手册,为后续的维护和交接提供支持。
03
薪资情况与职业价值
市场对这一职业的高度认可,直接体现在薪资待遇上。
据猎聘最新在招岗位数据显示,AI大模型应用开发工程师的月薪最高可达60k。

在AI技术加速落地的当下,这种“技术+业务”的复合型能力尤为稀缺,让该职业成为当下极具吸引力的就业选择。
AI大模型应用开发工程师是AI技术落地的关键桥梁。
他们用专业能力将抽象的技术转化为具体的产品,让大模型的价值真正渗透到各行各业。
随着AI场景化应用的不断深化,这一职业的重要性将更加凸显,也必将吸引更多人才投身其中,推动AI技术更好地服务于社会发展。
CSDN粉丝独家福利
给大家整理了一份AI大模型全套学习资料,这份完整版的 AI 大模型学习资料已经上传CSDN,朋友们如果需要可以扫描下方二维码&点击下方CSDN官方认证链接免费领取 【保证100%免费】

更多推荐


所有评论(0)