本文摘要:向量RAG召回代码常偏航:注释相似的文件混入,调用方反被漏掉。Graphify用AST建图,沿调用边遍历取回代码,每条边可解释。但意图类问题无法命中图结构,配置与PDF建图粒度需自行验证。
一、问题与结论
在Claude Code里对一个老 Java 项目提问:“如果我修改UserRepository.findById的实现,会影响哪些模块?”若按余弦相似度取 top-k,进榜的会是注释里写着 “user repository” 的docs/architecture.md和措辞接近的OrderService.java;只有一行userService.findById(id)的UserController.java词面无关,落在召回之外。相似度高不代表结构相关,这是余弦匹配的机制结果,不是某次偶然。
结论先给:把代码用确定性 AST 解析成“节点 + 边”的知识图谱,按调用、依赖边遍历取回,可以绕开相似度噪声;代价是不建向量索引,只回答结构上可推导的问题。
二、排查与选择依据
两条链路拆开看:
- 向量链路:代码切块 →
embedding→ 与问题向量算余弦相似度 → 取 top-k。结构信息在“切块”一步被摊平:A 调用 B 成了两个互不相干的片段,检索阶段无法还原。 - 图链路:AST 解析 → 节点(函数、类、文件、配置项)与边(调用、依赖、引用)→ 问题映射为图查询 → 沿边遍历返回节点与边解释。A 调用 B 是解析出的确定事实,不是概率估计。
选型看问题分布:先统计一周内代码问答里“结构类 / 语义类”的占比,再决定走图、走向量还是分流。
替代方案与取舍
| 方案 | 选择条件 | 代价 | 边界 |
|---|---|---|---|
| Graphify(AST 图检索) | 问题以调用链、影响分析、依赖追踪为主 | 图需随代码重建或增量更新 | 意图、设计原因类问题无法命中 |
| 向量 RAG(如 Dify pipeline) | 问题以设计说明、文档语义为主 | 需维护向量索引与chunking调优 | 结构关系常被语义相似度掩盖 |
| 混合路由 | 两类问题各占相当比例 | 两套索引、双倍维护与路由判定成本 | 路由写错会双重漏召回 |
grep/ 代码搜索 | 已知符号名,快速定位 | 不理解语义 | 无法回答跨文件影响面 |
不适合用图检索的情况:设计取舍、“为什么这么写”“哪段代码最可疑”类提问占比高;输入以 PDF、会议纪要为主;团队无法接受“提交后图滞后一拍”。
三、关键原理
确定性属于解析过程:同一份输入每次生成相同的图,查询可复现;向量检索的结果随embedding模型、切块策略、top-k设置漂移,换一批参数就换一批命中。
边可解释是检索质量的调试手段:召回不对时沿边回溯,能区分“建图漏了边”和“查询遍历方向写错”。向量链路里“为什么返回这段相似片段”通常是黑盒,只能改参数试。
两个成本先算:图基于代码快照,多人并行的monorepo里旧图会给出过时调用链,需要重建或增量更新;PDF、YAML 没有标准 AST,建图粒度要逐格式验证,application.yml的嵌套键可能只提到顶层。
四、可运行示例
环境:Claude Code(或Cursor)+ Graphify 的/graphifyskill;输入为 4 个文件的最小项目。命令与输出格式以仓库最新文档为准,以下输出均为未验证的概念输出。
mkdir-pdemo-project/src/{controller,service,repository}demo-project/configdemo-project/ ├── src/controller/UserController.java # 调用 userService.findById(id) ├── src/service/UserService.java # 注入 UserRepository ├── src/service/OrderService.java # 注释提及 user repository └── src/repository/UserRepository.java # findById(Long id)步骤:① 在Claude Code打开demo-project;② 调用/graphify建图;③ 提问“修改UserRepository.findById会影响哪些模块?”;④ 查看返回的节点与边解释。
预期输出:命中UserController → UserService → UserRepository.findById链路,每条边附解释(如 “UserService 注入 UserRepository”);因注释相似而混入的OrderService不出现在召回里。
实际输出:需在本地执行后填写。上述内容均为未验证推演,不给出命中率数字。
常见失败:/graphify报解析错误或节点缺失。原因:确定性解析器覆盖的语言特性有限,反射、动态派发解析不出边。处理:把该文件排除出建图范围,改用文本检索补查并在图里标注缺口,避免把“查不到”当成“没有依赖”。
五、验证结果与边界
按“结构可推导 / 语义意图”给问题分类,再对照两种检索的适配度:
| 问题类型 | 图检索适配 | 向量检索适配 | 判定依据 |
|---|---|---|---|
| 调用链追踪 | 高 | 中低 | AST 边是确定事实 |
| 影响面分析 | 高 | 中 | 沿依赖边遍历 |
| 设计原因 | 低 | 中 | 图不存业务语义 |
| 运行时性能根因 | 低 | 中 | 静态图无运行时数据 |
| 配置项定位 | 中(需验证) | 中 | YAML 建图粒度未验证 |
| API 使用方式 | 中 | 中高 | 语义示例匹配更强 |
未验证项:Graphify 的实际召回精度、支持的语言清单、PDF 与配置文件的建图深度、增量更新耗时,均无独立评测数据,请在目标仓库上自行验证后再选型。
参考资料
- Graphify-Labs/graphify
- langgenius/dify