LLM 应用的可观测性要关注哪些数据?
一句话回答
传统服务看请求量、错误率和延迟就够了,LLM 应用还要能回答:模型这次看到了什么、回答了什么、花了多少钱、用户满不满意。每次模型调用都要记录输入输出、模型和参数、token 用量和费用、首 token 延迟和总耗时、错误和结束原因;RAG 和 Agent 还要记录检索结果和每次工具调用,并关联用户反馈。这些数据里有用户隐私,要脱敏、控制访问权限,并设置保留期限。
详细解析
每次模型调用记录什么
| 类别 | 字段 | 用途 |
|---|---|---|
| 标识 | trace ID、会话 ID、用户 ID(哈希后)、功能入口、Prompt 版本 | 串起一次请求;按功能、版本统计 |
| 输入输出 | 完整的消息列表(系统提示可以只记版本号)、输出内容、结束原因 | 复现问题、分析失败案例 |
| 模型和参数 | 供应商、带版本的模型名、temperature、最大输出长度、提供的工具列表 | 对比不同配置,追踪上游模型的变化 |
| 用量和费用 | 输入 token、输出 token、缓存命中的 token(部分供应商会返回)、折算的费用 | 成本分析、异常消耗告警 |
| 性能 | 首 token 延迟(TTFT)、总耗时、输出速度、排队和重试次数 | 用户体验和容量规划 |
| 错误 | 错误类型(限流、超时、上下文超长、被内容审核拦截)、是否重试成功、是否降级到备用模型 | 稳定性 |
结束原因很有用:正常结束、达到长度上限被截断、被内容过滤、发起了工具调用,各自对应不同的问题。
链路上的中间结果和用户反馈
模型调用之外,链路上的其他步骤也要记录:
- RAG:改写后的查询、召回的文档 ID 和分数、重排后的顺序、最终放进上下文的片段
- Agent 和工具调用:每一步的工具名、参数、返回结果(太长时记摘要)、耗时、是否出错,以及总步数
- 后处理:结构化输出的校验结果、内容审核的结果
这些步骤要用同一个 trace ID 串成一棵树,才能看清一次请求的全过程(见 链路追踪)。用户反馈也要挂到对应的 trace 上:
- 显式反馈:点赞、点踩(附带原因选项:不准确、没回答问题、太长……)、文字反馈
- 隐式信号:重新生成、复制回答、修改后再用、换个说法再问、中途停止生成、放弃会话、转人工
- 关联到 trace ID 之后,从一个点踩就能直接看到当时的输入、检索结果和输出;只有少数用户会主动反馈,要结合隐式信号一起看
隐私和保留期限
- 写入前脱敏:手机号、身份证号、邮箱这类格式固定的信息用规则替换;姓名、地址需要实体识别模型或专门的脱敏服务
- 分级保存:统计指标长期保留;完整的输入输出只保留一段时间(按合规要求定),查看要有权限控制和审计
- 用户要求删除数据时,日志里的内容也要能删
- 使用第三方观测平台时,确认数据存储在哪里,必要时选择自托管(更多见 敏感信息泄露)
看板和告警
看板按功能、模型、Prompt 版本拆分,常看这几类:
- 流量:请求量、活跃用户
- 性能:首 token 延迟和总耗时的 P50、P95、P99
- 稳定性:按类型统计的错误率、重试率、降级率
- 成本:每天的 token 和费用、每次请求和每个用户的平均费用、消耗最多的用户
- 质量:点踩率、重新生成率、截断率、JSON 解析失败率、抽样评分(见 上线后怎么发现效果变差)
常见的告警:错误率或限流比例突增;P95 延迟超过阈值;每小时的费用超过预算,或者单个用户消耗异常(可能被滥用,或者程序陷入了循环);截断比例突增(往往是 Prompt 改动让输出变长了)。
代码示例
一条调用日志的示例(数值仅为示意):
{
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"feature": "kb_qa",
"prompt_version": "kb-answer@v12",
"model": "provider/model-2026-01-01",
"params": { "temperature": 0.2, "max_tokens": 800 },
"usage": { "input_tokens": 3120, "output_tokens": 286, "cached_tokens": 2048 },
"latency_ms": { "ttft": 820, "total": 4630 },
"finish_reason": "stop",
"retrieved_ids": ["doc-12#3", "doc-40#1"],
"feedback": null
}
写入日志前先脱敏:
// 规则只能覆盖格式固定的信息,姓名、地址要用实体识别模型
const RULES: [RegExp, string][] = [
[/(?<!\d)1[3-9]\d{9}(?!\d)/g, '[手机号]'],
[/(?<![\dXx])\d{17}[\dXx](?![\dXx])/g, '[身份证号]'],
[/[\w.+-]+@[\w-]+(\.[\w-]+)+/g, '[邮箱]'],
]
export function redact(text: string) {
return RULES.reduce((t, [pattern, label]) => t.replace(pattern, label), text)
}
面试官可能追问
全量记录输入输出,存储成本太高怎么办?
指标全量统计,完整内容按比例采样;出错、点踩、费用异常的请求全量保留。长而固定的系统提示只记版本号,检索到的文档只记 ID。按冷热分层存储,过期自动删除。
流式输出时,首 token 延迟和 token 用量怎么统计?
首 token 延迟是从发出请求到收到第一个内容片段的时间,在服务端和客户端分别测量,两者的差就是网络和中间层的开销。token 用量通常在流的最后一个事件里返回,有的接口要在请求里显式开启才会返回。用户中途停止时,要记录已生成的部分,并确认上游请求也被取消了(见 停止生成)。
怎么把成本算到具体的用户和功能上?
每次调用都带上用户 ID、租户、功能入口这些标签,按标签聚合 token 和费用。Agent 的一次任务包含多次模型调用和工具调用,要按 trace 汇总成"一次任务的成本"。这些数据也是配额和计费的依据。
易错点
- 只记录最终输出,不记录检索和工具调用的中间结果,出了问题无法复现
- 不记录 Prompt 版本和带版本号的模型名,改动前后没法对比
- 明文保存用户隐私,或者日志永久保留
- 只看平均延迟,不看 P95 和首 token 延迟
AI 模拟面试官
用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮
这道题你掌握了吗?
选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。
学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。