AI 与大模型

大模型应用的可观测性:日志、指标与追踪

大模型应用出问题时,"哪里错了"往往比传统服务更难定位——可能是检索没召回、可能是 prompt 有歧义、也可能是模型本身的随机性。可观测性决定了你能不能快速找到原因。

2026-09-23 约 10 分钟 4162 字 大模型 可观测性 监控 工程实践

一、为什么大模型应用更难排查

传统服务出了 bug,通常有明确的线索:异常堆栈、错误码、SQL 慢查询日志。链路是确定的,同样的输入必然得到同样的输出。

大模型应用不一样:

特点 带来的排查困难
概率性输出 同样的问题两次回答不同,无法靠"重放"复现
链路长 检索 → 重排 → 组装 → 生成,任何一环都可能出问题
失败很隐蔽 不报错,只是"答得不对"——而系统认为它成功了
输入不可控 用户可能问任何问题
外部依赖 模型 API 延迟波动、限流、内容过滤

最麻烦的是第三点:传统监控看错误率,但大模型应用的"答非所问"不会体现在错误率里。

二、三类可观测性数据

类型 回答什么问题 关键内容
日志(Logs) 这次请求到底发生了什么 完整 prompt、检索结果、模型输出
指标(Metrics) 整体健康度如何 延迟、token 消耗、成功率、成本
追踪(Traces) 时间花在哪一环 各阶段耗时分解、调用链

三者互补:指标发现异常 → 追踪定位环节 → 日志看清细节。

三、必须记录的日志字段

一次大模型请求,至少要能还原出这些信息:

public class LlmCallLog {
    private String traceId;          // 链路 ID,贯穿全流程
    private String userId;           // 谁问的
    private String sessionId;        // 会话 ID,用于还原上下文
    private String scene;            // 场景:导购/客服/文案生成

    // 输入侧
    private String userQuery;        // 原始问题
    private String rewrittenQuery;   // 改写后的查询(如果有)
    private List<String> retrievedChunkIds;   // 召回了哪些片段
    private List<Double> retrievedScores;     // 相似度分数
    private List<String> rerankedChunkIds;    // 重排后留下的
    private int inputTokens;         // 实际输入 token 数

    // 模型侧
    private String modelName;
    private String promptVersion;    // prompt 模板版本
    private int outputTokens;
    private long latencyMs;          // 模型调用耗时
    private String finishReason;     // stop / length / content_filter

    // 输出侧
    private String answer;
    private boolean success;
    private String errorMessage;
}

几个容易被忽略但很关键的字段

字段 为什么重要
promptVersion prompt 改动后效果变化,没有版本号就无法回溯
retrievedScores 判断是"没召回到"还是"召回了但没用上"
finishReason length 说明被 max_tokens 截断,答案不完整
rerankedChunkIds 对比召回和重排结果,判断重排是否丢了有用信息
inputTokens 定位 token 消耗异常

finishReason 特别值得注意:如果大量请求的 finishReason 是 length,说明 max_tokens 设小了,答案被截断——但用户看到的是一个"看起来正常"的不完整回答,不会报错。

敏感信息处理

日志里会包含用户输入和模型输出,可能含个人信息。处理原则:

数据 处理方式
手机号、身份证、银行卡 脱敏后存储
用户完整对话内容 加密存储,限制访问权限,设保留期限
模型输入输出 采样存储(不必全量)

全量存 prompt 和输出成本很高(一次 RAG 请求的 prompt 可能几千 token)。常见做法是全量存元数据 + 采样存完整内容(比如 10%),异常请求单独标记并全量保留。

四、关键指标

指标 计算方式 异常含义
首字延迟(TTFT) 请求发出 → 第一个 token 返回 用户感知的响应速度
总延迟 请求发出 → 生成完成 端到端耗时
检索耗时 向量库查询时间 检索性能下降
模型耗时 模型 API 调用时间 上游性能波动
输入/输出 token 按请求统计 成本异常
检索命中率 有结果的请求占比 知识库覆盖不足
空回答率 返回空的请求占比 模型或 prompt 问题
拒答率 模型拒绝回答的比例 prompt 过严或问题越界
重试率 重试次数 / 总请求 上游不稳定
用户反馈率 点赞/点踩占比 质量指标

首字延迟是最重要的体验指标

指标 用户感受
首字延迟 < 1s 流畅
1~3s 可接受
3~10s 明显卡顿
> 10s 以为卡死,大概率刷新

优化首字延迟的方法:流式输出、减少检索片段、用更快的模型做首轮响应。

延迟要分阶段统计

只知道"总延迟 8 秒"没法优化,必须拆开看:

