我一直在做Kivgraph,一个面向编程代理的本地开源代码图谱。市面上代码搜索和代码图谱工具已经不少,所以我对证明“图谱比grep强”这件事兴趣不大。grep在你明确知道自己要找什么的时候,表现极其出色。我想测试的是一个更窄的问题:一个解析过的代码图谱,能不能在保持同样准确率的前提下,回答结构性问题,同时让代理少读大量代码。
基准测试怎么做的
我在37个仓库上准备了29个问题,仓库语言覆盖Go、TypeScript、Rust、Python和Dart。每个问题都有人工标注的标准答案,涉及的内容包括:谁调用了这个符号、两步之内什么能到达这里、改了这个东西什么会坏、哪个仓库在消费它、它在哪里声明、给我看相关源码。
基线方法故意做得很朴素:用grep搜相关标识符,然后读匹配到的文件。结果很有意思——准确率基本一致,但上下文用量完全不是一回事。Kivgraph总共返回约3.6万个token,而grep加读文件的方式大约用了26.8万个token。
grep仍然赢了部分问题
不过grep在29个问题里还是赢了5个,通常发生在标识符很罕见、而且你已经知道它叫什么的时候。这个结果其实改变了我对这个工具的看法。图谱不应该取代grep。如果你已经知道要找的东西叫什么,grep往往就是最合适的工具。图谱的价值在于问题是结构性的那一刻。
名字不是一条边。我一直想避免的一件事,就是靠匹配标识符来建立关系。两个毫无关联的方法都叫Handle,不应该因为它们碰巧同名就被连起来。对于Go、TypeScript和Rust,Kivgraph分别用go/types、TypeScript类型检查器和rust-analyzer来解析关系。Dart用的是Dart Analysis Server。
Python的处理有意做得更保守。当Kivgraph无法用语义分析器证明某个关系时,内置的回退机制会把它报告为CANDIDATE,而不是当作EXACT关系呈现出来。这个区分在代理问“谁真正调用了这个”或者“改了这个符号什么会坏”的时候很重要。文本搜索能显示出现位置,而解析过的图谱能告诉你哪些出现位置代表真实的关系。
图谱遍历之前的问题
测试过程中我还反复碰到另一个问题。有时候编程代理在概念上很清楚自己要找什么,但完全不知道代码库里管它叫什么。比如:“决定一个失败请求要不要重试的代码在哪里?”实现里可能用retry,也可能把同一个概念叫requeue、backoff、reschedule,或者某个项目特有的名字。
这就是find_by_intent要解决的场景。代理问图谱这段代码是做什么的,Kivgraph对可能实现该意图的符号和文件进行排序,一旦代理拿到入口点,就可以切换到后续的精确查找。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.