Skip to content
Touchskyer's Thinking Wall
S1E03
7 min read

硅基团队 S1E03: 从「能跑」到「能信」

硅基团队 S1E03

安全审计 47/100。

这是 Hermes——一个代码 review advisor——对 OPC main branch 的评分。5 个 Critical,8 个 High。一个号称要检查其他项目代码质量的框架,自己的安全评分是 47 分。

这就好比一个卖防盗门的公司,自己的办公室门锁是坏的。

四处止血

最扎眼的四个问题,每个都是那种「知道了就睡不着觉」的级别。

命令注入。 Flow template 的名字会被直接拼进 shell 命令执行。如果有人把 template 名字写成 ; rm -rf /,系统会老老实实地执行。这不是理论上的风险——OPC 设计上就是让 AI agent 自己选择 flow template 的。AI 不需要恶意——它生成的内容可能包含 shell 元字符(分号、管道符、反引号),这些字符会被 shell 解释为命令分隔符或子命令,从而触发完全意想不到的操作。

修法核心思路:所有外来输入在进入 shell 前先过一道白名单——只允许字母、数字、下划线和短横线,其余一概拒绝。(技术实现:validateRelativePath() 检查路径合法性,禁止 .. 和绝对路径;template 名字必须匹配 /^[a-zA-Z0-9_-]+$/。)

路径穿越。 --flow-file 参数可以指向文件系统的任意位置。设计初衷是让用户加载自定义 flow 配置,但没有做边界检查。结果就是 AI agent 可以读到 OPC 工作目录之外的任何文件——配置文件、环境变量、SSH key。

修法:解析后检查 resolvedPath.startsWith(cwd),确保路径不出工作目录。内置 template 名字被保护,外部 flow 文件不能覆盖它们。

空文件作弊。 OPC 的 review 环节要求至少两个独立的 evaluation 报告。但验证逻辑只检查「有没有这个文件」,不检查文件里有没有内容。两个空文件就能过审。

这是上一集提到的「aspirational theater」的又一个例子——系统声称在做审查,实际上只是在检查文件是否存在。

修法不只是查「文件非空」。现在验证五件事:必须包含 severity marker(🔴🟡🔵 或 LGTM);行数 ≥ 50(太薄的 review 大概率是走过场);必须有 file:line 引用(review 必须锚定在具体代码上);两份 review 不能一模一样——复制粘贴直接报错,超过七成内容重复会被警告(技术上:byte-identical 报错,>70% 行重叠报 warning);两份 review 必须来自不同角色。

无限弹跳。 Gate 判定 ITERATE 会把流程推回到建造者。但如果建造者改了还是不达标呢?再次 ITERATE。再改。再不达标。无限循环。

修法:maxLoopsPerEdge = 3,同一条边走超过 3 次就强制停止。maxNodeReentry = 5,同一个节点进入超过 5 次就强制停止。像煤矿的安全绳——正常工作时你感觉不到它的存在,但它防止你掉下去。

止完血之后,安全评分从 47 涨到大概 75。Test suite 从 12 个涨到 16 个。但 75 分不够。

验收标准不是 Checklist,是合同

75 分到 90 分的关键,不是修更多 bug,而是想清楚一件事:验收标准到底是什么?

有人说验收标准就是列几个 bullet point。做完打勾就行。

不对。验收标准是合同。

想象甲方乙方的关系。甲方付钱,乙方干活。甲方的核心诉求不是「你干得好」,而是「我能证明你没干好的时候有依据」。验收标准就是那份合同——越具体、越可测、越不留解释空间,越有安全感。

一个坏的验收标准长这样:「系统应该很快。」

一个好的验收标准长这样:「P95 latency < 200ms。验证方式:用 wrk 跑 1000 个并发请求 30 秒,latency 分布的 P95 值 < 200ms。」

差别在哪?坏的标准你永远可以说「还行」——因为「很快」没有定义。好的标准你只能说「是」或「不是」——200ms 就是 200ms,没有中间地带。

