RAG答得像,不代表做对了:LangSmith把“检索质量幻觉”照了原形

我做 RAG 的前六个月,状态其实挺像一个“自我感觉良好”的学生。

分块切好了,embedding 调了,top-k 也试过几轮;自己拿几条熟悉的问题一测,答案顺得像教科书,甚至还能顺手补两句解释。那段时间我几乎已经默认:这套 RAG 应该是稳了。

直到真实用户开始问。

他们的问题并不刁钻,甚至很多都只是“换个说法问同一件事”,但模型给出的答案开始飘:有时答非所问,有时引用了不该引用的内容,有时明明文档里写得很清楚,它却像没看见。更尴尬的是——我自己回头测,还是没问题。

后来我才意识到,这不是系统突然变差,而是我一直在做一种很常见的事:主场测试偏差。你只拿自己最熟、最容易命中的问题去打分,当然容易得出“还不错”的结论。可一旦换成真实用户的提问方式,RAG 就会露馅。

直到接上 LangSmith,我才第一次看清:问题不是“模型会不会说”,而是检索链路到底有没有把对的材料送到模型面前

这也是 RAG 最容易被误解的地方:它看起来像一个回答系统,实际上首先应该是一个检索系统。

---

第一章:「感觉挺好用」的六个月

回头看,那六个月的我,其实一直在用“输出是否通顺”代替“链路是否正确”。

我会看答案有没有跑题、语气是否自然、是不是能把几段知识拼起来,但很少去问:

  • 检索回来的 chunk 里,真正相关的有几个?
  • 该出现的关键信息,真的被捞回来了吗?
  • 模型最后的回答,是基于文档,还是在“补全想象”?

这就是为什么很多 RAG 系统一开始看着都很像样:它不是不会答,而是答得像。

---

第二章:接上 LangSmith 的第一眼

如果只能用一句话定义 LangSmith,我会说:

它不是 RAG 工具,它是 RAG 链路的 X 光机。

以前你看到的是最终答案;接上 LangSmith 以后,你会第一次看到“答案是怎么长出来的”——检索到了哪些 chunk、每个 chunk 的来源是什么、模型最终引用了哪几段、哪些内容其实只是被喂进去了但没有被真正使用。

下面这类 Trace,基本就是“真相现场”:

LangSmith Trace截图:左侧是检索到的 chunks,右侧高亮模型实际引用的内容

你会很直观地发现两种经典失效:

  • 检索回来了 5 个 chunk,但 LLM 实际只用了第 1 个

其余 4 个不是“补充信息”,而是噪音。它们会挤占上下文窗口,让模型更难抓住重点。

  • 有些问题的关键证据压根没被检索回来

这时模型看起来依然能答,只是它是在拿残缺材料拼完整结论。

这一刻最重要的顿悟不是“模型不行”,而是:

可观测性本身就是基础设施。
你看不见链路,就永远只能猜。

---

第三章:真正决定 RAG 质量的 3 个指标

如果你想把 RAG 从“感觉还行”变成“能持续改进”,最先该盯的不是大模型参数,而是这三个指标。

| 指标 | 直觉理解 | 数学定义(简化表达) | 低分时会发生什么 | | Context Precision | 检索回来的内容里,有多少真相关 | 相关chunk数 / 检索chunk总数 | 喂太多噪音,模型开始“捡错重点” | | Context Recall | 该拿到的信息,有没有都拿到 | 已覆盖关键信息 / 所需关键信息总数 | 证据不全,模型只能拿残缺材料补答案 | | Answer Faithfulness | 回答是不是老老实实基于检索结果 | 被检索内容支持的答案断言数 / 总断言数 | 答案流畅但不忠实,开始自由发挥 |

1)Context Precision:你喂进去的是不是“有效材料”

精准率低,意味着你检索回来的 chunk 里混了太多不相关内容。

模型不是不会用信息,而是你给它的垃圾太多,它只能自己筛。筛不干净时,它会把一些不该被强调的内容当成线索,最后答偏。

2)Context Recall:该找回来的证据有没有找齐

召回率低,意味着真正决定答案的关键事实没进上下文。

这时候模型最危险,因为它会用一种很像“合理推理”的方式,把缺口补平。你看上去只差一点点,实际上可能差的是结论本身。

3)Answer Faithfulness:模型有没有“编”

这是最隐蔽的失效模式。

答案可以很流畅、很有条理、甚至像在引用文档,但如果这些内容没有被上下文支持,那就是典型的“说得对,但不是从你的资料里说出来的”。

---

第四章:怎么测这三个指标,才不是在赌运气

我的建议很简单:先建一个小型 golden dataset,再上评估管道。

别一上来就想着全量自动化。20~50 条高质量 Q&A 就够你先看出问题:

  • 哪类问题容易漏检索
  • 哪类问题容易引入噪音
  • 哪类问题最容易“答得像但不忠实”

下面是一个最小可用的样例结构:

