Zagens agent 的组合式 Harness 工程实践

Agent 长程任务的完成度信任问题,以及 Zagens 如何用组合式 Harness 解决它

  1. 模型自建的 checklist 有欠分解上限——open_items: 0 不等于真完成。
  2. Zagens 用三层可组合门禁:L1 防早停L2 退出码 OracleL3 交付物对账,均在 graph_complete 候选时由 Harness 主动裁决。
  3. 裁决信号必须是机器可回放的(退出码、路径命中、事件日志),禁止 LLM 当法官
  4. 对抗审计只做缺口枚举,最终绿灯仍由机器门决定;超大任务叠加 Cycle / Macro Loop。

术语速查

术语含义
LHTLong-Horizon Task,长程代码任务模式;Layer 1 的强制继续机制
CRAFT多代理 QA 段(Implementer + Reviewer + Verifier),与 LHT 实现段交替
Machine Oracle机器裁决:退出码、路径/glob 命中等可回放信号
graph_complete模型自产 plan + checklist 均无可办项时的完成候选状态
audit_unmet有界轮次耗尽后门仍未全绿时的诚实停机,不产生假绿灯
MicroStack02Go 微服务框架压测用例:24 类交付物 + 四门验收,暴露欠分解假绿
DEMO3–6Monkey 解释器等长程实证压测序列,逐轮修补早停泄漏与假绿路径

1. 引言:Agent 的「声称完成」陷阱

2025–2026 年,LLM Agent 的编码能力已经很强——能写数千行代码、做多文件重构、跑测试。但实践中暴露出一类深层问题:模型经常过早「声称完成」,而大量交付物实际上并未落地。

这不是模型在说谎。根因在于:

  • 模型自建的 checklist 存在欠分解(under-decomposition)——某些必要交付物从未进入它自己的任务图;
  • 模型检查自己的 checklist 全部打勾 → 任务图显示 open_items: 0 → 模型合法地宣布完成;
  • 但检视才发现:gzip 中间件没写,router trie 重构没做,e2e 脚本没跑过。

用 Zagens 团队的内部术语说:完成度的天花板 = 模型自分解 checklist 的完整性。模型自己画的作战地图画漏了,按图索骥也找不到漏掉的目标。

模型自建 checklist
(欠分解)

必要交付物
从未进入任务图

open_items: 0

模型合法宣布完成

检视发现遗漏
gzip / trie 重构 / e2e

Zagens 作为面向 DeepSeek V4 的开源 Agent Harness,核心工程命题是:如何构建一套不依赖模型自我声明的、可审计的、可回放的完成度信任机制。

本文从工程架构角度,拆解 Zagens Harness 系统的设计与实现。


2. 核心理念:Harness,不是聊天壳

Zagens 的判断很明确:不能信任模型自己说「做完了」。需要一套独立于模型的完成度判定系统。

这套系统的三条设计原则(源自 Zagens Harness 设计文档,经 DeepSeek Agent + Harness 负责人 Deli Chen 的持续学习研究印证):

  1. 信号质量 = 机器裁决(Machine Oracle)—— 最终判断依据是退出码(exit code)、路径命中(path/glob hit)等可精确回放的信号,不是 LLM 的散文判断;
  2. 信号独立性 —— 需要两层独立:规则独立(不靠模型推理,靠正则/文件扫描)和 Agent 独立(不是同一个 Agent 的自我确认);
  3. 独立性不能退化为「换一个 LLM 盖章」 —— 用 LLM 审计 LLM 的输出,只会把「建设者自我确认」变成「审计者-建设者共谋确认」,独立性名存实亡。

这些原则落实到工程上,就是 Zagens 的组合式 Harness(Composable Harness)—— 三层可插拔门禁系统。

Harness 设计原则

信号质量 = 机器裁决
退出码 · 路径命中 · 可回放

信号独立性
规则独立 + Agent 独立

禁止 LLM 盖章
审计者不能当法官

组合式 Harness
三层可插拔门禁


3. 引擎基础:Kernel V3 —— 事件溯源的 Turn 引擎

Harness 门禁要可审计、可回放,离不开底层引擎的事件持久化。Zagens v0.8.2 的 Kernel V3 是事件溯源 turn 循环——下文只保留与 Harness 相关的要点;完整 turn 机状态机见源码 LiveTurnMachine / ReplayTurnMachine

