LLM 系统的可观测性
下周有用户反馈答案不对,你需要能还原当时发生了什么。该记哪些日志,以及那个所有人都漏掉的字段。
用户说助手昨天给了他错误信息。你手上有他的问题,却复现不出来。
没有日志,这个排查还没开始就结束了。LLM 系统是不确定的,依赖会变化的检索内容,跑在版本号没变、行为却变了的模型上。只凭输入复现是不可能的。
该记什么
每个请求记录:
实际发出去的完整 prompt。 不是模板——是拼装后的文本,包括 system prompt、历史和检索到的内容。
原始响应,在任何解析或后处理之前。
模型标识和版本,外加用到的参数——温度、max tokens。
token 计数,输入和输出分开记。这是你的成本数据。
延迟,如果你做了流式输出,拆成首 token 延迟和总时间。
重试和错误,包括哪一步失败了、重试后产出了什么。
一个关联 ID,把多步流程里相关的调用串起来。
所有人都漏掉的那个字段
检索到的上下文。 对 RAG 系统,记录检索到了哪些文本块、各自的分数,以及来源标识。
这是价值最高的一个字段,也是最常缺失的一个,因为大多数 RAG 失败其实是检索失败。诊断时的问题几乎总是「正确的段落被检索到了吗?」——而没有这条日志,事后你根本答不上来。
只记问题和答案、不记检索到的段落,意味着每一次 RAG 排查都会卡在第一步。
给多步流程做链路追踪
一个用户请求可能引发好几次模型调用:查询改写、检索、重排序、生成。或者十几轮 agent 循环。
把这些记为一条调用链——每个用户请求一个父 span,每次模型调用和工具调用各一个子 span,每个都挂上耗时和 token 数。
相比扁平日志,它多给你两样东西:延迟消耗在哪个阶段,错误是哪个阶段引入的。对 agent 而言这是必需的,因为不知道第一到第八步,第九步的失败根本无从理解。
敏感数据
记全量 prompt 意味着你的日志里装着用户发来的一切。这常常比 API 调用本身造成更大的数据暴露面,因为日志留得更久,能读到的人也更多。
务实的折中办法:在写入之前而不是之后脱敏可识别字段,留存期按你真实的策略设而不是用默认值,日志访问权限按数据库的标准来管,全量 prompt 低比例抽样保留,同时所有请求都留元数据——外加全部失败样本,因为你要排查的就是它们。
该对什么告警
错误率,按类型分。429 变多说明是容量问题;解析失败变多说明模型变了,或者你的 prompt 漂移了。
延迟分位数,不是平均值。用户注意到的是尾部。
每小时成本。 最经典的无监控失效是:一个死循环或者一个失控的 prompt,直到月度账单出来才发现。按小时看花费并设阈值,一小时内就能抓到。
拒答率和降级率。 这里上升通常意味着模型更新改了行为——而除此之外它完全不可见。
校验失败率。 prompt 或模型出问题的先行指标。
检索质量的代理指标。 低分检索或空结果的占比上升,能在用户反馈之前预示坏答案。
把反馈当数据
一个「踩」按钮,是你能拿到的最便宜的评测用例来源。
记录评分时把关联 ID 一起记下,这样就能拉出完整调用链。一个差评加上它的调用链——prompt、检索到的上下文、响应——正好就是一个测试用例,而且收集它零成本。
这就闭环了:生产环境的失败变成评测集,用来防止它们再次发生。
要点回顾
- 不确定性、会变化的检索结果、静默的模型更新,让只凭输入复现成为不可能。
- 记录拼装后的 prompt、原始响应、模型版本、token 计数、延迟、重试,以及一个关联 ID。
- 记录检索到的上下文——价值最高也最常缺失的字段,因为大多数 RAG 失败都是检索失败。
- 多步流程用父子 span 做链路追踪;否则 agent 根本没法诊断。
- 日志本身就是暴露面:写入前脱敏、限制留存期、限制访问、抽样——但失败样本全部保留。
- 对错误率、延迟分位数、每小时成本、拒答率和检索质量告警。
下一篇: 成本监控与归因