一个开源项目,让 Claude Code、Codex 们少走 46% 的弯路
想象一个每天失忆的天才同事
假设你的团队来了个新人。
他聪明得吓人,任何语言都会写,通宵不累,从不抱怨。唯一的问题是:他每天早上醒来都会忘光前一天的一切。
于是每天上班,他都要重新问一遍:
• "我们的登录逻辑写在哪儿?" • "这个函数改了会影响谁?" • "数据库那层是怎么连的?"
他翻遍全项目,画出一张心智地图,漂亮地干完活——然后下班,地图清零。
第二天,重来一遍。
听起来荒诞。但这几乎是当下每一个 AI 编程助手的真实工作方式。

没有地图的 AI:grep 一个词、打开一个文件、跟着 import 跳走、退回来、再试一次
你给 Claude Code 一个任务,它并不是"直接开工"。
它先要 grep 一个关键词,打开一个文件,顺着 import 跳到下一个,发现不对,退回来,再试一次。
这个过程会烧掉一次任务里大部分的工具调用、token 和等待时间——而这些成本,和你真正想解决的问题毫无关系。
更扎心的是三件事:
• 重复:每个新任务,探索成本从零再付一遍 • 丢弃:这一轮好不容易搞明白的结构,会话结束就蒸发 • 不共享:你的同事和他的 AI,还得从头再来一次
人类进一个新项目,只需要"上手"一次。AI 每一次都要重新上手。
Nanonets 的解法:把理解写下来,钉在代码库里
最近在 GitHub 上蹿升很快的开源项目 Graft(来自 Nanonets 团队,MIT 协议,目前 2.5k star、212 个 fork),针对的就是这件事。

最直观的感受,是官方这段左右分屏的对比演示——同一个任务、同一个模型、同一套文件工具,唯一的区别是右边接上了 Graft:

左边:从零开始翻找,一个文件接一个文件。右边:先读地图,直奔目标
左边那位在反复地 grep、打开、退回、再试,屏幕上滚过一大堆你并不关心的文件名;右边那位几乎没有"找"的过程,它一上来就知道该去哪儿。
这不是剪辑技巧带来的错觉。官方给出的一组硬指标是:工具调用少 46%、token 少 42%、耗时少 60%,而在 SWE-bench Verified 这个业界标准评测上,正确率反而从 54% 提到了 66%——更快、更省,而且更对。
这三件事同时成立,是相当反直觉的,也正是这个项目值得聊一聊的原因。
它的想法朴素得近乎"土":既然 AI 每次都要重新理解一遍代码库,那就让它只理解一次,然后把结果写成文件存下来。
不是向量数据库,不是 embedding,不是需要常驻的索引服务。就是一个文件夹,里面是一堆互相链接的 Markdown 文件——每个文件对应代码库里的一个子系统、一个 API 或一个概念。
用它自己的话说:"这个图谱就是一组你的 agent 可以打开、grep、跟着链接跳转的文件,和它读仓库里任何其他文件的方式完全一样。"
这句话是整个项目最聪明的地方。
它没有发明一套新协议、新数据库、新查询语言,而是选择了AI 本来就最擅长的载体:人话写的文本文件。
一个"节点"里到底装了什么
大多数代码索引工具给你的是一个地址:"这个东西在那个文件的第 42 行。"
这告诉 AI 去哪儿找,但没告诉它会找到什么。
所以 AI 还是得打开源文件、从头读一遍。
Graft 的节点里塞的是意义,一个文件包含三层深度:
| Summary(摘要) | |
| Crux(关键) | |
| Sources(来源) | |
| Links(链接) | depends_on、uses、implements 这类动词连接到其他节点,写成 [[双链]],AI 可以顺着跳 |
| Notes(笔记) |
有个细节特别值得说:Crux 存的是代码本身,不是行号。
因为行号会漂移——上面随便插几行无关代码,42 行就变成 47 行了。
但真正重要的那几行本身不会变。
存文本而不存数字,这个决定看似微小,却让整套东西在真实的、每天都在变的代码库里站得住脚。
上手只要两条命令