OPC 的蓝图——14 个检查节点构成的质量堡垒

OPC 用了一个叫 criteria-lint 的工具来强制执行这件事。14 条 lint 规则,分三层:

结构层检查你的格式对不对:有没有 Outcomes 段?有没有 Verification 段?每个 outcome 有没有对应的验证方式?数量在 3-7 个之间?

内容层检查你的内容实不实:用了「fast」「clean」「intuitive」这种模糊词?如果后面没跟量化指标(「under 200ms」「WCAG AA」),直接报 fail。写了「should work as expected」?这句话永远为真,等于没说。验证方式是「manual inspection」「looks correct」?人眼检查不叫验证。两条标准 80% 的词一样?要么是复制粘贴的冗余,要么是没想清楚。

警告层提醒你可能遗漏了什么:scope 段是空的?没有写 failure mode(只写了成功的场景,没写失败了怎么办)?outcome 超过 5 个(太多意味着焦点模糊)?

这些规则不靠 AI 判断。它们是正则表达式和 Jaccard 相似度——跑完直接告诉你哪行不合格。

第十人

在设计 OPC 的评审环节时,有一个关键决策来自以色列情报机构的「第十人」制度。

规则是这样的:如果 9 个分析师都同意某个结论,第 10 个人的职责就是反对它。不是因为结论一定错了——而是因为共识本身就是最大的风险信号。

在 OPC 里,当 discussion 环节进入第二轮所有 agent 都趋同时,orchestrator 会自动引入 devil-advocate 角色。这个角色的职责就是找碴——不是因为找碴好玩,而是因为如果所有人都同意,要么是真的对了,要么是所有人犯了同一个错误。

对于不可逆决策——数据删除、public API contract、destructive migration——devil’s advocate 是强制的。不管有多少人同意,都必须有一个人尝试推翻它。

这个设计反映了 OPC 的一个核心信念:好的流程不是让所有人同意,而是让不同意的声音有地方存在。

不让 AI 变好,让坏后果变小

三周硬化做下来,test suite 从 12 个涨到 21 个,assertion 从 150 涨到 450,enforcement rule 从 20 条涨到 60 条,安全评分从 47 涨到大概 90。

但这些数字不是重点。重点是我在这个过程中理解了一件事:

传统软件的 invariant 是确定性的——输入 A 必须产出 B。Agent 框架的 invariant 是概率性的——你不能保证 AI 写出好代码,但你可以保证烂代码不会通过 gate。

所以 OPC 的哲学不是「让 AI 变好」。AI 的能力边界不是我能控制的——它取决于模型的训练、prompt 的质量、context 的大小。这些都是概率性的,我无法给出保证。

我能给出保证的是另一面:让坏后果变小。

60 条 enforcement rule 不是为了制造好的 output,而是为了拦截坏的 output。这个区别决定了整个系统的设计方向。OPC 不是一个让 AI 写更好代码的工具,而是一个让 AI 写的烂代码无法通过验收的工具。

就像大坝。大坝不会让雨下得更好。它让洪水过不去。

在后来的一次测试中,这个哲学得到了验证。一个 55 小时的 session,52 个 subagent 协作,产出了 639 个新测试。其中有一个 pre-commit hook 叫 check_test_imports.py,规则简单到粗暴:每个测试文件必须 import 真实的产品代码。如果你的测试自己定义一个函数然后测试它自己——这种 AI 生成测试最常见的陷阱——hook 直接 block。

639 个测试,每一个都 import 了真实模块。$150 的 token 成本,平均每个测试 $0.23。如果一个 senior engineer 花三天写同样数量和质量的测试,按 $800/天算是 $2,400。

但价格不是重点。重点是:这些测试是可信的。 不是因为 AI 写得多好,而是因为不可信的测试已经被机械地拦截了。

从 47 到 90,不是让 AI 变好了。是让不好的东西过不去了。


硅基团队 S1: AI 能写代码,凭什么信它? ← S1E02: 一个人的工程团队长什么样 | S1E04: 让框架长出骨骼 →

留言