为什么 coding agent 越来越"贵":token 黑洞与 42% 的解药
过去一年,围绕 Claude Code、Cursor、Codex CLI、Gemini CLI 的使用体验里,有一个反复被工程师吐槽的硬痛点:每次开新会话,coding agent 都像第一次访问这个仓库——它会重新 grep、重新打开文件、重新追踪 import、重新回退、再试一遍,把一小时前已经摸清的代码图谱扔掉,从头再来一遍。这种"每次任务都从零开始 onboard"的体验,直接体现在三件可量化的事情上:工具调用次数、token 消耗、任务延迟。三件件都是显性浪费,因为它们在每个任务里都会重复发生。
2026 年 8 月中旬,两个独立开源项目几乎同时给出了"用 Hook 体系把这份浪费拦腰砍断"的工程方案:一个是 NanoNets 团队的 Graft(Show HN: 2026-08-14,28 天前发布),把 grep token 直接砍掉 42%;另一个是 Contextual Labs 的 Contextual(2026-08-27 发布,16 天前),把整个代码库记忆做成 local-first 的语义搜索引擎。两条路径都瞄准同一个目标——让 coding agent 不再每次都"瞎子摸象",但它们选择的实现边界不同,这种"目标一致、路径分歧"恰好给 CLI Agent 上下文治理提供了一份难得的对照样本。
Graft 是什么:把代码库变成"可被 grep 的 markdown 图"
Graft 的核心理念可以一句话总结——把代码库一次性扫描成一张"机器可读、人可读、agent 可 grep"的 markdown 节点图,然后通过 Claude Code 的 Hook 体系把这张图塞进每一次 prompt。它不引入向量数据库、不引入 embedding、不引入相似度搜索,所有内容都是纯 markdown 文件加 typed links,agent 直接当作普通仓库文件来读。
技术栈细节决定了它的成本结构。Graft 用 tree-sitter 做底层代码图(纯确定性解析,无 LLM 调用、无网络),用任意兼容 OpenAI/Anthropic API 的 provider 生成每文件的 summary,再把 summary 按 subsystem / key file / concept 分组成节点。两个 pass 全部按内容哈希缓存——同一个文件第二次解析只要 0.18 秒,无改动时只比对 fingerprint,约 3 毫秒,且永远不调 LLM。
这种"结构性图 + 语义总结"双层架构带来的直接收益,是 Graft 的核心性能数字。官方在 SWE-bench Verified 上跑了 50 个真实 GitHub issue,Claude Sonnet 5 同一个模型,唯一变量是 Graft 是否接入:正确率从 54% 提升到 66%(+12 pts);token 节省 23%;工具调用节省 25%;wall-clock 节省 32%。在他们自建的 162 次两仓库横扫测试里,push 模式 token 节省 42%、工具调用节省 46%、延迟节省 60%、成本节省 32%,而正确率与冷启动 baseline 持平(93%);pull 模式 token 略多但正确率提升到 98%,比 baseline 高 5 个百分点。
为什么 42% 这个数字值得被认真对待
在 CLI Agent 领域,42% token 节省不是营销话术——它直接对应企业开发团队的真金白银账单。一个中型开发团队每月在 Claude Code 上的开销通常以万人民币为单位,其中 60%-70% 的 token 都被"重复探索仓库"这一种动作消耗掉。如果能把这部分砍掉 40%,整个 agent 工具栈的 ROI 会立刻发生质变:同样的预算可以覆盖更多工程师,或者同一些工程师可以承担更多任务。
但更值得注意的是 Graft 在 SWE-bench 上"既便宜又快还更对"的三连击。在传统的认知里,这三件事往往是两两 trade-off 的——为了快可能更不准确,为了准可能更贵更慢。Graft 的实验数据打破了这个 trade-off:它的 54%→66% 正确率提升,几乎完全是"agent 在第一次尝试时找对了文件"带来的。冷启动 baseline 在 django-11532 这种 issue 上经常只 patch 1 个文件、漏掉另外 4 个、改坏 18 个原本通过的测试;Graft 找到全部 5 个文件、一次性改完。这是真实生产里的价值,不是 demo 视频里的价值。
Hook 体系:Graft 把工程价值放在哪一层
Graft 在 Claude Code 上的集成不是写一个 README,而是完整利用了 Claude Code 提供的 5 个 Hook 点位:`SessionStart`、`UserPromptSubmit`、`PostToolUse`、`Stop`,加上 `statusLine`。这套 Hook 编排让 Graft 在以下时刻自动介入:
会话开始时,自动加载仓库级别的 repo map,作为初始上下文注入;每条用户 prompt 提交前,根据 prompt 内容匹配相关节点,把对应 markdown 节点拉进上下文;每次工具调用 完成后,如果被编辑的文件在图里,自动 blast radius 提示(谁依赖这个文件)并静默刷新对应的图节点;会话结束时,如果本轮改过代码,后台异步重建被影响的节点 markdown。整个流程中,只有"初始生成节点"这一步需要调一次 LLM,所有 Hook 路径全部是 tree-sitter 确定性 + 本地缓存,无额外 token 消耗。
这套 Hook 设计背后的工程洞察,值得所有正在做 CLI Agent 工具的团队学习:不要把"上下文增强"当成用户主动触发的命令,而要把它做成 agent 生命周期里的默认行为。SessionStart 注入减少首次困惑,UserPromptSubmit 匹配减少每轮搜索,PostToolUse blast radius 减少破坏性修改,Stop 异步刷新保持图与代码同步。这四条 Hook 共同构成一个"自动维护的上下文层",工程师不需要知道它存在,也不需要记得手动运行。
Contextual:另一条路径,local-first + 语义搜索
如果说 Graft 是"图驱动 + 文本可读",那 Contextual Labs 16 天前发布的 Contextual(1.0.0 beta)选择了"embedding 驱动 + 语义可搜"。它的设计哲学和 Graft 形成有意义的对照:同样的目标(消除 agent 每次都瞎子摸象的开销),但实现路径完全相反。
Contextual 把整个代码库解析成 3 万 + 个 chunk(默认按符号和段落切分),用 CodeRankEmbed 模型在本地生成 embedding,把所有 chunk 存到 ~/.contextual 目录,完全不上云、不出设备。然后通过 MCP server 提供 6 个工具给 Claude Code / Cursor / Codex 等 agent,最核心的 nexus_search 接收自然语言查询,返回按语义排序的代码节点、commit、PR 评论、RFC 段落,带"为什么这样改"的 blame 与 staleness 元信息。
它的核心性能数字是另一组。在它的示例 query"why did we switch the webhook signer to HMAC-SHA512?"上,系统从 4 个不同来源(commit b2e914a、PR #482 评论线程、webhooks/signer.ts 的 diff hunk、RFC-017.md 的 §3)组装答案,耗时 93.85 毫秒,零 token 出设备。这个 demo 清晰地展示了 Contextual 的独特定位:它不是 Graft 那种"通用 codebase graph",而是"决策可追溯的时间索引"——每一段代码、每一个 commit、每一段 RFC 都被锚定在时间轴上,agent 可以问"上个季度这个文件是什么意思"并得到一份带历史背景的回答。
三条路径分歧:为什么两个项目都很合理
Graft 和 Contextual 的差异不只是技术栈选型,更反映了对"agent 上下文治理"这个命题的三种不同判断。
第一条分歧:要不要 embedding?Graft 的答案是"不要"。它的论点是 agent 本身就能 grep、能 follow links、能按内容哈希缓存,引入 embedding 是把简单问题复杂化,且每次 embedding 调用都要付一笔 API 费用。Contextual 的答案是"要"。它的论点是自然语言查询("为什么我们换签名算法")在纯文本图上召回率太低,embedding 提供的语义相似度对这种查询是必须的。
第二条分歧:要不要云?Graft 走的是"完全本地 + 你自己的 provider key"。Graph 是 graft/ 下的 markdown 文件,跟 node_modules 一样被 .gitignore 忽略;summary 的生成走用户自己的 OpenAI / Anthropic / OpenRouter / LiteLLM / 本地模型,凭据保存在用户机器上。Contextual 更激进——连 embedding 都在本地用 CodeRankEmbed 跑,完全零云端调用、零 egress 字节、零上行日志。这种"local-first"哲学对受合规约束的企业(医疗、金融、政务)有直接吸引力。
第三条分歧:图的"粒度"在哪里?Graft 把图建在 subsystem / key file / concept 三个层级——一个中型仓库最后会变成几十个可读的 markdown 节点。Contextual 把图建在"每个 chunk"层级,一个中型仓库是 3 万 + 个语义节点。前者适合"人也能看懂的图",后者适合"机器语义搜索的图"。
工程基线:今天做 CLI Agent 上下文层必须解决的 5 件事
把 Graft 和 Contextual 摆在一起,可以看到一个成熟的 CLI Agent 上下文层今天必须解决的 5 件事。任何一件缺失,42% / 60% / 100% 这些数字都不可能复现。
1. 缓存到内容哈希,不缓存到时间。无论 Graft 的 tree-sitter 节点,还是 Contextual 的 embedding chunk,都必须按内容哈希缓存,不能用"上次构建时间"做判断。否则一次无关紧要的 git pull 就会让整个图从头重算,token 账单原地爆炸。
2. 结构性索引与语义索引分开。Graft 把"代码图"留给 tree-sitter 确定性解析,把"summary"留给 LLM;Contextual 把"embedding"放在本地,把"自然语言查询"放在 MCP server 工具层。这两类索引的成本结构和失效模式完全不同,绝不能混在一起共用一条 pipeline。
3. 必须有 blast radius 反馈。当 agent 编辑一个文件时,Hook 必须立刻告诉它"谁依赖这个文件"。这一步不是 nice-to-have,是避免破坏性修改的最后一道防线——Graft 在 PostToolUse Hook 里把这个做成 inline 输出,做到了不打断 agent 节奏。
4. 决策级上下文要有时间锚。Contextual 的 demo 最有说服力的部分不是 embedding,而是"为什么这样改"这个查询——agent 需要的不仅是"现在代码是什么",还有"过去某个时刻这段代码为什么变成这样"。任何没有时间轴的代码图,都只是当前状态的快照,无法回答演进类问题。
5. 隐私边界要先定。Graft 的 graph 文件不进 git、用户自己持 key,Contextual 的 embedding 完全本地——两个项目都在第一天就把"代码不出设备"当作默认假设。这种默认假设对国内受等保 / 数据出境约束的团队有直接价值:把工具的合规边界画清楚,比节省 token 更重要。
从 42% 到企业级:CLI Agent 上下文治理的下一步
Graft 和 Contextual 在 2026 年 8 月先后落地,传递的不是"又一个 prompt 优化技巧",而是 CLI Agent 进入了"必须有持久化上下文层"的阶段。当 Claude Code 已经成为越来越多开发团队的核心工具,每次新会话都从零探索的浪费,正在从"可接受的小成本"变成"必须解决的工程问题"。Hook 体系 + 结构化图谱 + 语义索引这三件套,正在快速变成这个领域的工程基线。
对企业技术决策者而言,这一轮工具演进给出的最直接启示是:评估一个 coding agent 时,不仅要问"它能写多复杂的代码",还要问"它第一次接触新仓库时浪费多少 token"。前者回答能力上限,后者回答真实 ROI。Graft 和 Contextual 用各自的方式把后者压到了原来的 60% 左右——而这正是接下来 12 个月,所有认真做企业级 coding agent 落地的团队必须正面回答的问题。