ApFramework 标志
发布日期

Graphify:代码知识图谱如何进入编码 Agent 的上下文链路

作者
  • 作者头像
    姓名
    Shoukai Huang
    Twitter
夕阳下,宇航员站在飞船旁
Photo by Imkara Visual on Unsplash

当编码 Agent 面对一个陌生代码库时,最先遇到的问题通常不是“不会写代码”,而是不知道应该先读哪些代码。它需要从入口文件开始搜索,再根据 import、调用关系和目录结构逐步扩展上下文。问题在于,文件系统提供的是位置,代码图谱提供的是关系。

Graphify 是一个把代码库、文档和其他输入转换成可查询知识图的开源工具。对编码 Agent 来说,它更像一张代码关系地图:先帮 Agent 找到相关文件和符号,再回到源码理解、修改和测试。这里的“结构预检索层”是本文根据接口和内部验证做出的判断,不是 Graphify 对 Agent 效果的官方结论。

下面的内容来自一次内部验证。使用的是 2026 年 10 月 23 日的 Graphify 版本(graphifyy 0.9.95),测试项目是 ApFramework 博客。为了先看清代码分析能力,只取了 app/、components/、lib/、scripts/、package.json 和 tsconfig.json,没有把整个项目都放进去。

一、从“读哪些文件”到“代码如何连接”

传统搜索适合回答“某个字符串出现在哪些文件”。但编码 Agent 还会遇到另一类问题:一个页面依赖了哪些组件?一个服务怎样连到数据库?两个模块之间经过了哪些调用?这些问题需要同时看文件、符号和它们之间的关系。

如果 Agent 直接把整个文件读进来,信息可能太多;只靠向量搜索,又可能找到“意思相近”但并不关键的文件。代码知识图谱先把文件、符号和关系整理出来,给出一张可以沿着关系查找的地图。

这张地图不能代替源码。它先解决的是“从哪里开始看”和“哪些地方有关联”。真正要改函数时,Agent 还是要打开源文件,读懂实现,再跑测试。

编码 Agent 的上下文链路:从结构预检索到源码、测试和回写

图 1:Graphify 更适合作为结构预检索层,先帮助 Agent 定位入口和关系,再回到源码、测试与决策记录完成闭环。

二、代码知识图谱记录什么

Graphify 用 tree-sitter AST 读取代码结构。代码建图可以在本地完成,不必调用 LLM;文档、图片、视频等内容的语义处理,则可能需要配置相应的后端。

默认构建流程通常产生三个主要文件;如果使用 --no-viz 等选项,输出可能不同:

  • graph.html:可以在浏览器中查看和搜索的交互式图;
  • GRAPH_REPORT.md:对高连接节点、社区和关键关系的摘要;
  • graph.json:供命令行、Agent Skill 或 MCP 查询的完整图数据。

可以把 graph.json 想成一张“代码关系表”。它主要记录两类东西:代码库里有哪些节点,以及节点之间有什么关系。比如,一个页面函数是一个节点,一个组件文件也是一个节点;页面导入组件,就是它们之间的一条边。

下面是一个简化的结构示意,帮助理解它大概长什么样。字段会随 Graphify 版本和节点类型变化,这段 JSON 不是本次内部验证生成文件的逐字内容:

{
  "graph": {
    "schema_version": "...",
    "graphify_version": "0.9.95"
  },
  "nodes": [
    {
      "id": "app/blog/[...slug]/page.tsx::Page()",
      "type": "function",
      "name": "Page()",
      "file": "app/blog/[...slug]/page.tsx",
      "line": 80
    },
    {
      "id": "components/MDXComponents.tsx",
      "type": "file",
      "name": "MDXComponents.tsx",
      "file": "components/MDXComponents.tsx"
    }
  ],
  "links": [
    {
      "source": "app/blog/[...slug]/page.tsx::Page()",
      "target": "components/MDXComponents.tsx",
      "relation": "imports_from",
      "provenance": "INFERRED"
    }
  ]
}

把它换成人话就是:

Page()                         一个页面函数
MDXComponents.tsx              一个组件文件
Page() --imports_from-->       MDXComponents.tsx

graph.json 是给程序和 Agent 用的,graph.html 是给人点着看的,GRAPH_REPORT.md 更像一份自动整理出来的摘要。Agent 通常不会把整个 JSON 全部读进上下文,而是用 explain、path 或 query 先取出和当前问题有关的部分,再回到源码阅读。

图中的节点可以是文件、类、函数、方法、依赖包或文档对象,边则表示 imports、calls、inherits、references 等关系。Graphify 还给边添加了两类标签:EXTRACTED 表示关系可以在源代码中直接找到,INFERRED 表示关系是通过解析和跨文件 resolution 推导出来的。

