Install
openclaw skills install @wljmmx/competitive-agent-loop3-Agent competitive loop with Planner/Generator/Evaluator and Sprint Contract
openclaw skills install @wljmmx/competitive-agent-loop自动加载,不需要手动触发
v2.0.1 修订(2026-08-06): 二次全流程时序与一致性校验——修正 2.3 VRAM 约束中编码模型归属错误(原误标 35B-A3B 为"编码代理独占",实际编码模型为 27B-MTP-CODER / UD-coder,并补充 35B-A3B 为 MoE 稀疏激活的说明);澄清 2.6 失活检测"无响应"定义(含 heartbeat 刷新语义);规范化 3.3 复杂度公式(明确输入变量与分级阈值);4.2 门禁凭证表加注"核验步骤本身不产出凭证";4.6/4.8/4.9 统一 PASS/RETRY 决策语义与迭代上限术语;5.2 补齐 workboard_read / workboard_release API 定义;6.5/6.6 区分 Worker/Planner 侧动作与角色职责;6.9 审查决策代码按 5.4 状态流转重写;9.3 人工介入条件与 0-10 分制对齐。
v2.0.0 修订(2026-08-06): 全流程时序一致性校验与结构优化——补齐阶段D 详细步骤、门禁凭证表与详细流程严格一一对应、统一状态流转表与打分尺度、修正卡片归属/领取规则(派发制)、澄清 sessions_send 超时语义。
Planner(规划)/ Coder(编码)/ Checker(审查)/ Memowriter(记录)四角色分离:
sessions_send 直接发消息到该 agent 的 QQ 主会话(如 agent:coder:qqbot:direct:3512d704...),让它在自己会话里执行,QQ 聊天全程可见sessions_spawn: 它创建的永远是 subagent 会话(agent:xxx:subagent:...),只借用模型配置在后台跑,QQ 里看不到任何记录,且容易丢失执行上下文(2026-08-05 实测:subagent 跑 31 分钟 0 输出失败)| 原则 | 说明 |
|---|---|
| 派发制 | 卡片归属在建卡时由 agentId 锁定,Planner 用 sessions_send 派发到对应 agent,Worker 只领取派发给自己名下的卡,不存在主动认领/竞争 |
| QQ 全程可见 | 所有执行经各 agent 的 QQ 主会话,sessions_send 派发,禁止 sessions_spawn |
| 串行执行 | 编码代理 + 审查代理互斥(VRAM 约束),通过 Workboard 状态机控制 |
| 状态留痕 | 跨代理信息交换必须走 workboard 评论,禁止文件系统/内存直接共享状态 |
| 角色 | 主模型 | 兜底模型 |
|---|---|---|
| main / planner(主/规划) | ollama/Qwen3.6-35B-A3B-MTP | ollama/Qwen3.6-27B-MTP -> ollama/Qwen3.6-27B-UD:latest -> deepseek/deepseek-v4-flash |
| coder / generator(编码/生成) | ollama/Qwen3.6-27B-MTP-CODER | ollama/Qwen3.6-27B-UD-coder:latest -> qwen3.6:27b -> ctyun/glm-5 |
| checker / evaluator(审查/评估) | Qwythos(首选) | 主模型可用时优先 |
| memowriter(记录) | ollama/qwen3.5:9b | ollama/qwen3.6:4b |
模型参数说明:
| 模型 | 显存占用 | 归属 |
|---|---|---|
| Qwen3.6-27B-MTP-CODER / UD-coder | 约 ~20GB | 编码代理独占(大模型串行) |
| Qwythos | 约 ~6GB | 审查代理独占 |
| qwen3.5:9b | 约 ~7GB | 记录代理 |
| Qwen3.6-35B-A3B-MTP(planner 主模型) | MoE 稀疏激活(3B active),占用小 | 规划/调度,串行加载不冲突 |
| 对象 | 策略 |
|---|---|
| 编码/审查代理 | 无固定执行超时 — 复杂模块迭代可能耗时数小时/数天;由质量门控制进度,而非时间限制 |
| 记录代理 | 600 秒(10 分钟)— 文档生成通常较快 |
| 平台熔断 | 派生会话挂起 > 30 分钟无输出,网关可能终止(平台默认) |
| 技能侧失活检测 | 无响应 > 30 分钟的会话标记供人工审查(不自动终止,与平台熔断相互独立) |
⚠️ sessions_send 超时语义(重要澄清):
timeoutSeconds是等待 Worker 首次确认回复的时间(建议 300s),不是任务执行时限。长任务 Worker 收到派发消息后应尽快回复"已收到,开始执行",实际产出通过 workboard 回填;Planner 用 workboard_list 跟踪完成状态,不依赖 sessions_send 等待结果。⚠️ "无响应"定义: 失活检测与平台熔断中的"无响应"指该会话在阈值时间内既未输出任何消息、也未调用 workboard_heartbeat 刷新。长任务每 10-15 分钟 heartbeat 即视为活跃,不受 30 分钟限制;"无固定执行超时"指不限制任务总时长,而非允许长期静默。
接收满足以下条件的任务时自动应用:
| 复杂度 | 条件 | 处理方式 |
|---|---|---|
| 低 | 单文件编辑,< 50 行 | 直接执行(不进入循环) |
| 中 | 多文件或需要测试 | 双方案质量门评估(阶段B 生成 2 个方案) |
| 高 | 架构设计或大型重构 | 三方案深度质量评估 + 人工审查门(阶段B 生成 3 个方案,阶段C 触发人工审查) |
输入变量(任务进入循环前由 Planner 评估):
| 变量 | 含义 | 取值 |
|---|---|---|
| fileCount | 改动文件数 | 整数 |
| testRequired | 是否需要测试验证 | true / false |
| architectureChange | 是否涉及架构变更 | true / false |
| unknownDependencies | 是否存在未知依赖 | true / false |
score = fileCount × 2
+ (testRequired ? 3 : 0)
+ (architectureChange ? 5 : 0)
+ (unknownDependencies ? 4 : 0)
分级:score ≤ 5 -> 低复杂度(直接执行,不进入循环)
6 ≤ score ≤ 12 -> 中复杂度(阶段B 双方案)
score > 12 -> 高复杂度(阶段B 三方案 + 阶段C 人工审查门)
🔒 阶段门禁机制(防跳步核心): 每个阶段结束必须产出可验证的完成凭证,Planner 逐项核验通过后才能进入下一阶段。凭证不齐 = 阶段未完成 = 禁止进入下一阶段,也禁止提前开展下一阶段的工作。 任何 Agent 都无权自我宣称"差不多了,先干起来再说"。
冲刺定义: 一个冲刺 = 阶段 A→D 一轮完整循环。跨冲刺总迭代上限 5 轮(见 4.8)。
核验时逐项对照「详细流程」中标注的步骤编号([A1][A6] / [B1][B5] / [C1][C3] / [D1][D3])核对产出物,严格按详细流程处理。任一凭证缺失即视为阶段未完成,禁止进入下一阶段。
| 阶段 | 对应步骤 | 完成凭证(缺一不可,逐项核验) | 核验人 |
|---|---|---|---|
| 阶段A | [A1]~[A6] | ① 契约 draft 文件(标注 [DRAFT v1.0],含目标/架构草图/技术方案/交付标准/依赖项/技术风险)[A1] ② sessions_send 送审调用记录 + 主卡评论"契约 draft v1.0 待审查" [A2] ③ Coder 实质性质疑清单 或 明确认可回复(QQ 消息,二选一必产,禁止默认跳过)[A3] ④ 修订版契约文件(v1.1、v1.2...,每轮含 sessions_send 重审 + 主卡评论留痕)[A4] ⑤ 契约终稿文件(去 DRAFT 标记,标注最终版本号 + 双方确认记录)[A5] ⑥ Coder 最终明确认可回复(QQ 消息,禁止"应该没问题"替代)[A5] ⑦ 阶段A 全部评论留痕齐全(A2 送审 + A4 每轮修订)[A2][A4] | Planner |
| 阶段B | [B1]~[B5] | ① sessions_send 派发记录(附契约终稿全文或摘要 + "严格按契约实现,禁止引入契约外需求、禁止自行变更方案"指令)[B1] ② 按复杂度要求的实现方案(中=2 个 / 高=3 个,每个方案:代码 + 单测 repo/tests/ + 简要说明)[B2] ③ 方案产物 workboard 评论留痕 [B2] ④ Checker 评分 JSON(单测/集成/回归分别验证分别打分 0-10 + 正确性/性能/健壮性/可读性 0-10 + verdict)+ 完整审计报告(repo/doc/reviews/)[B3] ⑤ 最高分方案选择记录 + workboard 评论 [B4] | Planner |
| 阶段C | [C1]~[C3] | ① 质量验证与对比结论(基于契约交付标准对选定方案最终验证)[C1] ② 决策记录(PASS 通过 / RETRY 重试 / BLOCKED 阻塞 + 理由)[C2] ③ 契约更新文件(PASS,进入下一冲刺时产出)或 返工指令(RETRY 时产出)[C2] ④ 决策 workboard 评论留痕 [C3] | Planner |
| 阶段D | [D1]~[D3] | ① 文档产物落盘路径(repo/doc/ 下项目/接口/用户文档)[D1] ② today-task 推送记录 [D2] ③ 主卡归档记录(全部子卡 done)[D3] | Planner |
注: 门禁核验步骤(A6 / B5 / C3 / D3)本身不产出新凭证,其职责是逐项核验本表列出的凭证;核验通过以当轮 workboard 评论留痕为据。
开始任何动作前,先回答三个问题,回答不齐禁止动手:
自检结果必须写进当轮回复/评论,让执行链路可审计。
核心原则:契约是双方谈判的产物,不是 Planner 单方定稿。 Planner 只产出初稿草案,由 Coder 审查质疑、多轮协商,双方在目标、架构、方案、交付标准上达成共识后,才形成最终契约并锁定范围。本阶段未完成,阶段B 不允许启动,Coder 不允许写任何实现代码。
步骤 A1 — 产出初稿草案(Planner)
步骤 A2 — 送审(Planner → Coder)【关键防跳步点】
步骤 A3 — Coder 审查质疑(Coder)
步骤 A4 — 多轮谈判(Planner ↔ Coder)
步骤 A5 — 范围锁定(双方确认)
步骤 A6 — 阶段A 门禁核验(Planner)
⚠️ 禁止(阶段A 防跳步红线):
- 禁止 Planner 独自写完全部内容后直接交给 Coder"盖章确认"——必须真实送审、真实谈判
- 禁止跳过 A2 直接开始编码——Coder 在收到阶段B 派发任务前,不得编写任何实现代码
- 禁止把"时间紧"作为跳过谈判的理由——跳步造成的返工成本远高于谈判成本
冲刺契约必须包含:
阶段B 启动前提:阶段A 门禁已通过(契约终稿 + Coder 认可凭证齐备)。
步骤 B1 — 派发实现任务(Planner)
步骤 B2 — Coder 生成方案(Coder)
步骤 B3 — Checker 量化打分(Checker)
步骤 B4 — 方案决策(Planner)
步骤 B5 — 阶段B 门禁核验(Planner)
评分与迭代决策(≥7 晋级 / <7 返工 / 迭代上限)统一见 4.8 质量门迭代规则。
步骤 C1 — 质量验证与对比结论(Checker)
步骤 C2 — 决策(Planner)
步骤 C3 — 阶段C 门禁核验(Planner)
阶段D 启动前提:阶段C 决策为 PASS(本冲刺交付已锁定)。
步骤 D1 — 文档产出(Memowriter)
步骤 D2 — 完成推送(Memowriter)
步骤 D3 — 阶段D 门禁核验与归档(Planner)
| 判定 | 条件 | 动作 |
|---|---|---|
| PASS | 审查评分 >= 7(且通过 C1 质量验证) | 采纳方案,更新契约,进入下一冲刺 |
| RETRY | 审查评分 < 7 | 返回编码代理改进选定方案(每冲刺最多重试 3 次),改进后重新打分 |
| BLOCKED | 不可恢复错误 / 需人工决策 | 标记阻塞,通知老板 |
0. 阶段定位:明确当前阶段 + 核验上一阶段门禁凭证(缺失 -> 先补齐,禁止前进)
1. 接收任务 -> 复杂度评估 -> 任务分类:
- 低复杂度 -> 直接执行,不进入循环
- 中/高复杂度 -> 进入冲刺循环(步骤 2-5)
2. 阶段A(冲刺契约):产出初稿 [A1] -> sessions_send 送审 Coder + 主卡评论 [A2]
-> Coder 审查质疑 [A3] -> 多轮谈判修订 [A4] -> 范围锁定(终稿 + Coder 明确认可)[A5]
-> 门禁核验 [A6]
3. 阶段B(多方案竞争):派发(附契约 + 指令)[B1] -> Coder 生成 2-3 个方案 [B2]
-> Checker 分方案打分 + 审计报告 [B3] -> 选定最高分方案 [B4] -> 门禁核验 [B5]
4. 阶段C(质量门与迭代):Checker 质量验证与对比结论 [C1]
-> Planner 决策 PASS/RETRY/BLOCKED [C2] -> 门禁核验 [C3]
5. 阶段D(归档):Memowriter 产出文档 [D1] -> today-task 推送 [D2]
-> Planner 核验并归档主卡 [D3]
6. 决策回路:
- PASS -> 本冲刺完成,更新契约进入下一冲刺(返回步骤 2,计入总迭代)
- RETRY -> 返回阶段C 重试循环(Planner 派发改进任务给 Coder -> Checker 复测,每冲刺最多 3 次)
- BLOCKED -> 人工介入
7. 总迭代上限:跨所有冲刺最多 5 轮;同一方案连续 3 轮重试无进展 -> 人工介入
创建/更新看板:
await _workboard.workboard_board_create({
id: "my-project", // 唯一看板标识
name: "My Project", // 显示名称
description: "项目描述",
icon: "board",
color: "blue",
defaultWorkspace: {
kind: "dir", // scratch | dir | worktree
path: "/绝对/路径/工作区"
},
orchestration: {
autoDecompose: true, // 自动拆解就绪卡片
autoDecomposePerDispatch: 10, // 每次分派最大拆解数
defaultAssignee: "main" // 默认分派人
}
});
列出所有看板:
await _workboard.workboard_boards({});
// -> { boards: [{ id, name, icon, status, activeCards, totalCards }] }
用途: 规划代理创建主任务/编排卡,或拆解时创建子任务
const card = await _workboard.workboard_create({
title: "搭建愤怒小鸟 H5 游戏", // 必填
notes: "验收标准...\n技术风险...",
status: "ready", // ready | running | review | done | blocked
priority: "high", // low | normal | high | urgent
labels: ["game", "h5"], // 标签数组
agentId: "main", // 分派的代理(归属在建卡时锁定)
boardId: "my-project", // 目标看板
tenant: "personal", // 命名空间
skills: ["competitive-agent-loop"] // 推荐技能
});
// -> { id, token, ... } // token 为建卡时返回的操作令牌
用途: 卡片归属在建卡时已由 agentId 锁定(派发制,无主动认领/竞争)。Worker 收到 Planner 的 sessions_send 派发后,调用 claim 领取自己名下的卡并获取操作令牌,将卡置为 running。若卡不在自己名下,claim 应被拒绝。
const claim = await _workboard.workboard_claim({ id: cardId });
// -> { tokenId, cardId, status } // tokenId 用于后续持卡操作(传 token 字段)
用途: 规划代理将大任务拆分为子卡,每个子卡指定 agentId(归属锁定)
await _workboard.workboard_decompose({
id: cardId,
token: tokenId, // 父卡令牌(建卡时获取)
summary: "分解为4个子阶段",
completeParent: true, // 自动标记父卡完成(编排)
children: [
{ title: "阶段A: 冲刺契约", agentId: "main" },
{ title: "阶段B: 多方案实现", agentId: "coder" },
{ title: "阶段C: 质量门审查", agentId: "checker" },
{ title: "阶段D: 归档", agentId: "memowriter" }
]
});
用途: 代理在卡片上留下沟通记录,实现跨代理同步(跨代理信息交换必须走评论)
await _workboard.workboard_comment({
id: cardId,
body: "规划代理: 冲刺契约 v1.0 草稿待审查",
token: tokenId
});
// 编码代理回复:
await _workboard.workboard_comment({
id: cardId,
body: "编码代理: 建议 Matter.js CDN + Canvas2D 兜底。标准 3 需量化。",
token: tokenId
});
用途: 长时间任务中刷新存活状态,防止被诊断系统标记为失效
await _workboard.workboard_heartbeat({
id: cardId,
token: tokenId,
note: "阶段B进行中 - 编码代理生成两个方案"
});
// 建议:长时间任务每 10-15 分钟调用一次
用途: 代理完成任务,提交结构化成果(摘要 + 证明 + 产物)
await _workboard.workboard_complete({
id: cardId,
token: tokenId,
summary: "阶段A完成: 冲刺契约 v2.0 已确认",
proof: {
status: "passed", // passed | failed | skipped | unknown
note: "验收标准与技术方案已审查"
},
artifacts: [
{ label: "sprint-contract-v2.md", path: "/路径/文件.md" }
]
});
用途: 代理遇到不可恢复的问题时标记卡片并释放领取(归还给 Planner 重新派发)
await _workboard.workboard_block({
id: cardId,
token: tokenId,
reason: "显存溢出 - 编码模型加载失败,所有兜底已耗尽"
});
用途: 查看当前看板/代理的卡片状态,用于路由决策
await _workboard.workboard_list({ limit: 50 }); // 所有卡片
await _workboard.workboard_list({ agentId: "coder" }); // 按代理
await _workboard.workboard_list({ status: "running" }); // 按状态
await _workboard.workboard_list({ boardId: "my-project" }); // 按看板
用途: 读取卡片完整上下文(评论、状态、产物),执行/审查前获取任务详情
const card = await _workboard.workboard_read({ id: cardId, token: tokenId });
// -> { id, title, status, agentId, comments: [...], artifacts: [...] }
用途: 主动释放已领取的卡(归还给 Planner 重新派发),如 Worker 判断自己无法继续
await _workboard.workboard_release({ id: cardId, token: tokenId, status: "ready", reason: "..." });
workboard_list(agentId=自己) 只看到派发给自己的卡,天然隔离workboard_claim 是原子的(实测确认),只接受领取自己名下的卡;若卡不在自己名下,claim 应被拒绝双卡模型说明: 阶段B 存在两张独立卡片,状态独立流转,通过评论/评分联动:
| 转换 | 触发方式 | 说明 |
|---|---|---|
| ready -> running | workboard_claim() | Worker 领取被派发的卡并开始工作(agentId 归属已锁定,无竞争) |
| running -> review | workboard_complete({proof}) | 提交完成待审查 |
| review -> done | 审查通过(PASS,分数 >= 7) | 批准晋级 |
| review -> running | 重试(RETRY,分数 < 7) | 拒绝,返回编码代理改进(最多 3 次/冲刺) |
| running -> blocked | workboard_block(reason) | 不可恢复错误 |
| running -> ready | workboard_release({status:"ready"}) | 释放卡,由 Planner 重新派发 |
核心原则:跨代理信息交换必须经过 Workboard 评论留下痕迹。
禁止行为:
| 场景 | 解决方式 |
|---|---|
| 领取令牌过期 | 重新调用 workboard_claim({id}) 续期 |
| 找不到卡 / ID 错误 | 调用 workboard_list() 刷新状态 |
| 代理会话断开 | 网关自动释放过期领取(30分钟),dispatcher 回收后由 Planner 重新派发 |
| 阻塞超时 | 自动触发阻塞状态,通知用户 |
| 派发归属冲突 | 不存在争抢:卡片归属由 agentId 锁定,workboard_claim 只接受归属自己的卡 |
| 循环阶段 | 规划/协调代理动作 | 执行代理动作 | Workboard 状态机 |
|---|---|---|---|
| 阶段A: 冲刺契约 | 建主卡(agentId=main)-> 产出契约 draft -> sessions_send 送审编码代理 + 主卡评论 | Coder 收到送审后在主卡评论回复质疑/认可(不单独领卡) | ready->running(Planner claim) -> running(协商) -> review(提交终稿) |
| 阶段B: 多方案竞争 | 拆实现子卡(agentId=coder)-> 派发编码代理;完成后派发审查卡(agentId=checker) | Coder 领取实现卡 -> 生成方案 -> complete;Checker 领取审查卡 -> 分方案打分 -> 评论结果 | 实现卡: ready->running(实现) -> review(打分);审查卡: ready->running(审查) -> review(评分完成) |
| 阶段C: 质量门与迭代 | 读取评分 -> 决策 PASS/RETRY/BLOCKED -> 评论留痕 | Checker 对选定方案做质量验证与对比结论(C1) | 实现卡: review -> done(PASS) / running(RETRY) / blocked(BLOCKED) |
| 阶段D: 归档 | 核验文档落盘 + today-task 推送记录 -> 归档主卡 | Memowriter 产出文档 -> today-task 推送 | 全部子卡 done -> 父卡 done(completeParent) |
能力说明:task 调度(llm-task 插件 / Gateway task-tracked run)与 Workboard 插件均为 OpenClaw 自带且已启用。Agent 调度通过「建卡(锁定 agentId)-> 派发 -> 领取执行 -> 完成回填」驱动,task 后台自动追踪每次运行。卡片归属在建卡时锁定,不存在主动认领/竞争。
任务进入 -> Planner 建主卡 -> 拆子卡(agentId 锁定归属)-> sessions_send 派发到 Worker 的 QQ 主会话 -> Worker 领取执行
-> heartbeat 保活 -> complete 回填 -> Planner 派发审查卡 -> Checker 领取审查
-> PASS(晋级) / RETRY(返工) / BLOCKED(阻塞) -> 全部 done 归档
await _workboard.workboard_board_create({
id: "loop-board",
name: "竞争式 Agent 循环",
icon: "loop",
orchestration: { autoDecompose: true, autoDecomposePerDispatch: 10 }
});
收到任务后,Planner 创建主任务卡,status: ready:
const card = await _workboard.workboard_create({
title: "任务标题",
notes: "需求描述 + 验收标准 + 技术风险",
status: "ready",
priority: "high",
agentId: "main", // 分派给主/规划代理
boardId: "loop-board",
skills: ["competitive-agent-loop"]
});
// card.token 为主卡操作令牌(建卡时获取,非认领)
Planner 将主卡拆为子阶段,每个子卡绑定对应 worker agent(归属在建卡时锁定):
await _workboard.workboard_decompose({
id: card.id, // 主卡 id
token: card.token, // 主卡 token(建卡时获取,非认领)
summary: "拆解为 4 个子阶段",
completeParent: true, // 子卡全完成时自动标记父卡完成
children: [
{ title: "阶段A: 冲刺契约", agentId: "main" },
{ title: "阶段B: 多方案实现", agentId: "coder" },
{ title: "阶段C: 质量门审查", agentId: "checker" },
{ title: "阶段D: 归档", agentId: "memowriter" }
]
});
Planner 在拆卡时已指定子卡 agentId(归属锁定)。拆卡后用 sessions_send 把任务派发到该 agent 的 QQ 主会话,Worker 领取自己名下的子卡并开始工作:
// ---- Worker 侧:领取被派发到自己名下的卡(agentId 归属已锁定,不存在竞争) ----
const claim = await _workboard.workboard_claim({ id: childCardId, ttlSeconds: 3600 });
// ---- Planner 侧:发任务到 coder 的 QQ 主会话 ----
sessions_send({
sessionKey: "agent:coder:qqbot:direct:3512d7045667f4df660228b731965c2", // coder 的 QQ 主会话
message: "执行阶段B: 实现方案,完成后调用 _workboard.workboard_complete 回填",
timeoutSeconds: 300 // 等待 Worker 首次确认回复的时间,非执行时限(见 2.6)
});
各 agent 的 QQ 主会话 sessionKey(固定):
agent:coder:qqbot:direct:3512d7045667f4df660228b731965c2agent:checker:qqbot:direct:3c2515212bbbed28731e70ef0dd5af4fagent:memowriter:qqbot:direct:fa5ee4a0bb61c7da1cf68a3cc87fc801要点:
⚠️ 任务消息必须要求 worker 按 loop 技能执行(防链断裂):
模板适用于阶段B/C/D 的执行派发(Planner → Coder/Checker/Memowriter)。阶段A 的 sessions_send 仅用于向 Coder 送审契约 draft(见 4.4 A2),不适用本模板。
Planner 发出的任务消息必须包含明确指令,要求 worker 严格按 competitive-agent-loop 技能执行对应阶段步骤,禁止 worker 自己另起逻辑、跳步或自由发挥:
【任务:阶段X - <角色名> <动作>】
按 competitive-agent-loop 技能执行,不要自行处理其他逻辑或跳步。
## 你的子卡
- 卡片ID: <childCardId>
- 标题: <阶段X标题>
- 归属: <agentId>
## 前置门禁检查(先做,不通过禁止开工)
- 确认上一阶段(<上一阶段名>)的门禁凭证齐备(对照 SKILL.md 门禁凭证表逐项核验)
- 凭证不齐 -> 回复 Planner 缺失项,拒绝开工,禁止自己补做或跳过上一阶段
- 凭证齐备 -> 在回复中声明"门禁通过",再继续
## 执行步骤(严格按 loop 技能,按序执行)
0. 先回复:当前所处阶段 + 上阶段门禁凭证核验结果
1. workboard_claim 领取子卡 <childCardId>(卡片归属已锁定给本 agent,只领取派发给自己的卡)
2. workboard_list 读取主卡/子卡上下文(boardId: <boardId>)
3. 按 loop 技能对应阶段执行(只做本阶段该做的事,禁止越阶段):
- 阶段A(Coder):审查契约初稿 -> 提出实质性质疑(技术方案/验收标准/架构/依赖风险)-> 参与谈判 -> 明确认可或要求修订。禁止直接盖章确认,禁止在本阶段写任何实现代码
- 阶段B(Coder):严格按已锁定契约实现(禁止引入契约外需求、禁止自行变更技术方案)
- 阶段B(Checker):对每个实现方案分别打分(0-10)+ 完整审计报告
- 阶段C(Checker):对选定的最高分方案做最终质量验证与对比结论
- 阶段D(Memowriter):产出文档并归档
4. workboard_comment 在主卡上留痕(跨代理通信必须走评论,写明你的明确结论)
5. workboard_complete 回填子卡(summary + proof + artifacts)
## 契约内容摘要
<关键上下文:契约/验收标准/任务说明>
完成后回复结果,并注明:你完成了哪个步骤、产出了什么凭证。
loop 链断裂的典型表现(禁止):
正确行为: worker 只执行自己阶段对应的 loop 步骤,完成后回填,把控制权交回 Planner(主会话)继续下一阶段。
长时间执行时刷新心跳,防止被标记 stale:
await _workboard.workboard_heartbeat({
id: childCardId,
token: claim.tokenId, // 领取时返回的令牌,用于持卡操作
note: "阶段B进行中 - 已生成方案1,正生成方案2"
});
// 建议:长任务每 10-15 分钟调用一次
Worker 完成子卡,提交结构化成果:
await _workboard.workboard_complete({
id: childCardId,
token: claim.tokenId,
summary: "阶段B完成: 生成 2 个实现方案",
proof: { status: "passed", note: "实现已完成" },
artifacts: [{ label: "solution1.md", path: "/路径/solution1.md" }]
});
阶段B: Planner 派发审查卡(agentId=checker)后,Checker 领取并分方案打分:
// ---- Checker 侧:领取审查卡,读取卡片上下文,完成打分后回填 ----
const c = await _workboard.workboard_claim({ id: reviewCardId, ttlSeconds: 3600 });
const card = await _workboard.workboard_read({ id: reviewCardId, token: c.tokenId }); // 读卡片上下文
// 打分结果写入 repo/doc/reviews/,并在审查卡评论留痕
await _workboard.workboard_comment({
id: reviewCardId, token: c.tokenId,
body: "Checker: 评分 JSON + 审计报告已产出(repo/doc/reviews/),实现卡可进入阶段C"
});
await _workboard.workboard_complete({
id: reviewCardId, token: c.tokenId,
summary: "审查完成: 分方案评分 + 审计报告",
proof: { status: "passed", note: "评分与审计报告已提交" },
artifacts: [{ label: "review-json", path: "repo/doc/reviews/review.json" }]
});
阶段C: Planner 依据评分决策,决策作用于实现卡的状态流转(见 5.4):
// ---- Planner 侧:读取评分,按 4.8 规则决策(作用于实现卡) ----
if (score >= 7) {
// PASS -> 实现卡 review -> done(批准晋级),进入 C1 质量验证后归档
} else if (score < 7 && retryCount < 3) {
// RETRY -> 实现卡 review -> running(返回 coder 改进,每冲刺最多 3 次)
// 通过 sessions_send 向 coder 派发改进任务(附返工指令),改进后回到 C1 复测
} else {
// BLOCKED -> 实现卡 -> blocked(不可恢复错误 / 重试耗尽),通知老板
await _workboard.workboard_block({ id: implCardId, token: plannerToken, reason: "..." });
}
| 层级 | 节点 | 用途 | 模型 |
|---|---|---|---|
| 调度层 | 192.168.50.10:11434(本机 NAS,纯 CPU) | Planner 事件驱动派生、workboard 查卡/派发/dispatch、dispatcher 兜底 | ollama_nas/qwen3.5:4b |
| 执行层 | 192.168.50.5:11434(GPU Ollama) | 真实编码、审查、文档产出 | MTP / UD / CODER / Qwythos / qwen3.5:9b |
设计原则:调度与执行物理隔离,零竞争。
模型分工澄清: Planner 的规划/决策推理走主模型(Qwen3.6-35B-A3B-MTP,见 2.1);查卡、派发、dispatch 等调度动作走 CPU 4b,不占用 GPU。两者不冲突。
注:192.168.50.10 既是 OpenClaw 运行主机(本机),也是 CPU 调度 Ollama 节点。Ollama 需保持服务常驻,qwen3.5:4b 建议 keep_alive=1h 常驻内存(16G 充足,保证轮询即点即用)。
| 模型 | 节点 | keep_alive | 理由 |
|---|---|---|---|
| ollama_nas/qwen3.5:4b | CPU 192.168.50.10 | 1h | 高频轮询,常驻避免重复加载 |
| GPU 各执行模型 | GPU 192.168.50.5 | 1h | 任务执行时常驻,避免频繁换载 |
核心:loop 执行调度由 Planner 事件驱动派生,不依赖独立 cron 轮询。cron 仅保留一个 dispatcher 做状态机兜底。
背景(2026-08-04 修正): cron agentTurn 每次会新建完整 isolated agent 会话(加载模型+工具+上下文),在资源受限(CPU 4b / GPU 换载)环境下 attempt-dispatch 阶段易超时;且 main 在处理任务时模型会卸载,systemEvent 也不可靠。故放弃"每 agent 定时轮询",改为事件驱动派生。
| Cron Job | 周期 | 挂载 | 动作 |
|---|---|---|---|
| loop-dispatcher-main | 每 10min | main (systemEvent) | workboard_dispatch 兜底状态机(promote 未阻塞卡/回收过期 claim/block 超时) |
主调度链条(事件驱动,无 cron 参与):
Planner 接收任务
-> 复杂度评估 -> 生成冲刺契约初稿草案
-> workboard_create 建主卡(注明各子阶段的 agentId)
-> workboard_decompose 拆子卡
-> 用 sessions_send 直接发任务到各 agent 的 QQ 主会话执行
(agent:coder:qqbot:direct:3512d704... 等,QQ 全程可见;禁止 sessions_spawn)
-> 各 worker 执行完 workboard_complete / block 回填
-> Planner 检查所有子卡 done -> 归档
dispatcher 职责(兜底,非主调度):
可选手动触发:
await _workboard.workboard_dispatch({});
异常恢复:
workboard_list(agentId=自己) 只看到派发给自己的卡,天然隔离workboard_claim 是原子的(实测确认),用于领取自己名下的卡并获取操作令牌;若卡不在自己名下,claim 应被拒绝workboard_heartbeat 刷新领取状态职责:
职责:
repo/tests/):单测代码由 Coder 写,Checker 运行验证workboard_complete 提交 artifacts(代码产物路径 + git commit/PR 链接)交付物:
repo/src/)repo/tests/repo/doc/ 对应文件职责(不止打分,是完整测试人):
repo/tests/测试环境:
repo/tests/评分输出(标准 JSON + 完整审计报告):
{
"taskId": "...",
"solutionId": "...",
"scores": {
"unitTest": 8, // 单测通过率/覆盖(0-10)
"integrationTest": 7, // 集成测试(0-10)
"regressionTest": 8, // 回归测试(0-10)
"correctness": 8, "performance": 7, "robustness": 8, "readability": 9
},
"verdict": "PASS|RETRY|BLOCKED",
"bugs": [{ "id": "BUG-1", "severity": "high", "desc": "...", "repro": "..." }],
"optimizations": ["..."],
"recommendations": "..."
}
交付物:
repo/doc/reviews/repo/doc/reviews/ 下 BUG 报告文件(含复现步骤)职责:
交付物:
repo/doc/ 下:项目文档、接口文档、用户文档| 数据类别 | 存放位置 | 载体 |
|---|---|---|
| 项目代码 | GitHub 仓库 | git 管理(repo/src/) |
| 测试代码 | GitHub 仓库 | repo/tests/ |
| 短期交互 / BUG 简述 | workboard | card comment |
| BUG 详情 / 审计报告 / 评分 | GitHub 仓库 | repo/doc/reviews/ |
| 项目/接口/用户文档 | GitHub 仓库 | repo/doc/ |
| 任务编排状态 | workboard | 卡片状态机(ready/running/review/done/blocked) |
出现以下情况时暂停并请求老板确认:
sessions_send({
sessionKey: "agent:coder:qqbot:direct:3512d7045667f4df660228b731965c2",
message: "任务内容...",
timeoutSeconds: 300 // 等待首次确认回复,非执行时限
})
注意:
sessions_send 发到其 QQ 主会话,QQ 全程可见执行记录sessions_spawn 只用于纯后台子代理任务(不需要用户可见的场合),它创建的 agent:xxx:subagent:... 会话与 QQ 主会话无关;loop 流程内禁止使用