给 AI 编程助手装一个"代码大脑":我是怎么用知识图谱 + 语义检索解决 Agent 代码理解问题的

本文介绍我开发的 igraph ------ 一个面向 AI 编程助手的代码知识图谱工具。和市面上已有的 CodeGraph 不同,igraph 在代码结构图的基础上加了语义摘要和向量检索,让 Agent 能用自然语言找代码。

体验地址

Git:github.com/Ychangqing/...

从一个真实痛点说起

我日常用 Claude Code 写业务代码,有个反复出现的场景:

我说:"帮我看看用户下单这块的逻辑"

然后 Claude Code 开始疯狂 grepfind、一个文件一个文件地 cat......翻了十几个文件之后终于找到了 createOrder 函数,再顺着调用链往下看。整个过程花了 30 多次工具调用,消耗了大量 token。

问题很明显:Agent 不认识你的代码仓库。每次都是盲搜,效率极低。

后来我用了 CodeGraph,情况有改善------Agent 可以通过图谱直接查符号、展开调用链,不用一个个文件翻了。但用了一段时间,发现它有个根本性的限制:

CodeGraph 是个结构查询工具,不是语义检索工具。

它要求你先知道函数名叫什么,然后帮你展开结构。但很多时候你只知道业务含义("处理退款的逻辑"),不知道代码里的命名(processRefundhandleRefundRequest、还是 refund?)。

这就是我决定自己做 igraph 的原因。

igraph 的核心思路

一句话概括:在代码结构图的基础上加语义层,让 Agent 能用自然语言搜代码。

整个系统分两条线:

markdown 复制代码
离线建库(一次性):
  源码 → Tree-sitter 解析 → 提取符号和调用关系 → 存入 SQLite
      → LLM 为每个函数生成中文摘要 → Embedding 向量化

在线查询(毫秒级):
  自然语言问题 → 向量化 → 文件粗筛 → 双通道精排 → RRF 融合 → 图谱展开

建库阶段把脏活累活都干了(解析、调 LLM、调 Embedding),查询阶段纯本地 SQLite 操作,零网络延迟。

和 CodeGraph 的区别在哪

先说清楚,两个项目底层技术有不少重合------都用 Tree-sitter 解析 AST、SQLite 存储、MCP 协议对接 AI 助手。但设计思路差别很大。

CodeGraph :建一张精确的代码结构图 → Agent 按图索骥 igraph:建图 + 语义摘要 + 向量化 → 支持自然语言检索

用一个例子说明:

arduino 复制代码
场景:我想找"处理用户退款"的代码

CodeGraph 的用法:
  → 你得先猜函数名可能叫 refund / processRefund / handleRefund
  → 调用 codegraph_node 查找
  → 找到后展开调用链

igraph 的用法:
  → 直接输入"处理用户退款的逻辑"
  → igraph_explore 返回最相关的函数(带摘要、源码、调用链)
  → 同时关联相关的 PRD 需求和数据库表

更详细的对比:

