系统审计:六条抱怨,逐条实测

September 7, 2026 · View on GitHub

关于这个运行时提出了六个问题。这份文档拿代码去核对每一条,而不是凭印象。下面每个数字 都是在撰写时对代码树实测得到的,并给出了可以自行复算的命令。

English version: system-audit.md

代码树规模: argus_skill/ 下 194,487 行 Python,随发行分发 264 份技能文档、共 22,765 行。

#抱怨判定
1过度防御成立 —— 2,277 个 try:,其中 235 个吞掉错误继续跑
2验证门槛过于 rigorous成立 —— 39 个失败码,5 个门要求精确的 CSV 列
3太经常问人类不必要的问题部分成立 —— 频率并不高,但路由靠一张词表
4指令遵循能力弱成立 —— 任务之前已有约 2,000 token 常驻指令,其中三分之一是无条件追加的
5冗余、过复杂、空转成立 —— 24% 的事件类型是死的;同一件事有四套实现
6schema 乱用在最要紧的地方已经修好了,但没推广

1. 过度防御 —— 成立

try:                                2,277
except Exception                      634
吞掉错误继续跑                          235
名字含 gate/verify/check/
audit/guard/contract/validate 的模块     42

每三个 except Exception 里就有一个直接丢掉错误继续跑。 这个习惯在 docstring 里是写明 了的——"Fail-open: any error is swallowed"(argus_skill/skills/capability_trace.py)、 "Fail-open to ()"(argus_skill/skills/checklist_store.py),以及 argus_skill/skills/stage_machine.py 里"绝不能弄坏提示词构建"这类注释。

每一处单独看都合理,加起来就不合理:一个不会失败的运行时,也就是一个没法告诉你它坏了的运 行时。

grep -rc "^\s*try:" --include=*.py argus_skill/ | awk -F: '{s+=\$2} END{print s}'

2. 验证门槛过于 rigorous —— 成立

不同的失败码            39   (LIT、MPKG、NOV、NSL、NUM、PT、TH)
门模块                   9
要求精确 CSV 列的门        5

光是 Novelty-Seeking 一个门,就要求在能动笔写稿之前先交出十个候选方向、每个十一列推理、 六项数值打分(argus_skill/verticals/physics/gates/novelty_seeking.py)——170 个表格 单元,换取"可以做一个声明"的资格。

代价不在于这道检查本身,而在于工作会朝着"把表格填满"弯过去。

已修复: novelty 表格门现在只保留为不阻塞旧会话的兼容入口。Planner 和 Reviewer 直接判断路线是否真正不同、预期上限、信息增益和实验反馈;不再要求固定想法数量、CSV schema 或打分表。

3. 不必要的人类打扰 —— 部分成立

与升级相关的出现次数     269  分布在 51 个文件
实测打扰频率        每 40.7 小时 1 次
其中属于研究判断的        13%  (1,548 小时里 5 次)

频率是低的,所以问题不是 Argus 老在打断你。问题是这个决定怎么做出来的。 argus_skill/core/role_handoff.py:20 用一条在散文上跑的正则来决定归属权:

permission|authorization|authorize|approval|approve|consent|confirmation|credential|access|secret|budget|purchase|pay|publish|release|deploy|production|irreversible|delete|destructive|…

access、release、production、delete 都是再普通不过的工程词。一份写着"删掉临时目 录"或"读取配置"的回合摘要就会命中。这条正则是被当作否决项用的——它阻止一个请求被改判成 普通的 review 请求——所以任何含有这些词的东西,默认就留给人类了。

一张词表分不清"权限"和"词汇"。

4. 指令遵循能力弱 —— 成立,但不在我们最初说的那个地方

我们前后测错了两次,两次修正都重要。

第一次错。 我们把 argus_skill/roles/prompts/manager.py 里所有字符串字面量加总,报出 "Manager 常驻指令 7,438 token"。但那个模块里装的是 20 个针对不同场景的 prompt 构造 器,一次调用只触发一个。把它们加总,什么也没测到。

第二次错。 我们接着拿物理 vertical 那个 7,893 字符的 banner 当作典型。它不典型,而且 它不会串:role_banner 只从当前激活的 vertical 解析出来 (roles/prompts/registry.py:76),物理的 banner 永远不会进到一个 kernel 任务里。

按正确口径实测。一次 Manager 阶段决策,在任何检查表、证据、任务内容之前:

组成字符作用范围
build_stage_decision_prompt3,844每次阶段决策
manager_rendering_prompt(live-view 块)2,923每次阶段决策,无条件追加(manager/_stage_ops.py:779)
vertical 的 role_banner102 – 9,749仅当前 vertical;中位数 1,318

所以典型的一次阶段决策带着约 **8,100 字符(约 2,000 token)**常驻指令,最差的 vertical 约 16,500(约 4,100)。

banner 的开销是真的,但它是集中的,不是系统性的。 23 个 vertical 里中位数只有 1,318 字 符;重量几乎全压在四个上:

nanochat      9,749      chip_design   6,362
physics       7,893      math_synth    4,282
speedrun      7,786      …中位数         1,318

真正系统性的那一项是渲染块。 2,923 个描述 live-view 和呈现的字符,被追加到每一个 vertical 的每一次阶段决策上,无论这次决策跟渲染有没有关系——它比 vertical banner 的中 位数还大,几乎和它所伴随的那个决策提示词一样大。

