LLM 成本异常检测
LLM 账单突然上涨,表面上是“调用变多了”,根因却可能完全不同:某个版本把完整对话重复塞进 prompt、失败请求进入无限重试、路由规则误把普通任务切到高成本模型,或者一个租户在短时间批量导入数据。只看每日总额,往往只能在损失发生后确认结果,无法告诉值班人异常从哪里开始。
成本异常检测要解决的不是“今天比昨天贵不贵”这么简单,而是持续判断:当前用量是否偏离了它本应处于的范围,偏离来自哪个维度,是否需要立刻处置。下面给出一套不依赖特定供应商、可以从小规模逐步扩展的工程方案。
一、先区分业务增长与系统异常
成本上涨不一定是事故。注册用户增长、付费客户扩容或批处理任务集中执行,都会带来合理增量。反过来,总成本没有明显变化,也可能藏着严重异常:某个功能成本翻倍,同时另一个功能流量下降,两者在总盘上互相抵消。
因此检测目标不能只有一个全局金额。至少要从四层观察:全站、租户、功能和模型。每层回答的问题不同:
| 检测层级 | 典型异常 | 判断时需要的上下文 |
|---|---|---|
| 全站 | 总体 burn rate 突升 | 工作日、活动、批任务窗口 |
| 租户 | 单客户突发放量 | 套餐、历史峰值、限额 |
| 功能 | 新版本单次任务变贵 | 发布版本、prompt 版本 |
| 模型 | 路由比例或单价口径变化 | 模型名、路由原因、价格版本 |
业务增长通常能在请求数、活跃租户数等指标上得到解释;系统异常则常表现为“单位任务成本”或“失败成本占比”突然变化。把总额拆成“任务量 × 单次任务成本”,是排除误报的第一步。
二、原始数据必须能支持回钻
检测算法再复杂,如果输入只有每日账单总额,也无法定位根因。建议每次模型调用生成一条成本事件,至少记录 request_id、时间、租户、功能、模型、输入与输出 token、缓存 token、状态、重试序号、prompt 版本和估算金额。
{
"request_id": "req_demo_01",
"tenant_id": "tenant_a",
"feature": "contract_summary",
"model": "model_route_standard",
"input_tokens": 12600,
"output_tokens": 940,
"retry_attempt": 2,
"status": "success",
"prompt_version": "summary-v17",
"estimated_cost": 0.084
}
这里的金额只是示例,不代表任何厂商价格。生产系统应让事件关联版本化价格表,并保留原始 token 口径。这样价格配置调整后可以重算历史数据,也能避免把“价格变了”误判成“应用行为变了”。更完整的记账结构可以参考 LLM Token 成本账本设计。
三、用多条基线代替一个固定阈值
“每小时超过固定金额就报警”适合早期止损,却很容易在流量周期明显的系统里反复误报。周一上午与周日凌晨、本月结算日与普通工作日,本来就不应该共享同一个期望值。
一个实用的起点是同时维护三条基线:
- 短周期基线:最近若干时间窗的移动中位数,用于发现突然跳变。
- 同期基线:过去几周相同星期、相同时段的分布,用于吸收业务周期。
- 单位基线:每次成功任务或每千次请求的成本,用于区分流量增长与效率退化。
相较均值,中位数和分位数不容易被少量极端值拉偏。团队不必一开始就引入复杂机器学习模型;只要历史窗口干净、维度合理,当前值 > 历史中位数 + 若干倍离散范围 就能覆盖大量真实事故。阈值中的倍数必须用自家历史回放确定,而不是照抄通用数字。
四、分层检测才能兼顾速度与噪声
检测频率越高、切分维度越细,响应越快,但误报和计算成本也会增加。可以采用由粗到细的两级结构:
- 第一级每几分钟扫描全局和主要业务线,发现 burn rate、单位任务成本或失败成本占比异常。
- 第二级只对可疑时间窗做租户、功能、模型、版本和重试原因下钻,生成贡献度排名。
例如全站成本抬升 40%,二级分析发现“合同摘要 + prompt v17”贡献了增量的 78%,且请求量只增加 5%,那么值班人应优先检查 prompt 和上下文拼装,而不是先限制全部用户。反之,如果增量均匀分布在多个功能,且成功任务数同步增加,更可能是正常业务增长。
低流量维度尤其需要保护。一个每天只有两次调用的功能,从一次涨到两次就是 100% 增长,却没有统计意义。常见做法是增加最小样本量或最小金额门槛,只有相对偏离和绝对影响同时满足时才通知人工。
五、把异常类型直接映射到排查路径
告警如果只写“成本超过基线”,值班人仍要从零开始查。更有效的方式是由指标组合推断异常类型,并在告警中附上排查入口:
| 指标组合 | 更可能的原因 | 优先检查 |
|---|---|---|
| 请求数不变,输入 token 上升 | 上下文膨胀 | prompt 版本、历史消息裁剪 |
| 失败成本与重试次数同步上升 | 重试风暴 | 429/5xx、退避与幂等 |
| 请求量不变,高成本路由占比上升 | 路由漂移 | 模型路由规则、fallback |
| 单租户成本突升,单位成本稳定 | 客户突发用量 | 配额、批量任务、账号安全 |
| 输出 token P95 上升 | 截止条件失效 | max_tokens、停止序列、工具循环 |
这类规则不要求百分之百自动判断根因,它的价值是把十几分钟的手工查询压缩为一个明确的调查方向。涉及错误重试时,可结合 LLM API 错误重试策略设计 检查退避、重试上限和不可重试错误分类。
六、告警要包含证据,而不只是严重级别
一条可处置的成本告警,至少应回答五个问题:何时开始、偏离基线多少、预计每小时额外消耗多少、前三个贡献维度是什么、最近是否有版本发布。最好同时给出代表性 request_id,让工程师能直接跳到 trace。
严重级别应由“异常置信度 × 财务影响 × 持续时间”共同决定。短暂小尖峰可以只进观察面板;连续多个窗口异常且额外消耗持续扩大,再升级到即时通知。对于已经确认的活动或批任务,应设置带过期时间的静默规则,避免永久豁免掩盖未来事故。
检测和止损也应解耦:检测器提供证据与建议,预算控制层决定降级、限流还是熔断。具体分级动作可参考 AI API 预算告警与自动熔断,不要让一个噪声较高的实验检测器直接关闭核心链路。
七、上线前用历史回放验证
异常检测不能只靠“上线后看看”。先准备一段包含工作日、周末、发布日和批任务的历史事件,标记已知事故,再回放不同窗口和阈值。评估时同时看召回率、误报次数、平均提前发现时间,以及每条告警能否定位到正确贡献维度。
上线初期建议只记录、不自动处置。每周复盘误报:是节假日周期没建模、业务活动没登记、样本量太小,还是价格版本发生变化。调整完成后再逐步把高置信度规则接入限流或降级。检测规则、基线版本和静默操作都应留下审计记录,便于解释某次事故为什么报警或没有报警。
八、相关阅读
如果你希望先统一多模型调用入口,再按租户、功能和模型沉淀成本事件,YoTradeApi 可以减少不同供应商协议带来的接入与统计口径差异。