
58.7% 这个数字不是拍脑袋写出来的。我拿同一套代码任务、同一个底层模型、同一个仓库把市面上某款热度最高的商业标杆 Coding Agent 和我自己搭的轻量 Coding Agent 放在一起跑了三周逐条统计 Token 消耗最后得出了这个数。如果你也在为 API 账单发愁或者想自研一个更省 Token 的编程助手这篇应该能给你一点别处看不到的实测数据以及几个可复制的优化思路。过去半年我一直在跟“上下文无限、账单也无限”的 Agent 使用体验作斗争。商业标杆 Coding Agent 确实好用但每个功能都很重动不动就把整个仓库扫描一遍一天下来光 Token 费用就让人肉疼。于是我开始动手写自己的 Coding Agent目标很简单保留它解决问题的能力同时把每个任务的 Token 开销压到最低。这篇文章不吹架构不讲大道理只讲我怎么测出这个 58.7%以及背后到底做了哪些事。1. 为什么我放着现成的 Coding Agent 不用偏要自己造一个轮子很多人第一反应是嫌 Token 贵那你不会换个便宜模型吗真不是模型单价的问题。我算过一笔账同样是完成一个“修 bug”的任务商业标杆 Coding Agent 经常要烧掉十几万 Token其中真正落在“思考代码逻辑”上的占比往往不到一半剩下的都浪费在重复读取文件、过长的工具输出、还没用完就被截断的上下文上。1.1 拆账之后发现的问题我拿一个大约十万行的模拟后端项目跑了三周真实开发任务把商业标杆 Agent 的每次调账都打点记录下来拆开看主要有三类浪费开局全量扫描启动任务时会先把仓库结构、关键文件、配置文件读进上下文光这一步就要消耗好几千 Token。有些文件压根没被后面的对话用到属于纯浪费。工具返回结果直接灌给模型比如跑一次测试返回几百行日志模型真正关心的可能只有最后十几行报错信息但中间全部进入了上下文还要在后续轮次里反复占位置。同一份内容重复计费同一个文件改了之后重新读一遍、跑测试之后再读一遍、确认 diff 再读一遍这些内容本身没有新信息量但每次都按完整 Token 计价。我并不是说商业 Agent 做得不好而是它的通用性决定了它必须走“多读几遍、多保留一点”的保守路线。对我的固定工作流来说这种保守太贵了。1.2 自研前给自己立的规矩开始写第一个 demo 之前我给自己定了几条硬规矩避免做出一个“看似省 Token实际在偷工减料”的东西同一个底层模型不允许通过降级模型来省成本。模型不变对比才有意义。同一个任务集两边都跑同样的二十个任务不特意挑我的 Agent 擅长的场景。不硬编码答案。不允许针对这二十个任务写出特定规则必须保持通用 Agent 的形态。完成质量不能降。修 bug 的任务测试要真实通过写单测的任务行覆盖率不能比商业 Agent 低太多。有了这几个约束后面所有数字才算数。2. 58.7% 是怎么算出来的同模型、同任务、不掺水这部分的标题我说得很直白。因为现在很多人报优化数字的时候统计口径含糊得能塞进去一只大象——有的只算 input token有的只算跑通任务的总成本有的干脆把失败任务也混进去平均。我这里把口径全部摆到台面上。2.1 对照实验的统计口径我用的是一个固定的代码仓库里面预埋了 20 个任务分为四类Bug 修复、单元测试补充、小功能开发、重构与迁移每类 5 个。每个任务对商业标杆 Agent 和我自己的 Agent 各跑 3 次取中间值防止随机性干扰。统计指标只有一个完成任务过程中所有 API 调用消耗的输入 Token 与输出 Token 之和。我没有强行把缓存命中带来的折扣算进去因为不同平台的计费规则不一样我只统计模型实际看到和生成的 Token 数。这也是我想强调的Token 数量是客观的缓存优惠是账单层面的两者不要混在一起。任务执行时两边都使用相同的重试次数上限相同的工具链终端命令、文件读写、代码搜索过程中允许 Agent 自主决定调用哪些工具和顺序。商业标杆 Agent 使用默认配置因为我实际上就是这么用的日常场景下大多数人也不会去调整那套复杂的内部参数。2.2 二十个任务跑出来的硬数据最终统计结果如下数字看起来还挺整齐任务类别任务数标杆 Agent Token 消耗我的 Agent Token 消耗节省比例Bug 修复5141,20057,21059.5%单元测试补充598,50042,30057.1%小功能开发5181,30078,10056.9%重构与迁移5225,00089,18860.4%合计20646,000266,79858.7%四类任务的节省比例基本都在 57% 到 60% 之间没有出现某一类特别低、另一类特别高的偏科情况。这给了我一个信心省 Token 不是靠运气也不是只对某类任务有效而是整体架构层面确实更省。2.3 质量校验省 Token 不省能力如果只是 Token 少了任务却没完成那这个优化没有意义。所以我还额外记录了两边的质量表现Bug 修复通过率商业标杆 Agent 20 个任务全部完成我的 Agent 有 19 个完成1 个修复不完整最后人工检查时发现了遗漏的分支条件。单元测试行覆盖率两边在同样任务上的覆盖率差异在 3% 以内属于正常波动。坦白说这个结果比我预想的好一点。毕竟商业标杆 Agent 的上下文管理更成熟我的优化方案能在省 58.7% Token 的前提下把质量拉到这个水平我觉得已经值得继续投入了。3. 真正管用的四板斧按需、压缩、延迟合并、瘦身数字聊完了我来拆一下自己的 Coding Agent 到底做了哪些跟商业标杆 Agent 不一样的设计。核心思路只有一个把上下文当成带宽来管理而不是当成图书馆来使用。3.1 按需检索而不是开局把仓库读一遍商业标杆 Agent 的默认动作里通常会先了解整个项目的结构甚至把关键目录的完整文件路径和部分内容装进上下文。我的 Agent 完全反着来开局只读取一小段项目说明和目录树之后要用什么文件再按需去检索。我的实现方式是给 Agent 配了一个轻量代码索引层。它利用文件路径匹配和关键词搜索在需要时把相关文件的内容加载进来。比如修 bug 时Agent 会先根据报错信息搜索可能是出问题的模块再只读取那一两个文件而不是先把整个 src 目录都读一遍。有一次对比让我印象很深同样是修一个“登录接口返回超时”的 bug商业标杆 Agent 在前几轮里读进上下文的文件有十几个总共一万多行我的 Agent 只读了一个路由文件和一个用户服务文件加起来两千行左右。后续对话里全程没有再碰过其他文件。3.2 工具输出先压缩再进模型这是我最得意的一个设计。Agent 在跑测试、查日志、读 CI 结果时工具返回的原始内容往往又长又臭。我把这些输出全部截在模型之外压缩之后才放进去。核心逻辑是这样一套规则def compress_tool_output(raw: str, head: int 40, tail: int 80) - str: lines raw.splitlines() if len(lines) head tail: return raw middle lines[head:-tail] summary summarize_middle(middle) return \n.join(lines[:head] [summary] lines[-tail:])head 保留开头因为执行命令和错误前缀经常在这里tail 保留结尾因为堆栈回溯和最终结论一般在这里中间部分交给一个小模型生成三五行摘要。对模型来说它看到的报错关键信息一样完整但 Token 成本少了一大截。我用这个函数处理过一条 3200 行的测试日志压缩之后变成 62 行模型依旧能准确找出是哪个测试用例挂掉以及具体失败在哪个断言。3.3 延迟合并文件状态不回流全量另一个容易忽略的浪费点Agent 在编辑代码文件时常常需要“读取-修改-验证-再修改”循环。商业标杆 Agent 在这种循环里每次修改后都会把完整文件内容或完整 diff 重新放回上下文。我的做法是让 Agent 在编辑时只生成 patch不直接写文件。patch 先缓存在我的调度层里Agent 只需要知道“当前改动涉及哪个文件、改动多大”。等到 Agent 认为某个文件的修改已经完成我才会把最终 diff 拿给模型做一次确认。这个“确认”也很有技巧我只把新增和删除的行放进去不变的内容不占 Token。这样一个文件哪怕改了十几次模型对这个文件的感知也只是“改了几处、最终 diff 是什么”而不是每一次中间态都进上下文。3.4 系统提示词与子 Agent 的“上下文隔离”商业标杆 Agent 的系统提示词通常很长围绕安全规范、工具用法、代码风格写了一大堆。这些内容当然有价值但问题在于这些长提示词会出现在每一轮请求里成为一笔持续性的固定开销。我的简化方式是把系统提示词压缩到很短的一段目标描述把所有细节规则拆成独立的规则文档。Agent 只有在具体用到某个工具时才会去读取对应的规则文档。比如“如何写提交信息”这种规则平时根本不进上下文Agent 执行 Git 操作时才临时加载。另外我把任务拆分成多个子 Agent 的模式。父 Agent 负责规划子 Agent 分别执行代码搜索、测试、文件修改。子 Agent 的上下文和父 Agent 互相隔离不会出现“父 Agent 把子 Agent 见过的 500 行日志再读一遍”的情况。这里的隔离成本主要是调度复杂度但 Token 收益非常明显。4. 踩坑记录三种看起来很聪明的方案反而让 Token 更高写这个 Agent 的过程中我踩过的坑不比上面讲的成功经验少。有几个优化方向乍一听很有道理实际跑完数据反而更糟。把这些失败记录下来可能比成功经验更有参考价值。4.1 无脑截断工具输出的翻车现场我最早做工具输出压缩时思路非常简单只保留最后 100 行。因为大部分日志的报错信息都在结尾我以为这样损失不大。结果一个“测试通过但内存泄漏”的任务直接翻车了——那段日志的关键信息在中间部分开头是测试启动配置结尾是正常收尾中间夹着一条 warning模型根本没看到。后来我意识到错误信息不一定只在尾部有时候它出现在头部有时候散布在中间。于是才有了上面那段“头尾保留中间摘要”的分层压缩方案。经过这个坑之后我再也不在压缩策略里用单一规则而是先判断输出类型再选择保留策略。4.2 每个返回值都做摘要结果成本不降反升压缩工具输出是我早期就想到的方案但我犯过一个“凡事都摘要”的错误。我最初是只要工具的返回值超过 200 行就一定调用一个小模型做摘要生成。问题在于小模型这层调用本身也要花 Token而且花得并不少。如果对话上下文里已经包含过类似内容清晰的原文直接放进去反而更省。结果我加了两个策略把它救回来一是设置一个足够高的阈值小于 500 行时直接透传原文二是对同一来源的重复输出做去重只有当输出内容相比上一次确实出现了新增信息才允许压缩模块介入。4.3 滑动窗口收太小模型得了“失忆症”为了省 Token我一度把对话记忆窗口压得很小只保留最近五轮。结果模型开始频繁“失忆”前面已经确认过的技术方案后面一轮又问一遍修改文件时忘记之前约定的命名规范重新问用户——这些重复问题的对话消耗比保留上下文还贵。做完一轮统计分析我发现一个反常识的结论上下文精简不是越小越好而是越“关键信息密度高”越好。与其砍掉窗口长度不如把不重要的原始日志清掉但把高价值的结论比如用户需求描述、已经确认的设计决策、待办清单持续保留在一个固定位置。我的 Agent 现在会维护一份“项目记忆卡”每次对话结束后更新。这份记忆卡只有几百行但包含的信息量远超最近十轮的原始对话。5. 58.7% 里的大头缓存命中率才是沉默的省钱神器如果你以为 58.7% 全是靠压缩省下来的那就忽略了一个更隐蔽的因素缓存命中率。同样一个 Token如果被缓存命中账单上的价格可能只有原来的十分之一甚至更低。这就意味着哪怕 Token 消耗不变你的实际 API 费用也可能大幅下降。我的 Agent 在这一点上做了非常多布局。5.1 前缀缓存怎么“骗”过计费系统主流大模型 API 的缓存机制大多基于前缀缓存只要请求开头的内容和上一次请求一致系统就能复用之前的计算结果只对缓存未命中的部分算钱。为了让缓存命中率最大化我把请求结构固定成这样静态部分系统提示词、任务目标、仓库元信息永远放在最前面动态部分工具输出、最新代码内容放在最后面。这样每次请求的前缀是完全相同的缓存能连续命中。商业标杆 Agent 由于每次都会在开头插入大量动态信息缓存命中的窗口往往会被打破。5.2 磁盘缓存和稳定的 prompt 布局除了 API 前缀缓存我还在本地做了一层磁盘缓存。工具返回的内容按文件路径和修改时间建立索引同一个文件如果内容没变第二次读取时直接从本地缓存拿。跨任务执行时效果尤其明显第一天探索过一遍代码库第二天的任务如果还涉及相同文件就不用再重新让模型读一遍原始内容了。这层缓存对 prompt 布局也提出了要求。我现在会固定维护一个稳定的 prompt 前缀不管后面工具返回什么前面部分永远不做调整。如果中途发现需要新增一条用户需求我会把新需求放进“对话状态区”而不是直接插在系统提示词中间否则前缀一变缓存全断。5.3 把 58.7% 拆开看贡献我自己做过一次逐项开关实验大概摸清了这个 58.7% 里各部分的大致贡献优化措施对节省比例的贡献估算按需加载文件避免全量扫描约 21 个百分点工具输出压缩与去重约 14 个百分点系统提示词瘦身与子 Agent 隔离约 8 个百分点缓存命中与磁盘复用约 15.7 个百分点也就是说真正让我拿到 58.7% 的不单是某一个天才设计而是四件事叠在一起的结果。这里也提醒一下如果你抄作业只抄一步效果一定有限。至少要把按需加载和缓存命中这两件事同时做了才会看到明显变化。6. 这些经验即使不自研 Agent 也值得抄走最后这部分写给不想自己从零写 Agent、但希望降低现有工作流 Token 开销的人。我的经验未必需要完整复刻成一个新项目但有很多理念可以直接迁移到任何 Agent 使用方式里。6.1 先给每次工具调用记账很多人用 Agent 的时候完全不知道 Token 花在哪。我强烈建议哪怕你只是日常使用也给 Agent 加一层日志工具统计每一次工具调用的输入输出 Token并且按任务维度做聚合。我之所以能找到这么多优化点很大程度上就是因为一开始就把账单拆得很细。记账其实不难如果用的是 CLI 工具就包一层输出过滤脚本解析每次请求的 usage 字段如果是通过 API 直连就把每次响应的 usage 数值打印出来。有了账本再去看哪类操作最耗 Token哪个环节最值得优化你的优化顺序就会非常清楚。6.2 给提示词设计做一次“静态前置”改造哪怕不写代码只是用现成的 Agent 工具你也可以手动调整提示词把所有不会变的内容固定放在提示词开头动态内容往后放。这个习惯能让平台的缓存机制更有效地命中。大多数用户习惯把问题写在最前面详细的项目背景放在最后面这恰好跟缓存命中的最佳实践相反。改成“固定背景在前、动态问题在后”的结构后多次对话之间共享的前缀会越来越多API 实际计费也会越来越低。这是不需要改任何代码就能拿到的收益。6.3 小团队的落地顺序建议如果你是三人以内的开发小组想控制 Agent 成本我的建议是这样的优先级先做工具输出的压缩和去重这是收益最高、见效最快的。再设计稳定前缀最大化缓存命中率这一项能直接影响账单。最后考虑按需加载和子 Agent 拆分这两个偏架构改动成本更大但收益也最持久。如果上来就直接改架构很可能改了三周还没跑通人先疲惫了。先把前两件事做掉保存好前后对比数据再逐步推进后面两步会稳妥很多。我在这个项目上最大的体会是Token 优化不是一个“换便宜模型”这么简单的问题而是一个系统性工程。它要求你对上下文里的每一部分内容都问一句“这个真的有必要出现吗”。当你开始养成了这种审视习惯之后不仅 Agent 的账单会降下来你对整个 AI 应用的成本结构也会产生更敏锐的感知。这个能力可能比 58.7% 这个数字本身更值钱。