RAG答得像,不代表做对了:LangSmith把“检索质量幻觉”照了原形
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.73Context Recall:0.46 → 0.81Faithfulness:0.58 → 0.89
这里我更想强调的,不是某个数字涨了多少,而是你终于知道该改哪一环。
以前你靠人工抽测,只能说“这次好像好了点”;
现在你能看到:是检索噪音太多,还是证据漏了,还是模型在编。
用人工抽测代替系统性评估,本质上是在给运气打分,不是在给系统打分。
---
结尾:第一步别再调参,先建评估
如果你现在正在做 RAG,我建议你今天就做三件事:
1. 先挑 20~50 条最常见的问题,做成 golden dataset
2. 接上 LangSmith,把检索链路完整打出来
3. 用 RAGAS 跑 Context Precision、Context Recall、Faithfulness
如果你想把这套流程跑得更快,8848AI 也可以直接拿来做评估阶段的模型调用:注册只要用户名+密码,不需要邮箱验证,平台内置 AI 对话功能,直接能用。新用户注册即送体验token。 国产模型(如 Deepseek、千问)完全免费,没有月租、没有订阅,按量付费,地址是 api.884819.xyz。
三个指标解决了“检索到没有、用了没用”的问题,但还有一个更深的坑我们今天没聊:embedding 模型本身选错了,再好的指标体系也救不了你。
下一篇:《同一份文档,换了 embedding 模型,Context Recall 从 0.41 涨到 0.79——我做了 6 组横向对比》本文由8848AI原创,转载请注明出处。
#RAG #LangSmith #RAGAS #AI工程 #人工智能 #8848AI #AI评估