这两个标签把“工具直接读到的内容”和“根据结构推出来的关系”分开了。Agent 可以先把推断关系当作线索,再回到源码核对。

图谱也有边界。它通常不保存完整的函数正文,也不会自动记录所有架构意图、历史决策和会话过程。一条 calls 边只能说明两个符号之间有调用关系,不能说明为什么要这样调用。

三、Graphify 现在是什么样

这次检查使用的版本是 graphifyy 0.9.95,命令仍然叫 graphify,需要 Python 3.10 及以上。

现在的 Graphify 不只是运行一次命令、生成一张图:

层次当前能力对 Agent 的意义
结构抽取tree-sitter AST、多语言代码解析获得文件和符号关系
图产物graph.json、HTML 和报告保存可查询的结构结果
查询接口explain、path、query按问题读取局部结构
能力接入Skill、项目级安装、MCP让 Agent 能调用图,而不只是人查看
持续维护hooks、增量更新、图版本标记让结构图随代码变化维护
输入扩展文档、PDF、图片、视频等将部分外部上下文关联到代码图

这些能力让代码图可以接入 Agent 的工作流程。图提供结构信息,Skill 说明怎么调用,MCP 或命令行提供入口。不过,Skill 安装不等于建立了 MCP 连接,hooks 是否生效也要看具体平台和安装状态。源码和测试仍然是最后的依据。

Graphify 的实现结构:从输入和 AST 抽取到图产物与查询接入

图 2:Graphify 的实现链路示意。接入层表示公开实现中的 CLI、Skill、MCP 和 hooks 入口,不等于本次局部实验已验证所有入口。

四、三个查询命令分别解决什么问题

1. explain:解释一个节点

explain 用来回答“这个符号是什么、和哪些东西相连”。输出通常会带上来源文件、行号、连接数和相关关系。

如果名称不唯一,Graphify 不会替用户随便选一个。本次输入:

graphify explain "Page()" \
  --graph graphify-out/graph.json

结果给出了 5 个候选节点,分别位于不同的页面文件中。换成带路径的写法:

graphify explain \
  "app/blog/[...slug]/page.tsx::Page()" \
  --graph graphify-out/graph.json

这次定位到了博客文章详情页源文件第 80 行的 Page()。

代码库里的 Page、Client、Config 可能在多个文件甚至文档中出现。工具要求补上路径,至少不会悄悄选错。

2. path:追踪两个节点之间的关系

path 用来回答“两个东西是怎么连起来的”。这次查的是页面函数到 MDX 组件的路径:

graphify path \
  "app/blog/[...slug]/page.tsx::Page()" \
  "components/MDXComponents.tsx" \
  --graph graphify-out/graph.json

返回了一条两跳路径:

Page() <--contains-- blog/[...slug]/page.tsx
      --imports_from--> MDXComponents.tsx

这条路径当然不是博客渲染的全部细节,但它给出了一个明确的阅读顺序:先看页面入口,再看导入的 MDX 组件。比起在整个项目里搜索“博客渲染”,这个结果更容易直接使用。

3. query:围绕问题返回范围受控的子图

query 适合处理范围更大的问题,例如:

graphify query "which components connect to the blog rendering pipeline" \
  --graph graphify-out/graph.json \
  --budget 1000

这次查询找到了 67 个相关节点,但 --budget 1000 只展示了 47 个,并给出 TRUNCATED 提示。把预算调到 1447 后,结果仍提示需要更高预算。也就是说,query 返回的是受预算限制的一部分关系,不是一份完整架构文档。

这对 Agent 的用处在于,结果不会无限扩大,而且会明确提示可能被截断。接下来可以提高预算、缩小问题,或者增加关系过滤。

五、在真实项目中做一次受控验证

这次用的是 ApFramework 博客仓库。先尝试把整个工作树交给 Graphify,但项目里有依赖、构建产物和大量静态资源,约 3.2GB,完整扫描没有跑完。

所以,做这类检查前最好先划清输入范围。否则扫描出来的很可能是项目环境的大小,而不是代码分析能力。

随后把输入缩小为项目的核心源码目录和两个配置文件:

app/
components/
lib/
scripts/
package.json
tsconfig.json

运行:

graphify extract \
  ./graphify-apframework-input \
  --code-only \
  --no-cluster \
  --out ./graphify-apframework-result

实际输出为:

[graphify extract] found 64 code, 0 docs, 0 papers, 0 images
[graphify extract] AST extraction on 64 code files...
[graphify extract] wrote .../graph.json — 373 nodes, 682 edges (no clustering)

这几个数字只说明这次选中的文件和这次运行,不能拿来代表整个 ApFramework 项目,也不能用来判断性能。因为用了 --no-cluster,社区聚类报告也不在这次检查范围内。

