跳到主要内容
照妖镜照到自己:no_human 那个在空类别上渲染 HALT 的脚本

照妖镜照到自己:no_human 那个在空类别上渲染 HALT 的脚本

毒角兽
毒角兽

· 阅读约 5 分钟

先说结论:我是带着踩「又一个 agent 框架」的心情去的,结果被一篇 PR 复盘按住了。

no_human 这项目,通稿和实测之间的落差是负的。实测比宣传好看。🙃

一句话说它是干什么的:本地跑,MIT,用你自己的 Claude 凭据,编排器把工单推到「已评审的 pull request」为止,从不自动合并。「已评审」到「合并」那一下,必须人来按。

这年头打着 agentic 旗号的东西,卖点清一色是「你不用管了」。它反过来,把「你必须按那个按钮」写进设计里。

这个边界,先记一功。

但我真正想聊的不是这个。

是 PR #229。

issue #114 第三阶段,原计划给编码者加个符号服务器,跳定义、找引用、悬停看类型。作者没直接建,先写了个脚本,量一量导航到底划不划算。

阈值事前登记在 15%。数字还没出来就定好,防的就是后面照着结果调参。

第一次跑:27.6%,判定 PROCEED。看着这功能值得做。

然后他注意到了 .md——整份语料里按读取量最大的扩展名。而没有任何符号调用能回答一个关于 README 的问题!

把语言限定到符号服务器真正支持的白名单,同一份语料,读数掉到 10.4% 和 13.7%。

判定反转。

这还只是第一层。更深的一层在这儿:脚本把最强的信号类别定义成 SYMBOL_QUERY_TOOLS = {Grep, Search}。

可 no_human 的编码者从来不发出这两个调用。它走 Bash。

车队数据库的真实计数:

Bash                              115,776
Read                               35,557
Edit                               18,425
Write                               3,010
Grep                                    0
Glob                                    0
Search                                  0
含 grep/rg/ag/ack 的 Bash 调用      50,459

脚本以为自己最强的那个信号类别,结构上是空的。

它就在这个空类别上,自信地渲染出了一个 HALT。

上个月我差点信了一个结构类似的数字。不展开了,这毛病我有。

修复是按二进制从 shell 命令里把搜索抽出来,每个二进制配各自的选项表。-r 在 grep 里不取值,在 ripgrep 里是 --replace,一张表糊弄不过去。

零值一律按失败关闭:一个有读取却没有搜索的语料,NoSearchChannel 直接拒绝。缺失的通道是仪器的缺口,不能当成关于代理的证据。

修完之后 symbol_lookup 从 0 升到读取量的 15.6%,HALT 反转为 PROCEED。原本结构上为空的那一类,成了最大的单一贡献者。

而且修完之后输出还挂着警告:结果变不稳健了。6000 字符处重判得 PROCEED,24000 字符处得 HALT。

这个警告我认!

一个把自身不稳健写在脸上的脚本,比一个递给你一个漂亮数字的脚本可信得多。

文章里那条原则是「如果验证机制位于代理的写入面之内,它就不是验证机制」。我补半句:如果验证机制自己的仪器没人验过,那它也不是验证机制。就这么简单。

顺手再过两个具体的。

PR #164 有个设计决定我很喜欢:沉默表示「没有运行」,不表示「干净」。检查器没装、崩了、输出解析不出来,全是 ran=False,渲染成空;只有真正跑完并且确实没问题,才渲染 net-new 为 0。

这两件事在别的工具里通常被压成同一个绿色的 0。那个绿色骗过我,不止一次 😑

另一个是 PR #221 的措辞事故。原提示词写的是「你对 X 的编辑引入了 N 个诊断」。维护者两下就把这句打翻。

第一下,mypy <file> 会跟随 import。让 app.py 前后 md5 完全相同、lib.py 新增一个错误,钩子照样告诉你 app.py 这次的编辑引入了它。

第二下,Bash 不在 _EDIT_TOOLS 里。sed -i、patch、ruff --fix、black 全部不可见,它们弄坏的东西,会在下一次 Edit 的时候被算到那次编辑头上。

最后改成「N 个位于 X 之上或从 X 可达的诊断,它们在该文件上次被检查时未被报告」。两种可能的误导方式,直接写在编码者能看到的那段文本里。干净。

把丑话说在前面:这次我确实没什么营销话术可踩。

唯一有落差的地方还写在它自己的 changelog 里。0.2.1 到 0.2.3,打包的桌面应用能打开 PR,但落不了地。合并门禁把冻结的二进制当成 Python 解释器调用,于是每一次 nh approve、连带面板上那个 Approve,都在测试步骤上失败。

能开 PR 却不能落 PR 的流水线,不叫 90% 可用。

它对唯一需要人的那一步失效了。而那一步,恰恰是它整个设计的立足点。

还有两条局限得说清楚,不然容易当信仰用。

评审者本身就是一个模型。项目给了自己的确认运行数字:19 个预埋缺陷召回 15 个,10 个对照的特异度是 7。有用的门禁,不是证明,误报属于常规,你得预留分流的成本。

另外「不同模型」是默认值,不是不变量。你把评审者和实现者配成同一个模型,整个设计依赖的那个属性就安静地没了。

这个坑特别安静!安静到不会有人报错。

锐评评分卡:这钱花得冤不冤?本地跑、MIT、不托管、用你自己的 Claude 凭据——严格说没有「这钱」两个字,你要算的是自己那份配额账。

值不值得现在跟:手上的活是范围清楚的 bug 修复、测试缺口、跨仓库的重复性维护,值得。工单是「把架构重构一下」这种,项目文档自己就写了不适合,它会给你一个结构化的升级加一个具体问题。

那不是它不行,是它不肯演。

最后一件事。作者自己说,自建代理工具的人应该把复现门偷走,那东西只是个二十行的概念。我同意。

但抄之前先回答一个问题:你的编码者是用 Grep 检索的,还是用 Bash 检索的。

这个想不清楚,那二十行白抄。

毒角兽
毒角兽

拿到新工具先上手拆一遍,官方通稿信一半留一半,实测说话。

查看主页 →