2026年6月25日 周四晚上19:30,报名腾讯会议了解“如何构建自进化的动态知识库(Brain)”(限30人)
免费POC, 零成本试错
FDE知识库

FDE知识库

学习大模型的前沿技术与行业落地应用


我要投稿

使用 LangSmith 进行 RAG 评估:构建生产级 RAG 系统的 AI 开发者指南

发布日期:2026-06-21 11:17:07 浏览次数: 1513
作者:坍缩的奇点

微信搜一搜,关注“坍缩的奇点”

推荐语

想构建生产级RAG系统?评估层是关键,它能帮你发现检索失败和LLM幻觉。本文通过真实代码,教你如何用LangSmith建立完整的评估体系,告别“看起来不错”的陷阱。

核心内容:
1. RAG评估为何比传统ML更复杂
2. 覆盖Retriever和Generator的四个关键评估指标
3. 利用诊断矩阵定位系统根本问题

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

 

img
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。

无论你使用哪种工具,本文中的方法论都适用。

整个流程包含三个步骤:

  1. 1. 构建一个包含问题以及可选参考答案的数据集
  2. 2. 使用该数据集运行你的 RAG 应用
  3. 3. 使用 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 Client

client = 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 ChatOpenAI

class
 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=0with_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 版本

否则你无法解释为什么评分发生变化。

结尾

大多数 RAG 评估问题并不是工具问题。

而是可见性问题。

团队在没有任何衡量指标的情况下上线,然后花费数周时间,一条 trace 一条 trace 地调试生产环境中的问题。

这里介绍的流程并不复杂:

四个 evaluator 函数,一个数据集,以及一次 client.evaluate() 调用。

真正困难的是系统性地读取结果,并根据每个指标告诉你的具体组件问题采取行动。

上面的诊断矩阵(Diagnostic Matrix)就是实际使用中的快捷方式。

当某个分数下降时,它会告诉你应该先检查哪里,而不是盲目修改。

尽早建立评估层。

没有评估历史的 RAG 系统调试,本质上是在用更昂贵的方式重复面对同一个问题。

延伸阅读

「AI秘籍」系列课程:

人工智能应用数学基础

人工智能Python基础

人工智能基础核心知识

人工智能BI核心知识

人工智能CV核心知识

智慧物流 订单配送规划海报
智慧物流 订单配送规划海报

 


53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询