事件溯源持久化

KernelEvent

LiveTurnMachine

outer 循环
step-frame → pre-inner → inner
→ post-inner → boundary grants

inner 循环
inner_step_live_plan
→ EffectInterpreter

InnerStepHost IO
streaming · tool execution · LSP notify

handle_deepseek_turn

Turn end
runtime-server host_impl

finish_kernel_turn

kernel_turn_replay_verify
+ projection compare

kernel_events
SQLite

每次 turn 的完整生命周期被记录为 KernelEvent,存储在 SQLite 的 kernel_events 表:

CREATE TABLE kernel_events (
    id      INTEGER PRIMARY KEY AUTOINCREMENT,
    seq     INTEGER NOT NULL,
    ts_ms   INTEGER NOT NULL,
    kind    TEXT NOT NULL,
    turn_id TEXT,
    payload TEXT NOT NULL  -- JSON KernelEvent
);

事件溯源对 Harness 的价值:

  • 可回放(Replayable):ReplayTurnMachine 能从事件日志重建状态,Harness 的金色夹具(golden fixtures)可在 CI 中精确验证门禁行为;
  • 可审计:所有 turn 生命周期事件(模型请求、工具调用结果、门禁判定)都有结构化持久化记录;
  • 可恢复log-first 会话恢复优先从事件日志重建消息,不依赖 session JSON。

基于这个引擎,Zagens 的 Harness 各层门禁得以可靠地挂载在 turn 循环的各个退出点上。


4. 三层组合式 Harness 架构

Zagens 的完成度门禁系统是三层可组合的:

graph_complete 候选时(原子执行)

运行中(全程)

checklist 全绿

Layer 1: 模型自驱
plan + checklist + nudge 继续

Stub 门 · 文件扫描

Layer 2: 硬验收门 · 退出码 Oracle

Layer 3: 交付物对账 · path/glob

✅ 真实完成

组合方式(可独立开关):

  • Layer 1 仅 = 原始效果(模型自驱 + 防早停);
  • Layer 1+2 = 纯粹的退出码门禁(最确定、最便宜);
  • Layer 1+2+3 = 完整组合,能捕获欠分解场景。

4.1 门禁在何时触发

§4 的流程图容易误读为「L1 跑完再跑 L2」。实际时序如下:

Layer 3 Layer 2 Stub 门 graph_complete 候选 Layer 1 (LHT) 模型 Layer 3 Layer 2 Stub 门 graph_complete 候选 Layer 1 (LHT) 模型 alt [graph.incomplete] loop [整个任务周期] alt [缺交付物] [全绿] alt [退出码 ≠ 0] [全绿] alt [发现 todo!/unimplemented!] [通过] 无工具调用 / step 耗尽 / loop_guard 等 注入 nudge,继续 plan + checklist 均无可办项 纯文件扫描(先于 L2/L3) 阻断,强制返工 Harness 主动执行 verify 强制返工 路径/glob 对账 missing_deliverables + 返工 ✅ 真实完成

要点: Layer 1 贯穿全程;Layer 2/3(及 Stub 门)仅在 graph_complete 候选时原子执行,同轮内 L2 全绿后才进入 L3。

4.2 案例:MicroStack02 欠分解假绿

MicroStack 框架压测(代号 MICROSTACK)规定 24 类交付物、四门验收 + [verify:] 纪律。一次典型失败跑(MicroStack02):

观测模型侧实际产物
UI / 节点checklist 100%、incomplete_stop=0gate_skip graph_complete ×3
规模声称完成仅 ~7045 行(目标 15–40K)
覆盖率checklist 项已勾app 16.3%、orm 4.7%
欠分解任务图全绿gzip 中间件、cmd/microstack/main.go、Router trie 重构从未进 checklist

各层分别拦住了什么?