一个在看到任务之前先被塞了约 2,000 token 常驻规则的模型不可能全部遵守,而这个失败看起来像 "不听话",其实是:规则比指令遵循的预算更多。 修法不是把语气写得更硬,而是把规则写得更 少——先从那个"相关不相关都要追加"的块开刀,然后是那四个离群的 banner。

python3 -c "
import ast,pathlib
for d in sorted(pathlib.Path('argus_skill/verticals').iterdir()):
    f=d/'stages.py'
    if not f.is_file(): continue
    t=ast.parse(f.read_text())
    for n in ast.walk(t):
        nm=getattr(n,'name','')
        if 'banner' in nm.lower():
            c=sum(len(x.value) for x in ast.walk(n)
                  if isinstance(x,ast.Constant) and isinstance(x.value,str))
            if c: print(f'{c:6} {d.name}')"

5. 冗余、过复杂、空转 —— 成立

死掉的仪表。 129 个 EventType 成员里,**31 个(24%)**在任何地方都没有被引用过——既没 有通过枚举符号,也没有通过它的字符串值。这 31 个里有 20 个是 SKILL_* 和 WIKI_*: 这个系统本该借以学习的那两个知识面,装的几乎全是没有任何东西会发射的事件。

另有 6 个是用裸字符串而不是枚举发射的(LIFE_MISSION_SKIPPED、 LIFE_MISSION_REQUEUED、LIFE_VERTICAL_RESOLVED、LIFE_INBOX_QUEUED、SKILL_OUTCOME、 OPERATOR_ALERT)。它们不是死的;它们是同一个事件有两种发射方式——这正是这份目录不再是 "运行时到底在做什么"的可靠索引的原因。

一个郑重其事地什么都不做的函数。 argus_skill/wiki/lifecycle.py:54 接收七个参数、丢掉 其中五个,而且它自己就是这么写的:

"""Do nothing: Agents maintain pages and INDEX.md during the mission."""

同一件事被实现了好几遍。

关注点实现
账本core/evidence_ledger.py、verticals/quant/search_ledger.py、verticals/research/literature_ledger.py
锁 / 租约core/daemon_lock.py、core/file_lock.py、core/workspace_lease.py、tools/gpu_lease.py
状态持久化core/pipeline_state.py、core/knob_store.py、daemon/state.py、life/memory.py、webapi/project_state.py

体积。 31 个文件超过 1,000 行,6 个超过 2,000 行。最大的是 daemon/self_maintenance.py,3,186 行;其次 life/memory.py,2,754 行。

空转面。 32 个 while True,15 处循环内 sleep。

6. schema 乱用 —— 在最要紧的地方已经修好了

这是六条里代码已经部分回答了的一条,而且它的论证值得原样引出来,因为这份审计其余部分 主张的正是这个立场。argus_skill/core/role_reply.py 直接从普通散文里读出角色的决定:

角色不被强制输出 JSON。一个被要求"只回一个 JSON 对象、别的什么都不要"的模型,会把它的回答 花在满足一个序列化器上而不是思考上,失去解释自己的能力,并且在多写一句上下文时让整个决定失 败。Harness 并不比 Agent 更聪明,而要求一种线格式,就是 harness 在决定 Agent 可以怎么说 话。

KEY=value 和 KEY: value 都行,上下方的散文不花任何代价,最后一次出现的为准;JSON 被接 受,但从不被要求。

它没有被推广到的地方。 5 个物理门仍然要求精确的 CSV 列集合;19 个模块在解析 frontmatter;274 个 @dataclass 和 21 个 BaseModel 描述着内部形状,其中一部分是要模型去 产出的。这个原则已经存在、也已经写下来了,只是没有贯穿到系统其余部分。


当前已落地的修复

角色现在先自然思考,末尾只写 Host 真正执行所需的少数字段;旧 JSON 仍能读取,但新 prompt 不再要求。无条件追加的 Manager 渲染 prompt 和 checkpoint 修复路径已经删除。Operator 路由 不再仅因为 production、release、delete 等普通工程词就把工作留给人类。170 格创新表已 退休,physics 各角色 banner 均低于 800 字符,research banner 从原约 2,800–9,800 字符降到 771–2,096。TEAM learning 只在最终结算成功且出现新候选批次时运行。

Manager 路由也不再要求或消费模型编写的 STAGES。新候选 domain 统一使用 runtime 持有的 execute → validate 生命周期;现有项目 domain 阶段、Planner 任务、checklist 和 runtime 阶段状态仍然具有权威性。

普通有限 direct 工程任务现在跳过 Planner 的单节点重包装,并只在 Vertical 或操作者要求时 调用 Reviewer。同题用户对照中,Argus 从超过 15 分钟、19 次模型调用降到 53.35 秒、2 次调用, 同一组测试仍全部通过。


这些数字合起来说明什么

六条里五条被代码证实,第六条在"既有修法没被应用到"的所有地方也都成立。它们不是六个问题, 而是同一个习惯的六种症状:出了事,我们就加一个机制。

每一次添加在局部都有正当理由。加总起来,是一个有 2,277 个 try:、任务前约 2,000 token 常驻指令、31 个死事件类型、四种加锁方式的运行时——以及一个忙着填表、为"delete"这个词请示权 限、并且不遵守那些它根本没有余量读完的指令的 Agent。

纠正的办法不是再加一个机制,而是删除。