总延迟 8.2s
├─ 查询改写        0.3s
├─ 向量检索        0.4s
├─ 重排            0.8s
├─ 上下文组装      0.1s
├─ 模型首 token    1.2s      ← 关键
└─ 生成剩余内容    5.4s      ← 关键

大多数情况下,模型生成占大头。如果检索环节占了 5 秒,那是检索的问题;如果模型首 token 就要 3 秒,那要考虑换模型或减少输入。

五、追踪:串联整条链路

大模型应用的调用链通常跨越多个组件:

用户请求
   ↓
业务服务 ──→ 检索服务 ──→ 向量库
   ↓            ↓
   │         重排模型
   ↓
模型网关 ──→ 大模型 API
   ↓
输出处理 ──→ 敏感词过滤

每个环节都要带上同一个 traceId,这样才能:

  • 看到一个请求完整的耗时分布
  • 定位是哪一环慢或出错
  • 把散布在各服务里的日志串起来

与模型调用链的对接

部分模型平台支持返回自己的调用 ID,建议一并记录:

String platformTraceId = response.getHeader("x-request-id");
log.info("traceId={}, platformTraceId={}, latency={}ms",
         traceId, platformTraceId, latency);

当怀疑是平台侧问题时,可以拿这个 ID 去平台查询,避免"双方都说不是自己的问题"。

六、质量监控:最难也最重要的一环

传统的可用性监控(错误率、超时)只能发现"服务挂了",发现不了"答得不好"。

三类质量信号

信号 采集方式 时效
用户反馈 点赞/点踩、连续追问比例 实时
自动评估 用模型或规则自动打分 准实时(采样)
人工抽检 定期抽样人工评估 离线

用户反馈最直接但覆盖低(只有小部分用户会点赞踩),自动评估覆盖高但可能不准,人工抽检最准但成本高。三者配合使用。

自动评估的可落地方案

方法 做法 成本
规则检查 检查答案是否为空、是否含引用、长度是否异常 极低
关键词检查 是否包含不该出现的内容 极低
模型打分 用小模型判断答案是否基于检索内容 中
一致性检查 同一问题问两次,答案差异是否过大 中

规则检查应该全量跑,因为它几乎零成本,却能抓住大量明显问题(空回答、超长、被截断)。

一个实用的采样策略

全量:元数据 + 规则检查 + 用户反馈
10%:完整 prompt 和输出
100%:异常请求(超时、空格、被截断、用户点踩)

七、告警该怎么设

大模型应用的告警容易走向两个极端:要么太吵(误报多被忽略),要么太迟钝(出问题没人知道)。

告警项 阈值建议 说明
错误率(5xx) > 1% 传统告警
首字延迟 P95 > 5s 体验劣化
空回答率 环比翻倍 可能是模型或 prompt 问题
拒答率 环比翻倍 可能是 prompt 过严
token 消耗 日消耗超预算 80% 成本预警
检索命中率 低于基线 20% 知识库或向量库问题
上游调用失败率 > 5% 模型平台不稳定

告警必须带上下文:只说"空回答率上升"没有价值,要能直接跳到对应 traceId 的日志。

小结

  • 大模型应用排查更难的原因:概率性输出、链路长、失败隐蔽(答得不对但不报错)
  • 三类数据互补:指标发现异常 → 追踪定位环节 → 日志看清细节
  • 必记字段里的关键项:promptVersion、retrievedScores、finishReason、rerankedChunkIds
  • finishReason = length 说明答案被截断,但不会报错,必须主动监控
  • 日志含用户输入,要脱敏 + 采样存储(全量存 prompt 成本很高)
  • 首字延迟(TTFT)是最重要的体验指标,> 10 秒用户会以为卡死
  • 延迟必须分阶段统计,否则无法定位优化点
  • 全链路共用 traceId;记录平台侧调用 ID,避免责任不清
  • 质量监控三类信号:用户反馈(实时但覆盖低)、自动评估(覆盖高但可能不准)、人工抽检(准但贵)
  • 规则检查应该全量跑——零成本,能抓住空回答、超长、截断等明显问题
  • 告警要带上下文,能直接跳到对应 traceId,否则没人会认真看

大模型应用的可观测性,本质上是把"黑盒"变成"可追溯"。当用户说"它答错了"时,你能否在几分钟内定位到是检索没召回、prompt 有歧义,还是模型理解偏差——这决定了系统能不能持续迭代。

留下点什么

评论基于 GitHub Discussions(giscus)。在项目根目录配置.env.local填入 NEXT_PUBLIC_GISCUS_* 四个变量后自动开启。