层级仅 Layer 1 时加上 Layer 2+3 后
Layer 1✅ 无早停;但 checklist 全绿 → 放行候选同左
Layer 2✅ 覆盖率门、gofmt 真门可拦「测试红/未格式化」
Layer 3middleware/gzip.go**/*trie*.go 等 manifest 项抓到「从未分解进清单」的交付物

根因代码定位:maybe_continue_incomplete_code_task 只看模型自产 plan + checklist——完成度上界 = 模型自拆清单完整度。Layer 3 把「模型欠分解」平移为「操作者预写 manifest」,但 manifest 可离线审查、可回归,远比每次现场分解稳定。

下面逐层深入。


5. Layer 1:强制继续(LHT)—— 不让模型用散文结束

Layer 1 解决的核心问题:模型在多步骤任务中途以文字总结结束,不再调用任何工具。

5.1 问题根因

源码定位在 crates/runtime-server/src/long_horizon/mod.rsmaybe_continue_incomplete_code_task

graph = CodeTaskGraph::from_snapshots(plan, checklist)
if graph.is_empty()         -> Skip("graph_empty")
if !graph.incomplete()      -> Skip("graph_complete")

完成判定完全依赖模型自产的 plan + checklist 快照。如果模型在初始分解时就遗漏了关键交付物,「open_items == 0」就是一个虚假的完成信号。

5.2 强制继续机制

maybe_continue_incomplete_code_task 被挂载在 no_tool_uses.rs 的分支链中(audit 之后、Break 之前):

模型无工具调用
no_tool_uses 路径

1. scratchpad_summary
+ pending steers?

Continue

2. pending steers?

Continue

3. sub-agent
completions?

Continue

4. REPL blocks?

Continue / Break

5. incomplete
audit continue?

Continue
(audit 独占)

6. ★ LHT
graph.incomplete?

Continue
(注入 nudge)

Break

当模型在工具调用后只输出文字总结,引擎走 no_tool_uses 路径 → 第 6 分支触发 → 注入一条强制继续的 nudge 消息:

长程代码任务尚未完成 — 请勿仅用文字总结结束本轮。

目标:将 auth 模块重构为基于 trait 的后端
进度:████░░░░░░ 42%(plan 1/3 阶段;checklist 2/5 项未完成)

仍待完成:
- [plan ◎] 引入 AuthBackend trait
- [todo ○] 更新集成测试

请继续用工具完成当前 in_progress 项,验证(如 cargo check/test),再 checklist_update / update_plan。

5.3 NudgeTracker:防死循环

为防止模型在同一个 item 上无限循环,Zagens 实现了 NudgeTracker

in_progress_id 被 nudge

有实质进展 → 重置计数

同一 item nudge 3 次无进展

同一 item nudge 5 次(硬上限)

连续 8 turn 无工具调用

long_horizon_blocked

用户消息恢复

请用户引导

Nudging

Blocked

WaitUser

AskUser

上图为状态机概览;阈值如下:

规则行为
同一 in_progress_id 被 nudge 3 次而无实质进展long_horizon_blocked
同一 item 被 nudge 5 次(硬上限)停止 nudge,等待用户消息恢复
in_progress_id 变化重置计数
连续 8 个助手 turn 无工具调用nudge 变为「请用户引导」,不再机械继续

5.4 进展判定

「有进展吗?」需要客观信号,而非正则的玄学判断:

信号判断方式性质
edit_file / write_file / apply_patch 成功工具返回 success客观
exec_shell + 退出码 0 + 匹配验证正则success + 匹配启发式
checklist_update / update_plan 成功状态机迁移客观
git working-tree 变化git status --porcelain 签名变化客观,语言无关

其中 git working-tree 信号(Phase 2.x 引入)解决了非主流语言项目中验证正则列表不全的问题——只要工作区文件发生了实际变化,就算进展。

5.5 演进中的关键修补

LHT 并非一次性设计完成。经过 DEMO3–DEMO6 四次实证压力测试,团队修复了多个隐蔽的早停泄漏路径:

泄漏路径症状修复
Step budget 耗尽模型在 100 step 后 break,无任何 nudgemaybe_continue_at_step_limit 给予新的预算窗口(最多 3 次续命)
loop_guard 截停同一工具连续失败 8 次,直接 Breakmaybe_continue_after_loop_guard_halt 清除失败计数 + 建议切换方案
上下文溢出上下文超出模型窗口,强制 Failedmaybe_cycle_handoff_on_context_overflow 强制一次 cycle 交接
欠分解导致的虚假完成checklist 全绿但关键交付物未写交给 Layer 2+3 解决(见 §4.2

每个泄漏路径都对应一个 run.rs 中的 break 出口。团队做了系统性审计:每个 turn 退出点都必须经过 LHT 门禁,否则就是一个新的早停泄漏。

早停泄漏路径(DEMO3–6 修补)

Step budget 耗尽

maybe_continue_at_step_limit
最多 3 次续命

loop_guard 截停

maybe_continue_after_loop_guard_halt
清除失败计数

上下文溢出

maybe_cycle_handoff_on_context_overflow
强制 cycle 交接

欠分解虚假完成

Layer 2+3 机器门禁

每个 break 出口
必须经过 LHT 门禁


6. Layer 2:硬验收门 —— Harness 主动执行,退出码当法官

Layer 1 只能保证「模型没提前停」,但不能保证「做对了」。Layer 2 扭转了判决权力:不再相信模型说「我跑过了,通过了」,Harness 重新跑一遍,看退出码。

6.1 设计铁律

不能用 LLM 当法官。 用 LLM 审计者「读一遍然后说 LGTM」是一个软的、非确定性的、可说服的、不能离线回放的裁决。

正确的分工(下图);硬验收门与交付物覆盖均由机器 Oracle 裁决,不由 LLM 散文判断:

✅ 机器 Oracle

❌ 禁止

软 · 不可回放

LLM 审计者
读一遍说 LGTM

退出码法官
Harness 主动执行 manifest

路径对账法官
预声明交付物扫描

不放行

通过 / 不通过

6.2 验收 Manifest

操作者在 ~/.zagens/config.toml 中声明验收门列表:

[long_horizon.completion_gate]
mode = "enforce"
max_manifest_rounds = 5

[[long_horizon.completion_gate.verify]]
id = "build"
cmd = "go build ./..."

[[long_horizon.completion_gate.verify]]
id = "contracts_stable"
cmd = "git diff --exit-code contracts/"

[[long_horizon.completion_gate.verify]]
id = "coverage_app"
shell = "none"
argv = ["zagens", "coverage-gate", "--pkg", "app", "--min", "75"]

关键约束:

  • shell = "none" + argv:跨平台(Windows 无 bash),避免引用语义漂移;
  • 退出码不是 0 就判不通过,强制模型返工;
  • 区分断言失败与基础设施错误exit_classassertion(测试红)和 infra(命令找不到、超时),连续 N 次 infra 则诚实宣布 audit_unmet
  • 只信任用户全局配置/内置测试夹具中的可执行命令,工作区配置/模型生成文件只能走 observe 模式(记录但不阻塞)。

6.3 任务无关的通用验收门

Layer 2 有三类 verify 来源;其中 操作者 manifest(§6.2)适合回归夹具与强约束任务,另有两类零 per-task 配置、全局开关即覆盖所有代码任务的通用来源:

来源配置开关命令从哪里来信任层级
操作者 manifestcompletion_gate.mode手写的 [[verify]] 列表受信任全局配置
模型 [verify:] 回放auto_verify_replay扫描已完成 checklist 项,Harness 主动重跑无需额外信任
工具链探测门toolchain_gate探测 go.mod/Cargo.toml/package.json内置固定命令

三类来源按归一化命令合并去重(优先级 operator > toolchain > model),一次跑完。日常任务可在 ~/.zagens/config.toml 中只开全局开关,无需 per-task manifest:

[long_horizon.completion_gate]
auto_verify_replay = "enforce"   # 主动复跑模型声明的 [verify:]
toolchain_gate     = "observe"   # 工具链探测 build/test

如此设计后,Layer 2 的价值核心不再是「每个任务写一份 manifest」,而是**「Harness 主动执行、退出码当法官」**——大多数日常任务打开上述开关即可。

发现 todo!/unimplemented!

通过

graph_complete 候选

Stub 门
纯文件扫描

立即阻止

Layer 2 硬验收门

操作者 manifest

[verify:] 回放

工具链探测门
go.mod / Cargo.toml / package.json

退出码 = 0?

Layer 3 交付物对账

强制返工

6.4 Stub 门(规则独立的接地信号)

Green build 可能掩盖缺失的功能实现——todo!() 编译能通过,但运行就崩。Zagens 在 Layer 2 之前插入一个纯文件扫描的 stub 门:

  • 阻塞级enforce):todo!()unimplemented!()NotImplementedErrorthrow/panic!/raise + “not implemented” 句式 → 立即阻止完成;
  • 记录级:纯 TODO/FIXME 注释 → 从不阻塞,仅计 telemetry。

这层门在 graph_complete 候选时先于 Layer 2/3 执行——纯文件扫描几乎零开销,如果发现 stub 就没必要花几分钟跑构建了。


7. Layer 3:交付物对账 —— 抓到模型从未分解进 checklist 的项

Layer 2 能阻止「测试没过但模型声称过了」,但它不能捕获「模型从未写在 checklist 里的交付物」——这才是 MicroStack02 的核心失败模式。

Layer 3 在 Layer 2 全绿后,用纯 Rust 同步扫描(非 agent_spawn、非 LLM)对工作区做 path/glob/tracked 对账,可选每项跑 optional_verify_cmd

退出码 ≠ 0

通过

操作者预声明
交付物 manifest

纯 Rust 同步扫描
非 agent_spawn · 非 LLM

路径/glob
存在?

missing_deliverables

可选 verify
命令

不通过

pass: true

结构化 JSON 输出
离线可回放

操作者在 ~/.zagens/config.toml 中声明 [[long_horizon.completion_gate.deliverable]](完整回归夹具见 fixtures/harness/microstack-completion-gate.toml):

[[long_horizon.completion_gate.deliverable]]
id = "gzip_middleware"
path = "middleware/gzip.go"

[[long_horizon.completion_gate.deliverable]]
id = "deliverable_24_refactor"
glob = "**/*trie*.go"
optional_verify_cmd = "go test ./... -run Refactor"

