前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
返回 AI 情报前线
All News · 全部资讯10185
  • AWS 智能体跨库查询如何落实用户级权限
  • 提示注入检测为何被同义改写绕过
  • Synapse 打通编程助手的记忆与配置
  • vLLM 与 SGLang 新增 TPU 原生后端
  • 给水印检测加门控,减少误选与修复风险
  • 用本地语音组件搭建可打断的 AI 助手
  • Claude Code 误删复盘:命令钩子的盲区
  • Mac 跨应用文本助手如何读取界面
  • 用 AI 编程智能体清理电视广告与预装应用
  • DeepSeek开放生产推理框架DeepInfer
  • 京东大促期间暂停外部安全测试
  • Coral NPU补齐矩阵单元与开源编译链
  • 向量检索与知识图谱如何协同支撑 RAG
  • 让编程助手接入浏览器完成调试闭环
  • 先验证分类器,再让 AI 排查运行轨迹
  • 录制模型响应,隔离评测代码与模型变动
  • 审查 AI 生成 PR,先核对任务边界
  • 用有效吞吐压测确定模型接口并发上限
  • Agent 改一个字段,如何证明操作正确
  • 用多任务决策模型自动分流 CVE 漏洞
  • 逐步核算 Token,定位 Agent 的结构性浪费
  • Agent 生成 SQL,如何控制重跑漂移
  • 审核超时后的任务释放与计费隔离
  • DeepSeek 开源大规模推理框架 DeepInfer
  • DeepInfer 开源,公开大规模推理部署能力
  • Cloudflare预览低价结构化抽取模型
  • Headroom 在本地压缩智能体上下文
  • 智能体改记忆,如何验证没有误伤
  • llama-server 工具控制与停止条件现兼容问题
  • 模型快十倍,智能体为何只快一点
  • 用决策模型做评测,先调分类阈值
  • 编码 Agent 实测:成本之外看交付细节
  • Mercury 3 发布:主打高速生成与百万上下文
  • 用 Node 拆解向量池化与检索质量
  • 补齐 Oracle 方言约束,轻量模型首答率跃升
  • 拆解 Claude Code 的完整智能体循环
  • 邮件 Agent 重试前先校验退信
  • 用信号队列约束 Agent 等待邮件
  • 用 Cloudflare 搭建 Agent 收信中枢
  • 一次字符串替换如何让线上文章翻倍
  • AI 搭项目失败,先确认代码是否拉取成功
  • 检索匹配再高,也救不了过期知识库
  • 本地模型帮你给常用命令起快捷名
  • MCP 无状态改版涉及哪些迁移工作
  • 检查 Supabase 服务端鉴权的信任来源
  • 流式 AI 接口延迟该如何拆分测量
  • 模型故障切换如何追踪实际调用路径
  • 百灵开放五款语音模型供开发者组合
  • Drex Max 为电脑操作智能体输出决策概率
  • 无人值守的 Claude 循环如何耗尽额度
  • Bedrock为Claude提供严格结构化输出
  • 已加载 51 / 10185
8.0
热点
AI SCORE
技术实践2026-10-20 17:44

逐步核算 Token,定位 Agent 的结构性浪费

dev.to · AI#Agent#Token#成本优化
Editor brief · 编辑速览

文章以验证失败后反复重传4000 Token 工具输出的案例,说明 Agent 预算可能被重试与重复上下文耗尽。作者提出按步骤计量用量、识别五类浪费,再决定是否调整模型路由。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

我曾合作过的一个团队,有个每晚执行的 Agent 任务,原计划运行六个小时。结果到了上午 11 点,当天的额度就耗尽了,而九份摘要里只有两份能用。

没人说得清,到底是哪一步吃掉了这些 token。router 日志能看到请求,却看不到成本。于是,大家的第一反应就是怪模型。

问题不在模型。真正的原因是第 7 步:校验连续失败了四次,每次重试都重新发送了同一份 4,000 token 的工具输出。

这个小案例浓缩了整个问题:Agent 预算很少被某一次巨大的调用耗尽。真正耗尽预算的,是请求日志里没有记录的结构性浪费。

下面是我现在动手修改之前都会做的一套核算:一个小型计量脚本、五种浪费特征,以及修复它们的先后顺序。

1. 从报告入手,别先动 router

路由决策不该是第一个调整项。如果计费 token 中有 40% 都花在某个始终失败的调用重试上,怎么重新路由都没用;你只是在用更低的成本继续失败。

先按步骤计量。这样,路由问题才能用数字来回答,而不是凭感觉。

术语表(六个术语,下文统一使用)

第六个术语最重要。一棵每次运行都给出三条建议的决策树,没人会照着执行。

2. 计量脚本(仅用标准库,约 60 行)

每个步骤需要三个数字,provider 已经在 usage 中返回了这些数据。另外,你还要自己补上两项标注:有多少 token 是静态内容,有多少 token 是从前面的步骤原样复用的。

