资讯动态

Token用量面板v2.2:拆分输入输出与调用质量统计

发布时间:2026/10/26 21:09:48 来源:尧图企业网站定制
1. 从“一笔糊涂账”到“明细分账”Token 用量面板 v2.2 到底改了什么做 AI 编程助手接入或者自建 Agent 网关的朋友大概率都经历过这样一个阶段月初看账单发现 Token 消耗比预期高出一大截但翻遍日志也说不清这些 Token 到底花在哪了。是输入提示词太长是模型输出啰嗦还是某几个高频调用在偷偷重试、把额度白白烧掉v2.1 之前的用量面板基本只能给你一个总数就像手机账单只告诉你“本月消费 328 元”却不告诉你流量、通话、短信各占多少——你根本没法针对性优化。Token 用量面板 v2.2 这次的核心改动就是把原来那个笼统的“总 Token 数”拆成了输入 Tokenprompt token和输出 Tokencompletion token两条独立曲线同时新增了调用质量维度把成功、失败、退避重试这些状态也纳入统计。这个改动看起来只是多了几个字段但对真正要控成本、调优提示词、排查异常调用的人来说价值是质变级别的。因为输入和输出的计价方式、优化手段、异常特征完全不同输入 Token 高通常是上下文塞太多、历史消息没裁剪、系统提示词冗余输出 Token 高往往是模型话痨、max_tokens 没设好、或者任务本身就需要长文本生成。两者混在一起看你永远找不到病根。这篇文章适合三类人一是正在用 Codex 这类 AI 编程工具、想搞清楚自己额度去向的开发者二是自建了模型调用网关、需要做用量监控和成本分摊的团队三是单纯对 Token 计量、调用质量监控这套体系感兴趣、想自己动手做一个面板的技术爱好者。我会从设计思路讲到字段定义再讲到退避重试怎么统计、调用质量怎么算最后把我踩过的坑和排查经验一并倒出来。全文基于常见工程实践补充细节你照着思路基本能复现一套自己的版本。2. 为什么非要拆输入和输出计价逻辑与优化路径的根本差异2.1 输入输出混算等于把两种病当成一种治先说一个最容易被忽略的事实绝大多数模型服务的输入和输出单价是不一样的而且差距往往不小。以常见的按量计费模式为例输入 Token 单价通常低于输出 Token有的平台输出价格是输入的 3 到 4 倍。这意味着同样是一万 Token如果全是输出成本可能是全输入的几倍。你只统计总量等于把两种单价完全不同的东西加在一起求了个平均数这个平均数既不能反映真实成本也不能指导优化。更关键的是优化手段完全不同。输入 Token 的优化核心是“减法”裁剪历史对话、压缩系统提示词、去掉重复的上下文、用摘要替代全文。输出 Token 的优化核心是“约束”设置合理的 max_tokens、在提示词里明确要求简洁、对长文本任务做分段生成。你把这两类问题混在一个指标里就像医生只量体温不分科室发烧了不知道该挂呼吸科还是消化科。2.2 拆分之后异常定位从“猜”变成“看”我举个实际场景。之前有个朋友反馈说他的 Codex 调用额度掉得特别快但任务量并不大。v2.1 面板上只看到总 Token 飙升完全没头绪。升级到 v2.2 拆开看之后发现输入 Token 是正常水平输出 Token 却高得离谱。进一步查日志才明白他有个提示词里写了“请详细解释每一步”模型每次都输出大段分析单次调用输出动辄两三千 Token。把提示词改成“用要点回答每点不超过两句话”之后输出 Token 直接降了六成。这个问题在混算面板里根本定位不到因为总量看起来只是“偏高一点”拆开才发现是输出端在疯狂放血。反过来如果输入 Token 异常高那基本就是上下文管理出了问题。常见的是对话历史没有做窗口裁剪每轮都把前面几十轮全带上或者系统提示词里塞了大量示例和规则每次调用都重复计费。这两种病拆开看一目了然混着看就是一笔糊涂账。2.3 调用质量维度把“失败重试”这个隐形黑洞揪出来v2.2 另一个容易被低估的改动是调用质量统计。什么叫调用质量简单说就是每次调用不只看它消耗了多少 Token还要看它是不是一次成功、有没有触发退避重试、失败了几次才成功。这个维度为什么重要因为退避重试是 Token 消耗的隐形黑洞。设想一个场景你的网关在调用上游模型时遇到限流触发了退避重试机制第一次失败、等两秒重试、第二次又失败、再等四秒重试、第三次成功。从用户视角看这是一次成功的调用任务完成了。但从 Token 账单看前两次失败的请求如果已经产生了输入 Token 消耗很多平台即使请求失败也会计入输入 Token那你就为一次任务付了三次输入的钱。如果面板只统计“成功调用的 Token”这个黑洞就被完全掩盖了。v2.2 把重试次数和失败状态纳入统计后你才能看到“有效 Token”和“实际消耗 Token”之间的差额这个差额就是重试带来的损耗。3. 核心字段设计与统计口径每个数字背后的定义3.1 输入 Token 与输出 Token 的采集方式要把输入输出拆开前提是你的调用链路能拿到这两个值。主流模型 API 的响应体里通常会返回 usage 字段结构大致是这样{ usage: { prompt_tokens: 1024, completion_tokens: 512, total_tokens: 1536 } }你要做的就是在网关层把这个 usage 原样落库而不是只取 total_tokens。这里有个坑流式响应stream场景下usage 字段往往只在最后一个 chunk 里返回或者需要额外开启一个参数才会返回。如果你用的是流式调用又没处理这个细节就会导致输出 Token 统计为 0。我的做法是在流式请求里显式要求返回 usage并在解析最后一个数据块时提取。还有一种情况是调用失败、根本没返回 usage。这时候输入 Token 怎么算常见实践是用本地分词器对请求体做一次估算虽然和官方计数有偏差但用于监控趋势足够了。输出 Token 在失败场景下一般记为 0因为模型没产出内容。3.2 调用质量的状态机定义调用质量不是一个单一数字而是一组状态。我在实现时把它定义成这样一个状态机每次调用最终落到其中一个状态状态含义是否计入有效消耗success_first首次调用即成功是success_retry经过至少一次重试后成功是但需标记重试次数failed_final重试耗尽仍失败否但输入 Token 可能已消耗rate_limited被限流进入退避视平台而定timeout超时视平台而定这张表是整个调用质量统计的基础。有了它你才能算出“重试损耗率”这个关键指标重试损耗率 实际消耗 Token - 有效任务 Token/ 实际消耗 Token。这个比率越高说明你的调用链路越不稳定要么是并发太高被限流要么是网络抖动严重要么是上游服务本身不稳。3.3 退避重试的统计口径要统一退避重试的统计最容易出分歧。同样是“重试了 3 次”有人算 3 次调用有人算 1 次任务。我的建议是双层统计任务层记录这个任务总共发起了几次请求请求层记录每一次请求的独立状态。这样你既能看“平均每个任务重试几次”也能看“单次请求的成功率”。两个指标配合看才能判断问题出在任务设计还是链路稳定性。退避策略本身也影响统计。常见的指数退避是 1s、2s、4s、8s 这样翻倍也有固定间隔的。统计时要记录每次重试的等待时长因为等待时长直接关系到任务的总耗时。如果面板只统计 Token 不统计耗时你会漏掉“Token 没多花但任务慢得离谱”这种情况——比如上游一直限流你一直等Token 消耗正常但用户体验极差。4. 面板实现从数据采集到可视化落地4.1 数据采集层网关埋点是关键整个面板的数据源头在网关。无论你用的是自建网关还是现成的代理层都要确保每次调用都产出一条结构化日志。我推荐的字段清单如下request_id请求唯一标识用于串联重试task_id任务标识同一个任务的多次重试共享model模型名称prompt_tokens输入 Tokencompletion_tokens输出 Tokentotal_tokens总量冗余存储方便对账status调用状态对应上面的状态机retry_count该任务已重试次数latency_ms本次请求耗时backoff_ms本次重试前的等待时长timestamp时间戳error_code失败时的错误码这些字段落库之后面板的所有统计都只是 SQL 聚合的事。我实测下来用一张宽表存这些字段配合时间戳和 task_id 建索引千万级数据量下聚合查询也能秒级返回。4.2 聚合层三个核心视图面板不需要花哨三个视图就能覆盖 90% 的需求。第一个是趋势视图按小时或按天展示输入 Token、输出 Token、总 Token 三条曲线。这个视图用来发现异常波动。比如某天输出 Token 突然翻倍你就能顺着时间点去查那段时间的调用日志。第二个是质量视图展示成功率、重试损耗率、平均重试次数。这个视图用来监控链路健康度。成功率跌破某个阈值比如 95%就该告警了。第三个是明细视图按模型、按任务类型、按调用方维度下钻。这个视图用来做成本分摊。团队里多个项目共用一个网关时谁用得多、谁的重试率高一目了然。4.3 可视化层别追求炫酷追求一眼看懂我见过不少面板做得花里胡哨各种环形图、雷达图堆满屏幕结果没人看。用量面板的核心是“对比”和“趋势”所以折线图和堆叠柱状图是最实用的。输入输出用堆叠柱状图展示一眼就能看出两者比例重试损耗用折线单独画一条和总量曲线对比着看损耗高不高立刻显现。颜色上有个小技巧输入 Token 用冷色比如蓝色输出 Token 用暖色比如橙色因为输出通常更贵暖色能起到视觉警示作用。重试损耗用红色失败用灰色。这套配色我用了大半年团队里没人抱怨看不懂。5. 实操复现一步步搭起你自己的用量面板5.1 环境准备与依赖选型假设你要从零搭一套我推荐的技术栈是采集层用轻量级的日志中间件存储用带时序优化能力的关系库或时序库聚合查询直接写 SQL前端用任意图表库。为什么不上重型方案因为用量面板的数据结构非常简单就是一张宽表加几个聚合查询上分布式时序数据库属于杀鸡用牛刀运维成本反而更高。具体来说采集层可以在网关的响应处理钩子里加一段逻辑把 usage 和状态字段组装成 JSON 写进消息队列再由消费者批量入库。批量入库比逐条插入快一个数量级我实测过逐条插入在每秒几百次调用时就开始拖慢网关了改成批量后轻松扛住每秒几千次。5.2 关键代码usage 提取与状态判定下面这段是 usage 提取的核心逻辑处理了普通响应和流式响应两种情况def extract_usage(response, is_streamFalse): if not is_stream: usage response.get(usage, {}) return { prompt_tokens: usage.get(prompt_tokens, 0), completion_tokens: usage.get(completion_tokens, 0), total_tokens: usage.get(total_tokens, 0), } # 流式场景遍历所有 chunk取最后一个带 usage 的 last_usage {} for chunk in response: if chunk.get(usage): last_usage chunk[usage] return { prompt_tokens: last_usage.get(prompt_tokens, 0), completion_tokens: last_usage.get(completion_tokens, 0), total_tokens: last_usage.get(total_tokens, 0), }状态判定则要结合重试计数器和最终结果def judge_status(retry_count, final_success, error_codeNone): if final_success and retry_count 0: return success_first if final_success and retry_count 0: return success_retry if error_code 429: return rate_limited if error_code timeout: return timeout return failed_final这两段逻辑不复杂但覆盖了绝大多数场景。注意流式场景那个遍历一定要把整个流读完再取 usage中途 break 会漏掉最后一个 chunk。5.3 退避重试的实现与统计联动退避重试的实现要点是每次重试都要复用同一个 task_id但生成新的 request_id。这样统计时既能按 task 聚合也能按 request 聚合。退避等待时长建议用指数退避加随机抖动避免多个任务同时重试造成二次拥塞import random import time def backoff_wait(retry_count, base1.0, cap30.0): wait min(base * (2 ** retry_count), cap) jitter random.uniform(0, wait * 0.1) time.sleep(wait jitter) return wait jitter这个函数返回实际等待时长直接写进日志的 backoff_ms 字段。有了这个字段你就能算出“重试等待占总耗时的比例”。如果这个比例超过 30%说明你的链路稳定性有大问题得优先解决限流或网络问题而不是继续优化提示词。5.4 面板查询 SQL 示例趋势视图的聚合查询大概长这样SELECT date_trunc(hour, timestamp) AS hour, SUM(prompt_tokens) AS input_tokens, SUM(completion_tokens) AS output_tokens, SUM(total_tokens) AS total_tokens FROM token_usage WHERE timestamp NOW() - INTERVAL 7 days GROUP BY hour ORDER BY hour;质量视图则要算重试损耗率SELECT date_trunc(day, timestamp) AS day, COUNT(*) AS total_requests, SUM(CASE WHEN status success_first THEN 1 ELSE 0 END) AS first_success, SUM(CASE WHEN status success_retry THEN 1 ELSE 0 END) AS retry_success, SUM(CASE WHEN status failed_final THEN 1 ELSE 0 END) AS failed, ROUND( SUM(CASE WHEN status success_retry THEN total_tokens ELSE 0 END)::numeric / NULLIF(SUM(total_tokens), 0), 4 ) AS retry_loss_ratio FROM token_usage GROUP BY day ORDER BY day;这两条 SQL 就是面板的核心。你可以把它们包成接口前端定时拉取渲染。6. 常见问题与排查技巧实录6.1 输出 Token 统计为 0 怎么办这是最常见的坑九成是流式响应没处理 usage。排查步骤先确认你的请求有没有开启返回 usage 的参数再确认解析逻辑有没有把整个流读完最后确认最后一个 chunk 的结构有些平台把 usage 放在chunk[usage]有些放在chunk[choices][0][usage]字段路径不一样。我踩过一次排查了两小时才发现是路径写错了。6.2 重试次数统计偏高或偏低偏高通常是 task_id 生成逻辑有问题把不同任务算成了同一个。偏低则是重试时没复用 task_id每次重试都当成新任务。检查方法很简单随便挑一个重试过的任务看它的日志里 task_id 是否一致、request_id 是否不同。一致且不同就对了。6.3 输入 Token 估算和官方对不上本地分词器估算和官方计数有 5% 到 15% 的偏差是正常的因为不同模型的分词规则不一样。我的建议是成功调用一律用官方返回的 usage只有失败调用才用本地估算并且在面板上标注“估算值”。这样既保证了主要数据的准确性又不会因为失败调用而丢失监控能力。6.4 面板数据延迟严重多半是入库方式的问题。逐条插入改成批量插入批量大小控制在 500 到 1000 条延迟能从分钟级降到秒级。如果还慢检查索引是不是建多了——宽表上建太多索引会拖慢写入用量面板只需要在 timestamp 和 task_id 上建索引就够了。6.5 退避重试导致任务超时这是策略问题不是统计问题。指数退避的 cap 设太大比如 60 秒重试几次任务就超时了。我的经验是 cap 设在 10 到 30 秒之间重试上限设在 3 到 5 次。超过这个范围与其继续重试不如直接失败让上层决定要不要重新发起任务。7. 几个我踩过的坑和压箱底的技巧第一个坑是时区。面板按天聚合时如果数据库存的是 UTC 时间而你看的是本地时间跨天数据会对不上。我建议统一存 UTC展示时在前端转换别在数据库层做时区转换否则聚合逻辑会乱。第二个坑是模型版本混用。同一个模型名可能对应多个版本不同版本的 Token 计数规则可能不同。统计时最好把模型版本也作为一个维度存下来否则你看到某个模型 Token 突然变化可能只是上游悄悄换了版本。第三个技巧是给重试损耗设告警。重试损耗率超过 10% 就发通知这个阈值是我试出来的低于 10% 属于正常波动高于 10% 基本就是链路出问题了。告警比事后看面板有用得多能帮你把问题扼杀在账单爆炸之前。第四个技巧是保留原始日志至少 30 天。聚合数据只能告诉你“哪里不对”原始日志才能告诉你“为什么不对”。我遇到过好几次聚合数据异常最后都是翻原始日志才找到根因比如某个提示词模板被误改、某个调用方突然加大了并发。这套面板我从 v2.1 用到 v2.2最大的体会是Token 监控这件事拆得越细省得越多。输入输出拆开之后我帮团队把输出 Token 压下去了将近四成靠的就是发现几个高频提示词在诱导模型长篇大论。调用质量维度上线后又揪出两个因为限流导致重试率偏高的调用方调整并发之后重试损耗从 15% 降到了 3% 以下。这些收益在只看总量的时代是想都不敢想的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