| 问题 | 标准答案 | 标注说明 | | 这个功能支持哪些权限? | 只支持 A、B 两类权限 | 重点检查召回 | | 如何重置密码? | 需要先验证邮箱,再发起重置 | 重点检查忠实度 | | 订单取消后多久到账? | 3 个工作日内原路退回 | 重点检查精准率 | | 导出报表失败怎么办? | 优先看权限、再看字段格式 | 重点检查是否检到关键证据 | | 这个接口是否支持批量请求? | 支持,但有上限 | 重点检查回答是否自由发挥 |

下面这段代码可以直接作为评估骨架:LangSmith 负责看链路,RAGAS 负责给指标,OpenAI-compatible endpoint 则负责 judge。

import os

from datasets import Dataset

from ragas import evaluate

from ragas.metrics import context_precision, context_recall, faithfulness

from langchain_openai import ChatOpenAI, OpenAIEmbeddings

from openai import OpenAI

LangSmith tracing

os.environ["LANGCHAIN_TRACING_V2"] = "true"

os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-key"

os.environ["LANGCHAIN_PROJECT"] = "rag-eval-demo"

OpenAI-compatible endpoint: judge model / embeddings

client = OpenAI(

api_key="your-key",

base_url="https://api.884819.xyz/v1"

)

llm = ChatOpenAI(

model="gpt-4o-mini",

api_key="your-key",

base_url="https://api.884819.xyz/v1"

)

embeddings = OpenAIEmbeddings(

api_key="your-key",

base_url="https://api.884819.xyz/v1"

)

data = [

{

"question": "这个功能支持哪些权限?",

"answer": "支持 A 和 B 两类权限。",

"contexts": ["文档写明:功能仅支持 A、B 权限。", "无关说明:界面颜色可配置。"],

"ground_truth": "只支持 A、B 两类权限。",

"ground_truth_contexts": ["文档写明:功能仅支持 A、B 权限。"]

},

{

"question": "如何重置密码?",

"answer": "先验证邮箱,再发起重置。",

"contexts": ["重置流程:先验证邮箱,再点击重置。"],

"ground_truth": "先验证邮箱,再发起重置。",

"ground_truth_contexts": ["重置流程:先验证邮箱,再点击重置。"]

}

]

dataset = Dataset.from_list(data)

result = evaluate(

dataset,

metrics=[context_precision, context_recall, faithfulness],

llm=llm,

embeddings=embeddings

)

print(result.to_pandas()[["context_precision", "context_recall", "faithfulness"]])

如果你不想为了跑评估单独申请 OpenAI API,这个 endpoint 兼容同样的调用格式,切换成本基本为零。

你甚至可以把它当成评估阶段的“临时 judge”,先把系统跑通,再决定后面要不要换更强的模型。

一个小但关键的原则

没有标准答案,一切评估都是空谈。

很多团队的 RAG 问题,不是“没指标”,而是“根本没有可复用的测试集”。

你今天手工问十个问题,明天换一批问题,结论就漂了。只有把高频问题沉淀成 golden dataset,评估才真的开始工作。

---

第五章:修完指标后,系统真正变了什么

我后来做的优化并不玄学,基本就是三板斧:

  • 调 chunk 粒度:让单个 chunk 不要装太多东西,减少噪音
  • 加 reranker:先粗召回,再精排,把真正相关的片段往前推
  • top-k:不是越大越好,能进上下文窗口的不一定都是好材料

改完之后,最明显的变化不是“答案更会说了”,而是答案更少乱说了

以一轮小规模评估为例,指标会从这种状态变成更稳的状态:

  • Context Precision:0.41 → 0.73
  • Context Recall:0.46 → 0.81
  • Faithfulness:0.58 → 0.89

这里我更想强调的,不是某个数字涨了多少,而是你终于知道该改哪一环

以前你靠人工抽测,只能说“这次好像好了点”;

现在你能看到:是检索噪音太多,还是证据漏了,还是模型在编。

用人工抽测代替系统性评估,本质上是在给运气打分,不是在给系统打分。

---

结尾:第一步别再调参,先建评估

如果你现在正在做 RAG,我建议你今天就做三件事:

1. 先挑 20~50 条最常见的问题,做成 golden dataset

2. 接上 LangSmith,把检索链路完整打出来

3. 用 RAGASContext PrecisionContext RecallFaithfulness

新建 RAG 的第一步,不是调参数,是建评估管道。

如果你想把这套流程跑得更快,8848AI 也可以直接拿来做评估阶段的模型调用:注册只要用户名+密码,不需要邮箱验证,平台内置 AI 对话功能,直接能用。新用户注册即送体验token。 国产模型(如 Deepseek、千问)完全免费,没有月租、没有订阅,按量付费,地址是 api.884819.xyz

三个指标解决了“检索到没有、用了没用”的问题,但还有一个更深的坑我们今天没聊:embedding 模型本身选错了,再好的指标体系也救不了你。
下一篇:《同一份文档,换了 embedding 模型,Context Recall 从 0.41 涨到 0.79——我做了 6 组横向对比》
本文由8848AI原创,转载请注明出处。

#RAG #LangSmith #RAGAS #AI工程 #人工智能 #8848AI #AI评估