From 62796bc36993c2e5ee62019589eab4f637b16941 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Fri, 15 May 2026 12:32:25 +0800 Subject: [PATCH] auto-sync: 2026-05-15 12:32:25 --- docs/design/architecture-v2.6.md | 419 ++++++++++++++++--------------- 1 file changed, 213 insertions(+), 206 deletions(-) diff --git a/docs/design/architecture-v2.6.md b/docs/design/architecture-v2.6.md index a7e22a7..22bdd40 100644 --- a/docs/design/architecture-v2.6.md +++ b/docs/design/architecture-v2.6.md @@ -14,21 +14,21 @@ | v2.0 | 2026-05-04 | 初始版本:SQLite 4表 + 状态机 + DAG 引擎 | | v2.6 | 2026-05-15 | **架构重构**:Shared Workspace(Blackboard)取代 DAG 引擎为编排核心 | | v2.6.1 | 2026-05-15 | 司马懿评审反馈 + Mail 退役决策 + 质量门控 + 决策记录 + 工程修正 | -| v2.6.2 | 2026-05-15 | 课题1设计决策:三层执行模型、续杯机制、AI驱动retry、Guardrail体系、must_haves三件套、分级审查矩阵 | -| v2.6.2.1 | 2026-05-15 | 司马懿评审反馈:L2/L3区分标准、timeout修正、outputs关联attempt、Scope Guard异步、risk_level自动 | +| v2.6.2 | 2026-05-15 | 课题1设计决策:三层执行模型、续杯机制、AI驱动retry、Guardrail体系、must_haves三件套、分级审查矩阵 | +| v2.6.2.1 | 2026-05-15 | 司马懿评审反馈:L2/L3区分标准、timeout修正、outputs关联attempt、Scope Guard异步、risk_level自动 | -### 课题 1 遗留 TODO(需后续课题解决) +### 课题 1 遗留 TODO(需后续课题解决) | # | 待解决事项 | 归属课题 | 说明 | |---|----------|---------|------| -| T1-1 | spawn sub 是否阻塞?需要调查 | 课题 2 | 决定 L2 层能否真正实现"轻量异步" | +| T1-1 | spawn sub 是否阻塞?需要调查 | 课题 2 | 决定 L2 层能否真正实现"轻量异步" | | T1-2 | 事件驱动取代 polling tick | 课题 2 | Retry、Agent 协商等依赖即时响应 | -| T1-3 | 依赖推进(done→自动解锁下游) | 课题 2 | 需要事件驱动的 complete→auto-unlock | +| T1-3 | 依赖推进(done→自动解锁下游) | 课题 2 | 需要事件驱动的 complete→auto-unlock | | T1-4 | Agent 间自主协商机制 | 课题 2+3 | 课题 2 事件驱动 + 课题 3 挑战体系共同支撑 | | T1-5 | Scope Guard 的 Skill 定义 | 课题 4 | scope_declaration 格式、检查 prompt 模板 | -| T1-6 | truths 验证的具体实现 | 课题 4 | AI 级别验证,怎么让 AI 判断 truths 达成 | +| T1-6 | truths 验证的具体实现 | 课题 4 | AI 级别验证,怎么让 AI 判断 truths 达成 | | T1-7 | outputs attempt_number 过滤规则 | 课题 4 | 重试时 Agent 看到之前 attempt output 的规则 | -| T1-8 | 状态机细化(review 轮次、sub_status) | 课题 3 | 挑战体系引入 review 内部状态 | +| T1-8 | 状态机细化(review 轮次、sub_status) | 课题 3 | 挑战体系引入 review 内部状态 | --- @@ -177,11 +177,11 @@ CREATE TABLE IF NOT EXISTS tasks ( -- 重试 retry_count INTEGER NOT NULL DEFAULT 0, max_retries INTEGER NOT NULL DEFAULT 2, - - -- must_haves 与风险等级(课题1设计决策) + + -- must_haves 与风险等级(课题1设计决策) must_haves TEXT, -- JSON: {truths: [], artifacts: [], constraints: []} risk_level TEXT DEFAULT 'standard', -- high/standard/low/research - estimated_duration_minutes INTEGER -- 预估工时(续杯硬上限 = 3x 此值) + estimated_duration_minutes INTEGER -- 预估工时(续杯硬上限 = 3x 此值) ); CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); @@ -287,7 +287,7 @@ CREATE TABLE IF NOT EXISTS agents ( capabilities TEXT -- JSON array: ["coding", "review", "deploy"] ); --- ===== 任务尝试记录(参考 Hermes task_runs)===== +-- ===== 任务尝试记录(参考 Hermes task_runs)===== CREATE TABLE IF NOT EXISTS task_attempts ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id TEXT NOT NULL, @@ -300,16 +300,16 @@ CREATE TABLE IF NOT EXISTS task_attempts ( metadata TEXT, -- JSON: {duration_seconds, token_count, ...} started_at TEXT NOT NULL DEFAULT (datetime('now')), completed_at TEXT, - + FOREIGN KEY (task_id) REFERENCES tasks(id) ); CREATE INDEX IF NOT EXISTS idx_attempts_task ON task_attempts(task_id); --- agents 表更新规则: --- Agent claim 任务时:自己更新 current_status='working', current_task=task_id --- Agent 完成退出时:daemon 更新 current_status='idle', current_task=NULL --- Daemon tick 检测到 zombie:daemon 更新 current_status='offline' +-- agents 表更新规则: +-- Agent claim 任务时:自己更新 current_status='working', current_task=task_id +-- Agent 完成退出时:daemon 更新 current_status='idle', current_task=NULL +-- Daemon tick 检测到 zombie:daemon 更新 current_status='offline' ``` **连接配置:** @@ -452,21 +452,21 @@ def add_comment(task_id: str, author: str, body: str, mentions: list = None): ### 3.7 黑板是索引不是仓库 -**核心原则:黑板只存元数据 + 摘要 + 文件路径,不存大段文本内容。** +**核心原则:黑板只存元数据 + 摘要 + 文件路径,不存大段文本内容。** -设计推导(课题 2): -- Network-AI 的核心洞察:Agent 只读黑板摘要,详细数据在文件中 -- Claude Code 的 file reference 模式:不内联,只引用 -- 一个典型任务全量黑板信息 ~1100-1750 tokens,极端 ~4000 tokens——远小于 128K context -- 问题不是空间不够,而是**信号噪声比**:全量注入让 Agent 在无关信息上浪费注意力 +设计推导(课题 2): +- Network-AI 的核心洞察:Agent 只读黑板摘要,详细数据在文件中 +- Claude Code 的 file reference 模式:不内联,只引用 +- 一个典型任务全量黑板信息 ~1100-1750 tokens,极端 ~4000 tokens--远小于 128K context +- 问题不是空间不够,而是**信号噪声比**:全量注入让 Agent 在无关信息上浪费注意力 -落地到 schema: -- `outputs` 表:`content_path` + `summary`,不存文件内容 -- `comments` 表:`body` 可能较长(Agent 分析报告),但评论本身是 Agent 输出的一部分 -- `decisions` 表:`decision` + `rationale` 是结构化文本,通常较短 -- `observations` 表:`body` 是简短风险描述,通常 <100 字 +落地到 schema: +- `outputs` 表:`content_path` + `summary`,不存文件内容 +- `comments` 表:`body` 可能较长(Agent 分析报告),但评论本身是 Agent 输出的一部分 +- `decisions` 表:`decision` + `rationale` 是结构化文本,通常较短 +- `observations` 表:`body` 是简短风险描述,通常 <100 字 -Agent 获取信息的分层策略(L1/L2/L3)详见 §4.4。 +Agent 获取信息的分层策略(L1/L2/L3)详见 §4.4。 --- @@ -476,116 +476,116 @@ Agent 获取信息的分层策略(L1/L2/L3)详见 §4.4。 > **Daemon 是投递员,不是决策者。所有决策发生在黑板上,daemon 只执行。** -Daemon 做三件事: -1. **读黑板** — 定期 tick,检查黑板状态 -2. **Spawn Agent** — 根据黑板上的指示,spawn 对应的 agent -3. **清理 Session** — agent 执行完后,存档 jsonl + 清理 sessions.json +Daemon 做三件事: +1. **读黑板** - 定期 tick,检查黑板状态 +2. **Spawn Agent** - 根据黑板上的指示,spawn 对应的 agent +3. **清理 Session** - agent 执行完后,存档 jsonl + 清理 sessions.json -Daemon **不做**: -- ❌ 不决定谁做什么(agent 自己决定或庞统在黑板上分配) -- ❌ 不维护状态机(黑板就是状态) -- ❌ 不做业务逻辑(不解析产出、不做评审) +Daemon **不做**: +- ❌ 不决定谁做什么(agent 自己决定或庞统在黑板上分配) +- ❌ 不维护状态机(黑板就是状态) +- ❌ 不做业务逻辑(不解析产出、不做评审) -**三层执行模型**:Daemon 的操作按成本和复杂度分为三层: +**三层执行模型**:Daemon 的操作按成本和复杂度分为三层: | 层级 | 方式 | 成本 | 适用场景 | 例子 | |------|------|------|---------|------| -| **L1 Daemon 直接操作** | SQLite 读写、文件操作 | 几乎为零 | 纯机械动作 | 更新状态、记录事件、机械验证(文件存在、JSON格式、字段非空) | -| **L2 spawn sub** | `openclaw agent --agent --session-id ` | 轻量(隔离 session,单任务) | 轻量 AI 判断 | scope guard、格式校验、快速评估、假死 reminder | -| **L3 run agent** | spawn 完整 Agent 到黑板上工作 | 完整(读黑板+思考+写回) | 重度 AI 工作 | 庞统拆解、张飞编码、司马懿 review、庞统纠错 | +| **L1 Daemon 直接操作** | SQLite 读写、文件操作 | 几乎为零 | 纯机械动作 | 更新状态、记录事件、机械验证(文件存在、JSON格式、字段非空) | +| **L2 spawn sub** | `openclaw agent --agent --session-id ` | 轻量(隔离 session,单任务) | 轻量 AI 判断 | scope guard、格式校验、快速评估、假死 reminder | +| **L3 run agent** | spawn 完整 Agent 到黑板上工作 | 完整(读黑板+思考+写回) | 重度 AI 工作 | 庞统拆解、张飞编码、司马懿 review、庞统纠错 | -关键区别: -- L2 的 sub 是一次性、单任务的("帮我检查这个输出是否在 scope 内"),执行完就退出 -- L3 的 agent 是完整的黑板参与者(读全局、自主决策、写回多个表) +关键区别: +- L2 的 sub 是一次性、单任务的("帮我检查这个输出是否在 scope 内"),执行完就退出 +- L3 的 agent 是完整的黑板参与者(读全局、自主决策、写回多个表) -**L2 与 L3 的区分标准**:是否读黑板全局。 -- L2:不读黑板全局上下文,只拿当前任务的特定字段做判断。spawn 时传递局部数据(如 scope_declaration 文本 + task.truths),sub 返回结果后退出。 -- L3:读黑板全局(tasks + comments + outputs + decisions + observations),做全局决策。spawn 时只传任务 ID + 触发原因,Agent 自己读黑板。 +**L2 与 L3 的区分标准**:是否读黑板全局。 +- L2:不读黑板全局上下文,只拿当前任务的特定字段做判断。spawn 时传递局部数据(如 scope_declaration 文本 + task.truths),sub 返回结果后退出。 +- L3:读黑板全局(tasks + comments + outputs + decisions + observations),做全局决策。spawn 时只传任务 ID + 触发原因,Agent 自己读黑板。 -这个区分决定了 spawn 时的消息内容——L2 传数据,L3 传指针。 +这个区分决定了 spawn 时的消息内容--L2 传数据,L3 传指针。 -### 4.2 双层事件架构(课题 2 设计决策) +### 4.2 双层事件架构(课题 2 设计决策) -#### D2-1:架构总览 +#### D2-1:架构总览 -> **设计推导**:v2.6 原设计为 60s polling tick,但 @mention 响应延迟、依赖解锁延迟、用户操作无法即时响应等痛点要求事件驱动。open-multi-agent 证明纯 EventEmitter 零基础设施即可实现,Network-AI 证明 file-backed 信号可实现跨进程通知。用户确认“事件驱动这块需要设计完一起实施”。 +> **设计推导**:v2.6 原设计为 60s polling tick,但 @mention 响应延迟、依赖解锁延迟、用户操作无法即时响应等痛点要求事件驱动。open-multi-agent 证明纯 EventEmitter 零基础设施即可实现,Network-AI 证明 file-backed 信号可实现跨进程通知。用户确认"事件驱动这块需要设计完一起实施"。 -**双层架构**: +**双层架构**: ``` ┌──────────────────────────────────────────────────────────────────┐ │ Daemon (Python asyncio) │ │ │ -│ Layer 1: EventBus(asyncio.Queue) │ +│ Layer 1: EventBus(asyncio.Queue) │ │ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ 进程内事件总线,~0ms 延迟 │ │ +│ │ 进程内事件总线,~0ms 延迟 │ │ │ │ • task_completed → 解锁下游依赖 + spawn 对应 Agent │ │ -│ │ • task_failed → 触发 retry 链(spawn 庞统) │ │ +│ │ • task_failed → 触发 retry 链(spawn 庞统) │ │ │ │ • comment_added → @mention 检测 → spawn 被提及者 │ │ │ │ • user_action → 即时响应 │ │ │ │ • task_ready → 依赖满足 → spawn 对应 Agent │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ ↑ │ -│ Layer 2: Signal File Watcher(~500ms) │ +│ Layer 2: Signal File Watcher(~500ms) │ │ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Agent(外部进程)写 SQLite 后,同时写 signal file │ │ +│ │ Agent(外部进程)写 SQLite 后,同时写 signal file │ │ │ │ Daemon 每 500ms 扫描 signal 目录 │ │ │ │ 读取信号 → emit 到 EventBus → 即时处理 │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ ↑ │ -│ Layer 3: Tick(30s 简化版,兜底 + 健康检查) │ +│ Layer 3: Tick(30s 简化版,兜底 + 健康检查) │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ • 僵尸检测、stale 任务回收 │ │ -│ │ • Signal 遗漏先底(万一 signal file 处理失败) │ │ -│ │ • 低优先级事件批量处理(task_created, output_written) │ │ +│ │ • Signal 遗漏先底(万一 signal file 处理失败) │ │ +│ │ • 低优先级事件批量处理(task_created, output_written) │ │ │ └─────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────┘ ``` -**不选的替代方案**: -- SQLite update_hook:~0ms 但需要 C API 绑定,且只能在 SQLite 操作时触发 -- Redis pub/sub:引入新依赖,v2.6 已去掉 Redis -- fswatch/watchdog:跨平台兼容性差,signal file 更简单 +**不选的替代方案**: +- SQLite update_hook:~0ms 但需要 C API 绑定,且只能在 SQLite 操作时触发 +- Redis pub/sub:引入新依赖,v2.6 已去掉 Redis +- fswatch/watchdog:跨平台兼容性差,signal file 更简单 -#### D2-2:事件类型与优先级 +#### D2-2:事件类型与优先级 | 事件类型 | 触发方式 | 延迟要求 | 处理方式 | |---------|---------|---------|----------| -| `task_completed` | Signal File + EventBus | ~0ms | EventBus 即时:解锁下游依赖 | -| `task_failed` | Signal File + EventBus | ~0ms | EventBus 即时:触发 retry 链 | -| `comment_added` | Signal File + EventBus | ~0ms | EventBus 即时:@mention 检测 → spawn | +| `task_completed` | Signal File + EventBus | ~0ms | EventBus 即时:解锁下游依赖 | +| `task_failed` | Signal File + EventBus | ~0ms | EventBus 即时:触发 retry 链 | +| `comment_added` | Signal File + EventBus | ~0ms | EventBus 即时:@mention 检测 → spawn | | `user_action` | 直接 API 调用 | ~0ms | EventBus 即时处理 | -| `task_ready` | EventBus(内部事件) | ~0ms | EventBus 即时:spawn 对应 Agent | +| `task_ready` | EventBus(内部事件) | ~0ms | EventBus 即时:spawn 对应 Agent | | `task_created` | Signal File | ≤30s | Tick 批量处理 | -| `task_claimed` | EventBus(Daemon 内部) | ≤30s | Tick 批量处理 | +| `task_claimed` | EventBus(Daemon 内部) | ≤30s | Tick 批量处理 | | `output_written` | Signal File | ≤30s | Tick 批量处理 | -**关键洞察**:真正需要即时响应的场景只有 4 个(task_completed / task_failed / @mention / user_action),其他 60s 延迟完全可接受。 +**关键洞察**:真正需要即时响应的场景只有 4 个(task_completed / task_failed / @mention / user_action),其他 60s 延迟完全可接受。 -#### D2-3:依赖声明的并行/串行自动决策 +#### D2-3:依赖声明的并行/串行自动决策 -> **设计推导**:open-multi-agent 的核心模式——complete→auto-unlock,纯依赖声明驱动。不需要额外的冲突检测或 AI 判断并行性。 +> **设计推导**:open-multi-agent 的核心模式--complete→auto-unlock,纯依赖声明驱动。不需要额外的冲突检测或 AI 判断并行性。 -**串行触发链**(事件驱动版): +**串行触发链**(事件驱动版): ``` Agent A 完成 task-001 → 写黑板 outputs + 更新 status → done → 写 signal file: task_completed → Daemon EventBus 即时处理: 查询所有 depends_on 包含 task-001 的 pending 任务 - → task-002 depends_on: [task-001],检查 task-001 done ✅ + → task-002 depends_on: [task-001],检查 task-001 done ✅ → 触发 task_ready 事件 → spawn Agent B 执行 task-002 ``` -**并行**:`depends_on` 为空且 assignee 不同的任务,自然并行(Daemon 分别 spawn)。不需要额外逻辑。 +**并行**:`depends_on` 为空且 assignee 不同的任务,自然并行(Daemon 分别 spawn)。不需要额外逻辑。 -**不做 files_modified 冲突检测**(D2-4):Agent 通过黑板评论自然协调(“我在改 main.py,你别碰”),不需要系统强制。Scope Guard(课题 1)作为兜底。 +**不做 files_modified 冲突检测**(D2-4):Agent 通过黑板评论自然协调("我在改 main.py,你别碰"),不需要系统强制。Scope Guard(课题 1)作为兜底。 -#### D2-5:Signal File 规范 +#### D2-5:Signal File 规范 ```python -# Agent 操作黑板后写 signal file(CLI 自动完成) +# Agent 操作黑板后写 signal file(CLI 自动完成) SIGNAL_DIR = Path("~/.sanguo_projects/sanguo_moziplus_v2/signals") # Signal file 格式: {event_type}.signal @@ -608,7 +608,7 @@ async def watch_signals(): await asyncio.sleep(0.5) ``` -**关键**:Signal file 写入由 `blackboard.py` CLI 自动完成,Agent 无需额外操作。任何 `blackboard.py` 的写操作(comment/output/claim/status update)都会同步写 signal file。 +**关键**:Signal file 写入由 `blackboard.py` CLI 自动完成,Agent 无需额外操作。任何 `blackboard.py` 的写操作(comment/output/claim/status update)都会同步写 signal file。 #### 与课题 1 的兼容性 @@ -617,7 +617,7 @@ async def watch_signals(): | 续杯机制 | task_completed 事件即时触发依赖解锁 | @mention 从 ≤60s 降到 ≤1s | | retry 由 AI 决策 | task_failed 事件即时触发 retry 链 | 庞统更快介入 | | Guardrail 吹哨人 | observation 写入触发 signal file | Daemon 即时感知问题 | -| 三层执行模型 | 不变,事件处理仍按 L1/L2/L3 分层 | ✅ 一致 | +| 三层执行模型 | 不变,事件处理仍按 L1/L2/L3 分层 | ✅ 一致 | ### 4.3 Session 生命周期 @@ -645,185 +645,185 @@ async def watch_signals(): - Gateway WS `sessions.delete` 需要 `operator.admin` scope(token 模式不授予,不可用)❌ - 回退方案:直接编辑 `sessions.json` 是安全可靠的 ✅ -### 4.4 Agent Spawn 的上下文分层传递(课题 2 设计决策) +### 4.4 Agent Spawn 的上下文分层传递(课题 2 设计决策) -> **设计推导**:GSD Wave Execution 证明隔离 session + 新鲜 context > 单一 session + 压缩。Claude Code 的 file reference 模式证明“引用而非内联”是最优策略。问题不是 context 不够大,而是信号噪声比。 +> **设计推导**:GSD Wave Execution 证明隔离 session + 新鲜 context > 单一 session + 压缩。Claude Code 的 file reference 模式证明"引用而非内联"是最优策略。问题不是 context 不够大,而是信号噪声比。 -**D2-5:三层上下文传递(L1 必传 / L2 按需 / L3 按需)** +**D2-5:三层上下文传递(L1 必传 / L2 按需 / L3 按需)** | 层级 | 内容 | Token 估算 | 谁决定 | |------|------|-----------|--------| -| **L1(spawn message)** | 任务核心 + 角色 + 触发原因 + 依赖状态 + 最近评论 + must_haves | ~300-500 | Daemon 自动 | -| **L2(CLI 按需)** | 完整评论线程 + 产出摘要 + 决策记录 + 观察记录 | ~500-1500 | Agent 自主决定 | -| **L3(文件按需)** | 产出物文件完整内容 + 完整事件日志 + 子任务详情 | ~2000-10000 | Agent 自主决定 | +| **L1(spawn message)** | 任务核心 + 角色 + 触发原因 + 依赖状态 + 最近评论 + must_haves | ~300-500 | Daemon 自动 | +| **L2(CLI 按需)** | 完整评论线程 + 产出摘要 + 决策记录 + 观察记录 | ~500-1500 | Agent 自主决定 | +| **L3(文件按需)** | 产出物文件完整内容 + 完整事件日志 + 子任务详情 | ~2000-10000 | Agent 自主决定 | -**L1 Spawn Message 模板**: +**L1 Spawn Message 模板**: ```python def build_spawn_message_L1(task_id: str, agent_id: str, trigger: str) -> str: task = get_task(task_id) - - # 依赖状态摘要(1行/依赖任务) + + # 依赖状态摘要(1行/依赖任务) deps_status = [] for dep_id in json.loads(task['depends_on'] or '[]'): dep = get_task(dep_id) deps_status.append(f" {dep_id}: {dep['status']} - {dep['title']}") - - # 最近 3 条评论摘要(截断 100 字符) + + # 最近 3 条评论摘要(截断 100 字符) recent_comments = get_comments(task_id, limit=3) comments_str = "" for c in recent_comments: comments_str += f" [{c['created_at'][:16]} {c['author']}] {c['body'][:100]}\n" - + # must_haves 摘要 must_haves = json.loads(task.get('must_haves') or '{}') truths_str = ', '.join(must_haves.get('truths', [])) - - return f"""黑板任务通知(L1): -任务:{task['title']}({task['id']}) -状态:{task['status']} | 类型:{task['task_type']} | 风险:{task['risk_level']} -触发原因:{trigger} -描述:{task['description'] or '(无)'} -验收标准(truths):{truths_str or '(未定义)'} -依赖状态: -{chr(10).join(deps_status) if deps_status else ' (无依赖)'} + return f"""黑板任务通知(L1): +任务:{task['title']}({task['id']}) +状态:{task['status']} | 类型:{task['task_type']} | 风险:{task['risk_level']} +触发原因:{trigger} +描述:{task['description'] or '(无)'} +验收标准(truths):{truths_str or '(未定义)'} -最近评论: -{comments_str if comments_str else ' (无评论)'} +依赖状态: +{chr(10).join(deps_status) if deps_status else ' (无依赖)'} -请使用以下命令获取更多信息: - L2(扩展):blackboard.py read --task {task_id} --level L2 - L3(全量产出):blackboard.py read --task {task_id} --type outputs +最近评论: +{comments_str if comments_str else ' (无评论)'} + +请使用以下命令获取更多信息: + L2(扩展):blackboard.py read --task {task_id} --level L2 + L3(全量产出):blackboard.py read --task {task_id} --type outputs """ ``` -**D2-6:不需要 Auto-compact**:v2.6 的 Agent 每次 spawn 都是隔离的新鲜 session,天然没有 context rot。唯一可能有累积的是庞统主 session(长期在线协调),属 Phase 3 优化。 +**D2-6:不需要 Auto-compact**:v2.6 的 Agent 每次 spawn 都是隔离的新鲜 session,天然没有 context rot。唯一可能有累积的是庞统主 session(长期在线协调),属 Phase 3 优化。 -**D2-7:Context 预算分配**(128K 模型): +**D2-7:Context 预算分配**(128K 模型): | 组件 | 预算 | 说明 | |------|------|------| | System Prompt + SOUL.md + IDENTITY.md | ~3K-5K tokens | 固定开销 | | Skills + AGENTS.md | ~2K-4K tokens | 固定开销 | | L1 spawn message | ~300-500 tokens | 必传 | -| L2 黑板扩展(按需) | ~500-1500 tokens | Agent 自主决定 | -| L3 产出物文件(按需) | ~2K-10K tokens | Agent 自主决定 | -| 工作空间(Agent 思考+输出) | ~30K-50K tokens | 预留 | -| **总计** | **~40K-70K tokens** | 远小于 128K,安全 | +| L2 黑板扩展(按需) | ~500-1500 tokens | Agent 自主决定 | +| L3 产出物文件(按需) | ~2K-10K tokens | Agent 自主决定 | +| 工作空间(Agent 思考+输出) | ~30K-50K tokens | 预留 | +| **总计** | **~40K-70K tokens** | 远小于 128K,安全 | ### 4.5 续杯与心跳 参考 v1.0 实践 + Hermes v0.13 Claim TTL。 -**正常流(大多数情况):** +**正常流(大多数情况):** 1. Agent spawn → 开始工作 -2. Agent 每个关键进展写黑板 observation(既是进度汇报,也是心跳信号) -3. Daemon tick 看到 working 状态 + 有新 observation → 不干预(健康状态) +2. Agent 每个关键进展写黑板 observation(既是进度汇报,也是心跳信号) +3. Daemon tick 看到 working 状态 + 有新 observation → 不干预(健康状态) 4. Agent 完成产出 → 写 output + 状态流转 → Daemon 检测到继续下一步 -**异常流:** +**异常流:** | 情况 | Daemon 检测到 | 行为 | 层级 | |------|-------------|------|------| -| Agent 有进展 | 黑板有新 observations | 不干预(无限续) | L1 | -| Agent 没进展但 session 活跃 | 无新 observations 但 session 还在 | 不干预(可能正在思考) | L1 | -| ↑ 判断信号:`observations 最后写入时间 < estimated_duration_minutes`,纯 L1 查询,不依赖 AI 判断 | | | | -| timeout(agent run 返回超时)+ 产出达标 | agent run 返回超时 + outputs 表有内容 | 幻觉门控验证产出 → 通过则继续流转 | L1→L2 | -| timeout(agent run 返回超时)+ 产出不达标 | agent run 返回超时 + outputs 为空 | L2 spawn sub 发 reminder 让 Agent 继续(假死处理) | L2 | -| timeout + 产出不达标 + reminder 后仍无进展 | 二次 timeout | 回收到 pending,记录 failure_detail | L1 | -| 非timeout 错误(进程退出) | 进程已死 | 进入 AI 纠错流程 | L3 | -| 硬上限超时 | working 状态超过 3x 预估工时 | 强制回收,记录事件 | L1 | +| Agent 有进展 | 黑板有新 observations | 不干预(无限续) | L1 | +| Agent 没进展但 session 活跃 | 无新 observations 但 session 还在 | 不干预(可能正在思考) | L1 | +| ↑ 判断信号:`observations 最后写入时间 < estimated_duration_minutes`,纯 L1 查询,不依赖 AI 判断 | | | | +| timeout(agent run 返回超时)+ 产出达标 | agent run 返回超时 + outputs 表有内容 | 幻觉门控验证产出 → 通过则继续流转 | L1→L2 | +| timeout(agent run 返回超时)+ 产出不达标 | agent run 返回超时 + outputs 为空 | L2 spawn sub 发 reminder 让 Agent 继续(假死处理) | L2 | +| timeout + 产出不达标 + reminder 后仍无进展 | 二次 timeout | 回收到 pending,记录 failure_detail | L1 | +| 非timeout 错误(进程退出) | 进程已死 | 进入 AI 纠错流程 | L3 | +| 硬上限超时 | working 状态超过 3x 预估工时 | 强制回收,记录事件 | L1 | -**设计推导**: -- v1.0 实践证明:看结果不看过程(即使 CLI 报错/超时,产出文件存在且有效就算成功) -- 续命和重试是两个独立预算:续命(Agent有进度→无限续),重试(Agent真挂→有限次) -- Hermes 的 Claim TTL(默认15分钟)提供了超时回收的参考值 +**设计推导**: +- v1.0 实践证明:看结果不看过程(即使 CLI 报错/超时,产出文件存在且有效就算成功) +- 续命和重试是两个独立预算:续命(Agent有进度→无限续),重试(Agent真挂→有限次) +- Hermes 的 Claim TTL(默认15分钟)提供了超时回收的参考值 -**timeout 的检测**:timeout 信号来自 `openclaw agent --agent ` 的返回值(阻塞调用)。Agent 在执行过程中通过写黑板 observations 维持活跃信号——Daemon tick 检查 observations 的最后写入时间,如果有新 observation 说明 Agent 还在工作。但最终判断 Agent 是否超时,以 agent run 的返回值为准。 +**timeout 的检测**:timeout 信号来自 `openclaw agent --agent ` 的返回值(阻塞调用)。Agent 在执行过程中通过写黑板 observations 维持活跃信号--Daemon tick 检查 observations 的最后写入时间,如果有新 observation 说明 Agent 还在工作。但最终判断 Agent 是否超时,以 agent run 的返回值为准。 -reminder 后的硬时间上限:reminder 后如果超过 `estimated_duration_minutes` 仍未完成(从 reminder 时间算起),才回收任务。 +reminder 后的硬时间上限:reminder 后如果超过 `estimated_duration_minutes` 仍未完成(从 reminder 时间算起),才回收任务。 -### 4.6 AI 驱动的 Retry(纠错协商) +### 4.6 AI 驱动的 Retry(纠错协商) 参考 v1.0 _handle_blocked_node() + Hermes task_runs + Claude Code Teams "before retrying, answer what failed"。 -**核心原则**:Retry 原因由 AI 判断,Daemon 只执行。 +**核心原则**:Retry 原因由 AI 判断,Daemon 只执行。 -**流程:** +**流程:** -1. Agent 失败(产出 status=failed 或 Daemon 检测到异常终止) -2. Daemon 不判断原因,只在黑板上记录这次 attempt(task_runs 模式,每次 attempt 独立记录) -3. Daemon spawn 庞统(L3)看黑板上的失败记录 + 之前所有 attempts -4. 庞统在黑板上写决策(四种选择之一): +1. Agent 失败(产出 status=failed 或 Daemon 检测到异常终止) +2. Daemon 不判断原因,只在黑板上记录这次 attempt(task_runs 模式,每次 attempt 独立记录) +3. Daemon spawn 庞统(L3)看黑板上的失败记录 + 之前所有 attempts +4. 庞统在黑板上写决策(四种选择之一): - "同一 Agent 重试" + 失败原因分析 + 改进建议 - "换 Agent 重试" + 为什么换 + 新 Agent 优势 - "任务需要用户介入" + 卡在哪 + 建议 - - "任务无法完成,建议取消" + 为什么 -5. Daemon 读庞统决策,执行对应操作 + - "任务无法完成,建议取消" + 为什么 +5. Daemon 读庞统决策,执行对应操作 6. 如果重试后仍失败 → 新 attempt 记录 → 再次 spawn 庞统 -7. Circuit breaker:同一 task 总 attempt 数达到 N 次(默认3次,不区分是哪个 Agent)→ 自动 block + 通知用户。理由:3 次尝试都不成功说明问题在任务本身而非 Agent 能力。 +7. Circuit breaker:同一 task 总 attempt 数达到 N 次(默认3次,不区分是哪个 Agent)→ 自动 block + 通知用户。理由:3 次尝试都不成功说明问题在任务本身而非 Agent 能力。 -**失败记录**:谁记录什么? +**失败记录**:谁记录什么? | 记录者 | 记录内容 | 黑板位置 | |--------|---------|---------| -| Daemon | 机械类失败(进程退出码、超时) | events 表,event_type=task_failed | -| 司马懿 | 内容类失败(评审不通过) | reviews 表(verdict=needs_revision + issues) | -| 庞统 | 方向类失败(需求偏离) | decisions 表(重规划原因) | -| Agent 自己 | 能力不足/专业外,主动报告失败 | comments 表(说明原因)+ tasks status→failed | -| Agent(重试时) | 新 attempt 的产出 | outputs 表(带 attempt_number) | +| Daemon | 机械类失败(进程退出码、超时) | events 表,event_type=task_failed | +| 司马懿 | 内容类失败(评审不通过) | reviews 表(verdict=needs_revision + issues) | +| 庞统 | 方向类失败(需求偏离) | decisions 表(重规划原因) | +| Agent 自己 | 能力不足/专业外,主动报告失败 | comments 表(说明原因)+ tasks status→failed | +| Agent(重试时) | 新 attempt 的产出 | outputs 表(带 attempt_number) | -**Agent 重试时能看到什么**:黑板上的 events(失败记录)+ reviews(评审意见)+ comments(讨论)。全部在黑板上,spawn 时自然读到。 +**Agent 重试时能看到什么**:黑板上的 events(失败记录)+ reviews(评审意见)+ comments(讨论)。全部在黑板上,spawn 时自然读到。 -**设计推导**: -- v1.0 实践:庞统分析原因 → 司马懿 challenge → 三轮协商 → 执行,方向正确但由引擎硬编码调用 -- v2.6 改进:Agent 在黑板上自主协商(需要事件驱动支持,见课题2),Daemon 只 spawn 不调度 -- Hermes task_runs:每次 attempt 独立记录(attempt_number, outcome, log_path, exit_code),可追溯可审计 +**设计推导**: +- v1.0 实践:庞统分析原因 → 司马懿 challenge → 三轮协商 → 执行,方向正确但由引擎硬编码调用 +- v2.6 改进:Agent 在黑板上自主协商(需要事件驱动支持,见课题2),Daemon 只 spawn 不调度 +- Hermes task_runs:每次 attempt 独立记录(attempt_number, outcome, log_path, exit_code),可追溯可审计 -### 4.7 Guardrail 体系(吹哨人机制) +### 4.7 Guardrail 体系(吹哨人机制) 参考 OpenAI Agent SDK OutputGuardrail + GSD must_haves + v1.0 M4 Guard 机制。 -**核心原则**:Guardrail 是吹哨人不是终结者。检测到问题写黑板(observation),触发后续 AI 判断链。决策权在黑板上,执行权在 Daemon。 +**核心原则**:Guardrail 是吹哨人不是终结者。检测到问题写黑板(observation),触发后续 AI 判断链。决策权在黑板上,执行权在 Daemon。 -**三个 Guardrail:** +**三个 Guardrail:** | Guardrail | 触发时机 | 检测方式 | 发现问题后 | |-----------|---------|---------|-----------| -| **Scope Guard** | Agent claim 任务后在工作过程中写 decisions(scope 相关)时 | L2 sub 异步对比 scope_declaration vs task.truths | 写 observation(severity=warning),Daemon 下次 tick 触发庞统判断 | -| **Output Guard** | Agent 写 output 时 | L1 机械检查(文件存在、格式正确、字段非空)+ L2 语义检查 | 机械失败直接打回,语义问题写 observation | +| **Scope Guard** | Agent claim 任务后在工作过程中写 decisions(scope 相关)时 | L2 sub 异步对比 scope_declaration vs task.truths | 写 observation(severity=warning),Daemon 下次 tick 触发庞统判断 | +| **Output Guard** | Agent 写 output 时 | L1 机械检查(文件存在、格式正确、字段非空)+ L2 语义检查 | 机械失败直接打回,语义问题写 observation | | **Format Guard** | Agent 写任何结构化数据时 | L1 JSON Schema 校验 | 格式错误直接打回重做 | -**后续动作链(问题升级):** +**后续动作链(问题升级):** ``` Guardrail 检测到问题 → 写黑板 observation ↓ Daemon tick 读到 observation ↓ -根据 severity 分级处理: +根据 severity 分级处理: - blocking → L3 立即 spawn 庞统 - - warning → L3 spawn 庞统(下次 tick 统一处理) - - info → 只记录,不触发 + - warning → L3 spawn 庞统(下次 tick 统一处理) + - info → 只记录,不触发 ↓ -庞统在黑板上写决策: - - "确认偏离,打回" → Daemon 改状态回 pending - - "方向扩展合理,批准继续" → 继续 +庞统在黑板上写决策: + - "确认偏离,打回" → Daemon 改状态回 pending + - "方向扩展合理,批准继续" → 继续 - "需要用户判断" → 通知用户 ``` -**设计推导**: -- OpenAI Agent SDK:Guardrail 本身是轻量 AI Agent(并行运行,专门做检查),不是 if-else 规则 -- GSD must_haves truths:面向可观测行为,不是实现步骤 -- v1.0 M4 Guard:entry/exit guard + skill 化检查逻辑,方向正确但绑定在 DAG 节点上 +**设计推导**: +- OpenAI Agent SDK:Guardrail 本身是轻量 AI Agent(并行运行,专门做检查),不是 if-else 规则 +- GSD must_haves truths:面向可观测行为,不是实现步骤 +- v1.0 M4 Guard:entry/exit guard + skill 化检查逻辑,方向正确但绑定在 DAG 节点上 -**Scope Guard(异步检查,不阻塞 Agent 执行)**: -- 触发时机:Agent claim 任务后在工作过程中写 decisions(scope 相关)时 -- 检查方式:L2 sub 异步对比 scope_declaration vs task.truths -- 不阻塞:Agent 写完 scope_declaration 后继续工作,不等 Guard 结果 -- 发现问题:写 observation(severity=warning),Daemon 下次 tick 触发庞统判断 -- 兜底:即使 Scope Guard 漏报,庞统在 review 阶段仍会检查方向正确性 +**Scope Guard(异步检查,不阻塞 Agent 执行)**: +- 触发时机:Agent claim 任务后在工作过程中写 decisions(scope 相关)时 +- 检查方式:L2 sub 异步对比 scope_declaration vs task.truths +- 不阻塞:Agent 写完 scope_declaration 后继续工作,不等 Guard 结果 +- 发现问题:写 observation(severity=warning),Daemon 下次 tick 触发庞统判断 +- 兜底:即使 Scope Guard 漏报,庞统在 review 阶段仍会检查方向正确性 --- @@ -841,12 +841,12 @@ Agent 被 spawn - 读 observations 表:已知风险 ↓ 2. 想 → 根据自己的职责自主决策 - - 我是编码先锋,这个 pending 任务适合我 → claim - - 我是风控守将,这个 comment @ 我 → 回复 - - 我是副军师,这个任务需要分解 → 创建子任务 - - Agent claim 任务后、开始工作前,写 scope_declaration 到 decisions 表: - "我计划做什么,产出什么" - Scope Guard(L2 sub)会对比 scope_declaration vs task.truths + - 我是编码先锋,这个 pending 任务适合我 → claim + - 我是风控守将,这个 comment @ 我 → 回复 + - 我是副军师,这个任务需要分解 → 创建子任务 + - Agent claim 任务后、开始工作前,写 scope_declaration 到 decisions 表: + "我计划做什么,产出什么" + Scope Guard(L2 sub)会对比 scope_declaration vs task.truths ↓ 3. 做 → 执行任务 - 编码、审核、数据分析等 @@ -854,14 +854,14 @@ Agent 被 spawn - 需要其他人协助 → 写 comment @mention ↓ 4. 写回黑板 → 产出、评论、状态更新、决策记录 - - 写 outputs 表:产出文件路径 + 摘要 - - 写 comments 表:完成说明 - - 写 decisions 表:关键决策(哪怕自己的决策也要填一条) - - 更新 tasks 表:status → done/review - - must_haves 三件套(任务创建时由庞统定义): - - truths:用户视角的可观测行为("用户能看到回测结果"),不是实现步骤("编写回测脚本") - - artifacts:必须存在的产出文件 - - constraints:继承的约束(如"不超过500行"、"必须用vnpy") + - 写 outputs 表:产出文件路径 + 摘要 + - 写 comments 表:完成说明 + - 写 decisions 表:关键决策(哪怕自己的决策也要填一条) + - 更新 tasks 表:status → done/review + - must_haves 三件套(任务创建时由庞统定义): + - truths:用户视角的可观测行为("用户能看到回测结果"),不是实现步骤("编写回测脚本") + - artifacts:必须存在的产出文件 + - constraints:继承的约束(如"不超过500行"、"必须用vnpy") ↓ 5. 退出 → daemon 自动清理 session ``` @@ -912,28 +912,35 @@ python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py create --title "分 ## 6. 关键场景流程 -### 6.1 庞统规划 + Agent 领任务 +### 6.1 庞统规划 + Agent 领任务(事件驱动版) ``` -用户 → 庞统(主session):"设计一个动量因子策略" +用户 → 庞统(主session):“设计一个动量因子策略” ↓ 庞统在黑板上写: - - 创建 task-001(数据准备,pending) + - 创建 task-001(数据准备,pending,无依赖) - 创建 task-002(因子计算,pending,depends_on: [task-001]) - 创建 task-003(回测验证,pending,depends_on: [task-002]) - - 评论:"建议赵云领 001,张飞领 002 和 003" + - 评论:“建议赵云领 001,张飞领 002 和 003” ↓ -Daemon tick 发现 task-001 pending + 庞统评论建议赵云 +庞统写 signal file: task_created ↓ -Daemon spawn 赵云 → 赵云读黑板 → claim task-001 → 执行 → 写产出 → 退出 +Daemon EventBus 收到 task_created(低优先级) + → Tick 批量处理: spawn 赵云通知 task-001 ↓ -Daemon tick 发现 task-001 done → task-002 depends_on 满足 +赵云读黑板 → claim task-001 → 执行 → 写产出 → 更新 status→done + → 写 signal file: task_completed ↓ -Daemon spawn 张飞 → 张飞读黑板 → claim task-002 → 执行 → 写产出 → 退出 +Daemon EventBus 即时收到 task_completed + → 查询 depends_on 包含 task-001 的 pending 任务 → task-002 + → task-002 的依赖全部满足 → 触发 task_ready + → spawn 张飞执行 task-002 ↓ -(同理 task-003) +(同理 task-002 done → 即时触发 task-003) ``` +**对比 polling 版**:task-001 done 到 task-002 spawn 的延迟从 ≤60s 降到 ~0ms。 + ### 6.2 Agent 间协作讨论 ``` @@ -1110,7 +1117,7 @@ Agent 执行过程中的每个关键决策都必须记录在黑板的 decisions | rationale | 为什么这样选 | | alternatives | 被排除的选项 | -**哪怕是自己做的决策也要填一条。** 目的: +**哪怕是自己做的决策也要填一条。** 目的: - 后续复盘时能追溯"当时为什么这样选" - 审核时司马懿能理解决策背后的思考 - 经验沉淀的原始素材 @@ -1121,17 +1128,17 @@ Agent 执行过程中的每个关键决策都必须记录在黑板的 decisions | 风险等级 | 任务类型 | 审查深度 | 参与者 | |---------|---------|---------|--------| -| **高风险** | 量化策略、生产部署、数据删除 | 三阶段审查(方案审查→Output Guardrail→产出审查)+ 可选多视角对抗 | 庞统+司马懿+对应执行者 | -| **标准** | 编码、数据处理、配置修改 | 二阶段(Output Guardrail + 产出审查) | 司马懿+执行者 | -| **低风险** | 调研报告、文档更新、日志查看 | 一阶段(Output Guardrail 机械检查) | Daemon 自动 | -| **调研** | 技术调研、方案探索 | 一阶段(庞统确认方向) | 庞统 | +| **高风险** | 量化策略、生产部署、数据删除 | 三阶段审查(方案审查→Output Guardrail→产出审查)+ 可选多视角对抗 | 庞统+司马懿+对应执行者 | +| **标准** | 编码、数据处理、配置修改 | 二阶段(Output Guardrail + 产出审查) | 司马懿+执行者 | +| **低风险** | 调研报告、文档更新、日志查看 | 一阶段(Output Guardrail 机械检查) | Daemon 自动 | +| **调研** | 技术调研、方案探索 | 一阶段(庞统确认方向) | 庞统 | -**风险等级**:庞统创建任务时标注。默认值为 `standard`。庞统的 Skill 中内置规则:创建 task_type 为 `strategy` 或 `deploy` 的任务时自动设为 `high`,`research` 类型自动设为 `research`。无需庞统手动判断。 +**风险等级**:庞统创建任务时标注。默认值为 `standard`。庞统的 Skill 中内置规则:创建 task_type 为 `strategy` 或 `deploy` 的任务时自动设为 `high`,`research` 类型自动设为 `research`。无需庞统手动判断。 -**设计推导**: -- v1.0 实践:每个节点都要司马懿审查,简单任务过重 -- superpowers:三阶段审查(implementer → spec reviewer → code quality reviewer),不同阶段不同深度 -- Hermes:per-task retry budget,任务级别差异化 +**设计推导**: +- v1.0 实践:每个节点都要司马懿审查,简单任务过重 +- superpowers:三阶段审查(implementer → spec reviewer → code quality reviewer),不同阶段不同深度 +- Hermes:per-task retry budget,任务级别差异化 ---