Appearance
11.3.1 如何做 RAG 的日志、观测和故障排查?
先给结论:RAG 的日志和观测必须以链路为单位来设计,否则很难定位问题。最小可用的做法是:记录“输入 -> 检索 -> 重排 -> 上下文 -> 生成”的关键字段,并能把一次请求完整串起来。
很多系统的日志只有:
- 请求时间
- 最终回答
这对排查几乎没有帮助。真正有用的日志必须回答:
- 这次请求的证据从哪里来
- 哪一层决定了最终结果
- 哪一层开始出现异常
一、日志必须“可串联”
RAG 是一条链路,日志也必须能串起来。最小要求是:
- 每一次请求有唯一
trace_id - 每一层都有
trace_id对应记录
没有这个,系统只能看到孤立的片段,看不到链路。
二、每一层至少记录什么
下面是一套更稳的最小记录清单:
1. 请求与输入层
- 原始问题
- 标准化后的 query
- 解析出的意图或过滤条件
2. 检索层
- 检索策略和参数(如
top_k) - 命中文档或 chunk 列表
- 命中结果的得分分布
3. 重排层
- 重排模型或策略版本
- 重排后的排序变化
- 最终保留结果列表
4. 上下文构造层
- 最终上下文长度
- 是否发生截断
- 是否发生去重或聚合
5. 生成层
- 模型与 prompt 版本
- 是否触发拒答或安全策略
- 生成耗时与 token 消耗
这些字段不是为了做大而全,而是为了让你在排查时能回答:
- 证据是否进了候选
- 证据是否进入最终上下文
- 生成是否忠实使用证据
三、观测要分层,而不是只看总指标
很多团队只看最终评分或满意度,这会掩盖链路问题。更稳的做法是:
按链路层分指标
检索指标、生成指标、端到端指标按错误桶分指标
召回问题、忠实性问题、版本问题等
这样你能看到:
- 哪一层开始退化
- 哪一类问题在变多
四、一个可落地的排查流程
当你拿到一个失败案例,最稳的排查流程是:
- 看检索结果中是否有关键证据
- 看重排后关键证据是否还在
- 看最终上下文是否被截断或稀释
- 看生成是否忠实使用证据
这能把大量问题迅速归因到具体链路层。
五、常见日志误区
误区一:只记录最终答案
没有链路信息,几乎无法归因。
误区二:没有版本信息
没有版本,你无法判断:
- 这是模型问题
- 还是策略变化引入的问题
误区三:只看平均值
平均值会掩盖:
- P95 / P99 延迟
- 某一类问题的集中退化
一个最小日志结构示意
python
trace = {
"trace_id": "req_123",
"query_raw": "...",
"query_norm": "...",
"retrieval": {"top_k": 20, "hits": ["docA#3", "docB#1"]},
"rerank": {"enabled": True, "final_hits": ["docB#1", "docA#3"]},
"context": {"tokens": 4200, "truncated": False},
"generation": {"model": "x", "tokens": 800, "abstained": False}
}这个示意的重点是:
- 能把一次请求完整串起来
一句话总结
RAG 的日志和观测必须围绕链路来设计:可串联、可分层、可追溯。只有这样,故障排查和调优才会真正高效。