site logo

Marico's space

你的LLM追踪全绿,为什么RAG答案还是错的?

AI技术与应用 2026-09-11 17:34:53 12

最近给项目上了LLM(大型语言模型)可观测性,仪表盘全绿,延迟正常,token消耗在预算内。结果用户反馈AI客服的回答过时了——产品功能早就改了,AI还在一本正经地引用旧文档。

模型调用成功了,每个指标都漂亮。但答案错了整整六个月。

这就是以模型为中心的可观测性的盲点:它只能告诉你最终传给模型的上下文是什么,无法告诉你系统搜索的是不是对的关键词、有没有漏掉新文档、为什么选了这个结果而不是那个。

对于RAG(检索增强生成)应用和联网Agent(智能体)来说,需要观察的核心单元不是模型调用,而是完整的证据链路。

模型调用成功,不代表请求成功

一个典型的LLM trace(追踪记录)会记录prompt、响应内容、模型名称、token消耗、延迟、错误信息,运气好的话再加个工具调用。这对诊断慢请求、格式错误的输入、意外烧钱的情况很有用。

但它没法告诉你模型拿到的事实对不对。

在检索类应用中,最终的prompt是由上游系统拼装出来的。这个系统可能做了:查询改写、选择搜索provider(提供商)、应用时间或领域过滤器、抓取页面、提取文本、去重、重排序、选择段落塞进context window(上下文窗口)。

模型可以完全按照指令执行,但只要上游决策出了错,答案就会跑偏。

当前的OpenTelemetry生成式AI语义约定把向量数据库或搜索系统的检索单独作为一个span(追踪片段)来对待,里面包含了数据源、top-k、检索到的文档ID、分数、有效检索查询等概念。

但这些约定目前标记为开发中,而且像查询文本和返回文档这类敏感字段是可选的。它们作为通用词汇很有用,但不应该被当成现成的内部schema(模式)。

LangSmith的retriever tracing也是类似思路,把检索当成独立的run(运行单元)来处理,附加文档元数据比如源URL、chunk ID、分数。

关键问题不在于你用哪个追踪平台,而在于当答案出错时,你的trace能解释多少。

一次搜索调用背后藏着整条证据流水线

应用代码可能把网页检索封装成一次工具调用。但实际上它更像这样:

问题 → 查询改写 → 搜索 → 页面抓取 → 提取 → 去重 → 重排序 → 证据选择 → 回答

每个环节都有可能出问题。

查询改写可能把重要的日期或产品限定词搞丢了。搜索可能返回看起来相关但已经过时的页面。提取可能跳过了包含答案的那段话。好几个URL可能引用同一篇转载文章,制造出多个独立来源的假象。

重排序模型可能更偏好语义相似度而不是时效性。然后上下文构建器为了不爆token budget(token预算),把最相关的那段passage(段落)给丢掉了。

"搜索成功完成"这句话基本等于什么都没说。

有意义的搜索感知trace应该保留足够的信息,能还原证据是怎么流过这条流水线的。

环节 有用的trace数据
搜索决策 为什么要搜索、选择了哪个数据源、时效性策略
查询 原始问题、改写后的查询、过滤器、策略版本
检索 provider(提供商)、top-k、排名、分数、耗时、重试次数、缓存状态
证据 规范URL、发布时间、检索时间、内容hash、选中的段落
回答 声明ID、证据ID、引用映射、模型和prompt版本

这些字段里只有一部分属于新兴的遥测约定。规范URL、内容hash、缓存状态、时效性策略、声明到证据的映射,这些都是应用层元数据,需要团队自己设计。

不是说要把每个网页都永久存储。元数据、内容hash和传给模型的passage往往足够诊断问题了。敏感查询和检索内容还是要脱敏、控权限、定保留期限。

目标不是记录一切,而是保留足够信息来解释一个答案。

URL不是证据

很多应用在答案旁边放几个URL就说是provenance(溯源)了。URL只能标识一个位置,不能标识模型具体用了哪段信息。

页面会变。搜索摘要可能和后续抓取的内容不一致。两个URL可能指向同一篇转载文章。页面的发布时间也可能和最后更新时间不一样。

