大模型 API 费用异常上涨怎么排查:用单次成功任务成本定位变化发生在哪一步

简介: 当费用增速超调用量时,应计算“单次成功任务成本”(总费用÷验收通过数),并拆解为三个归因乘数:每任务调用次数、单次请求平均费用、任务通过率。通过本地JSON Lines日志+轻量Python脚本即可精准定位成本异动根源,无需建库。

费用涨得快于调用量时,先算单次成功任务成本,再看它的三个组成部分哪一项变了。

  • 指标:统计期内全部请求费用(含失败和重试)除以验收通过的任务数。
  • 拆分:指标等于每任务调用次数、单次请求平均费用、任务通过率三个乘数的组合。变化能定位到其中一项。
  • 方法:每次请求写一行日志,用一个 Python 脚本汇总,再用平台用量导出对账。脚本在模拟数据上的输出与手算一致,本文没有用真实账单验证。

一、单次成功任务成本怎么算?

分母只数验收通过的任务,失败和重试的费用全部留在分子里,因此失败会直接拉高这个指标。

单次成功任务成本 = 统计期内全部请求费用(含失败、重试) ÷ 验收通过的任务数

用调用次数做分母会掩盖两件事:

  • 失败和重试的费用被摊平在成功请求的单价里。
  • 一个任务可能调用模型好几次,调用次数说明不了完成了多少工作。

二、费用变化来自三个乘数中的哪一个?

指标可以拆成三个乘数,每个乘数对应不同的排查方向。这个拆分由定义直接推出,与模型和价格无关。

单次成功任务成本 = 每任务调用次数 × 单次请求平均费用 ÷ 任务通过率

乘数 含义 偏高时先查
每任务调用次数 一个任务发出的请求数,含工具循环和重试 Agent 循环是否失控,同一工具、同一参数是否反复出现
单次请求平均费用 输入、缓存、输出按单价折算后的平均值 输入是否变长,Top-K 是否过大,输出有没有上限,模型是否偏大
任务通过率 验收通过的任务占全部任务的比例 失败是否集中在某一类任务,校验规则是否变严

通过率下降时,即使每次请求的费用没有变,指标也会上升。按调用次数统计看不到这一点。用第七节的模拟数据代入:每任务调用次数 2.00,通过率 0.5,单次请求平均费用约 0.0564,乘积约为 0.2255,与脚本输出一致(手算,未实测)。

三、每次请求要记录哪些字段?

日志每行对应一次请求,包括失败和重试。字段要先归一化,才能跨模型相加。每个字段对应一个乘数:

日志字段 对应乘数
input_tokens、cache_read_tokens、cache_write_tokens、output_tokens 单次请求平均费用
model 单次请求平均费用(按模型拆分)
task_id(同一任务的行数) 每任务调用次数
task_passed 任务通过率

input_tokens 只记未缓存输入,不含缓存读取和缓存写入。返回字段的命名因接口而异。本文参考的阿里云百炼上下文缓存文档示例中,缓存命中数写在 prompt_tokens_details.cached_tokens,缓存创建数写在 cache_creation_input_tokens。各家是否把缓存部分计入 prompt_tokens,口径不同,写入日志前要用一条请求核对。没有缓存的字段填 0,不留空。task_passed 在任务验收后写入,同一任务的每一行值相同。

对账时,平台侧的用量要按 request_id 和本地日志对齐。本文示例使用 灵眸 AI 的用量导出接口,选用它的原因是导出数据逐条包含 request_id、各类 Token 数和实扣费用 actual_cost,可以直接和本地日志核对。第七节说明了对账步骤。

四、为什么用日志文件加脚本,不建数据库?

日志文件加离线脚本就能回答"哪一步变贵",而且实现最少。下面是几种备选方案的取舍。

方案 结论 原因
只看调用次数和单价 放弃 失败重试的费用被摊平,多次调用的任务无法比较
只看账单月总额 放弃 没有任务维度,无法判断哪一步变贵
用平台导出做日常统计 只用于对账 导出数据没有任务 ID 和验收结果
写入数据库并接入监控告警 暂不做 统计是离线的,日志量小时文件更容易检查
JSON Lines 加脚本 采用 每行独立,写入中断只影响一行;同一文件可以反复复算

日志采用 JSON Lines 格式。规范要求 UTF-8 编码,每行是一个合法的 JSON 值,适合逐行追加。脚本只依赖 Python 标准库中的 json 模块。文中的方案没有使用阿里云 ECS、日志服务或云监控。