[[long_horizon.completion_gate.deliverable]]
id = "contracts_frozen"
path = "contracts/server.go"
tracked = true   # 须 git 仓库且已 commit,否则无基线

扫描完成后输出结构化 JSON,例如:

{
  "pass": false,
  "missing_deliverables": [
    {"id": "gzip_middleware", "what": "middleware/gzip.go does not exist", "evidence": "workspace path missing"},
    {"id": "deliverable_24_refactor", "what": "Router trie refactor not executed", "evidence": "glob router/*trie* zero hits"}
  ],
  "manifest_round": 2
}

pass 只取决于退出码和路径命中——不依赖任何 LLM 的「感觉」,纯函数输出,离线可回放,可做快照回归。

诚实上限

三层门禁各自有界计数器:max_manifest_roundsmax_audit_rounds。如果耗尽而门仍未全绿,不会无限循环,而是记录 audit_unmet + 未达标门列表,不产生虚假绿灯


8. Cycle & Handoff:可信的回合间交接

长程任务往往单次会话的上下文窗口不够。Zagens 通过 **Cycle(循环)**机制实现上下文无缝交接。

8.1 触发条件

条件默认
活动输入 token ≥ 阈值768K(约 1M 窗口的 75%)
无飞行中的工具/流/审批in_flight: false
LHT 增强在 75–85% 警告带内,优先在 checklist item 完成时触发,避开编辑中途

