推高 AI 编程智能体账单的,不是模型有多聪明,而是它在代码库里的走法。以静态分析闻名的 Sonar 公开了自家仓库的实测数据。一次约 800 行的改动,累计消耗了 1.56 亿上下文 token。智能体通过 grep 和读文件收集到的内容会一直留在对话里,之后每一轮都被重新计费,这套机制第一次有了具体数字。

智能体绕的每一次路,每轮都要付钱

大语言模型每规划下一步,都会把此前的整段对话重新作为输入接收一遍。提示词缓存能把这些重复 token 的单价压到输入价格的一成左右,但不会归零。所以一个 token 的真实成本不是它的体积,而是体积乘以它存活的轮数。

在第 40 轮打开一个 600 行文件的智能体,并不是为 600 行付了一次钱,而是为 600 行付了剩下 470 轮的钱。读的文件越多、会话拖得越长,早期的过度读取就越像利息一样滚起来。

800 行改动烧掉 1.56 亿 token

Sonar 本身就是用 AI 智能体在开发自家的语义分析引擎,并完整保留了过程日志。这次拿出来的样本,是一个包含约 800 行后端改动的拉取请求。

这个 PR 消耗了 1.56 亿上下文 token,其中缓存读取占 1.528 亿。上下文窗口峰值达到 45.9 万 token,费用约 41 美元(约 6,400 日元)。而最终的代码差异,人来看五分钟就能读完。

智能体做的事情,其实就是集成开发环境免费提供的"转到定义"。为了找到调用目标,它敲下这样的命令:

grep -rn "resolve_return_type"

返回的是 Python、TypeScript、Java、Rust、C# 以及公共内核各版实现混在一起的列表。正则表达式没有办法判断某次调用究竟绑定到哪一个。于是它打开文件、宽松地读一大段,再去找生成返回值的辅助函数,再打开一个文件。这些读取全部留在了对话里。

一次多读,膨胀成 270 万 token

其中一个案例算得很清楚。智能体只想弄懂一个 67 行的函数,但因为分不清函数从哪开始到哪结束,它把整个 618 行的文件读了下来。载入 6,472 个 token,真正用上的约 700 个,当场浪费约 5,770 个。

这次读取在第 42 轮进入对话,之后又待了 470 轮。5,770 乘以 470,约等于 270 万 token。缓存读取的价格约为每百万 token 0.2 美元(约 31 日元),所以仅这一次就花掉约 0.54 美元(约 85 日元)。同类的过度读取在这一个 PR 里发生了约 10 次,此外还有几十次全树 grep,其中几次一无所获,只能放宽条件再搜一遍。

把同一仓库中 18 个同等规模的 PR 平均下来,每个约消耗 2.34 亿上下文 token、约 65 美元(约 1 万日元),中位数约 52 美元(约 8,000 日元)。与模型的往返约 700 次,上下文窗口峰值散布在 45 万到 97.5 万 token 之间。一旦触到 100 万 token 的上限就要压缩,此前的上下文随之丢失。这个离散程度反映的不是最终差异有多大,而是智能体被迫在代码库里走了多远。

※1 美元 = 157 日元(截至 2026 年 9 月 3 日)

grep 找得到字符串,找不到含义

比钱更麻烦的是另一个副作用。正则表达式只能找到你想得到的那个写法。经由接口的调用、通过别名的引用、来自另一种语言的调用,只要检索词不同就会漏掉。

这次的 PR,正是要把 C# 里已经实现的调用点类型解析搬到 Python。可 C# 那边的函数叫 resolve_type_node,与 Python 侧的 resolve_return_type 用词不同。搜其中一个,永远不会带出另一个。漏掉的调用点会以构建失败的形式返回,带来持续集成的重跑和返工,而每一轮都要重新缴一次上下文税。

把文本搜索换成图查询

Sonar Vortex 想替换掉的正是这套查找方式。它进入智能体的处理循环内部,不再问文件系统,而是向代码库的图发出查询并返回答案。

构建这张图的,是 Sonar 自研的语义分析引擎 SemSitter。它把函数、方法、类、字段、参数作为节点,用 calls、references、returns、has-param、is-type、contains、extends 等带类型的边连接关系,形成统一依赖图(UDG),并在每次改动时即时更新。

智能体的问法也变了。不再是"哪些文件提到了 resolve_return_type",而是"给我这次调用绑定的定义、拥有它的类型、返回值以及调用方"。返回的只有一个方法体,加上能回答其余问题的若干条边。周围的文件不会被带进来,也不需要放宽条件重搜。前面那次过度读取,换成图查询只相当于约 33 万 token,大约是九分之一。

效果更大的是结构关系之外的两类边。一是连接代码与文档的 documented_by,碰到某个函数时只浮现设计文档中相关的那一段,把"让智能体读文档反而被带偏"的老问题反过来解决。二是跨语言的 semantically_related,即使名字不同也能把等价实现连起来。有了这条边,上面 C# 与 Python 的错位就只是顺着边走一步的事。

可以后期接入现有的编程工具链

Sonar Vortex 以 MCP(模型上下文协议)为核心进行集成,可以后期接入 Claude Code、Cursor、GitHub Copilot、Windsurf、Google Gemini CLI、OpenAI Codex CLI 等手头已有的工具。判定所用的规则直接沿用 SonarQube 现有的质量配置,不必另写一套规范。写代码前注入上下文与约束,写的过程中实时验证,这两件事作为一个循环运转。

总结

在大型代码库里让 AI 编程智能体卡住的,不是推理质量,而是移动方式。Sonar 的实测显示,一个约 800 行的 PR 消耗 1.56 亿上下文 token,18 个 PR 平均每个约 65 美元(约 1 万日元),上下文窗口一再逼近 100 万 token 的上限。加之字符串检索会漏掉其他语言中的等价实现,这部分最终以返工的形式回弹。把查找换成图查询,是一种减少而非增加智能体所携带信息的优化思路。由于代码库越大差距越明显,日常大量使用智能体的团队,或许值得把账单的明细重新看一遍。

※ 缩略图为 AI 生成的示意图。