第 12 / 22 篇

第 11 章:让成功率、延迟与成本说同一件事

教学演练里,面板显示 HTTP 成功率 100%,用户却反馈答案经常停在半句。排查发现监控在发送 200 时就计成功,后续 SSE 断流没有进入分母;与此同时,第二次尝试被计成另一位“用户”。漂亮的数字来自口径错误,无法帮助值班者决定是否回退。

11.1 先写分母,再画图

入口调用、获得准入的请求、上游尝试和业务任务是四组对象。401 没有租户身份,能力不匹配也没有进入账本;如果只统计 admitted 日志,就看不到这些拒绝。建议先定义以下教学指标,生产实现时再映射到指标系统:

指标 分子与分母
准入比例 获准请求数 / 通过身份与输入校验的请求数
完整结束比例 收到有效 usage 与 done 并完成交付的请求数 / 获准请求数
尝试放大系数 上游尝试数 / 获准请求数
未知用量比例 终态为 unknown 的请求数 / 已结束的获准请求数

再单独统计未认证调用、输入错误、预算拒绝和并发拒绝。不要把被拒请求算进上游成功率,也不要从分母删除已准入的超时。窗口应固定,进行中的请求单列;否则窗口末尾刚到达的长流会暂时拉低“完成率”。跨窗口分析可以按准入批次追踪到终态。

例如 10 个获准请求,8 个完整结束,2 个中断,其中一个经可信未开始拒绝后切换,产生共 11 次尝试。请求完整结束比例为 80%,尝试放大系数为 1.1;仅凭这些数据不能算各上游的成功率,还需要每次尝试的结果。没有业务验收记录,也不能称作任务成功率。

11.2 首事件与完成各有计时点

选择入口收到合法请求的单调时刻 t0,再记录首个完整上游协议事件 t1、首个正文事件 t2、本地完成最后写入 t3,以及清理完成 t4。由此分别得到首事件等待、首正文等待、交付完成和资源释放耗时。每次尝试另有自己的开始时刻,排队与前次尝试仍计入请求总耗时。

响应头不是正文,心跳也未必代表业务前进。取消或断流没有成功完成延迟,应记录终止耗时与原因;只把成功样本放入完成延迟直方图时,面板必须同时显示中断比例,防止“慢请求都失败了,所以延迟变快”。本地写入完成也不能证明用户已经阅读或远程应用已持久保存。

OpenTelemetry 的 GenAI 文档提供模型、usage 和首块观测语义,但来源 S06 固定读取的版本仍标为 Development。接入时应固定版本并说明映射;不要把本地首正文耗时直接改名成标准首块字段。实验 audit 的墙上时间用于事件关联,不是上述单调计时实现,目前也没有 OTel 导出器。

11.3 用关联记录还原一次中断

可以沿 (tenant, request_id) 找到 admitted、带 route 与 attempt 的 route_attempt、可能的 route_failed,以及 finished。这些记录解释调用是否准入、联系过谁、结束原因和 usage_state。单次尝试编号保留在日志或 trace 中,适合排查具体请求。

指标标签则使用受控的路由、结果和原因枚举。request_id、原始 URL、任意错误文本会制造无界维度,不宜成为时间序列标签。按租户统计也要有容量与访问控制,避免数十万租户创建无限序列,或让普通调用者看见别人的用量。

实验的 Audit 使用字段白名单,保存的是内存记录;没有记录所有入口拒绝,也没有每次尝试的完整成功终态。因此可以用它检查教学过程,不能宣称现成支持上述全套生产指标。

11.4 内容默认不进遥测

排查流断开通常需要阶段、字节 credit、队列峰值、取消传播和错误分类,不需要完整 prompt。实验也不记录输出正文、Authorization 或上游凭证。任意异常字符串可能携带 URL 或密钥,应转为受控原因码,而非直接把整个请求和异常对象序列化。

内容诊断若确有必要,应另设授权入口,限制采样、脱敏、访问与保留时间;低采样率仍可能采到秘密,不能代替这些控制。实验 credit 是 UTF-8 字节,图表必须注明单位;真实 token 与费用需要适配器和供应商证据,缺失 usage 保留未知,不填零改善面板。

11.5 从症状推导告警

若 HTTP 200 稳定,而 unknown 预留金额和中断比例上升,应先检查终止事件、协议适配与上游断连;不能直接提高预算掩盖积压。若首事件正常、完成变慢且 backpressure_waits 上升,则检查慢客户端与缓冲。告警应附路由版本、受影响请求范围和少量可访问的关联 ID,门槛由自己的基线决定。

现有脱敏行为可执行验证:

PYTHONPATH=tests python3 -m unittest \
  test_integration.GatewayHTTPTests.test_audit_is_useful_without_prompt_tokens_or_keys

练习: 按本章口径计算“20 次入口调用、2 次认证失败、3 次预算拒绝、15 次准入、12 次完整结束、3 次中断、18 次尝试”的四个指标。先声明其余身份与输入校验均通过,再设计一个不会把 request_id 放进指标标签的故障查询流程。