后来我在博客页面文件里加了一行不改变逻辑的注释,再用另一个输出目录重新抽取,结果还是 373 个节点、682 条边。这只能说明这次改动没有改变抽取结果。它不能算 graphify update 的增量性能测试,因为前后用的是两个独立的 extract 输出目录。

这次检查的步骤很简单:

  1. 先排除依赖和构建产物,选出要看的代码;
  2. 用 code-only 模式建图,记录文件、节点和边;
  3. 用 explain 看节点能不能定位;
  4. 用 path 看跨文件关系;
  5. 用 query 看结果范围是否受预算控制;
  6. 回到源码核对关键关系。

graphify update、检索质量、Token 成本和修改正确率,这次都没有继续验证。

六、代码图是 Agent 记忆的一层,不是全部记忆

把 Graphify 称为“代码记忆”没有问题,但要说清楚它记住的是什么:文件、符号、依赖,以及它们之间的连接方式。

编码 Agent 还需要其他几类记忆:

记忆层主要回答的问题典型载体
代码结构记忆代码现在如何连接?AST-derived graph、graph.json
来源知识外部资料表达了什么?raw、wiki、文档
会话记忆上一次发生了什么?logs、chats、resume
决策记忆为什么这样设计?ADR、永久笔记、PR 评论
偏好与规则项目通常应该怎么做?rules、skills、项目记忆
相似性检索哪些文本与当前问题相似?向量索引

这些信息各管一部分。图查询能告诉 Agent 页面和组件之间有 imports_from 关系,却不能告诉它团队为什么选这个组件;向量检索能找到相似的设计文档,却不一定能给出调用路径;会话日志记得发生过什么,但不等于当前代码的结构。

实际使用时,可以先用结构图找入口和关系,再读源码补齐细节,用测试确认行为,把决策和会话记录留下来。Graphify 能减少的是找代码的成本,不是所有上下文成本。

编码 Agent 的记忆层边界对比

图 3:不同记忆层的边界对比。Graphify 主要补充代码结构记忆,不能自动提供来源背景、会话过程、设计理由或项目规则。

七、从一次性建图到上下文编排层

Graphify 这几年的变化,主要在四个方面。

第一,输出不再只有可视化图。graph.html 适合人浏览,graph.json 则可以被命令、Skill 或 MCP 查询。

第二,工具增加了 Agent 接入方式。graphify install、项目级 Skill、MCP 和部分平台的 hooks,都可以让“先查图”变成工作流程的一部分。但不同平台的能力不一样,不能理解成安装后所有文件搜索都会自动被拦截。

第三,边上增加了来源标签。EXTRACTED 和 INFERRED 能帮助调用方区分直接抽取的关系和推导出来的关系,但它们不是统一的概率分数。遇到 INFERRED,还是要回源码核对。

第四,知识图开始考虑持续维护。图里有 schema/version 标记,也提供更新命令和 hooks 相关能力。图如果长期不更新,Agent 看到的入口就可能已经过时。

这些能力并不等于 Graphify 已经是完整的编码 Agent 平台。更准确地说,它负责把代码库整理成一个可以导航、追踪和查询的结构层。

八、边界:一次验证不能证明什么

这次能确认的事情很有限:选中的源码可以被抽成包含节点和边的图;explain 能定位节点,也会暴露名称歧义;path 能返回跨文件路径;query 会按 token 预算返回部分关系;关系标签和源码位置方便后续核对。

但它没有证明以下事情:

  • 没有证明完整 ApFramework 项目能够在当前环境中顺利完成构图;
  • 没有证明 Graphify 能自动提高代码修改正确率;
  • 没有证明一次局部查询就能还原完整架构意图;
  • 没有独立复现项目方 README 中的 benchmark 或 Cloud 节省比例;
  • 没有验证 graphify update 在同一缓存目录中的增量性能;
  • 没有证明 INFERRED 关系不需要人工或测试核对。

边界也很清楚:图能帮助 Agent 更快找到该读的地方,但找到代码不等于理解原因,理解原因也不等于修改一定正确。

结语:先给 Agent 一张可追溯的地图

Graphify 的价值不只是把代码画成网络图,而是给 Agent 一个可以查询的结构入口。“我应该先看哪里”可以先用 explain、path 和 query 找到线索,再回到源码和测试确认。

在项目里使用时,可以先选一小块源码:先建图、查询,再回源码核对。确认这套关系对当前项目有帮助后,再考虑接入 Skill、MCP、hooks 和持续更新。

代码知识图谱可以作为编码 Agent 上下文中的一层结构记忆,但不是完整的记忆系统。它回答“代码现在怎样连接”,其他记忆层回答“发生过什么”“为什么这样决定”以及“这里通常应该怎么做”。实际使用时,需要把这些信息接起来。

参考资料