六个月前,我开始做一个本地优先的代码智能服务器,想让AI编程助手不再瞎编函数名。上周跑完基准测试,我的工具在F1分数上输给了一个调优的grep命令——差了9分。
但我决定把结果发出来。这件事本身比数字更值得聊。
![]()
从"感觉好用"到"拿数字说话"
我做的工具叫sverklo,给Claude Code、Cursor、Windsurf这些AI编程助手用的。核心卖点一直很简单:给它们一个真正的符号图谱,而不是靠grep做模式匹配。
口号听着顺耳,但六个月下来,我没有任何公开的基准数据。什么"迭代速度快"的故事,都是讲给自己听的。
所以我建了一个测试集:60个手工验证的检索任务,两个真实的开源代码库(expressjs/express和我自己的sverklo仓库),三个基线对比( naive grep、smart grep、sverklo)。测的不只是检索质量(F1、召回率、精确率),还有AI代理真正要买单的东西:输入token数、工具调用次数、实际耗时。
结果放在sverklo.com/bench,原始JSONL输出在仓库的benchmark/results//目录下。整个测试用一条npm命令就能跑。如果你对我的数字有异议,欢迎提issue,附上你的机器配置。
核心发现:调优的grep赢了F1,但代价惨烈
一个精心调过的ripgrep命令——带语言过滤、定义型模式——F1比我的混合检索栈高9个点。
这是我开工时完全没料到的。
但sverklo在其他维度碾压:
• 比naive grep少62倍token(255 vs 15,814)
• 比smart grep少2.9倍token(255 vs 731)
• 1次工具调用,而grep需要7-12次
• 冷启动3.7秒建索引后,实际查询约1毫秒
这里的关键认知转变是:站在终端前用rg的人,和AI代理的需求完全不同。
为什么"每个正确答案的token成本"才是硬指标
人用grep时,F1重要,因为你亲自读匹配结果。AI代理不付这个钱,但付另一个钱——token。
假设你的上下文窗口是20万token。烧掉1.5万个token的grep噪音去找一个函数,实际改代码时就少了1.475万个token可用。用255个token拿到答案的代理,能多1.475万个token干活。
真正重要的指标是"每个正确答案的token成本":输入token除以召回率。测试报告分了两组:gated(F1≥0.8)和ungated。
sverklo在gated子集上是203 token/正确答案。naive grep是3,557。smart grep是165——当它的F1达标时,单位成本确实能打。
我差点犯的错误:优化F1。AI编程代理要的是最便宜的正确检索,不是用12次工具调用堆出来的高精确率检索。
分场景拆解:三种方法各自的优势区间
测试把任务分了类,规律很明显:
sverklo赢的场景,正是结构化检索能直接回答问题的场景。定义查找(P1)和文件依赖(P4)就是典型——符号图谱、导入图谱直接命中。
引用查找(P2)反过来了,正则模式匹配更顺手。grep擅长找"谁调用了X",因为调用点分散在代码各处,模式比结构遍历更快。
实现查找(P3)和跨文件依赖(P5)是混战区,取决于具体查询的拓扑结构。
这个分布让我重新理解自己的产品:sverklo不是grep的替代品,是互补层。符号图谱解决grep搞不定的结构化问题,grep覆盖sverklo过重的轻量查询。
技术细节:我的混合检索栈怎么工作
sverklo的核心是本地构建的代码知识图谱。解析器用tree-sitter,支持的语言直接复用它的grammar。图谱节点分几种:模块、函数、类、变量、类型定义。边包括:定义关系、调用关系、导入关系、继承关系。
查询时,系统做两层路由:
第一层,查询分类器(轻量BERT模型,本地跑)判断用户意图:找定义?找用法?找依赖?还是模糊搜索?
第二层,根据意图选检索策略。定义查找走符号索引,引用查找走反向调用边,依赖分析走模块拓扑,模糊搜索才回退到向量检索。
这次测试暴露的弱点:我的向量检索组件在纯模式匹配任务上确实不如ripgrep。不是召回率低,是精确率被噪声拖累了。树状结构遍历的 overhead 在小代码库上不明显,但在express这种中等规模项目上,冷启动3.7秒 vs grep的零延迟,是真实成本。
更意外的是工具调用次数。我以为"一次调用返回结构化结果"是优势,但测试显示AI代理在某些场景下更喜欢"多次轻量调用"——可能是延迟感知,也可能是中间结果的可检查性。
行业参照:其他人在做什么
代码检索这个赛道,大厂和小团队都在挤。
GitHub Copilot用的是混合方案:语义检索+语法分析,但细节不公开。Sourcegraph的Cody明确做了代码图谱,但他们的MCP服务器是云端优先,本地延迟是硬伤。JetBrains的AI助手深度集成IDE索引,但绑定自家生态。
我的差异化赌注是"本地优先":数据不出机器,冷启动后查询极快,适合对隐私敏感或代码不能上云的场景。但测试说明,这个赌注的代价是索引构建时间和初始资源消耗。
另一个观察:MCP(模型上下文协议)的生态还在早期。Claude Code、Cursor、Windsurf对工具调用的行为差异很大。同样的sverklo服务器,在Claude Code里更激进地用工具,在Cursor里更保守。这直接影响"工具调用次数"这个指标的解读——不是纯技术问题,是产品交互设计问题。
我差点没发布的真实原因
F1输9分,第一反应是"再调调,调好了再发"。
但六个月的经验告诉我,这种延迟是陷阱。没有公开基准,就没有真实反馈;没有真实反馈,优化方向就是猜。我告诉自己"速度即迭代"的故事,其实是在回避被数字打脸的风险。
另一个顾虑:竞争对手会看。但sverklo是开源的,代码本来就在那儿。藏着测试结果不解决问题,只会让我自己活在幻觉里。
最终决定发出来,是因为这个"失败"本身有信息价值。它揭示了AI编程工具领域一个被低估的维度:检索质量的经典指标(F1、精确率、召回率)和代理实际成本结构之间的错位。
如果我的工具在F1上输了,但在token效率上赢了17.5倍,这到底算成功还是失败?答案取决于你服务的是终端用户还是AI代理。
下一步:从"符号图谱"到"成本感知路由"
测试给出的明确方向:不要追求单一指标的全面胜利,要做智能路由。
具体计划:
• 集成ripgrep作为轻量查询的后端,符号图谱专注结构化任务
• 查询分类器增加"成本预测"维度,预估不同策略的token开销
• 暴露更多调参接口,让用户在"更快"和"更准"之间自己权衡
• 补测更多代码库规模,验证冷启动成本曲线
一个开放问题:MCP协议本身是否需要扩展,让服务器能向客户端声明"预估成本"?现在的工具调用是黑盒,代理无法做全局优化。如果sverklo能告诉Claude Code"这个查询预计消耗X token",代理或许能做出更好的多步规划。
这超出了单一产品的范围,是整个生态的基础设施问题。
给同行的参考数据
如果你也在做AI编程工具的基础设施,几个可能有用的数字:
• expressjs/express仓库:约500个源文件,测试子集覆盖60个手工验证的检索任务
• sverklo冷启动索引构建:3.7秒(M1 MacBook Pro,16GB内存)
• 索引大小:约为源代码体积的2.3倍
• 查询延迟:符号查找<1ms,向量检索5-15ms,混合查询20-40ms
• naive grep平均每次任务:7-12次工具调用,15,814输入token
• sverklo平均每次任务:1次工具调用,255输入token
这些数字的测试条件、原始输出、复现脚本都在公开仓库里。不同机器会有偏差,但数量级应该稳定。
60个任务,两个真实代码库,三个基线对比,输9分F1但赢17.5倍token效率。这组数字本身不会决定sverklo的成败,但它把我从"感觉好用"的舒适区拽进了"拿数字说话"的硬地。对于花六个月做一款工具的人来说,这可能是比任何优化都更有价值的产出。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
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.