五、怎么运行脚本算出单次成功任务成本?

脚本算出的是按单价估算的数字,不替代账单。它做三件事:

  • 读取日志。
  • 按任务汇总,统计通过数和调用次数。
  • 按单价重算每条请求的费用。

验收结束后,同一任务的所有行要写入相同的 task_passed。回填方式可以是重写这些行,也可以单独记录验收结果,汇总时按 task_id 关联。脚本读取的是已填好的文件。

运行前先把 PRICES 换成所选型号官方价目表上的单价,并注明核对日期。价目表里没有的模型名会抛出 KeyError。

import json
import sys

# 示例单价:元 / 百万 Token,发布前替换为所选型号官方价目表的数字
PRICES = {
   
    "model-large": {
   "input": 10.0, "cache_read": 1.0, "cache_write": 12.5, "output": 40.0},
    "model-small": {
   "input": 1.0, "cache_read": 0.1, "cache_write": 1.25, "output": 4.0},
}
USAGE_FIELDS = ("input_tokens", "cache_read_tokens", "cache_write_tokens", "output_tokens")


def record_cost(rec):
    # 字段已归一:input_tokens 是未缓存输入,不含缓存读取和缓存写入
    p = PRICES[rec["model"]]
    return (rec["input_tokens"] * p["input"]
            + rec["cache_read_tokens"] * p["cache_read"]
            + rec["cache_write_tokens"] * p["cache_write"]
            + rec["output_tokens"] * p["output"]) / 1e6


def has_usage(rec):
    # 任一用量字段缺失都不计费,避免按 0 计
    return all(rec[k] is not None for k in USAGE_FIELDS)


def summarize(path):
    passed = {
   }  # 任务 ID -> 验收是否通过,同一任务的每条记录填相同值
    calls = missing = 0
    cost_all = input_all = cache_all = 0.0
    with open(path, encoding="utf-8") as f:
        for line in f:
            rec = json.loads(line)
            calls += 1
            passed[rec["task_id"]] = rec["task_passed"]
            if not has_usage(rec):
                missing += 1  # 用量缺失时不按 0 计,单独统计
                continue
            cost_all += record_cost(rec)
            input_all += rec["input_tokens"] + rec["cache_read_tokens"] + rec["cache_write_tokens"]
            cache_all += rec["cache_read_tokens"]
    ok = sum(passed.values())
    print(f"任务数 {len(passed)},验收通过 {ok},调用次数 {calls},平均每任务 {calls / len(passed):.2f} 次")
    print(f"总费用(含失败与重试):{cost_all:.4f}")
    if input_all:
        print(f"缓存命中率(缓存读取 / 全部输入):{cache_all / input_all:.1%}")
    if ok:
        print(f"单次成功任务成本:{cost_all / ok:.4f}")
    if missing:
        print(f"警告:{missing} 条记录缺少用量,未计入费用,上面的数字偏低,需对账")


if __name__ == "__main__":
    summarize(sys.argv[1])

示例日志 usage.jsonl 的数据为虚构,只用于验证脚本。

{
   "task_id":"t1","model":"model-large","input_tokens":8000,"cache_read_tokens":6000,"cache_write_tokens":0,"output_tokens":500,"task_passed":true}
{
   "task_id":"t1","model":"model-small","input_tokens":1200,"cache_read_tokens":0,"cache_write_tokens":0,"output_tokens":80,"task_passed":true}
{
   "task_id":"t2","model":"model-large","input_tokens":9000,"cache_read_tokens":0,"cache_write_tokens":0,"output_tokens":700,"task_passed":false}
{
   "task_id":"t2","model":"model-large","input_tokens":null,"cache_read_tokens":0,"cache_write_tokens":0,"output_tokens":null,"task_passed":false}

Windows PowerShell 中先设置编码,否则控制台可能出现中文乱码。

$env:PYTHONIOENCODING = "utf-8"
python cps.py usage.jsonl

六、费用偏高时先改哪一项?