npm install -g @nanonets/graft # 装 CLI,一次
graft init # 建图谱 + 接进 Claude Code就这样。graft init 会问你要接哪些 agent(Claude Code、Cursor、Codex、Gemini、Copilot、Kiro、Windsurf 都支持),然后往对应的配置文件里写入接线。
从下一次会话开始,Graft 就自动随行:每次提问自动把相关节点塞进上下文,每次改完代码在后台自动重建图谱。
没有守护进程,没有需要记得去重跑的索引。
值得一提的两个设计克制之处:
• 不写任何东西,除非你点头。 graft init --dry-run会先列出它打算碰的每一个文件。在没有终端交互的环境(CI、Docker)里,它干脆什么都不写,只打印一条命令让你自己跑。• 基础层完全不用 API key。 结构图谱是 tree-sitter 硬解析(共 20 门语言的真实 AST,其中 TypeScript/JavaScript、Python、Go、Java 是全保真的跨文件调用解析),确定性的、不联网、不调模型。只有生成"人话摘要"的 --deep那一层才需要模型,而且用你自己的 key、你自己选的模型——OpenAI、Anthropic、OpenRouter、本地模型都行。• 零遥测。 唯一的网络请求就是你自己配的那个模型调用。
增量也快得离谱:官方给的数据是 124 个文件的仓库,冷启动 0.74 秒,改一个文件后重建 0.18 秒。
正因为便宜,它才敢做到"每次查询前都先刷新一遍图谱"——一次结构比对只要约 3 毫秒,且完全不花钱。
所以你得到的答案,描述的永远是此刻的代码,包括你刚改完还没提交的部分。
数据:省了多少,错了没有
这类工具最容易翻车的地方是:快了,但答得更糙了。
Graft 团队没有回避这点,做了一个 162 次运行的对照测试:同一个 agent、同一套文件工具,唯一变量是有没有图谱。而且用另一个模型当裁判打分,还设了关键词底线,防止"答得快但答得错"混过去。
| $0.0292(−32%) | ||
| 4,650(−42%) | ||
| 2.3(−46%) | ||
| 15.8 秒(−60%) | ||
等待时间砍掉六成,工具调用砍掉近一半,正确率没掉。
还有一个更有意思的结果:如果不主动往上下文里塞,而是让 agent 自己按需去问图谱("pull 模式"),速度优势会缩水,但正确率从 93% 跳到 98%——比冷启动高 5 个百分点。
团队给的建议很实在:"要快就 push,要准就 pull。"
真实项目上的测试也做了。他们在 PocketBase(Go,约 350 个文件)上跑了 15 个任务,其中 5 个是真实已合并的 PR,回滚到基线提交重新实现,然后对比 agent 改的文件是不是维护者当初改的那批:
| $11.02(−21%) | ||
| 1,762 秒(−14%) | ||
| 5 / 5(改的文件一模一样) |
差距最大的地方,正是跨文件理解——"OAuth2 各家提供商的鉴权是怎么走通的"这个问题,成本从 0.84。
这符合直觉:越是需要在多个文件之间来回穿针引线的问题,"有地图"的优势越明显。
还有一份"别人家的卷子"
上面这些都是团队自己设计的测试,自说自话总归有嫌疑。
所以他们又跑了一遍业界标准的 SWE-bench Verified——真实 GitHub 项目里的真实 issue,用官方评分程序打分。
这个评测的好处是没法糊弄:没有裁判模型,没有相似度打分。你的补丁被打上去,跑维护者自己写的测试,要么把原本失败的测试修好且没弄坏别的,要么就是不及格。
50 道题,两边都用 Claude Sonnet 5,同样的 Docker 镜像、同样的轮次上限:
| 33 / 50(66%),+12 个百分点 | ||
| 1.09 亿(省 23%) | ||
| $42.43(省 19%) | ||
| 1,031 次(省 25%) | ||
| 8,922 秒(省 32%) |
更值得看的是它赢在哪儿。 官方指出,每一个正确率上的胜负,形状都一样:没有地图的那一方,只改对了一个文件,漏掉了它的兄弟文件。
比如 Django 的一个 issue,正确的修复需要动 5 个文件,冷启动的 agent 只改了 1 个,结果连带弄坏了 18 个原本通过的测试——还连续犯了两次。
另一个 issue 需要动 4 个文件,它改了 1 个,103 分拿了 102 分,差的就是那个"没想到还要改这里"。
Graft 找齐了剩下的。而且在其中一道题上,它用了一半的 token 和一半的时间。
这几乎是对"上下文"价值最精确的注解:AI 的失误,很多时候不是不会写代码,而是不知道还有什么在等着被改。
看得见的地图
Graft 还有个让人眼前一亮的功能:graft viz,本地起一个交互式图谱查看器。
搜索 → 跳到节点 → 依赖关系亮起:琥珀色是它依赖谁,青色是谁依赖它
这里的边不是抽象的"相关",而是代码自己的动词:uses、calls、produces、configures、validates、implements……每一个动词对应一个真实的工程问题:
• part_of/contains—— 这东西住在哪儿?• uses/depends_on—— 我改了它,什么会崩?• configures—— 什么能不改代码就改变它的行为?• validates—— 什么在检验它?(测试、漂移检查)
而更实用的是"爆炸半径"(blast radius)——你刚改完一个文件,它立刻告诉你谁会受影响:
改文件 → 影响范围内联显示 → 图谱自动重新同步 → 在 graft viz 里得到确认
对于任何维护过大型代码库的人来说,这个功能的价值不用解释。
比工具本身更值得琢磨的事
Graft 好不好用,一年后自有分晓(它目前还是 pre-1.0,从 main 分支持续发布)。但它指向的那个问题,值得所有关注 AI 的人认真想一想。
过去两年,行业的注意力几乎全在"模型有多强"上。 参数量、上下文窗口、跑分。但当模型强到一定程度之后,瓶颈就悄悄换了位置——不再是它会不会,而是它知不知道。
一个能考 SWE-bench 高分的模型,扔进你公司那个五年历史、三十万行、注释稀烂、原作者早就离职的代码库里,它一样会抓瞎。不是因为它笨,是因为没有人给它做过入职培训。
这就是最近被反复提起的"上下文工程"(context engineering)。整个 2025 到 2026 年,这个领域的共识正在从"让模型自己去 grep"转向"预先构建结构化的上下文层"。
学术界也在跟:一篇 2026 年的研究显示,把 tree-sitter 构建的知识图谱通过 MCP 暴露给 agent,在 31 个仓库上把 token 用量降到了约十分之一。
Graft 在这条路上的选择很有性格——不用向量、不用 embedding、不建数据库,就是纯文本文件加确定性解析。
这在一堆"AI 原生"方案里显得有点复古,但它换来的是三样很珍贵的东西:可读、可 diff、可审查。
图谱错了?你能看见。代码变了图谱没跟上?在 PR 的 diff 里一目了然,而不是烂在某个外部存储里悄悄发霉。
这或许才是最有意思的一点:当 AI 越来越多地参与写代码,"给 AI 看的文档"和"给人看的文档"正在合并成同一样东西。
一份好的架构说明,从此不只是给新同事看的了。它同时是你 AI 助手的记忆。写好它,收益翻倍。
最后
如果你在用 Claude Code、Codex 或任何编程 agent,并且经常感觉"它在我的项目里像个无头苍蝇"——这个方向值得你花二十分钟试试。
npx @nanonets/graft init --dry-run # 先看看它想动哪些文件不装全局、不写任何东西,先看一眼再决定。
而如果你只是个旁观者,那么记住这句话就够了:
人类进一个项目,只需要上手一次。AI 每一次都要重新上手。
谁先把这件事解决掉,谁就拿到了下一轮的门票。
项目地址:https://github.com/NanoNets/Graft
官网:https://graft.nanonets.ai
本文数据与图片均引自项目官方 README 与官网,部分基准为团队自测结果,仅供参考。
夜雨聆风