跳转到内容
cd /blog

语言递归自我提升:在约 280 种语言上打磨代码智能

[架构][语言][智能体]

> 我们为约 280 种语言提供代码智能支持,没有任何人能靠人工逐一审核这个规模。于是我们搭建了一套语言递归自我提升循环——抽查、LLM 担任评审、修一处、重新验证——并用一支相互隔离的智能体舰队运行它,直到提取结果真正正确,而不只是“绿灯通过”。

本文中的数字反映了发布时(2026 年 5 月)的系统状态。最新数据请参见我们的团队页面

Maguyva 从大约 280 种语言的源代码中提取符号、引用和依赖关系图。每种语言都对应一个自定义的 tree-sitter 处理器——查询、启发式规则、边界情况——每个处理器都可能以自己独特的方式出现细微的错误:一次方法调用被记录成了读取;一个函数被归属到错误的外层作用域;一段根本不存在的关系。

这种问题无法靠人工逐一核查。没有任何团队能够通读跨越 280 种语法的提取结果并找出其中的坏边。所以真正有意思的问题不是“我们的提取是否正确”,而是“在这样的规模下,如何在不让人工介入每一个循环的情况下发现它是错的”。我们的答案是语言的递归式自我改进:由语言智能体驱动的质量闭环,以 LLM 充当裁判,以及一条我们不断重新学习的规则——绿灯不等于正确。

绿灯不等于正确

每种语言都有一套 fixture 测试集,发布关卡会在五个维度上为其打分——准确性、结构完整性、完整度、质量和性能。只有当某种语言在其 fixture 上精确率 ≥ 0.95、召回率 ≥ 0.99、F1 ≥ 0.97,且至少有 20 条预期边以保证统计置信度时,该语言才会被判定为绿灯(GREEN)。低于这个标准就是黄灯或红灯,不能发布。

这道关卡是必要条件,但不是充分条件。Fixture 是针对我们自己编写的 fixture 做验证的,它们只编码了我们已经想到的那些情形。一个处理器可以在其 fixture 上表现完美,却仍会在真实代码中出现的模式上出错——一个宏惯用法、一个泛型约束方法、一个没人为它写过 fixture 的语言特性。绿灯只意味着 fixture 通过了,并不意味着真实代码仓库能被干净地提取。所以这个闭环必须离开 fixture,走向真实世界。

内层循环:抽查、裁判、修复、验证

核心闭环每次运行一种语言:

        ┌──────────────────────────────────────────────────────────┐
        │                                                          │
        ▼                                                          │
  1. corpus run ── clone real-world repos, extract relationships   │
        │                                                          │
        ▼                                                          │
  2. spot-check 100 edges (seed 42, then seed 123 to cross-check)  │
        │                                                          │
        ▼                                                          │
  3. LLM judge classifies every sampled edge:                      │
        CORRECT · FALSE_POSITIVE · TYPE_ERROR ·                    │
        SCOPE_ERROR · METADATA_ERROR                               │
        │                                                          │
        ▼                                                          │
  4. fix ONE thing — handler .py, .scm query, or config           │
        │                                                          │
        ▼                                                          │
  5. re-validate — F1 + re-classify + manifest diff (no regressions)│
        │                                                          │
   better? ──no──► revert, try a different fix ────────────────────┤
        │ yes                                                       │
        ▼                                                           │
  6. promote the fix into fixtures (a permanent regression guard) ──┘

有几个设计让这套流程真正起作用,而不是原地打转。

裁判是智能体本身,而不是一次 API 调用。 我们所说的“LLM 作裁判”,指的是语言智能体亲自将每一条抽样得到的边与真实源码对照,并按照一套固定的五分类标准进行判定:这条边是正确的、是误报、是关系正确但类型错误、是挂错了作用域,还是携带了错误的元数据?这套评判标准才是关键所在——在你知道“23% 的错误率”究竟是真实缺陷还是裁判数错之前,这个数字本身毫无意义。

