ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

代码问答总找错文件:Graphify 不用向量库,AST 建图反而更准

代码问答总找错文件:Graphify 不用向量库,AST 建图反而更准 本文摘要向量检索按相似度召回片段代码问答常落到词面相近的错误文件。Graphify 用 AST 把代码与配置建成可查询图谱每条边带行号与理由可逐条核验。一、问题与结论在Claude Code里问「订单金额在哪算的」检索层把report.py中带total变量的报表代码排在前面真正的billing/calculate_total落在后面。模型基于错误上下文作答读起来流畅落点却是错的文件。把这类失败拆开通常落在三层词面层提问是自然语言代码是标识符词面不重叠关系层真正想问的是「谁调用谁、谁写哪张表、哪个配置影响哪些代码」这是边向量检索返回的是点相似片段动态层依赖注入、反射、配置驱动路由产生的运行期边任何静态方案都看不见。Graphify 以/graphifyskill 接入Claude Code、Cursor、Codex、Gemini CLI本地确定性解析代码、SQL schema、配置与 PDF每条边带解释不使用向量库。它补的是第 2 层。需要说清一点「更准」在来源里没有测量依据。能确认的是归因准确——答案可指到文件、行号与理由召回准确找回正确文件的比例必须自测下文数字一律标注为作者自测且未验证。二、排查与选择依据结论先按提问类型分类再决定检索层——结构类问题靠边意图类问题靠语义。词面失配可用标识符拆分、同义词表缓解但只改善排序不产生关系关系失配需要显式边调用、继承、读写表、配置引用。这类边由语法结构决定适合确定性解析每条边可回溯到行号动态边缺失是静态方案的硬边界只能靠运行期追踪补边解析器解决不了。替代方案与取舍方案选择条件代价边界向量 RAG提问以意图类为主如「哪里处理超时」返回片段无关系落点需人工核对相似但无关的片段会挤掉真答案grep Agent 多轮搜索一次性小仓库、问题零散成本转嫁到推理轮次跨 SQL、配置、PDF 时检索碎片化AST 符号图谱结构性问题占比高、答案需可核验建图成本前置需核对语言覆盖动态派发边缺失意图类提问偏弱图谱 向量混合两类提问都多两套索引的一致性维护成本最高小项目不划算不适用场景一次性小项目、问题以意图为主、或仓库以反射与注入为主的框架代码占多数——此时图谱给出的边看起来完整且每条都有解释却恰好漏掉框架织入的那条可解释性反而放大误信。采用前需核对/graphifyskill 的安装入口、支持的语言与解析器、图的输出形态JSON 还是图查询语言、是否完全无向量依赖、大仓重建耗时、License与商用限制、PDF/SQL 的解析深度。来源均未提供属未验证项。三、关键原理结论图谱的价值在于每条边可解释而不是「更准」这个未经测量的结论。AST 建图把函数、表、配置项、文档段落建成节点把调用、读写、引用建成边每条边附from、to、line、why。回答「谁写orders表」时返回的不是相似片段而是写入点 - orders的路径可回溯到行号。这就是归因准确答案自带依据。召回准确取决于别名解析、跨文件符号表与语言覆盖必须用标注提问集实测仓库描述没有准确率数据这里不给数字。动态边要作为重点限制写进判断Autowired字段注入、Transactional动态代理、ServiceLoader/SPI、反射调用都不在 AST 调用边上。问「谁会触发OrderService.confirm()」图只能给显式调用点。四、可运行示例以下是作者自建的最小复现脚本演示「边可解释」与「边悬空」不是 Graphify 的命令输出。环境Python 3.10仅用标准库ast无第三方依赖。步骤 1建样例仓库sample_repo/ ├── report.py ├── billing.py └── app.pysample_repo/report.pydefgenerate_summary():total1returntotalsample_repo/billing.pydefcalculate_total(items):returnsum(items)sample_repo/app.pyfrombillingimportcalculate_totaldefcheckout(cart):returncalculate_total(cart)步骤 2写建图脚本mini_graph.py为每条边写whyimportast,jsonfrompathlibimportPath ROOTPath(sample_repo)defparse(root):funcs,calls[],[]forpyinsorted(root.rglob(*.py)):treeast.parse(py.read_text(encodingutf-8),filenamestr(py))forfnin[nforninast.walk(tree)ifisinstance(n,ast.FunctionDef)]:qualf{py}::{fn.name}funcs.append({name:fn.name,id:qual,line:fn.lineno})fornodeinast.walk(fn):ifisinstance(node,ast.Call):ifisinstance(node.func,ast.Name):calls.append((qual,node.func.id,node.lineno,callee is plain Name, statically resolvable))elifisinstance(node.func,ast.Attribute):calls.append((qual,node.func.attr,node.lineno,callee is Attribute, receiver type unknown))returnfuncs,callsdefmain():funcs,callsparse(ROOT)table{}forfinfuncs:table.setdefault(f[name],[]).append(f[id])edges[]forcaller,target,line,whyincalls:hitstable.get(target,[])edges.append({from:caller,to:target,line:line,why:why,resolved:hitsorNone,ambiguous:len(hits)1})print(json.dumps({nodes:funcs,edges:edges},ensure_asciiFalse,indent2))print(\n[query] 谁调用了 calculate_total)foreinedges:ife[to]calculate_total:print( ,e[from],line,e[line],|,e[why],-,e[resolved])if__name____main__:main()预期输出运行结果节选[query] 谁调用了 calculate_total sample_repo/app.py::checkout line 4 | callee is plain Name, statically resolvable - [sample_repo/billing.py::calculate_total]JSON 中还会出现sample_repo/billing.py::calculate_total - sum的未解析边库函数不在符号表内why说明成因、resolved为null这同样可解释。实际输出本机未执行改写调用方式后的对照方法把app.py中的调用改成cart.pricing.calculate_total(cart)再运行同一查询输出callee is Attribute, receiver type unknownresolved为null——边悬空答案指不到目标文件。常见失败与处理同名方法多处定义时脚本标ambiguous: true边指向多个候选。原因是只按函数名匹配、缺类型信息。可用模块限定名二次消歧或按导入别名解析无法消歧时保留标记交给人工不要静默丢边。五、验证结果与边界结论边界必须写进采用决策尤其第一条。动态边缺失注入、代理、SPI、反射产生的调用不在图上答案看起来完整却漏掉关键路径接收者类型未知obj.helper()、鸭子类型会导致漏边或假边示例中的悬空与ambiguous即此状态意图类提问偏弱「哪里处理了超时重试」是意图问题图只能答结构关系这是不用向量库的对价规模与非代码资产确定性解析通常全量重建monorepo 的耗时与内存未验证PDF 若仅作纯文本节点入图会污染路径查询。自建评测流程结果未验证准备 20 个真实提问如「事务在哪开启」「谁写orders表」人工标注正确文件分别跑向量检索与图查询记录 Top-1 命中文件数与「答案可指认依据」的比例。跑出数字之前「更准」只应理解为「更可追溯」。思考运行期注入边该由静态规则推导还是用一次 trace 回填更可靠意图类提问占比到多少时纯图谱方案不如图谱与向量混合参考资料Graphify-Labs/graphify
返回列表