5.4 监控三张仪表盘:命中率、成本、质量


文档摘要

5.4 监控三张仪表盘:命中率、成本、质量 本节摘要:缓存省没省,不能靠感觉。本节设计命中率、成本、质量三张仪表盘,给出每张该画什么曲线、埋点记哪些字段、告警怎么设阈值,以及三张图如何互相印证定位问题。最后给一段可直接跑的聚合统计代码。 5.3 把 Agent 的命中率做上去了,但"做上去了"三个字本身不是结论,是待验证的假设。这一节我们把前面所有动作产出的数据,变成三张能贴在监控大屏上的仪表盘。它们既是本章的收尾,也是第 6 章财务账的原料——没有这些数,下一章的"每回收一个 token 值多少钱"就无从算起。 看不见的回收率怎么算清 缓存的本质是"回收已经付过的算力",可算力付没付、回收多少,默认是看不见的。引擎只报 token 总量,网关只报命中次数,业务只关心延迟和成本。

5.4 监控三张仪表盘:命中率、成本、质量

本节摘要:缓存省没省,不能靠感觉。本节设计命中率、成本、质量三张仪表盘,给出每张该画什么曲线、埋点记哪些字段、告警怎么设阈值,以及三张图如何互相印证定位问题。最后给一段可直接跑的聚合统计代码。

5.3 把 Agent 的命中率做上去了,但"做上去了"三个字本身不是结论,是待验证的假设。这一节我们把前面所有动作产出的数据,变成三张能贴在监控大屏上的仪表盘。它们既是本章的收尾,也是第 6 章财务账的原料——没有这些数,下一章的"每回收一个 token 值多少钱"就无从算起。

看不见的回收率怎么算清

缓存的本质是"回收已经付过的算力",可算力付没付、回收多少,默认是看不见的。引擎只报 token 总量,网关只报命中次数,业务只关心延迟和成本。三股信息各说各话,结论就永远模糊。所以我们不画一张大图,而是画三张各有侧重、又能互相印证的图:一张说命中了多少,一张说省了多少钱,一张说质量有没有塌。

第一张:命中率仪表盘

命中率仪表盘回答"缓存生效没有"。它至少画三条线:整体命中率(命中 token / 总输入 token)、分层命中率(引擎前缀缓存、网关精确缓存、语义缓存各自占比)、以及按业务线的命中率曲线。再加一个"未命中原因分桶"——键漂移、缓存逐出、前缀本就不同,各占多少。

只看整体命中率会骗人:它可能很高,但其实是因为某一条长前缀请求刷高了均值。按业务线拆开,才能看到"哪条线根本没接住"。未命中原因分桶则直接告诉你是键算错了、块不够了、还是流量本身就不重复。

第二张:成本仪表盘

成本仪表盘回答"省了多少钱"。核心三个数:节省金额(命中 token × 单位算力成本)、有效单价(总花费 / 有效生成 token)、缓存写溢价占比(为写缓存多占的显存/计算 ÷ 总缓存开销)。

有效单价这个概念很关键。开了缓存,你的"每次请求平均成本"会下降,但"为维持缓存多付的写溢价"在上升。成本仪表盘的价值,就是让这两条线同框:当命中率足够高时,溢价被摊薄,净节省为正;命中率一旦跌破某个点,溢价反而吃掉收益。第 6 章会把这个临界点算成具体数字。这里提前给一个直觉:写溢价不是固定成本,它和缓存容量、命中率都有关。命中率低时,你为维持一份很少被命中的缓存持续付费,溢价占比就高;命中率高时,同一份缓存被反复命中,单次命中的边际溢价趋近于零。所以成本仪表盘最该画的是"写溢价占比随命中率变化"的曲线,而不是两个孤立的数字。

第三张:质量仪表盘

成本降了,回答质量不能塌。质量仪表盘看三件事:命中回答的采纳率(用户是否真的用了缓存返回的回答)、用户负反馈率(被采纳的命中回答里有多少被点踩)、以及语义缓存误命中抽检(语义层把"看似相同"的请求判命中,有没有返回错误内容)。

