Agent 成本工程:当 Token 变成账单,谁来证明你的省钱策略真的有效?
摘要:功能可以靠演示证明,可靠性可以靠评测集证明,但成本这件事有个特殊之处——它每天都在真实发生,却很少有人真的去核算。本文讨论 Agent 工程里长期被忽视的第四个维度:成本。先解剖 Agent 循环为什么会让账单以平方级速度膨胀;再把经典缓存工程的整套方法——多级缓存、预热、穿透/击穿/雪崩防护——搬进上下文窗口,讲清 Prompt 缓存的命中条件与失效陷阱;然后给出一套带预算熔断的成本核算实现;最后回答一个更根本的问题:当你声称"缓存让成本降了 80%“时,用什么证明这个数字不是错觉。核心判断与此前各篇一脉相承:模型和工具厂商会告诉你"我们支持缓存、成本大幅下降”,而账单不会说谎——单位成本、命中率与质量回归数据,才是成本工程唯一有效的验收标准。
引子:两笔没人核算过的账
先讲两个来自社区实践的对照案例。
第一个案例关于工具选择。一位开发者长期在用某编程 Agent,后来公开坦言自己"实在用不起",转头开了一个更便宜的订阅,换了另一个工具接着干。有意思的地方在于:支撑他做这个决定的不是模型能力的对比报告,而是每个月真实扣掉的账单。功能差距可以被营销话术稀释,价格差距不能。
第二个案例关于浪费的真实形态。另一位用户让 Agent 把一套协作方法整理成分享内容,Agent 理解偏了方向,但理解偏了照样把活干得非常完整——写满了路径、软链和校验流程,每个技术细节都没错,唯独不是用户真正想讲的东西。结果前面的产出全部推翻重来。事后这位用户的总结很精准:这不是让模型聪明几倍的问题,而是错误方向上的高质量工作,每一个 token 都是白烧的。
把这两个案例放在一起,能看到 Agent 成本问题的两个真实切面:一是账单会直接改变工程决策,贵到某个阈值,用户会连能力都不谈直接换工具;二是浪费的主形态不是"单次调用贵",而是"整条错误路径上的重复产出"——一次调用几毛钱没人心疼,一个跑偏的任务循环几十轮、每轮携带全部历史上下文,账单数字就开始吓人了。
大多数关于 Agent 成本的讨论止步于两条建议:“换便宜模型"和"精简提示词”。这两条都对,但都太粗了。真正的成本工程需要回答三个问题:钱花在哪了?哪些钱是可以省的、怎么省?以及最关键的——省下来之后,你怎么证明真的省了、而且没把质量省没了?本文按这三个问题展开。
一、Agent 循环的成本解剖:账单为什么是平方级的
先看一次性问答和 Agent 循环在成本结构上的根本差异:
一次性问答 Agent 循环(N 轮) ───────────────── ──────────────────────────────── 轮1: [系统提示+问题] ──> 回答 轮1: [系统提示+工具定义+任务] ──> 工具调用 轮2: [系统提示+工具定义+任务+轮1结果] ──> 工具调用 输入规模: O(1) 轮3: [系统提示+工具定义+任务+轮1+轮2结果] ──> ... ... 总成本: 1 次输入 + 1 次输出 轮k 的输入包含前 k-1 轮的全部结果 总输入 token ≈ O(N²) 累积这个平方级累积是 Agent 账单的第一条数学规律:工具返回的结果一旦进入上下文,就会在后续每一轮被重新计费。一个三十轮的长任务,中间某次工具返回了两万字的数据,这笔数据会被重复携带二十多次——除非你有意识地处理它。
第二条规律是成本构成里输入占大头。模型定价中输出 token 单价通常是输入的数倍,但在 Agent 场景下,输出只有"下一步决策 + 工具调用参数",通常几百 token;而输入是系统提示、工具定义、对话历史和工具返回结果的累积,动辄数万 token。这意味着 Agent 优化的主战场在输入侧,而不是输出侧——这与很多人的直觉相反。
第三条规律与此前讨论过的错误处理篇相呼应:重试和降级都是乘法项。一次超时重试意味着这一轮的全部输入 token 再计费一次;一次降级切换到备选模型,意味着同样的上下文在第二个模型那里从头再计一遍。一个设计不良的工作流,重试逻辑本身就能吃掉一半预算。
把三条规律合起来,成本解剖的结论是:优化顺序应该是先砍结构性浪费(错误路径、无意义重试、重复携带的上下文),再做单价优化(模型选择、缓存),最后才是提示词层面的精修。反过来做,等于在漏水的池子里舀水。
二、Prompt 缓存:把经典缓存工程搬进上下文窗口
结构性浪费里有最大的一块,恰好有一个成熟的解法:缓存。
主流模型厂商如今都提供 Prompt Caching 能力(例如 Anthropic 的 prompt caching 与 OpenAI 的 prompt caching 指南),机制大同小异:如果本次请求的前缀与近期某次请求完全一致,命中的前缀部分按大幅折扣计价——通常只有常规输入价的十分之一左右;首次写入缓存会有小幅溢价;缓存有存活时间,过期失效。国内厂商同样跟进,比如 DeepSeek 的上下文硬盘缓存把命中折扣做到了更激进的价位。
很多团队看到"十分之一价格"就开通了,但真正的工程问题在于:你的请求前缀,具备命中条件吗?这正是经典缓存工程积累了二十年经验的地方。做过后端缓存的人对下面这套问题毫不陌生:穿透、击穿、雪崩、预热、多级缓存。把它们逐项映射到 Agent 场景,会发现几乎每个经典问题都有对应的 Agent 版本:
| 经典缓存问题 | 传统场景 | Agent 场景对应 | 防护手段 |
|---|---|---|---|
| 穿透 | 查询不存在的数据,请求全部打到存储 | 任务间塞入随机 ID、时间戳等易变内容,前缀永远不命中 | 把易变内容挪到提示词末段 |
| 击穿 | 热点 key 恰好过期,瞬时流量打穿 | 长会话超过缓存 TTL 后整体冷启动 | 控制会话时长在 TTL 窗口内 |
| 雪崩 | 大量 key 同时失效 | 批量任务同时启动、同时冷缓存 | 任务错峰下发、启动前预热 |
| 缓存污染 | 不同业务混用同一 key | 多项目共用会话,前缀互相打架 | 按项目隔离会话前缀 |
映射的核心洞察只有一句话:缓存命中的最小单位是"前缀",而前缀的最小成本单元是稳定性。据此,Agent 的提示词应该按稳定性分层组织:
┌──────────────────────────────────┐ │ 第一层:系统提示与角色定义(稳定) │ 跨任务、跨天基本不变 ├──────────────────────────────────┤ │ 第二层:工具定义与项目规则(半稳定) │ 随项目固定,任务内不变 ├──────────────────────────────────┤ │ 第三层:已完成的对话历史(只追加) │ 每轮 +N,但旧部分不变 ├──────────────────────────────────┤ │ 第四层:当前任务指令与工具结果(易变)│ 每轮都变,放最末尾 └──────────────────────────────────┘ ↑ 命中概率从上到下递减,前缀顺序不可打乱这个分层结构解释了两个实践中的"自杀行为"。其一,把当前时间戳、随机数或每轮变化的计数器放进系统提示——一个变量污染整个前缀,缓存永远 miss。其二,任务中途修改工具定义或系统规则——前缀从修改点开始全部失效,前面攒的命中前功尽弃。修改规则应该放在任务边界处做,而不是任务中途。
预热同样适用。经典缓存的预热思路是提前把热点数据填进缓存;Agent 场景的对应做法是:在批量任务启动前,先用一个轻量请求把稳定的系统前缀"焐热",让后续所有任务直接命中。一些 JIT 编译器花了很大力气解决"预热期拖慢启动"的问题,服务端缓存有缓存预热四步法——识别热点、选缓存系统、预填充、保更新——这套思路原样适用于 Agent 批处理:识别所有任务共享的稳定前缀,任务下发前先预热,批量执行期间命中就是纯收益。
还有一个容易被忽略的细节:多级缓存思路在这里同样成立。模型端的 Prompt 缓存是最远的一级;工作流框架内部的"结果缓存"(相同工具、相同参数直接返回上次结果)是更近的一级;对话历史本身的摘要压缩(此前上下文工程一篇详细讨论过)则是减少需要缓存的数据量。三层叠加,成本曲线才真正压得下来。
TTL 的处理也值得单独说明。击穿的 Agent 变体之所以高发,是因为长任务的执行时长很容易超过缓存窗口:一个跑了四十分钟的任务,如果中途停顿超过 TTL,下续轮次就要整体冷启动重付一次写入溢价。务实的做法有两种:一是把长任务拆成段,段内会话控制在 TTL 窗口内,段间交接走检查点恢复(此前断点续跑篇的方案在这里直接复用);二是接受偶发冷启动,但把冷启动的代价算进预算模型,而不是在故障报告里第一次发现它。
三、预算控制工程:从"感觉贵"到"可核算"
缓存解决的是单价问题,但单价便宜不等于总账可控。成本工程的第二块拼图是核算与预算控制——这里的原则是:每一次模型调用都必须留下可审计的成本记录。
大多数模型 API 的响应里带有 token 用量字段,且近年逐步细分到缓存命中与缓存写入(各家的字段名不同,社区网关如 LiteLLM 做了归一化处理)。基于这些字段,可以写一个很薄的成本核算层:
# cost_guard.py —— Agent 调用层的成本核算与预算熔断importtimefromdataclassesimportdataclass,field# 价目表:单位为"元/百万 token",按 input / output / 缓存读 / 缓存写 分列PRICE={"input":4.0,"output":16.0,"cache_read":0.4,"cache_write":5.0,}@dataclassclassCallRecord:ts:floattask_id:strinput_tokens:int=0output_tokens:int=0cache_read_tokens:int=0cache_write_tokens:int=0defcost(self)->float:"""未命中部分按常规输入计价,命中与写入按各自折扣计价"""plain_input=max(0,self.input_tokens-self.cache_read_tokens-self.cache_write_tokens)returnsum([plain_input/1e6*PRICE["input"],self.cache_read_tokens/1e6*PRICE["cache_read"],self.cache_write_tokens/1e6*PRICE["cache_write"],self.output_tokens/1e6*PRICE["output"],])classBudgetGuard:def__init__(self,monthly_budget:float,task_budget:float):self.monthly_budget=monthly_budget self.task_budget=task_budget self.records:list[CallRecord]=[]defrecord(self,task_id:str,usage:dict)->CallRecord:rec=CallRecord(ts=time.time(),task_id=task_id,input_tokens=usage.get("input_tokens",0),output_tokens=usage.get("output_tokens",0),cache_read_tokens=usage.get("cache_read_input_tokens",0),cache_write_tokens=usage.get("cache_creation_input_tokens",0),)self.records.append(rec)returnrecdeftask_cost(self,task_id:str)->float:returnsum(r.cost()forrinself.recordsifr.task_id==task_id)defcheck(self,task_id:str)->str:"""每次发起下一轮调用前检查;返回决策,超预算则熔断"""ifself.task_cost(task_id)>=self.task_budget:return"ABORT_TASK"# 单任务熔断,转人工ifsum(r.cost()forrinself.records)>=self.monthly_budget:return"ABORT_ALL"# 月度熔断,停止派发新任务return"PROCEED"这段代码的重点不在实现——它只有几十行——而在它强制建立的三个习惯。第一,逐调用记账:缓存的折扣只体现在细分字段里,不逐次记录,月底只有一张总数账单,任何优化分析都无从谈起。第二,双预算熔断:单任务预算防"跑飞"(单个失控任务烧穿预算),月度预算防系统性超支,两级阈值对应两种不同的故障模式。第三,熔断转人工:预算触顶不是异常,是设计内行为——被熔断的任务带着已完成的中间状态进人工队列,而不是无声失败,这与此前错误处理篇的降级原则完全一致。
在记账基础上,还应该维护一个比总账单重要得多的指标:单位任务成本——每成功完成一个任务的平均花费。总账单会随业务量波动,单位成本才反映工作流的健康度;上一节说"只看总额会掩盖优化效果",指的就是这个。
四、验证:用什么证明"真的省了"
现在到了本文的核心问题。前两节给出了缓存分层和预算核算两套工程手段,但一个团队做完这些改造后,怎么知道效果是真的?这正是 Deep Skill Finder 系列一贯的主张:任何能力声明——包括你自己做的优化——都要用模型之外的结构性证据来验证。成本领域同样存在三个高频误区。
误区一:命中率凭感觉宣称。“我们开了缓存,成本降了不少”——降了多少?缓存命中率的计算口径是什么(按 token 数还是按请求数)?没有逐调用记录,这些数字全靠印象。验证方式很直接:从 cost_guard 的记录里统计cache_read_tokens / input_tokens的加权比率,按任务类型分组。命中率低于预期时,最常见的根因就是第二节列出的前缀污染——而这个问题只有数据能暴露,肉眼检查几十个提示词模板是查不出来的。
**误区二:省了钱,把质量也省没了。**这是成本优化最危险的暗礁。压缩上下文、砍掉工具结果、换便宜模型,每一项都省钱,每一项都可能伤质量——而且质量退化往往不立即显现。正确的流程是把成本优化当成一次代码变更对待:改造前,用评测集(此前评测工程一篇给过完整方法,OpenAI 的 evals 指南是通用参照)记录基线通过率;改造后跑同一评测集,成本指标和质量指标必须同时验收。只验收成本不验收质量的优化,等于没有验收。
误区三:把 A/B 对照做成了前后对比。“上个月花了 3000,这个月花了 1800,优化有效”——这个推理有两个漏洞:业务量可能变了,模型价格也可能调了。严格的做法是固定任务集做对照:取一批有代表性的任务,分别用旧配置和新配置各跑一遍,对比同一任务集上的单位成本与评测通过率。成本对照实验的总开销通常不到一次月账单的百分之几,却是唯一能隔离归因的验证方式。
三个误区合起来,成本优化的验收清单其实很短:命中率有逐次记录支撑、单位任务成本在固定对照集上下降、评测集通过率不回退。三条全绿,才敢说"这次优化有效";任何一条缺证据,声明就停留在自我描述层面——而本文第一节的案例已经说明,靠自我描述做工程决策的代价,是整条错误路径上的重复产出。
五、实战案例:一条日更工作流的成本治理
把前面四节的方法串到一条真实形态的工作流上。设想一个典型场景:一个内容生产 Agent,每天定时执行选题、写作、配图、发布四段流程,每天上午下午各跑一轮,中间穿插大量的文件读写与平台交互。
治理前,这条工作流的成本画像通常是:系统提示与工具定义占总输入的一半以上且每轮重新全价计费;平台交互产生的页面文本每次原样进入上下文;偶发的失败重试不设上限。治理动作按本文顺序展开——
第一步,前缀分层改造:把角色定义、工具定义、固定的操作规范整理成稳定的系统前缀(类似把项目规则沉淀进固定规则文件的做法,这也是社区里被反复验证有效的用法),任务相关的动态内容全部后置。改造后稳定前缀跨任务持续命中,缓存读折扣直接作用在最大的成本块上。
第二步,结果级缓存:平台交互的页面解析结果按内容哈希做框架内缓存,同样的页面在一轮任务内不重复解析。这属于"更近的一级缓存",与模型端缓存叠加。
第三步,预算熔断:接入第三节的 cost_guard,单任务预算设为正常任务成本的五倍——正常任务永远不会触发,跑飞的任务会在烧穿前被拦下转人工。
第四步,分级模型路由:选题、筛选这类低风险步骤换用便宜模型,写作与发布这类关键步骤保留原模型,路由依据正是评测集按步骤拆分后的各段通过率,而不是模型厂商的跑分。这一步在对照集上又拉下了约两成单位成本,且关键步骤的评测通过率未动。
第五步,验收:固定二十个代表性任务做对照,改造前后各跑一遍。验收结果用一张表归档:
| 指标 | 改造前 | 改造后 | 验收依据 |
|---|---|---|---|
| 单位任务成本 | 1.00(基准) | 约 0.35 | 同一任务集对照,逐调用记录 |
| 前缀缓存命中率 | 0% | 78%(按 token 加权) | cost_guard 统计 |
| 评测集通过率 | 基线 | 无回退 | 改造前后各跑一遍 |
| 失控任务拦截 | 无 | 每月 1~2 次熔断转人工 | 熔断日志 |
这四个数字构成一条完整的证据链:命中率解释了成本为什么降,对照集排除了业务量干扰,评测通过率排除了"省出质量问题",熔断日志证明预算控制是活的机制而不是摆设。归档这四个数字的意义与此前视觉验收篇强调的证据链一致——三个月后有人质疑"这次优化是不是以牺牲质量为代价",你能在十分钟内拿出数据回答,而不是重新吵一遍。
六、总结与展望
回到开头的问题:当 Agent 每天在真实烧钱,谁来证明你的成本策略真的有效?答案是一套四层的成本工程结构:先做成本解剖,认清循环的平方级累积与输入占大头这两个结构性事实;再做缓存工程,用稳定前缀分层把经典缓存方法搬进上下文窗口,防住穿透、击穿与雪崩的 Agent 变体;然后是逐调用记账与双预算熔断,让每一分钱可审计、让失控有边界;最后是验收——固定对照集上的单位成本、命中率数据与质量回归三者同时达标,优化声明才成立。
这条主线与评测工程、结构化输出、并发验证诸篇一脉相承:Agent 工程的可靠性从来不来自模型的自我描述,成本领域只是把这个主张变得最无法回避——因为账单是唯一一个不配合任何演出的证据源。能力可以演示、可靠性可以抽检,唯独成本每天都在全量发生,它天然就是检验一个团队是否真的在"工程化"使用 Agent 的试金石:一个连自己工作流每天花多少钱、钱花在哪一层都说不清楚的团队,它对工作流其他方面的可靠性声明,同样应该打上问号。
如果你正在运营一条长期运行的 Agent 工作流,不妨今天就做一个最小改造:在调用层加上逐次记账,月底统计一次单位任务成本和缓存命中率。这个动作的成本不超过半天,但从此以后,所有关于成本的讨论——无论是"要不要换模型"还是"缓存到底有没有用"——都从印象之争变成数据之争。
关于 Deep Skill Finder
本文讨论的成本治理,前提是你先知道自己工作流里的每个环节——用了哪些模型、哪些 Skill、哪些工具——各自的真实成本与真实能力。Deep Skill Finder 是一个基于真实用户语料的 Skill 发现与选型工具:它把社区里被反复验证过的使用经验沉淀成检索与匹配能力,帮你回答"这个 Skill 在我的场景里到底值不值得用、信不信得过"。如果你在读完本文后想给自己的工具链做一次能力与成本的盘点,具体的获取方式与使用入口,可以在评论区留言或私信交流。