维度 CodeGraph igraph
检索方式 按符号名精确查找 向量语义 + 全文关键词双通道,RRF 融合排序
语义理解 无,纯 AST 结构 LLM 为每个符号生成摘要,向量化后支持语义搜索
多模态 不支持 可挂载 PRD 文档和 DB Schema,需求和代码自动关联
降级策略 依赖运行环境 无 LLM → 启发式摘要;无 Embedding → 纯全文检索
增量更新 文件监听实时同步 sha256 diff + 50% 阈值摘要复用
支持语言 7 种(含 C/C++/Rust/C#) 5 种(TS/JS/Python/Java/Go)

各有优劣,CodeGraph 胜在实时同步和语言覆盖面,igraph 胜在语义检索和多模态。

几个关键技术决策的思考

1. 为什么要双通道检索

最开始我只做了向量检索,很快发现一个问题:用户搜 fetchUserList 这种精确标识符时,向量检索的效果反而不如全文搜索。

原因也简单------向量模型是按语义编码的,fetchUserListgetUserData 在向量空间里可能很近,但用户要的就是那个精确的名字。

所以最终做了两个通道并行:

  • Dense 通道 (向量 KNN):擅长语义匹配,"获取用户列表" 能匹配到 fetchUserList
  • FTS5 通道 (trigram 全文):擅长关键词匹配,搜 fetchUser 直接精确命中

两个通道的结果用 RRF(Reciprocal Rank Fusion) 融合:

scss 复制代码
rrfScore(d) = Σ w_c / (k + rank_c(d))

核心思想是只看排名不看分数。因为向量距离和 BM25 分数量纲完全不同,直接加没有意义。RRF 把它们统一到排名维度上做融合,简单有效。

2. FTS5 为什么选 trigram 分词器

这个选型踩了坑。一开始用的 SQLite FTS5 默认的 unicode61 分词器,发现中文搜索基本废了------它把连续汉字当成一个巨大的 token,搜"用户"匹配不到"获取用户列表"。

换成 trigram(长度为 3 的滑动窗口)之后,任意 ≥3 字符的子串都能匹配。不管是中文"用户列表"还是英文标识符里的 Trade,都能搜到。

代价是 <3 字符的查询词 trigram 搞不定(没法生成 token),我们用 LIKE 子串扫描兜底。

3. LLM 摘要的批处理 + 断点续跑

一个大仓库可能有几千个文件,逐个调 LLM 太慢了。我们的做法是一次 API 调用处理一个文件的所有符号------一个有 20 个函数的文件只需要 1 次调用而不是 20 次。

更重要的是断点续跑。每个文件在数据库里有状态字段(pending / done / error),每次启动只处理 pending 的。中途 Ctrl+C 了、网络断了、API 限流了,下次跑直接从断点继续,已完成的不会重跑。

SIGINT 信号还做了优雅处理------收到 Ctrl+C 后不立即退出,等当前在途的请求完成再退出,避免写了一半的脏数据。

4. 50% 阈值的增量摘要复用

增量更新时,一个文件改了 1 个函数,需要把整个文件的所有摘要都重新生成吗?

我们的策略是:对比每个节点的源码是否变化,如果 ≥50% 的节点没变,就只对变化的节点重跑 LLM,未变化的直接复用旧摘要。

效果很直观:一个 20 函数的文件改了 1 个函数,只需要 1 次 LLM 调用(而不是整个文件重来的 1 次批量调用),节省 95% 的 API 成本。

5. 多模态资源挂载

这是我觉得和 CodeGraph 差异化最大的一个功能。

实际开发中,理解代码不光要看代码本身,还要知道"这段代码对应哪个产品需求"、"操作的是哪张数据库表"。igraph 可以把 PRD 文档(Markdown / PDF / DOCX)和 DB Schema(SQL / JSON / XLSX)挂载进来。

挂载过程:

  1. 解析文档 → 按章节/表维度切片
  2. 每个切片向量化
  3. 用切片向量和已有的文件向量做 KNN 匹配
  4. 相似度 ≥ 0.85 建 strong 关联,0.70~0.85 建 weak 关联

这样 Agent 查到一个函数时,能同时看到"这个函数实现的是 PRD 第 3.2 节的需求"、"它操作的是 orders 表"。

6. 优雅降级

不是所有人都有 LLM API 和 Embedding 服务的。igraph 的原则是:不管什么环境都能用,只是效果有差异

复制代码
完整模式:LLM 摘要 + 向量检索 + 全文检索 + 多模态关联
↓ 没有 LLM
降级 1:启发式摘要(函数签名拼接)+ 向量检索 + 全文检索
↓ 没有 Embedding
降级 2:启发式摘要 + 纯全文检索
↓ 什么都没有
最低保障:纯 AST 结构图 + FTS5 关键词搜索

igraph build --no-llm 在完全离线环境下也能跑通,只是摘要质量差一些。

存储方案:为什么全塞进 SQLite

这个问题估计很多人会好奇。图数据为什么不用 Neo4j?向量为什么不用 Milvus?全文搜索为什么不用 Elasticsearch?

答案是场景决定选型

igraph 是一个本地开发者工具,核心诉求是零运维、开箱即用。一个 .igraph/igraph.db 文件搞定所有事情------关系数据、全文索引、向量索引全在里面。

  • 图遍历 :用递归 CTE 做 N 跳展开,GROUP BY id + MIN(depth) 天然去环。几万个节点、几跳展开,SQLite 毫秒级完成。
  • 全文搜索:FTS5 是 SQLite 内置模块,trigram 分词器覆盖中英文。
  • 向量检索:sqlite-vec 是个 SQLite 扩展,加载进来就有 vec0 虚拟表,支持 KNN。

如果哪天要做成在线服务,这些组件可以逐个替换。但对于当前的本地工具场景,引入任何一个外部服务都是过度设计。

目前的不足

实事求是地说几个短板:

  1. 首次建库慢:要跑 LLM + Embedding,比 CodeGraph 纯 AST 解析慢很多。大仓库可能要几十分钟甚至更长。
  2. 语言覆盖少:目前只支持 TS/JS/Python/Java/Go 五种,CodeGraph 支持更多(包括 C/C++/Rust/C#)。
  3. 没有实时 watch :改了代码要手动跑 igraph build 触发增量更新,不如 CodeGraph 的文件监听自动同步方便。
  4. Embedding 模型耦合:换了 Embedding 模型需要重新向量化所有数据,因为不同模型的向量空间不兼容。

后续计划做的事情:

  • 实时 watch 模式(文件监听 + 防抖 + 增量)
  • PRD 图片识别(目前只提取文本内容)
  • 更多语言适配器

技术栈概览

层次 选型 理由
语言 TypeScript (ESM) 前端/全栈生态
解析 Tree-sitter (N-API) 多语言统一 API
存储 better-sqlite3 + WAL 同步 API、单文件
全文 FTS5 (trigram) 内置、中英文子串匹配
向量 sqlite-vec (vec0) 零额外进程
LLM OpenAI 兼容 API(裸 fetch) 不依赖 SDK
Embedding BGE-M3 via TEI,1024 维 开源可自建、多语言
MCP 官方 SDK,stdio 传输 Claude Code / Cursor 直接对接
CLI Commander.js 轻量声明式

写在最后

igraph 和 CodeGraph 不是替代关系,更像是不同侧重点的两个方案。如果你的主要需求是结构导航(知道函数名、看调用链),CodeGraph 的实时同步和语言覆盖更好。如果你更需要语义搜索、想让 Agent 通过自然语言理解代码、还想关联 PRD 和数据库,igraph 可能更合适。

欢迎交流技术细节。

相关推荐
码哥字节2 小时前
AI知识库搜不准?缺的不是更好的模型,是这三层内容筛选
ai编程
京东云开发者2 小时前
拆解海博 AI-Native 落地保障:Harness、双 Loop、知识库与技能自主迭代实践
llm·ai编程·前端工程化
Rain的Java大神实战圈2 小时前
致焦虑的程序员:AI 不会让你失业,但“写 CRUD”会
ai编程·架构设计
老王以为2 小时前
解剖 Claude Code:逆向工程视角下的入口架构分析
前端·ai编程·claude
shepherd1113 小时前
别再把 MCP 当成大模型的“手脚”:LLM 并不会直接调用 MCP
后端·ai编程·mcp
爱丶不疚3 小时前
Code Review「问意图」这件事,在 AI 时代还重要吗?
ai编程·vibecoding
众人皆醒我独醉3 小时前
什么是输入上下文、MCP、Agent、Skills?—— 四个让你用不好 AI 的概念,一次讲清楚
面试·ai编程
唐老板3 小时前
从写代码变成管 AI:开发者的新疲劳
ai编程
李剑一3 小时前
Kimi暂时关上新用户订阅渠道你以为是缺钱吗?其实可能更缺卡!
aigc·openai·ai编程