一次只修一件事,然后证明它有效。 每一次迭代只改动一项可编辑资产,随后针对固定的测试基准重新运行,只有当 F1 提升且重新分类的结果更好时才保留这次改动,否则就回滚。没有成批的投机式改动,也没有“应该会更好”这种说法。一个改动要么证明了自己的价值,要么就被丢弃。而当一次修复站稳脚跟后,它会被提升进入 fixture 测试集——这样它修复的那个 bug 就再也不会悄悄回归。正是这一步“提升”操作,让这个闭环成为递归的,而不仅仅是重复的:每一轮都在加固下一轮据以验证的那个基准。

我们不断重新学到的教训:指标会过度报告

这里有一个陷阱,而我们一头扎了进去。次级语料库指标——比如提取出的目标有多少比例找不到可解析的符号、有多少符号看起来“孤立”等等——会大幅度地过度报告问题。它们大多数情况下是范式产物,而不是 bug。

最典型的例子是:llvm 曾一度显示出 73% 的“有源无符号”比例,被贴上了“灾难性”的标签。我们深入排查后发现,真实准确率其实是 98.5%。那些“缺失的符号”几乎全部是合法的外部引用——调用标准库、调用框架、调用仓库之外的代码。这项指标衡量的是这门语言本身的特性,而不是处理器的缺陷。像 Zig、COBOL 和 Odin 这样的语言“孤立”比例高达 65%–70%,但完全正确;COBOL 甚至零真实错误。

如果我们当初任由这些数字牵着走,就会花上数周时间去“修复”那些本来就没问题的处理器,反而忽略了那些真正存在隐蔽 bug 的语言。结论很直白:聚合指标充其量只是一个粗略的分诊信号。真正的质量信号来自带有边分类的抽查——逐条查看真实代码仓库中的实际边并逐一判定。数据胜于直觉,但前提是你得先知道哪些数据在说真话。

外层循环:一支舰队,而不是一场马拉松

如果一次只处理一种语言,280 种语言要跑到天荒地老,所以内层循环被包裹进一个能并行运行多种语言的外层循环中。

   pick a wave of near-GREEN / high-error languages


   fan out 10–15 agents, each ISOLATED in its own git worktree,
   each grinding ONE language, committing to its own branch


   orchestrator integrates serially: file-scoped apply, then
   `manifest diff` — any cross-language regression blocks the batch


   gated push (reviewed and confirmed) ──► rotate to the next wave

每个智能体都在一个一次性的工作树中运行,彼此互不干扰。编排器逐个整合它们的修复,每一次都要通过完整清单的回归检查:一个改动即便让自己那门语言受益,只要悄悄破坏了另外三门语言,就不会被合入。集成过程受到把关并在推送前得到确认——回归关卡决定什么是安全的,而人来决定什么可以发布。之后,整个语言池会轮换到下一批语言,整个流程再来一遍。

仍不完美之处

裁判也会出错,而且出错是有方向性的:上下文太少的智能体往往会过度报告。在某一批次中,有八种语言被标记为 5%–20% 的错误率;仔细排查后,只有一种是真正的语言特定 bug——其余都是裁判因为没理解该语言自身语义而犯下的错误(同一行源码合理地产生多条边、参数绑定被误判为赋值、按标识符逐一生成引用的语言)。这也是为什么我们用两个种子分别抽样并交叉核对,以及为什么裁判与 fixture 之间的分歧被视为值得关注的信号,而不是定论——有时候错的其实是 fixture。

我们对目标也保持诚实。目标是零真实错误,毫无保留——但“零”是我们一门语言接一门语言不断磨出来的方向,而不是一个可以打钩的选项。永远还有下一个仓库、下一种惯用法在等着。

靠赢得,而非靠断言

Maguyva 为智能体所做的一切——查找一个符号、追踪一条依赖、用引用的代码回答一个问题——都建立在底层提取正确的基础上。跨越 280 种语言,“正确”无法靠断言获得,它必须在真实代码面前被持续地赢得。这个闭环就是我们赢得它的方式:一个自主的抽查—修复循环,它对自己的指标始终保持怀疑,为每一次改动提供证明,并把每一次修复都变成对下一次回归的防线。这并不光鲜。但正是这份工作,让我们能够说出“我们支持你的语言”这句话并且言出必行。绿灯很容易,正确要靠赢得。

相关阅读

更多来自 Maguyva 开发日志的内容