先按第二节判断哪个乘数偏高,再只改对应的一项。下面的改动按成本从低到高排列。每次只改一项,并用同一统计期比较改前改后。

  1. 先看失败集中在哪。(任务通过率)按任务类型统计失败率。失败集中在某一类任务时,先修这类任务的输入或校验规则。增加重试解决不了这类问题,还会抬高分子。
  2. 给流程设边界。(每任务调用次数)Agent 设最大轮次、超时和预算。同一工具、同一参数重复执行时中止,并记录原因。能用代码校验的格式交给代码,重试集中在一处并设上限。
  3. 换模型,不动流程。(单次请求平均费用)分类、标签这类任务先试小模型。在同一批样本上比较准确率和完整任务费用,再小范围切换。
  4. 精简输入。(单次请求平均费用)删除重复的系统指令。历史保留关键事实和最近几轮,早期内容改成摘要,摘要本身也计费。RAG 先去重,再缩小 Top-K 并测试召回质量。时间范围、产品版本、排除项这类限制条件不要删。
  5. 调整缓存前缀。(单次请求平均费用)稳定内容(指令、文档、工具定义)放在前面,变化的问题放在后面。阿里云百炼的上下文缓存文档写明,显式缓存的创建按输入单价的 125% 计费,命中按 10% 计费,有效期 5 分钟;隐式缓存命中按 20% 计费,命中率不确定;缓存块的内容最少为 1024 Token。所以只有前缀在 5 分钟内被多次命中,缓存才会省钱。低频复用的前缀,写入成本可能高于节省的部分。
  6. 约束输出,但别卡死。(单次请求平均费用)各家接口对输出上限的参数名不同。Anthropic 的 Messages API 用 max_tokens,OpenAI 的 Responses API 用 max_output_tokens。上限过紧会截断答案并触发重试,推理内容也占生成额度。
  7. 比较供应商时算完整任务价格。(单次请求平均费用)输入、输出、缓存读写和存储费一起算,不能只比最低输入单价。

【建议补上 EEAT|专业:写出你们遇到的例外,例如哪些分类任务换小模型后准确率下降,以及判断依据。】

七、脚本结果可信吗?能和平台账单对上吗?

脚本输出与手算一致,验证的是计算逻辑,不是账单。

验证环境为 Windows,Python 3.14.3。样本是 2 个虚构任务、4 次调用,其中 1 行用量缺失。手算如下:大模型两次调用为 (8000 × 10 + 6000 × 1 + 500 × 40 + 9000 × 10 + 700 × 40) ÷ 10⁶ = 0.224,小模型一次调用为 (1200 × 1 + 80 × 4) ÷ 10⁶ = 0.00152,合计 0.22552。脚本输出如下:

任务数 2,验收通过 1,调用次数 4,平均每任务 2.00 次
总费用(含失败与重试):0.2255
缓存命中率(缓存读取 / 全部输入):24.8%
单次成功任务成本:0.2255
警告:1 条记录缺少用量,未计入费用,上面的数字偏低,需对账

模拟任务的费用几乎全部来自大模型。两个大模型调用占总费用的 99.3%,小模型只占 0.7%(手算,未实测)。缓存命中率 24.8% 也全部来自 t1 的大模型调用。因此第六节的第三项(换小模型)应先评估。

判断用量缺失时要检查全部用量字段。只检查输入字段,遇到 output_tokens 为空的行,脚本会在计算费用时抛出 TypeError。另用一份数据测试,修正后的判断把这一行计入缺失警告:

任务数 2,验收通过 1,调用次数 2,平均每任务 1.00 次
总费用(含失败与重试):0.1000
缓存命中率(缓存读取 / 全部输入):0.0%
单次成功任务成本:0.1000
警告:1 条记录缺少用量,未计入费用,上面的数字偏低,需对账

【建议补上 EEAT|经验:放一次真实改动的前后对比,写明统计期、任务数和模型;没有真实数据就不写。】

对账步骤按接口说明编写,没有用真实账户执行。灵眸 AI 的用量导出接口需要账号鉴权,调用分两步:先用账号和密码请求登录接口换取 JWT,再用 JWT 按 start_date、end_date 和 timezone 分页调用用量接口。使用时要注意以下几点。

  • 接口只接受账号 JWT,不接受 sk- 开头的 API Key。接口说明把这一点列为有意的安全设计。
  • 账号密码等同于完整的账户访问权限,应放在环境变量里,不写进脚本。
  • 导出字段 actual_cost 是按美元计的实际扣费,等于 total_cost 乘以 rate_multiplier。第五节的脚本按单价重算,不能替代这个值。
  • 导出字段里没有任务 ID 和验收结果,调用时要把 request_id 与 task_id 一起记下。
  • 接口说明没有写明 input_tokens 是否包含 cache_read_tokens。用一条已知缓存命中的请求核对后,再套用归一化规则。
  • 日期参数要同时传 timezone,否则日期边界按 UTC 切分,会和本地日志差出一段时间。
  • 调用元数据保留 90 天,跨季度对账前要定期导出存档。