这些标注可以手动填写,也可以用启发式方法估算。这恰恰是它的价值所在:它会迫使你认真看一遍 prompt。

#!/usr/bin/env python3
"""meter.py - per-step token accounting for agent runs. Python 3.10+, stdlib only."""
from __future__ import annotations

import json
import sys
from dataclasses import dataclass

@dataclass
class Step:
    name: str
    prompt_tokens: int
    completion_tokens: int
    static_tokens: int = 0   # system prompt + tool schemas, paid per call
    reused_tokens: int = 0   # context carried over unchanged from an earlier step
    attempt: int = 1
    ok: bool = True

def load(path: str) -> list[Step]:
    with open(path, encoding="utf-8") as fh:
        return [Step(**row) for row in json.load(fh)]

def summarize(steps: list[Step]) -> dict:
    prompt = sum(s.prompt_tokens for s in steps)
    completion = sum(s.completion_tokens for s in steps)
    if not steps or prompt == 0:
        return {"steps": len(steps), "billed_tokens": prompt + completion}

    billed = prompt + completion
    wasted_retry = sum(
        s.prompt_tokens + s.completion_tokens for s in steps if not s.ok
    )
    ok_steps = [s for s in steps if s.ok]
    first = ok_steps[0].prompt_tokens if ok_steps else 0
    last = ok_steps[-1].prompt_tokens if ok_steps else 0

    return {
        "steps": len(steps),
        "billed_tokens": billed,
        "overhead_ratio": round(sum(s.static_tokens for s in steps) / prompt, 3),
        "retry_amplification": round(wasted_retry / billed, 3),
        "redundancy_ratio": round(sum(s.reused_tokens for s in steps) / prompt, 3),
        "prompt_growth": round((last - first) / first, 3) if first else 0.0,
    }

ACTIONS = {
    "B_retry": "install a stop rule before touching anything else",
    "A_overhead": "shrink the system prompt and tool schemas",
    "C_redundancy": "collapse steps or externalize state",
    "D_drift": "cap the transcript, move history to a scratch file",
    "F_leave_it": "budget is healthy; change nothing",
}

def classify(m: dict) -> str:
    if not m.get("billed_tokens"):
        return "F_leave_it"
    if m["retry_amplification"] > 0.25:
        return "B_retry"
    if m["overhead_ratio"] > 0.60:
        return "A_overhead"
    if m["redundancy_ratio"] > 0.40 and m["steps"] >= 8:
        return "C_redundancy"
    if m["prompt_growth"] > 0.30:
        return "D_drift"
    return "F_leave_it"

def main(argv: list[str]) -> int:
    if len(argv) != 2:
        print("usage: meter.py steps.json", file=sys.stderr)
        return 2
    report = summarize(load(argv[1]))
    leaf = classify(report)
    report["leaf"] = leaf
    report["first_action"] = ACTIONS[leaf]
    print(json.dumps(report, indent=2))
    return 0

if __name__ == "__main__":
    raise SystemExit(main(sys.argv))

输入是一个扁平的 JSON 数组。用三行数据就足以展示它的结构:

[
  {"name": "plan",            "prompt_tokens": 3200, "completion_tokens": 410, "static_tokens": 2400, "reused_tokens": 0,    "attempt": 1, "ok": true},
  {"name": "fetch_schema",    "prompt_tokens": 5100, "completion_tokens": 120, "static_tokens": 2400, "reused_tokens": 2600, "attempt": 1, "ok": true},
  {"name": "validate_schema", "prompt_tokens": 5400, "completion_tokens": 90,  "static_tokens": 2400, "reused_tokens": 2600, "attempt": 3, "ok": false}
]
python meter.py steps.json

注意:这个脚本使用 Python 3.10+,不依赖第三方库。我只用合成的 usage 字典测试过它,因此,应当把它的输出看作对运行结构的描述,而不是任何模型或 provider 的基准测试结果。

3. 决策树:按修复顺序排列

分支的排列依据是忽视问题的代价,而不是形式上是否优雅。首先检查重试,是因为它修起来成本最低,放着不管的代价却最高。

retry_amplification > 0.25 → 叶节点 B。四分之一的预算花在了失败的尝试上。应该更早终止运行。

overhead_ratio > 0.60 → 叶节点 A。每次 prompt 的大部分内容,都是你写过一次、此后却一直在付费的固定模板。

redundancy_ratio > 0.40,且至少有 8 个步骤 → 叶节点 C。长流程一直在重复发送相同的材料。

prompt_growth > 0.30 → 叶节点 D。对话记录的增长速度超过了实际工作的推进速度。

以上均不满足 → 叶节点 F。什么都不用做。这个叶节点确实有必要存在,而且应该经常命中。

叶节点 B 的停止规则

比例只能帮助诊断;你还需要在代码里设置强制停止条件。