8.2 交接内容

每次 cycle 交接有两层:

层 2: Carry Forward(模型手写)

长程目标(一行)

待办 item ids

上次验证命令与结果

正在编辑的文件路径

失败方案 / 约束

层 1: StructuredState(自动保留)

模式 / 工作区 / cwd

plan → 阶段列表 + 状态标记

checklist → 进度 + 未完成项

working set → 最近读写文件

sub-agent → id + role + objective

audit scratchpad → run_id

Cycle 触发条件

活动 token ≥ 768K

in_flight: false

LHT: 优先在 checklist item 完成时

Cycle 交接

新 Cycle 会话

层 1(StructuredState)由引擎确定性保留;层 2(carry_forward)由模型在 cycle 边界手写。Carry forward 模板示例:

Also include in <carry_forward>:
- Long-horizon objective (one line)
- Open checklist/plan item ids or labels still pending
- Last verification command and outcome (pass/fail/not run)
- Files currently being edited (paths only)
- Failed approaches / constraints

8.3 可视化的 Cycle 时间线

下图仅为示意,不代表真实耗时。

token ≥ 768K

再次触线

Cycle 1
实现 + 工具调用

交接
StructuredState + carry_forward

Cycle 2
继续实现

交接

Cycle 3
收尾验证

用户在 LongHorizonPanel 的 Cycle 标签页中可以看到:

  • 当前 cycle 编号 + 时间线;
  • 每轮 carry_forward 摘要(可展开预览);
  • 768K 警告线与当前上下文使用量的对比。

