延迟别再看平均值了:AI 应用指标与告警实战(O03)

17 阅读4分钟

延迟别再看平均值了:AI 应用指标与告警实战(O03)

系列《AI 应用生产化手册》第 8 篇(共 30 篇)|配套开源项目:github.com/ChenYingbo/…

一、先看问题:trace 回答不了"整体表现"

O02 有了 trace,能看"单次请求内部发生了什么",但马上遇到第 3 个问题:

  1. "整体表现"没有答案——今天比昨天慢了吗?失败率多少?每请求平均花多少钱?trace 一次看一条,回答不了。
  2. 退化是悄悄发生的——P95 从 2s 涨到 5s,是两周才涨上去的;没有聚合指标,等用户抱怨才发现。
  3. 看板 = 老板问什么你答什么——"最近稳定吗?"你只能翻 trace 碰运气。

解法:把"单次事件"聚合为"指标"——延迟分位、成功率、成本,再配上看板和告警。

核心认知:指标 = 日志的聚合视图。日志回答"这次发生了什么",指标回答"整体怎么样、在变好还是变坏"。告警让机器在"变坏"时主动叫你。

二、原理

在线指标:选哪些、为什么

指标定义为什么重要
延迟分位(P50/P95/P99)响应时间分布P95 才是用户体感,P99 暴露最差体验
成功率 / 错误率成功请求 / 总数最基础的"活着吗"信号
Token 消耗/请求每次请求平均 token成本与质量的双重指标
成本/请求token × 单价上线后的真金白银
幻觉率(采样)抽样人工/评测判分质量趋势

设计原则:一张图回答一个问题。 看板不是堆指标。

为什么用分位不用平均值(必懂)

请求延迟:1s ×9, 60s ×1
平均 = 6.9s  ← 看起来还行?
P95 = 1s     ← 真实体感:大部分用户 1 秒内
P99 = 60s    ← 但最差的用户等了一分钟

平均值掩盖分布,分位暴露分布。生产监控只用分位。

本系列的真实数据更说明问题:样例日志平均延迟 1.7s,但 P95 = 3000ms——看平均值你根本不知道有人在等 3 秒。

告警设计三原则

原则做法
阈值 = 基线 + 容差先跑基线再定,不拍脑袋
分级WARNING(观察)→ CRITICAL(行动),不要只有一个"严重"档
抗告警疲劳告警要可行动(写清"看哪、怎么修");连续告警合并去重

关键问题:收到告警的人,第一反应知道"干什么"吗?不知道 = 这个告警是噪音。

指标从哪来(两条路径)

路径数据源用在哪
Langfuse 内置面板trace日常看板(人看)
metrics.py结构化日志自动化告警/巡检(机器跑)

两条路径数据同源,互为补充——面板给人看,脚本给机器跑。

三、动手:算指标 + 验证告警

git clone https://github.com/ChenYingbo/ai-prod-demo.git && cd ai-prod-demo
source .venv/bin/activate

# 1. 用样例日志算指标(免 Key)
python scripts/metrics.py --log tests/fixtures/sample_structured.log \
  --input-cost-1m 2 --output-cost-1m 8

真实输出:

请求数                     10
成功 / 失败                 9 / 1
错误率                     0.1
总延迟 P50/P95/P99(ms)     1200.0 / 3000.0 / 3000.0
LLM 延迟 P50/P95/P99(ms)  1100.0 / 2900.0 / 2900.0
平均 token (入/出)          136.0 / 23.6
估算成本                    0.0046
# 2. 告警验证:P95 超过阈值应报警(退出码 1,可接 cron/CI)
python scripts/metrics.py --log tests/fixtures/sample_structured.log --alert-p95-ms 2500
echo "exit=$?"     # 1(ALERT 触发)
# 3. 真实日志(有 API Key 后):跑 10 个问题产生日志 → 算真实指标
python scripts/ask.py -f eval/e01_questions.txt
python scripts/metrics.py --log /tmp/app.log --input-cost-1m 2 --output-cost-1m 8

设定你的告警基线

  1. 连续跑 3 次评测问题集,记录 P95 和错误率
  2. 按"基线 + 20% 容差"定阈值
  3. 写进定时巡检(cron):
0 10 * * * cd /path/to/ai-prod-demo && .venv/bin/python scripts/metrics.py \
  --log /tmp/app.log --alert-p95-ms 5000 --alert-error-rate 0.05

四、真实踩坑

  1. 只看平均值:平均 1.7s 掩盖 P95=3s——监控只用分位
  2. 告警阈值拍脑袋:先跑基线再定;阈值写进配置而不是散在脚本里
  3. 告警疲劳:阈值太紧天天响,最后没人看——宁可少而准
  4. 成本算错:单价没配(默认 0)或输入输出价搞混——按实际模型配置
  5. 口径不一:总延迟(含失败)vs LLM 延迟(纯模型)混为一谈——分两列输出,别合并
  6. (实测)口径差异会骗人:同题压测(缓存命中)P50=44ms、QPS 7.07;变题压测(真实模型)才是 P95=4.5s——报指标必须说清口径,否则"缓存性能"会被当成"模型性能"
  7. 指标和日志脱节:指标异常了没法下钻到具体请求——窗口期日志要留档,配合排障 SOP

五、小结

  • 分位不是平均数:P50 常态 / P95 体感 / P99 兜底
  • 告警三原则:基线+容差 / 分级 / 抗疲劳
  • 两条路径同源:面板(人看) + 脚本(机器跑)

明天(O04):《线上问题定位 SOP》——用 trace + 日志 + 指标三层配合,从"用户报错"到根因。 收藏 + 关注,每天一篇,30 天把 AI 应用送上生产。