DAILY_ALLOWANCE = 1_000_000          # your number, from your own account
MAX_WASTE_RATIO = 0.25
wasted = 0

for step in steps:
    result = run_step(step)
    if not result.ok:
        wasted += result.prompt_tokens + result.completion_tokens
    if wasted > DAILY_ALLOWANCE * MAX_WASTE_RATIO:
        raise SystemExit("stop: waste budget exhausted, fix the failing step first")

这样就把看不见的资源流失变成了看得见的崩溃。崩溃会有人修;资源流失只会继续出现在账单上。

4. 各个叶节点的具体示例

下面的数字来自用于说明问题的示例工作负载,并非对任何产品的实测结果。

叶节点 B——重试放大比例为 0.41。 九个步骤,计费 token 共 180k,其中 74k 花在了失败的校验尝试上。第一步:让校验器返回准确的字段路径,而不是 "invalid input"。第二步:应用上面的停止规则。预期效果有明确边界:你能限制损失,却无法收回已经消耗的 token。

叶节点 A——固定开销比例为 0.72。 平均每次 prompt 为 4,300 token,其中包含一份 3,100 token 的 system prompt 和四份 tool schema。第一步:把三个很少使用的工具移到第二次调用中。如果某份 schema 只有在规划之后才需要,就不该放进规划器的 prompt。

叶节点 C——冗余比例为 0.55,共 12 个步骤。 同一份代码仓库结构图被粘贴进了八个 prompt。第一步:将它移到外部文件中,让 Agent 按路径读取,只在 prompt 中传入一行索引。第二步:检查第 4 步和第 5 步能否合并。这些步骤之所以分开,往往是因为过去存在某个执行顺序约束,而如今这个约束已经不成立了。

叶节点 D——prompt 增长比例为 0.84。 第一次成功调用的 prompt 为 2,900 token,最后一次为 5,300 token。第一步:每三轮对话做一次摘要,写进临时笔记,然后移除原始对话。第二步:重新计量。如果仍在增长,说明 Agent 正在积累自己根本不会读取的状态。

叶节点 F——所有指标均低于阈值。 这套流程的正确输出,往往就是“不做改动”。记录报告,为 retry_amplification 设置告警,然后去做别的事。

5. 免费额度究竟在哪里能改变成本计算

有一种叶节点能从低成本算力中受益,但它并不是人们以为的那个。

叶节点 C 和叶节点 D 往往需要一个摘要器:在昂贵步骤读取历史记录之前,先用一个步骤将历史压缩。这一步重复性高、风险低,而且容易校验,很适合交给免费 endpoint,因为糟糕的摘要会在下一步明显暴露问题,而不是悄悄出错。

MonkeyCode 适合在这个环节进入工作流,而不是出现在文章标题里。该项目宣称提供免费的模型访问和免费服务器选项,撰文时还提供 1,000 万 token 的额度。这些都是运营方公布的数字,在据此制定计划之前,你应该先核实当前条款。利益披露:本文是作为 MonkeyCode 产品推广活动的一部分撰写的。

我不会先把规划步骤迁过去。先迁移那个最容易发现失败的步骤,再跑一次计量脚本,对比迁移前后的 billed_tokens。如果数字没有变化,免费额度就只是分散了注意力,没有带来优化。

6. 局限,以及哪些人可以跳过这套流程

usage 核算方式无法直接跨 provider 通用。 不同 provider 对缓存 token、推理 token 和工具调用 token 的报告方式各不相同。必须先统一口径,否则算出来的比例会误导你。

标注需要手动完成。 static_tokens 和 reused_tokens 来自你对 prompt 的阅读判断,而不是 API 返回的数据。

它衡量的是消耗,不是质量。 一次运行即使命中叶节点 F,结果也可能毫无用处。还需要配合任务级别的成功检查。

如果已经有 tracing,可以跳过。 如果你的技术栈已经记录了每个 span 的 token 数量,而且你信任这些数据,就直接用它们,只借鉴这里的修复顺序。

如果延迟才是主要瓶颈,可以跳过。 在受延迟限制的流水线中,为了节省 token 而缩短 prompt,可能付出的代价比节省的还多。

修复顺序比阈值更重要。先处理重试,再处理固定模板,然后处理冗余,最后处理增长。做完这些,通常就不需要再改什么了。

如果今天就想试试,把一次运行的 usage 字段保存成 JSON,再用计量脚本分析。整个过程很小,午饭前就能完成,而它返回的叶节点,比再重写一遍 router 更适合作为起点。如果你判断摘要器值得迁移,该项目的免费额度是个合理的试验选择——同时,继续运行计量脚本。

如需采取进一步行动,你可以考虑屏蔽此人和/或举报滥用行为。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
用多任务决策模型自动分流 CVE 漏洞
下一篇
Agent 生成 SQL,如何控制重跑漂移