作者设计了一套检验机制让AI不谎报完成状态——在AI循环外构建可审计内核,每次提交都强制验证而非依赖模型自述,对AI编程质量控制有直接指导意义。
你的 agent 报告「完成了 —— 所有测试都过了」。你信吗?
这句话里没有任何证据,而付出代价去验证这件事的人,是日后的你。我和 AI 编程助手打交道多年,真正让我不断浪费时间的问题从来不是模型写了烂代码。而是模型告诉我它做完了,我信了它。这篇文章要讲的是我为此构建的机制——写得足够详细,你可以自己判断它是否经得起你自己的 agent。
Ranex 是一个内核 —— 普通的、可审查的代码 —— 位于 AI 循环之外,对它工作中的每一步进行评判。它从不问模型下一步该做什么。agent 能读取的规则只是建议;编译进代码的规则才是约束。
问题不在于 AI 写了烂代码
AI 写软件就像一个蒙着眼扔飞镖的人,旁边有个引导员在喊坐标。两件事会出错,而且它们是两个独立的问题:
扔的人是瞎的。它无法感知自己的飞镖是否命中,所以无论结果如何它都会报告成功。
引导员不行。坐标在扔之前就是错的或模糊的。
还有第三种失败,而且是最常见的一种:
大多数工具让扔的人在飞镖落地后自己画靶心。
同一个角色写代码、写测试、然后宣布成功。这就是为什么 AI 说「所有测试都过了」毫无意义 —— 靶子移到了飞镖落点。
注意,以上问题没有一个能通过更好的模型解决。更强的 agent 能画出更可信的靶心 —— 所以给仓库换一个更强的模型并不解决任何问题。这就是为什么我不再试图提升扔的准度,而是开始研究如何计分。
三个端口,只有一个产生裁定
架构刻意做得很无聊:
Model 端口 —— 一次补全,强制结构化输出。摄取、审查、将机器状态翻译成自然语言。无状态。
Worker 端口 —— 一个拥有独立循环和工具的 agent,运行在隔离的 git worktree 中。返回一个 diff。按设计可替换。
Check 端口 —— 唯一产生可计数输出的端口。
三个端口围绕一个内核。只有 check 端口产生裁定。
模型只出现在三个角色中 —— 提议者、批评者、翻译者 —— 但没有一个能通过门控。提议者产生提案。批评者产生发现。翻译者产生文本。没有人做决定。
把它想象成 make 之于不确定的编译器。make 调用 gcc;没人会问 gcc 下一步该构建什么。
裁定究竟是什么
裁定是 (gate, evidence, subject, approver) 的纯函数。同输入,同裁定,永远如此。这不是设计目标,而是让一切其他事情成为可能的前提 —— 我在另一篇文章中更详细地写过为什么裁定必须是纯函数。
每次评估都满足四个性质:
缺失即阻断。必需的声明若没有满足条件的证据即为 FAIL —— 从不是默认值,从不是跳过。
证据绑定于 subject 摘要。同一条命令在不同 commit 上运行,无法证明当前这一个。
无自我审批。产生证据的人不能审批它。
无法成为阻断条件的门控在构造阶段就被拒绝。无阻断能力的门控只是装饰,所以内核不会构建这样的门控。
还有一个不变量让我对这一切保持诚实:从机器上移除所有模型凭证,必须不会改变任何一个裁定。如果会改变,那说明裁定路径中有什么地方在问模型的看法,这就是 bug。这个不变量是可移植的 —— 把你现在用来给 agent 打分的工具的模型凭证撤掉,看看它的答案是否会动。
take the next ready task
→ create an isolated git worktree
→ spawn a worker with the task envelope
→ wait for it to exit
→ read the DIFF ON DISK (the worker's own summary is discarded)
→ run the checks (code, not a model)
├─ pass → THE KERNEL merges (workers never merge)
└─ fail → retry ×3 with the failure output
→ still failing → escalate to a human in plain language
Ranex 从不信任 worker —— 包括它自己循环中的。它不需要控制循环内发生什么,只需要控制允许什么从里面出来。containment 是比 control 更小的问题:出口是可枚举的,内部不是。
什么阻止了 agent 修改自己的测试
能修改自己测试的 agent 永远会通过。如果在你的设置里同一个角色既写代码又写测试,你已经知道结局会是什么。四条规则防止这种情况:
测试在构建开始前就被冻结。生成、摘要、只读。任何触及测试文件的 diff 会立即导致门控失败。
先红后绿,强制执行。每个生成的测试必须在实现前的代码树上失败。在代码存在之前就通过的测试不是靶子 —— 它是在飞镖落点画的圆。
边覆盖是门控,不是指标。不是「80% 的行覆盖」,而是「批准图中的每条边至少有一个通过的测试」。
无自我审批。实现某个场景的任务不能创作或评判它的测试。
这个项目自身也应用了这些规则。SLICE-001 测试在 b495e3635 提交时是红色的,在任何实现存在之前 —— 先红后绿是 git 历史中的事实,而不是文档里的声明。
一次通过的构建实际证明了什么
每个在主人批准图上的行为都至少有一个可执行的测试。每个测试都运行了。每个测试都通过了。这里是证据,钉在这个精确的代码摘要上。
而这些不是 Ranex 声称的东西:
计划是对的。只有拥有目标的人才能评判这一点,而且只有通过使用这个东西。
计划之外任何事。未指定的行为不受约束。需求的缺失即保证的缺失。
非功能性属性 —— 性能、可访问性、安全性 —— 除非你为它们添加了门控。
我在「门控裁定断言了什么 —— 以及它拒绝什么」中更详细地阐述了这个边界。「符合批准规范」是真实的、可辩护的、可交付的。「正确」不是任何人都能声称的东西。
Ranex 不能提升准度
一丝一毫都不能。它让失误可见且廉价,让命中可证明。我在任何地方都没有声称更多 —— 文档里没有,程序输出里没有,这篇文章里也没有。
现状
Ranex 处于预发布状态。它还不是一个可用的产品。它是一个内核,有一条工作的裁定路径,除此之外几乎什么都没有,README 在说其他任何内容之前先说了这一点。
目前可用的:evaluate()、subject 绑定的证据、缺失阻断、无自我审批、只增不减的哈希链式日志、Ed25519 签名的证据、ranex run 和 worker 调度。内核已经在这个仓库自己的测试套件上建立了门控 —— 738 个冻结的测试 ID,针对当前真实 commit 在 provisioned、sealed 和离线状态下运行。
还不行的:flow graphs、scenario 编译、budget、escalation。设计了,还没建。
粗略地说:概念上最难的部分已经存在,而它周围几乎所有表面都还没有。内核采用 MIT 许可证 —— 读决定通过或失败的那些代码,试着去打破它。
人们真正会问的问题
Ranex 实际上做了什么?
它通过证据和可执行检查来评判 AI 生成的工作,而不是根据模型自己的报告。一段普通代码的内核位于 AI 循环之外,读取磁盘上的 diff,运行检查,产生裁定。agent 的摘要被丢弃。
Ranex 能让我的 AI 写出更好的代码吗?
不能。一丝一毫都不能。它让失误可见且廉价,让命中可证明。Ranex 优化的是计分,不是扔。
我现在能用 Ranex 吗?
还不行。Ranex 是预发布状态,README 在说其他任何内容之前先说了这一点。裁定路径是可用的,并且已经为 Ranex 自己的 738 测试套件建立了门控,但 flow graphs 和 scenario 编译是设计了还没建。
它需要模型或云服务才能运行吗?
不需要。一个声明的不变量是:从机器上移除所有模型凭证,必须不会改变任何一个裁定。检查在本地针对你的代码运行。
你可以向现在给 agent 打分的任何工具提三个问题,不管它是不是 Ranex。撤掉模型凭证 —— 裁定会变吗?移除一条必需的证据 —— 它会失败,还是无所谓?问谁签了字 —— 是和写代码的同一个角色吗?这些答案告诉你手上的绿灯值多少钱。
试试它。打破它。告诉我哪里坏了。内核采用 MIT 许可证 —— 如果你发现决定通过或失败的代码里有漏洞,那是贡献。
披露:这篇文章在 AI 辅助下起草。每个事实声明都可追溯到仓库的 README 或 slice 记录 —— 和产品对代码执行的事实门控是同一个东西。它只在 Anthony 本人审查后发布。