八、这套方法有哪些限制?

这套方法能指出费用变化来自哪一个乘数,不能保证省钱。

  • 省下的费用如果换来质量下降,任务通过率会变化,指标可能反而上升。
  • 脚本只统计已记录的请求。平台返回但日志里没有的请求,要和账单逐条对账。
  • 价格写死在 PRICES 中,官方调价后要同步更新,并注明核对日期。阶梯价、时段价和批量折扣没有实现。
  • 缺失的用量不能按 0 计。按 0 计时,总费用和指标都会偏低,容易误判优化已经见效。
  • 自动重试只能处理部分临时错误,不能消除所有 429,也不能替代上游额度规划。
  • 失败请求是否计费,以厂商文档为准。无法确认时按可能计费处理,计入分子。
  • 缓存命中率的分母是全部输入,即未缓存输入、缓存读取和缓存写入之和,不含输出。只用未缓存输入做分母,比率会偏高。

九、上线前要检查哪些项?

上线前对照下面七项检查。每项都做到,指标才能用来判断优化是否有效。

  • [ ] 每次请求都写一条日志,包括失败和重试
  • [ ] 输入、缓存读取、缓存写入、输出分开记录
  • [ ] 日志里有请求 ID 和任务 ID,导出后能关联
  • [ ] 按任务统计验收通过数,计算单次成功任务成本
  • [ ] Agent 设最大轮次和预算,分类类任务限定模型
  • [ ] 导出明细时传入时区,并定期存档
  • [ ] 每次优化只改一项,用同一统计期比较

费用上涨时,先算三个乘数里哪一个变了,再决定改哪一步。你们的单任务成本主要花在哪一个乘数上?

常见问题

没有明确验收标准的任务,怎么算成功?

没有验收标准,这个指标就算不出来。先定义可判定的结果,例如输出通过 JSON 校验、测试用例全部通过,或人工抽检通过,并把判定方式记在日志里。

为什么不直接用平台导出的 actual_cost 做统计?

actual_cost 是每次请求的实际扣费,但导出数据没有任务 ID 和验收结果,算不出单次成功任务成本。它适合核对总额,任务统计要靠本地日志按 task_id 汇总。

平台导出的用量和本地日志对不上,先查什么?

先查三项:导出时是否传了 timezone,两边的 request_id 能否对上,缓存部分是否包含在 input_tokens 里。三项都确认后仍有差异,再逐条比对。

价格调整后,历史数据怎么算?

每个统计期保存当时生效的价目表,分别运行脚本。本文的 PRICES 只有一套价格,直接替换后重算,会用新价格覆盖旧的结论。

参考资料

【发布前核对:Anthropic 与 OpenAI 的页面需在可访问的网络下逐个打开确认,本次核对环境无法打开。】

相关文章
|
6天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
2785 22
|
1天前
|
云安全 人工智能 安全
|
5天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
|
6天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
1249 5
|
云安全 安全 网络安全
|
7天前
|
安全 算法 定位技术
《高性价比人生指南》完整原版:普通人用最少的资源,过好这一生的底层逻辑~How To Live Better
📖《高性价比人生指南》是一份基于实证、拒绝焦虑的生存手册,倡导以“人生时薪”为视角,重新计算时间、金钱与精力的成本与收益。它不承诺逆袭,只教人算清账:省下的钱若耗掉时间便亏;买体验比买物品更值;睡眠是最高杠杆的健康投资;关系贵在情绪价值而非表面热络;学习重在改变行为而非自我安慰。核心理念:用低成本、高回报的微小行动,换取长期的选择权——不是成为谁,而是掌控自己人生的主动权。
|
19天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
3364 52
|
11天前
|
人工智能 JSON Linux
【保姆级】ComfyUI部署教程(下载+安装+配置+工作流,2026最新)
ComfyUI 是一款开源节点式AI生成工具,支持图像、视频、音频及3D内容创作。通过拖拽连线组合模型加载、提示词、采样等节点,构建可复用、易修改的工作流,兼容SD1.5、SDXL、Flux、Qwen Image等主流模型。

热门文章

最新文章