如果只保留URL,明天打开可能根本找不到当初用的证据了。

一个合格的证据记录需要关联四样东西:来源、检索到的版本、选中的段落、以及它支撑的声明。

通常需要:规范URL、检索时间戳、发布时间(能拿到的话)、内容hash、以及传给模型的passage。然后用一个稳定的evidence ID让这段passage能跟着重排序、上下文构建、生成一路追踪下去。

在多Agent系统里这更重要。共享的URL缓存可能阻止四个Agent重复抓取同一个页面,但没法证明它们消费的是同一个版本或选中了同一个passage。

内容hash和evidence ID让这种关系变得可见。它们也能防止重复内容虚高置信度——五个URL不代表五个独立来源,当它们都是同一篇原始报道的转载时。

按顺序排查证据链路

回到那个过时的产品答案问题。

先看有效查询。如果用户问的是"现在还支持吗",但改写后的查询把"现在"这个词丢了,那问题从检索之前就开始了。

然后检查返回的来源。如果最新文档根本没出现,说明是发现层的问题,可能是查询、过滤器或搜索provider的锅。

如果最新页面出现了但排名在旧页面后面,就看重排序和时效性权重。如果它挺过了重排序但相关段落没被选中,那问题出在提取或上下文构建。

只有当正确证据确实到了模型手上,答案还跟它矛盾的时候,才开始像真正的生成问题。即使这样,也可能涉及上下文顺序、截断或冲突证据。

引用失败是另一个类别。答案可能事实正确,但引用的页面其实不支持相关声明。一个泛泛相关的链接不算证据,除非被引用的passage真的支撑了答案的说法。

这些区分很重要,因为每类问题的修复方式不同。新的system prompt(系统提示词)没法找回根本没被检索到的来源。增大top-k可能让重复证据更严重。换更贵的模型不会让过时的文档变新。

有意义的trace把"答案错了"变成一个关于具体环节的可测试假设。

把trace变成生产信号

Trace对调试单个case很有用,但更大的价值在于聚合。

团队可以定义:检索成功率——至少一个选中来源达到相关性阈值的运行占比;时效性违规率——系统使用了超过问题允许时效的证据的频率;重复证据比例——多少看似不同的结果其实属于同一个规范URL或内容hash组。

引用覆盖率应该表示有支撑证据的实质性声明比例,而不是简单数链接数。一个答案可以引用五个来源,但最核心的论断可能一个都没支撑。

我要加一个指标:每个有据可查答案的成本

(搜索 + 提取 + 重排序 + 生成成本) / 通过grounding阈值的答案数

只看模型单次调用成本是误导的。当一个廉价的workflow(工作流)反复搜索、反复拉重复页面、生成的回答最后还过不了验证的时候,per-call cost(单次调用成本)根本反映不了真实花费。

Trace还应该流入评估而不是变成无人问津的归档。生产上跑失败的case可以变成回归测试集。改了查询策略、提取规则或重排序模型之后,用同样的case再跑一遍,看证据链路有没有改善。

MLflow当前的RAG评估文档把检索相关性、groundedness(基于证据的程度)和sufficiency(充分性)分开,而且要求检索在trace里显式出现。这种分离很关键,因为端到端的总分没法告诉你该改什么。

自动评判不完美,但提供了一个有用的闭环:观察一个失败、分类它可能的环节、加入评估集、改一个组件、测量结果。

换模型之前先 instrument 检索链路

当AI应用产出差劲答案时,开发者第一个想换的往往是模型。改prompt、加context、升级模型,但根本不知道失败是不是生成阶段造成的。

对于支持搜索的RAG系统,可观测性需要更早介入。检索、重排序、上下文选择应该作为同一请求下的独立嵌套步骤出现。

一个合格的production trace应该能回答三个问题:

系统问了什么?系统看到了什么证据?为什么这些证据变成了这个答案?

在这之前,你只是在监控模型,而不是观察整个系统。

当RAG答案出错时,你的当前trace能说清楚来源是没找到、排名被压低、从context里被丢弃、还是被模型忽略了?这四种情况里,哪种最难被你们团队发现?