可观测性
可观测性是让大模型系统“出问题时能解释清楚”的工程能力。
普通 Web 服务的可观测性通常关注 QPS、错误率和接口延迟。LLM 应用还要额外关注 prompt、token、上下文长度、流式输出、RAG、工具调用、模型版本、推理参数、GPU 和 KV Cache。
一句话概括:
LLM 可观测性 = 请求链路 + token 用量 + 模型行为 + 资源状态 + 业务结果
如果没有可观测性,线上问题会很难定位。用户说“模型变慢了”时,原因可能是输入变长、RAG 召回变慢、prefill 排队、GPU 显存紧张、工具接口超时、网关缓冲、prompt 版本变化,或者只是客户端渲染卡顿。
1. 观测对象
LLM 系统至少要观测五类对象。
| 对象 | 关注点 |
|---|---|
| 请求链路 | request id、trace id、网关、业务服务、推理服务、工具和 RAG |
| 模型输入输出 | prompt 版本、input tokens、output tokens、finish reason、采样参数 |
| 推理性能 | TTFT、ITL、E2E latency、queue time、prefill time、decode time |
| 资源状态 | GPU 利用率、显存、KV Cache、batch、waiting / running requests |
| 业务质量 | 命中率、人工反馈、安全拦截、引用正确性、工具成功率 |
这些信息要能串起来。只看单点指标,很容易误判。
例如 TTFT 变高,可能来自:
- 网关排队。
- RAG 检索变慢。
- prompt 变长。
- tokenizer 慢。
- scheduler waiting queue 变长。
- prefill 计算变慢。
- worker 冷启动。
只有把链路拆开,才能知道真正瓶颈在哪里。
2. 请求日志
请求日志是排障的基础。
建议每个请求至少记录:
| 字段 | 说明 |
|---|---|
request_id | 单请求唯一标识 |
trace_id | 跨服务链路标识 |
tenant_id / user_id | 租户和用户,必要时哈希化 |
model | 外部模型名或别名 |
model_version | 实际命中的模型版本 |
prompt_version | prompt 或 system prompt 版本 |
template_version | chat template 版本 |
input_tokens | 输入 token 数 |
output_tokens | 输出 token 数 |
max_tokens | 用户或系统设置的最大输出 |
stream | 是否流式输出 |
finish_reason | stop、length、tool_calls、error 等 |
error_code | 失败时的稳定错误码 |
latency_ms | 端到端耗时 |
日志不要只记录“请求成功 / 失败”。LLM 请求的成本和风险差异太大,必须记录 token 和版本信息。
一个最小化的结构化日志可以长这样:
{
"request_id": "req_123",
"trace_id": "trace_abc",
"tenant_id": "tenant_hash",
"model": "qwen3-32b",
"model_version": "2026-04-18",
"prompt_version": "support-v12",
"input_tokens": 1840,
"output_tokens": 512,
"stream": true,
"finish_reason": "stop",
"latency_ms": 8420,
"ttft_ms": 920,
"error_code": null
}
日志字段要稳定,方便后续查询、聚合和告警。
3. Prompt 和 Output 采样
prompt 和 output 对排障很有价值,但也最容易触碰隐私和安全边界。
建议分层处理:
| 内容 | 记录策略 |
|---|---|
| prompt 原文 | 默认不全量记录,只在受控环境或采样场景记录 |
| output 原文 | 默认采样记录,敏感业务需要脱敏或摘要 |
| prompt 版本 | 必须记录 |
| system prompt 版本 | 必须记录 |
| RAG chunk id | 建议记录 |
| tool schema 版本 | 建议记录 |
| 推理参数 | 必须记录 |
不要把“完整 prompt 进日志”当成默认方案。更稳妥的方式是:
- 记录 prompt 模板版本和变量摘要。
- 记录 token 数和上下文组成。
- 对原文做采样。
- 对敏感字段脱敏。
- 给原文日志设置更严格的访问权限和保留周期。
排障时经常需要重放请求。为了重放,至少要保留:
- 模型版本。
- tokenizer 版本。
- chat template 版本。
- prompt 模板版本。
- RAG 检索配置。
- tool schema 版本。
- 推理参数。
- 输入数据的可追溯引用。
如果只保留最终文本,很多问题无法复现。
4. Token Usage
token 是 LLM 服务的核心计量单位。
必须记录:
- input tokens。
- output tokens。
- total tokens。
- cached tokens。
- reasoning tokens,若模型或服务暴露。
- 每个 RAG chunk 的 token 数。
- tool schema 占用的 token 数。
- 历史对话占用的 token 数。
token usage 用于:
- 计费。
- 限流。
- 成本分析。
- 容量规划。
- 上下文裁剪。
- 排查 TTFT。
- 识别异常长请求。
常见问题是只看 QPS,不看 token。一个 QPS 很低的长文档总结服务,可能比高 QPS 的短问答服务更吃 GPU。
建议按这些维度聚合 token:
| 维度 | 用途 |
|---|---|
| model | 对比不同模型成本 |
| tenant / user | 配额、账单和异常使用 |
| endpoint | 区分 chat、embedding、rerank、tool |
| prompt version | 判断版本变更是否导致 token 膨胀 |
| input length bucket | 观察长上下文占比 |
| output length bucket | 观察长输出占比 |
如果 prompt 版本升级后 input tokens 均值突然上升,要及时告警。这类变化会直接影响 TTFT、显存和成本。
5. 延迟指标
LLM 延迟不能只看 E2E latency。
建议拆成:
| 指标 | 含义 |
|---|---|
| E2E latency | 从客户端发起到完整响应结束 |
| TTFT | Time To First Token,首 token 延迟 |
| ITL | Inter Token Latency,token 间隔 |
| queue time | 进入推理服务后的排队时间 |
| prefill time | 处理输入 prompt 的耗时 |
| decode time | 生成输出 token 的耗时 |
| RAG latency | 检索、rerank、上下文组装耗时 |
| tool latency | 工具调用耗时 |
不同指标对应不同问题:
- TTFT 高:用户觉得系统迟迟不开始回答。
- ITL 高:用户觉得输出一顿一顿。
- E2E 高:完整任务耗时长。
- queue time 高:容量或调度不足。
- prefill time 高:输入太长或长上下文压力大。
- decode time 高:输出太长、模型慢或并发高。
线上仪表盘至少要看 p50、p90、p99,而不是只看平均值。
平均延迟容易掩盖少量长上下文、长输出或工具超时造成的长尾问题。
6. 流式输出观测
流式输出要额外观测:
- active streams。
- first chunk time。
- chunk 间隔。
- stream error rate。
- client disconnect rate。
- cancel rate。
- cancel 后 worker 是否释放资源。
[DONE]或结束事件是否正常发送。- usage 是否在最后返回。
流式接口常见的线上问题包括:
- 本地流式,线上被网关缓冲。
- 客户端断开后,GPU 仍继续生成。
- 中途错误只表现为连接断开,没有稳定错误码。
finish_reason = length被当作正常完成。- 前端每个 chunk 全量渲染,导致 UI 卡顿。
因此流式日志里要记录:
- 开始时间。
- 首 token 时间。
- 结束时间。
- 是否用户取消。
- 是否客户端断开。
- 是否上游异常。
- finish reason。
对应阅读:流式输出。
7. GPU 和 KV Cache 指标
推理服务必须观测 GPU 和 KV Cache。
建议监控:
| 指标 | 说明 |
|---|---|
| GPU utilization | GPU 计算利用率 |
| GPU memory used / reserved | 显存使用和预留 |
| GPU memory free | 剩余显存 |
| KV Cache usage | KV Cache 使用率 |
| KV Cache blocks free | 可用 cache block |
| preemption / eviction | 抢占或缓存淘汰 |
| running requests | 正在运行的请求 |
| waiting requests | 等待调度的请求 |
| batch size | 当前 batch 中 sequence 或 token 数 |
| input tokens/s | prefill 吞吐 |
| output tokens/s | decode 吞吐 |
不要只看 GPU 利用率。
GPU 利用率高可能说明吞吐好,也可能说明长 prompt 或长输出把服务打满。GPU 利用率低也不一定说明系统空闲,可能是 tokenizer、RAG、队列、网络或客户端消费速度拖住了链路。
KV Cache 对长上下文和高并发更敏感。很多服务不是权重显存不够,而是运行时 KV Cache 被长请求占满。
8. 错误码和异常分类
LLM 服务需要稳定的错误分类,不能只返回 500。
常见分类:
| 类型 | 示例 |
|---|---|
| 请求错误 | 参数非法、上下文超长、模型不存在 |
| 鉴权配额 | API key 无效、配额不足、限流 |
| 调度错误 | 队列满、worker 不可用、KV Cache 不足 |
| 推理错误 | OOM、CUDA error、模型执行失败 |
| 上游依赖 | RAG 检索失败、工具超时、数据库错误 |
| 安全策略 | 输入拦截、输出拦截、权限不足 |
| 客户端行为 | 客户端取消、连接断开、超时 |
建议错误日志包含:
- 稳定
error_code。 error_type。- 是否可重试。
- 发生阶段。
- request id / trace id。
- worker id。
- 上游依赖名称。
发生阶段很关键。timeout 可能发生在网关、RAG、排队、prefill、decode、工具调用或客户端消费阶段,处理方式完全不同。
9. 链路追踪
一次 LLM 请求可能经过多个服务:
Client
-> API Gateway
-> Business API
-> RAG Service
-> Reranker
-> LLM Gateway
-> Inference Worker
-> Tool Service
-> Database / External API
需要用 trace id 把这些步骤串起来。
建议每个 span 记录:
- span name。
- start / end time。
- request id / trace id。
- model / version。
- input / output token。
- error code。
- dependency name。
- retry count。
典型 span 可以包括:
- auth。
- rate limit。
- prompt build。
- retrieval。
- rerank。
- tokenizer。
- scheduler queue。
- prefill。
- decode。
- tool call。
- output postprocess。
链路追踪的价值是定位“慢在哪里”,而不是只知道“这次请求慢”。
10. RAG 召回日志
RAG 问题经常表现为“模型答错”,但根因可能是没有召回正确内容。
建议记录:
- query。
- query rewrite 结果。
- embedding model。
- index version。
- top k。
- rerank model 和版本。
- 命中的 document id / chunk id。
- chunk score。
- rerank score。
- 最终进入 prompt 的 chunk id。
- 引用是否出现在答案中。
原文内容是否记录,要根据隐私和权限决定。即使不记录原文,也要记录可追溯的 chunk id 和 index version。
排查 RAG 时要能回答:
- 有没有召回正确文档?
- 召回了但 rerank 是否排低了?
- 进入 prompt 的内容是否被上下文裁剪掉?
- 模型是否忽略了引用内容?
- 答案引用是否和实际 chunk 对齐?
对应阅读:RAG 工程化。
11. 工具调用日志
Agent 和 tool calling 场景必须记录工具轨迹。
建议记录:
- tool schema version。
- tool name。
- tool call id。
- 参数摘要或脱敏参数。
- 参数校验结果。
- 开始时间和结束时间。
- 工具返回状态。
- 工具错误码。
- retry 次数。
- 是否命中权限拦截。
- 工具结果是否进入下一轮模型输入。
工具日志用于判断:
- 模型是否选错工具。
- 参数是否生成错误。
- 工具本身是否超时。
- 权限是否配置错误。
- 重试是否造成重复副作用。
- 工具结果是否被模型正确使用。
高风险工具还要记录审批、确认和审计信息。
对应阅读:工具调用。
12. 安全与隐私
可观测性不能以牺牲隐私为代价。
常见敏感内容包括:
- 用户输入。
- 文档原文。
- 检索结果。
- 工具参数。
- API key。
- 邮箱、手机号、身份证、地址等个人信息。
- 内部系统 ID。
- 业务交易数据。
建议策略:
- 默认结构化记录元数据,不默认全量记录原文。
- 对 prompt / output 做采样。
- 对敏感字段脱敏。
- 原文日志单独存储,单独授权。
- 设置日志保留周期。
- 记录访问审计。
- 高风险业务支持关闭原文采样。
脱敏要在进入日志系统前完成,不能依赖后续查询时再处理。
13. 告警
告警要覆盖用户体验、服务健康和成本风险。
常见告警项:
| 告警项 | 说明 |
|---|---|
| error rate 上升 | 服务失败增多 |
| p99 TTFT 上升 | 首 token 体验变差 |
| p99 ITL 上升 | 流式输出卡顿 |
| queue time 上升 | 容量或调度不足 |
| KV Cache usage 过高 | 接近显存或缓存瓶颈 |
| OOM / CUDA error | 推理 worker 异常 |
| timeout rate 上升 | 链路或上游依赖异常 |
| token usage 异常增长 | 成本或 prompt 膨胀风险 |
| safety block rate 异常 | 安全策略或流量变化 |
| tool error rate 上升 | 外部依赖异常 |
告警阈值要按模型、业务和租户区分。长文档总结服务和短问答服务的正常延迟范围不同,不能使用同一套阈值。
14. 仪表盘
建议至少建立几类仪表盘。
| 仪表盘 | 内容 |
|---|---|
| 入口流量 | QPS、请求成功率、错误率、限流率 |
| 延迟体验 | TTFT、ITL、E2E、p50 / p90 / p99 |
| Token 用量 | input / output tokens、tokens/s、长请求分布 |
| 推理资源 | GPU、显存、KV Cache、batch、队列 |
| RAG 质量 | 召回量、rerank 分数、引用命中、检索耗时 |
| 工具调用 | 调用次数、成功率、耗时、错误码 |
| 成本 | 按模型、租户、业务线拆分的 token 和 GPU 成本 |
仪表盘要支持下钻到:
- model。
- model version。
- tenant。
- endpoint。
- prompt version。
- worker。
- region。
否则整体平均值会掩盖局部故障。
15. 常见问题
15.1 用户说变慢了,但 QPS 没变
可能原因:
- input tokens 变长。
- output tokens 变长。
- prompt 版本变更导致 token 膨胀。
- RAG 检索或 rerank 变慢。
- scheduler queue time 上升。
- KV Cache 接近上限。
排查顺序:
- 看 TTFT、ITL、E2E 哪个变差。
- 看 input / output token 分布是否变化。
- 看 queue time 和 KV Cache。
- 看 RAG / tool span 是否变慢。
- 看最近模型、prompt、模板和路由是否发布过。
15.2 答案质量变差,但模型没换
可能原因:
- prompt 版本变了。
- RAG index 更新了。
- 检索 top k 或 rerank 配置变了。
- 工具 schema 变了。
- 推理参数变了。
- 上游业务数据变了。
需要对比:
- model version。
- prompt version。
- retrieval config。
- tool schema version。
- sampling params。
- 命中的 chunk id。
15.3 GPU 利用率高,但吞吐没提升
可能原因:
- 长 prompt prefill 占用算力。
- batch 调度不合理。
- KV Cache 频繁抢占。
- worker 间负载不均。
- 输出很长导致 decode slot 被占住。
要看 tokens/s、queue time、running / waiting requests、KV Cache usage,而不是只看 GPU utilization。
15.4 线上问题无法复现
常见原因:
- 没记录模型真实版本。
- 没记录 chat template 版本。
- 没记录 prompt 变量。
- 没记录 RAG chunk id。
- 没记录推理参数。
- 线上使用随机采样,未记录 seed 或无法复现。
- 工具调用结果已变化。
复现能力要在设计日志时就考虑,不能等事故后再补。
16. 实践检查清单
上线前至少确认:
- 每个请求都有 request id 和 trace id。
- 日志记录 model、model version、prompt version 和 template version。
- 日志记录 input tokens、output tokens 和 finish reason。
- 延迟拆分到 TTFT、ITL、E2E、queue、prefill、decode。
- 流式输出记录取消、断开和中途错误。
- GPU、显存、KV Cache、running / waiting requests 有指标。
- 错误码稳定,并能区分发生阶段。
- RAG 记录 index version、chunk id、score 和进入 prompt 的内容引用。
- 工具调用记录 tool name、schema version、参数校验和错误码。
- prompt 和 output 原文日志有采样、脱敏、权限和保留周期。
- 告警覆盖错误率、TTFT、ITL、queue、KV Cache、OOM 和 token 异常增长。
- 仪表盘能按模型、租户、版本和 worker 下钻。
17. 和其他概念的关系
- 和 推理服务架构:可观测性要贯穿 API、调度、worker 和资源层。
- 和 流式输出:TTFT、ITL、取消率和中途错误是流式体验的核心指标。
- 和 并发与批处理:queue time、batch、running / waiting requests 决定高并发下的延迟。
- 和 容量与成本规划:token usage、GPU 利用率和稳定吞吐是成本估算的输入。
- 和 RAG 工程化:召回日志和引用链路决定 RAG 问题能否定位。
- 和 工具调用:工具轨迹决定 Agent 行为能否审计和复现。
18. 总结
LLM 可观测性的核心不是多记日志,而是把“用户请求如何变成模型输出”这条链路拆清楚。
最关键的几类信息是:
- 请求和链路标识。
- 模型、prompt、template、RAG 和工具版本。
- token 用量。
- TTFT、ITL、E2E 和阶段耗时。
- GPU、显存、KV Cache 和队列状态。
- 错误码、finish reason 和安全策略命中。
只有这些信息能串起来,线上问题才能从“模型好像不对”变成可验证、可定位、可回滚的工程问题。