文章
我翻了 205 个本地会话,token 浪费在哪里
从本地 Codex 会话统计出发,复盘无信息等待、超长工具输出和上下文膨胀,并记录一套能持续改进的工作方法。
最近我总觉得 Codex 做一件事花的 token 有点多。
这种感觉很难直接拿来改东西。一个任务代码多、日志长、检查严,用量高很正常。要是只看总数,很容易把正常工作也算成浪费。于是我把本地会话做了一次只读审计,先用脚本解析日志,再把正文留在磁盘上,只让模型看到时间、大小、哈希和聚合结果。
我一共扫到 205 个 8 月上半月的本地会话文件,体积约 343 MiB。随后又参考了一次口径更严的近 30 天审计。那次审计覆盖 245 个有效会话,按每个会话的累计最大值去重,得到约 28.89 亿个已处理 token。
这个数字很吓人,也最容易被误读。
其中 96.37% 的输入命中了缓存。已处理 token 不等于账单金额,缓存输入、新输入、缓存写入和输出也不能按一个价格算。本机还混用了不同提供方,本地记录里没有完整计费规则。所以这篇只谈能够确认的无效消耗,不估算省了多少钱。
最费 token 的动作是在等
那次审计确认了约 1.094 亿个浪费 token,占总处理量的 3.787%。其中约 1.029 亿来自无信息等待,占已确认浪费的 94%。
这类浪费很朴素。一个子任务还在运行,主会话调用一次等待工具,结果没有新输出。模型被重新唤醒,看完原有上下文,只能再等一次。任务没有向前走,整段历史却又被处理了一遍。
最严重的匿名会话里有 230 次重复等待,浪费约 2920 万个 token。另一条匿名样本更直观。等待工具只返回了 150 字节的无信息结果,随后一轮推理处理了 238540 个 token,接着继续等待。
缓存命中率高,只能让这件事便宜一些,不能让它变得有用。
我后来把等待规则写得很具体。长任务尽量使用工具侧的异步等待,一次给足合理时间。相同调用得到相同结果后,不允许原样重试。再次尝试必须改变等待时长、查询范围或处理办法,还要提前写明什么时候停。
这几句话比“少浪费 token”有用得多。Agent 能照着执行,也能在复盘时检查。
工具输出太长,会被反复带回下一轮
我对 205 个会话做了另一轮交叉统计,发现 18961 次工具调用一共产生约 9600 万字符的输出。其中 2798 次超过一万字符,856 次超过三万字符,另有 533 次输出发生截断。
一次很长的 rg、构建日志或 JSON dump,问题不只在它出现的那一刻。只要输出进入会话历史,后面每一轮推理都可能继续带着它。Agent 原本只想找一个错误行,最后却反复处理整份日志。
这里也有一个让我不太满意的变化。我把 8 月 1 日至 8 日和 8 月 9 日至 17 日的用户会话分开比较,每回合工具调用从 16.32 次降到 10.87 次,单次响应平均处理的输入从约 15.4 万降到 12.4 万。可超过一万字符的工具输出占比却从 11.69% 升到了 16.81%。
前后任务难度并不相同,这组比较不能当成严格实验。它至少提醒了我一件事,少调用工具不代表每次调用都更克制。
现在我更倾向先用 rg 定位文件和行号,再读附近的小段内容。测试和构建会限制返回长度,完整日志留在本地文件里。确实需要大范围分析时,先让脚本在本地算出分组、计数和异常样本,模型只接收聚合结果。
这次审计本身也按这个办法完成。两百多个会话没有被整批塞回模型上下文,公开文章里也没有任何会话原文、本机路径或账号信息。
长会话会把一次小动作变贵
这批 8 月会话里出现了 130 次上下文压缩,分布在 49 个会话中。压缩能让长任务继续做下去,却不会自动清掉工作习惯上的重复。
有些会话压缩以后,又重新读取已经看过的说明、Skill 和项目文件。内容刚被压进摘要,下一轮又整份装回来,几次之后再次靠近上下文上限。严格审计把能够确认的压缩后重读算出约 107 万个浪费 token。数字比等待小很多,处理办法却很明确。
压缩以后先用现有摘要。只有摘要缺少会改变下一步的事实,才回到原文件,并且只读缺失的部分。任务主题已经明显变化时,另开一个边界清楚的会话通常更省事。旧会话负责留下结论,新会话带着必要结论继续做,不必背着全部调查过程往前走。
子任务也有相同的成本。205 个会话里有 124 个来自子 Agent,共处理约 4.86 亿个输入 token,调用了 4791 次工具。并行调查对几个互不依赖的模块很有用,小任务也拆出去,子 Agent 就要重新认识仓库、规则和目标,省下的时间未必抵得过这段重复理解。
我现在只把边界独立、能够并行、验收方式明确的工作交给子 Agent。任务里会写清文件范围和禁止事项,最后要交回测试结果。主会话还要检查真实工作区和差异,不能拿一段完成报告代替验收。
自我改进要落到下一次动作里
另一段本地会话讨论的是 Codex 自我改进方案。它让我看到一种常见偏差。方案写得很完整,里面却混着过时数量、未经核对的配置判断,还有删除日志和合并 Skill 之类风险较高的动作。若照单执行,维护很容易变成新的返工。
最后的处理很克制。先保留原方案,另写一份校正版。随后只做可恢复的维护,把六个已经确认的零字节临时文件移入隔离目录,用 SQLite 在线备份活动日志库,并分别跑完整性检查。记忆、Skill、模型和权限配置都没有顺手改动。
这段经历给我的启发很直接。自我改进不能靠一次大扫除,也不能靠写一份宏大的准则。先量出一个问题,改一组动作,用同一批代表性任务观察变化。有效的规则留下,没有证据的设想继续待着。
目前能看到一些变化。前后两个时间段相比,每回合工具调用约少了三分之一,连续完全相同的调用占比从 3.46% 降到 3.01%,每回合发生的上下文压缩也下降了约三成。超长输出还在恶化,新输入量也受任务类型影响,暂时不能宣布已经省下多少成本。
我会继续保留这套审计脚本的思路,隔一段时间再看等待、工具输出和压缩后的重读。数据若没有变好,就回到具体会话找原因。数据变好了,也要确认任务质量和验收没有跟着缩水。
省 token 最后省下来的其实是返工。少一次没有信息的唤醒,少读一份无关日志,少让新 Agent 重查已经确认的事实,任务会更快,判断也会更稳。
这大概是我现在理解的自我改进。每次只改一点,下次真能少走一步。