这一张最容易被省略,却最关键。前缀缓存是字节级精确,几乎不会错;但如果你在 5.2 网关里加了语义层缓存,误命中就会真实发生。质量仪表盘就是给"降本"这把刀装个护手——降得狠了,负反馈先报警。质量仪表盘最难做的是"语义误命中抽检"——你不可能逐条人工看,也没法全量跑一遍正确性校验。实务做法是分层抽样:每天从命中回答里抽千分之一,用更强的模型或规则做一致性核对,估算误命中率上限。这个数字哪怕只是区间,也远比"我们相信语义缓存不会错"这种假设靠谱。采纳率则要从前端埋点拿,别用"返回了就算采纳",那会把所有命中都算成有效,掩盖质量问题。

埋点字段设计

三张仪表盘的数据,来自每条请求的统一埋点。一张字段表:

字段 类型 用途
request_id 字符串 串联一次请求的全程日志
model 字符串 区分多模型路由,成本分桶
biz_line 字符串 按业务线拆命中率
input_tokens 整数 计算命中率分母
cache_hit_tokens 整数 命中率分子
cache_layer 枚举 命中发生在引擎/网关/语义哪层
miss_reason 枚举 未命中归因:漂移/逐出/本就不同
cost_saved 浮点 本次节省金额,成本仪表盘直接取
adopted 布尔 回答是否被用户采纳,质量用
negative_fb 布尔 用户负反馈,质量用

这些字段在 5.2 网关的命中/未命中分支里各补一行就能产出;引擎层的前缀命中 token 从引擎暴露的指标端点同步过来。字段齐了,三张图只是不同的聚合视角。

告警阈值建议

  • 整体命中率连续 10 分钟低于该业务线基线 15 个百分点,告警——可能是键漂移或逐出加剧。
  • 缓存写溢价占比连续上升且节省金额转负,告警——命中率跌破经济临界点。
  • 命中回答负反馈率超过 1%,告警——优先排查语义层误命中。

阈值要随业务线分别设,不能全网一个值。长前缀、高重复的业务线天然命中率高,用低基线会一直误报;短前缀、强个性化的线命中率本就低,用高基线会永远不报。

图 5-4:三仪表盘联动与问题定位路径

图 5-4:三仪表盘联动与问题定位路径

三张图如何互相印证

单看一张容易误判,三张对着看才能定位。举例:命中率仪表盘显示整体下跌,别急着改键——先看成本仪表盘,如果节省金额还是正的,说明只是长尾流量变化,不影响收益;再看质量仪表盘,如果负反馈没涨,说明下跌没伤质量。三张都稳,才是真稳。反过来,命中率跌、成本转负、质量报警三者同时出现,那基本可以断定是语义层误命中或键设计崩了,直接去查 miss_reasonnegative_fb

一段聚合统计代码

下面这段 Python 把埋点日志聚合成三张仪表盘的核心指标。假设日志是每行一个 JSON 的请求记录。

import json from collections import defaultdict rows = [] with open("access_log.jsonl") as f: for line in f: rows.append(json.loads(line)) # 命中率:按业务线聚合 by_line = defaultdict(lambda: [0, 0]) # [命中token, 输入token] for r in rows: b = r["biz_line"] by_line[b][0] += r["cache_hit_tokens"] by_line[b][1] += r["input_tokens"] print("== 各业务线命中率 ==") for b, (hit, tot) in by_line.items(): rate = hit / tot if tot else 0 print(f"{b}: {rate:.1%}") # 成本:总节省与写溢价占比 total_saved = sum(r["cost_saved"] for r in rows) write_premium = sum(r.get("write_premium", 0) for r in rows) print(f"总节省金额={total_saved:.2f} 写溢价占比={write_premium / (total_saved + write_premium):.1%}") # 质量:负反馈率与采纳率 neg = sum(1 for r in rows if r["negative_fb"]) adopt = sum(1 for r in rows if r["adopted"]) print(f"负反馈率={neg / len(rows):.2%} 采纳率={adopt / len(rows):.1%}")

同样的聚合用 SQL 也能写:SELECT biz_line, SUM(cache_hit_tokens)*1.0/SUM(input_tokens) ... GROUP BY biz_line。无论哪种,字段表对得上,三张仪表盘就都能直接生成。

收尾:数据交给下一章

本章从引擎开关一路做到监控大屏,手里现在有命中率曲线、节省金额、有效单价、负反馈率这一整套数。它们不是终点——第 6 章会把"节省金额"和"写溢价"换算成一张财务账,告诉你每回收一个 token 值多少真实成本,以及缓存要在多大命中率下才划算。工程跑通、度量齐全,账才能算得清。这也是"算力预付、缓存回收"这条主线,第一次完整闭环。三张盘联动的排障顺序如下:


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U