9. 宏观循环(Phase 4):LHT ↔ CRAFT 交替

何时启用: 默认长程任务 Layer 1–3 + Cycle 即可。Macro Loop 面向 15K–20K 行级超大重构,在实现与 QA 之间交替多轮;回归基线见 fixtures/harness/lht-eval-arms/lht_long_refactor.toml

CRAFT(Implementer + Reviewer + Verifier 多代理段)负责质量闭环与缺口识别,没有 graph_complete 放行权——最终仍由 Layer 2/3 机器门裁决。

Zagens 实现了 Phase 4 Macro Loop——在 LHT 实现段和 CRAFT QA 段之间交替:

代码实现

识别缺口

Layer 1–3

验证通过

auto_continue

CRAFT QA 段

Implementer

Reviewer

Verifier

LHT 实现段

Layer 1 防早停

Layer 2 退出码门

Layer 3 交付物对账

LHT 修复段

完成 / 下一轮

每轮 LHT 段使用 Layer 1–3 门禁推进代码实现;CRAFT 段使用多代理(Implementer + Reviewer + Verifier)做质量闭环。Macro Loop 的 auto_continue 机制让这个过程可以无人值守地跑多个回合。

这个宏循环的回归基线固定在 fixtures/harness/lht-eval-arms/lht_long_refactor.toml 中,作为 CI 的定期验证夹具。


10. 对抗审计器:Agent 独立的缺口枚举器

可选扩展: 默认 Stub 门 + Layer 2/3 已覆盖大多数场景。对抗审计在 config.toml 中 opt-in 启用,用于 Stub 扫不到的「无标记占位实现」或「规格有、清单无」的缺口枚举。

Layer 2 的 stub 门(正则扫描)只能捕获标记明确的残缺实现。对「函数体返回 return Ok(()) 占位但没有标记」或「整个模块从未进入 checklist」这类情况,需要另一个 Agent 来发现。

但这里有一个微妙的设计边界:「法官」vs「缺口枚举器」

法官型(禁止)缺口枚举器型(允许)
权力直接判 pass/fail,放行或阻塞没有放行/否决权;只输出「疑似缺口」候选
输出“LGTM/不通过” 散文机器可测试的断言{file:line, 缺什么, 建议的 [verify: cmd]}
谁最终裁决自身(软的、可说服的、不可回放)仍然是机器 Oracle——候选注入后,stub 门/退出码/路径对账来裁决
失败模式审计者-建设者共谋盖章最坏情况「报几个假缺口」,机器门一跑就驳回了

对抗审计器的输出永远不直接进入 graph_complete 的放行/阻塞判断;它只能扩展机器的门禁检查面。最终绿灯仍然由退出码和路径命中决定。

全绿

未通过

禁止直连

对抗审计 Agent
缺口枚举器

输出候选
file:line · 缺什么 · verify 建议

注入门禁检查面

Stub 门扫描

退出码 Oracle

路径/glob 对账

机器裁决

✅ graph_complete

返工 / audit_unmet

❌ 直接放行/阻塞


11. 可视化:让完成度可见

Harness 产生事实,可视化让事实可见。

Zagens 的桌面 UI 中有一个 2×2 的 Harness Grid

下排

LongHorizonPanel
Task Graph · Cycles · Context
门禁状态 · 768K 阈值

AgentPanel
Sub-agents / CRAFT

上排

ChecklistPanel
计划与 checklist 进度

AuditScratchpadPanel
审计草稿与恢复区

LongHorizonPanel 有三个子标签页:Task Graph(计划/checklist/门禁摘要)、Cycle(时间线与 carry_forward)、Context(768K 阈值 vs 上限)。

读屏场景:如何判断「真完成」?

你看到的含义建议
Task Graph 100% + 门禁全绿Layer 2/3 已通过✅ 可信任完成
Checklist 100% + 门禁琥珀色「有条件完成」checklist 全勾但 manifest 未绿或 observe 缺口继续让模型返工或检查 config
Nodes 有 gate_skip graph_complete 但无 manifest_gate_result未启用 completion_gate考虑打开 Layer 2/3
Nodes 有 audit_unmet有界轮次耗尽人工介入,不假绿

Nodes 标签页记录 Harness 决策流:

Nodes 决策流(颜色编码)

continue_injected

step_limit_continue

gate_skip

blocked

incomplete_stop

audit_unmet

verify_gate 裁决


背景:DEMO3–6 压测序列

代号载体主要发现
DEMO3~2W 行 Go Monkey 解释器unverified_acceptance 软提示→软门禁;[verify:] 纪律
DEMO4同上step budget 耗尽无声早停 → maybe_continue_at_step_limit
DEMO520K 行解释器plan/checklist 双计数、verify_gate 文本匹配误报、cycle 阈值 mid-turn 不评估
DEMO6Monkey 双后端checklist_write 批量更新绕过 verify_gate

12. 经验教训与演化

Zagens Harness 不是纸面设计——它在 DEMO3–DEMO6 四次实证压力测试中暴露出许多隐蔽问题,并逐一修补。以下是几个有普适性的教训:

12.1 所有 turn 退出点都必须是 LHT 门禁

最初 LHT 只挂载在 no-tool-uses 路径上。但 step budget 耗尽、loop_guard 截停、上下文溢出——每个外循环 break 路径都可能产生虚假的 Completed,必须系统性审计每个退出点。

12.2 进展判定不能依赖文本匹配

最初用 result_contains_success 检查 "exit code: 0" 子串来判定验证命令是否成功,但 exec_shell 成功路径返回的是裸 stdout(ok monkey/lexer 0.078s),根本不包含退出码信息。修复很简单:删除多余的文本检查,success 布尔值就是退出码 0 的权威信号。

12.3 checklist 和 plan 不能算两份工作量

DEMO5 中,模型创建了 12 个 plan 项但全部放弃(pending),同时用 checklist 推进了 19 项全部完成。原来的进度算法将两方面相加,结果 12 + 19 = 31 总项、12 项 pending,进度卡在 61%。修复:当 checklist 非空时,以 checklist 为完成度的权威来源。

12.4 [verify:] 纪律是基础

模型的 checklist 项经常把「可运行的验收」退化为「创建文件」项——“create example scripts” 在 checklist 中标记完成只是创建了文件,但从未真正跑过。Zagens 在 base.md 中强化了 checklist 写作纪律:任何需要运行的验收项必须写作 [verify: <command>] <label>,并在引擎层做了判断强化。

12.5 门禁系统的天花板 = manifest 的完整性

这是一个诚实的边界声明。Layer 3 保证「manifest 中的交付物不会漏掉」,但不能保证「规范中写了但 manifest 中没写的」。这本质上是把「模型欠分解」变成了「操作者欠写 manifest」。但 manifest 可以离线审查、可回归、可复用——比模型每次现场分解稳定得多。


13. 测试与回归架

Zagens Harness 的验证体系包括:

CI: verify-workspace.sh
+ verify-lint.sh

kernel-v3-replay/

microstack-completion-gate.toml

lht-harness-baseline.json

strict-task-seed/

lht_long_refactor.toml

夹具路径均在 fixtures/harness/ 下;设计规格见 docs/harness/COMPOSABLE_HARNESS.md


14. 结语

Zagens 的 Harness 工程回答了一个核心问题:当 AI Agent 说「我做完了」时,你怎么知道它是真的做完了?

答案不是信任模型,而是构建一整套独立于模型的机器门禁系统:

Zagens Harness 全景

上下文续命

超大型重构

扩展检查面

Layer 1 · LHT
防早停 · nudge 继续

Layer 2 · 硬验收门
退出码 Oracle

Layer 3 · 交付物对账
路径/glob 扫描

Cycle 交接
StructuredState + Carry Forward

Macro Loop
LHT ↔ CRAFT 交替

对抗审计
缺口枚举 → 机器门裁决

可审计 · 可回放 · 真实完成

这套系统的设计哲学可以浓缩为一句话:Harness 不替模型做事,它只负责检查模型有没有把事做完。检查的手段是机器可回放的、可审计的、不依赖模型自身表达的。

本文基于 Zagens v0.8.2 的公开设计文档与源码。作品名称:Zagens(MIT 协议),开源地址:github.com/didclawapp-ai/zagens

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值