From 9e7d52240a9099925925ed0bb96f5c2eb126f1d0 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Fri, 15 May 2026 13:44:39 +0800 Subject: [PATCH] auto-sync: 2026-05-15 13:44:39 --- docs/design/architecture-v2.6.md | 4 + docs/design/architecture-v2.6.md.bak | 1266 -------------------------- 2 files changed, 4 insertions(+), 1266 deletions(-) delete mode 100644 docs/design/architecture-v2.6.md.bak diff --git a/docs/design/architecture-v2.6.md b/docs/design/architecture-v2.6.md index 4b4ee14..0ea5af1 100644 --- a/docs/design/architecture-v2.6.md +++ b/docs/design/architecture-v2.6.md @@ -37,6 +37,10 @@ | T2-5 | L2/L3 分层读取 API | Phase 2 实现 | blackboard.py read --level L2/L3 | | T2-6 | 仓库级上下文(Agent Context Pack) | Phase 3 | 参考 agent-chorus Context Pack:结构化仓库情报让 Agent 不需要自己探索。量化项目可抽象为项目结构/代码规范/常见陷阱 | | T2-7 | Handoff Comment 的 Skill 引导 | Phase 2 | Agent Skill 中明确“结束前必须写 Handoff Comment”的行为规范 | +| T2-8 | Handoff Comment 的 Skill 解析规则 | 课题 4 | 下一个 Agent 的 Skill 中如何解析 Handoff 格式 | +| T2-9 | inbox 并发写入的竞态处理 | Phase 1 验证 | 多 Agent 同时写 inbox 文件时的安全性(agent-chorus 同样用追回写入,无锁) | +| T2-10 | inbox 文件的 rotate/truncate 策略 | Phase 2 | 长期运行后文件膨胀的防范 | +| T2-11 | Tick 频率 30s vs 60s 的性能验证 | Phase 1 验证 | 黑板查询量的实际测算 | --- diff --git a/docs/design/architecture-v2.6.md.bak b/docs/design/architecture-v2.6.md.bak deleted file mode 100644 index ec56607..0000000 --- a/docs/design/architecture-v2.6.md.bak +++ /dev/null @@ -1,1266 +0,0 @@ -# AI原生DevOps Platform 架构设计 v2.6 - -**版本**: v2.6(Shared Workspace + Blackboard 架构) -**基于**: architecture-v2.md + v2.0 AI Native 调研 + 技术验证 -**作者**: 庞统(副军师) -**日期**: 2026-05-15 - ---- - -## 变更历史 - -| 版本 | 日期 | 变更内容 | -|------|------|---------| -| 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.3 | 2026-05-15 | 课题2设计决策:双层事件架构(EventBus+Signal File+Tick)、L1/L2/L3上下文传递、黑板是索引不是仓库、依赖驱动并行/串行、Phase规划更新 | - -### 课题 1-2 遗留 TODO(需后续课题解决) - -| # | 待解决事项 | 归属课题 | 说明 | -|---|----------|---------|------| -| ~~T1-1~~ | ~~spawn sub 是否阻塞?需要调查~~ | ~~课题 2~~ | ✅ 课题 2 解决:不阻塞,signal file 异步 | -| ~~T1-2~~ | ~~事件驱动取代 polling tick~~ | ~~课题 2~~ | ✅ 课题 2 解决:双层事件架构 | -| ~~T1-3~~ | ~~依赖推进(done→自动解锁下游)~~ | ~~课题 2~~ | ✅ 课题 2 解决:task_completed 事件即时解锁 | -| ~~T2-1~~ | ~~files_modified 冲突检测~~ | ~~课题 2~~ | ✅ D2-4 决策:不做,Agent 评论自然协调 | -| ~~T2-2~~ | ~~Auto-compact~~ | ~~课题 2~~ | ✅ D2-6 决策:不做,隔离 session 天然无 context rot | -| T1-4 | Agent 间自主协商机制 | 课题 3 | 事件驱动 + 挑战体系共同支撑 | -| T1-5 | Scope Guard 的 Skill 定义 | 课题 4 | scope_declaration 格式、检查 prompt 模板 | -| T1-6 | truths 验证的具体实现 | 课题 4 | AI 级别验证,怎么让 AI 判断 truths 达成 | -| T1-7 | outputs attempt_number 过滤规则 | 课题 4 | 重试时 Agent 看到之前 attempt output 的规则 | -| T1-8 | 状态机细化(review 轮次、sub_status) | 课题 3 | 挑战体系引入 review 内部状态 | -| T2-3 | blackboard.py 写操作自动写 signal file | Phase 1 实现 | CLI 层自动完成 | -| T2-4 | EventBus + Signal File Watcher 实现 | Phase 1 实现 | Daemon 核心改造 | -| T2-5 | L2/L3 分层读取 API | Phase 2 实现 | blackboard.py read --level L2/L3 | - ---- - -## 1. v2.6 核心变革:从 DAG 状态机到 Shared Workspace - -### 1.1 为什么变? - -v2.0 的核心是 **DAG 引擎 + 状态机 + 邮件通信**,本质是给 AI 团队做了一套 ERP: -- 编排是确定性状态机(固定流程) -- 交互是点按钮(Dashboard) -- Agent 间靠邮件异步通信(信息分散在 mail 目录) -- 人的参与密度不变(全程驾驶) - -v2.6 的核心是 **Shared Workspace(Blackboard)+ Agent 自主决策 + Daemon 投递**: -- 编排是 AI agent 在黑板上自主领活(动态协作) -- 交互是自然语言对话 -- Agent 间通过黑板共享一切(信息集中在任务空间) -- 人只做方向决策和验收 - -### 1.2 核心原则 - -> **黑板是唯一真相源,所有 agent 读它、想、行动,写回结果。Daemon 是投递员,不是决策者。** - -1. **Agent 决策,Daemon 执行** - 庞统做 plan、张飞领任务、关羽发现风险,都写在黑板上。Daemon 读黑板,执行 spawn/通知。 -2. **产出在黑板,不在邮件** - 所有任务产出、讨论、观察都在任务的黑板空间里,Sanguo Mail 不介入任务协作。 -3. **Daemon 不阻塞 Agent** - Daemon 是常驻管家,定期 tick 检查黑板,spawn agent 执行,不占用任何 agent 的主 session。 -4. **Session 用完即清** - Agent 通过 `openclaw agent --agent --session-id ` spawn 隔离 session,执行完 daemon 存档 jsonl 并清理 sessions.json。 - ---- - -## 2. 架构总览 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ 用户 / 触发器 │ -│ (Web / CLI / Cron) │ -└──────────────────────────┬──────────────────────────────────┘ - │ 写入黑板或触发 daemon -┌──────────────────────────▼──────────────────────────────────┐ -│ Shared Workspace(黑板) │ -│ │ -│ ┌────────────────────────────────────────────────────────┐ │ -│ │ SQLite (blackboard.db) │ │ -│ │ tasks / comments / outputs / agents / events │ │ -│ │ 原子读写(propose→validate→commit 或 SQLite 事务) │ │ -│ └────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ -│ │ 任务列表 │ │ 评论线程 │ │ 产出空间 │ │ 讨论区域 │ │ -│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ -└──────────────────────────┬──────────────────────────────────┘ - │ daemon tick 读写 -┌──────────────────────────▼──────────────────────────────────┐ -│ Daemon(管家) │ -│ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ -│ │ Tick 循环 │ │ Session 管理 │ │ 健康检查 │ │ -│ │ (60s 轮询) │ │ spawn/archive │ │ zombie/reclaim │ │ -│ │ 读黑板→决策 │ │ /cleanup │ │ /stale 任务 │ │ -│ └──────┬───────┘ └──────┬───────┘ └──────────────────┘ │ -│ │ │ │ -│ Daemon 只做三件事: │ │ -│ 1. 读黑板,发现需要介入的 │ │ -│ 2. Spawn 对应 agent │ │ -│ 3. 清理完成的 session │ │ -└──────────────────────────┬──────────────────────────────────┘ - │ openclaw agent --agent --session-id - │ 执行完 → 存档 jsonl → 清理 sessions.json -┌──────────────────────────▼──────────────────────────────────┐ -│ Agent 层(将军们) │ -│ │ -│ Agent 不常驻。被 spawn 时: │ -│ 1. 读黑板 → 了解全局状态 │ -│ 2. 想和做 → 根据职责自主决策 │ -│ 3. 写回黑板 → 产出、评论、领任务 │ -│ 4. 退出 → session 被 daemon 清理 │ -│ │ -│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ -│ │庞统 │ │司马懿│ │姜维 │ │关羽 │ │张飞 │ │赵云 │ │ -│ │策划 │ │质量 │ │平台 │ │风控 │ │编码 │ │数据 │ │ -│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │ -│ │ -│ 每个 Agent: SOUL.md + IDENTITY.md + Skills + Workspace │ -│ Agent 主 session 不参与任务执行(不被污染) │ -└─────────────────────────────────────────────────────────────┘ -``` - -### 关键区别:v2.0 vs v2.6 - -| 维度 | v2.0 | v2.6 | -|------|------|------| -| 编排核心 | DAG 引擎 + 状态机 | Blackboard(Shared Workspace) | -| 决策者 | Daemon(状态机驱动) | Agent(在黑板上自主决策) | -| Daemon 角色 | 调度器(决定谁干什么) | 投递员(执行黑板上的决策) | -| Agent 通信 | Sanguo Mail(异步邮件) | 黑板 Comment 线程(共享空间) | -| 信息位置 | 分散(mail + task目录 + session) | 集中(黑板 SQLite) | -| Agent 生命周期 | 固定节点执行 | Spawn 隔离 session,用完即清 | -| 通知机制 | Mail 轮询 | Daemon tick + spawn | -| 协作模式 | 指令式(庞统分配→将军执行) | 自主式(看黑板→领活→写回) | - ---- - -## 3. Shared Workspace(黑板)设计 - -### 3.1 参考系统对比 - -| 系统 | 存储 | 原子性 | 讨论 | 状态机 | 发现 | -|------|------|--------|------|--------|------| -| Claude Code Agent Teams | JSON 文件 | 无(last-write-wins) | inbox 点对点 | pending/in_progress/completed | Agent 轮询 | -| Hermes Kanban v0.13 | SQLite | SQLite 事务 | Comment 线程 | 7 状态完整机 | Dispatcher 60s tick | -| Network-AI | Markdown 文件 | flock 三阶段提交 | signal key | 无 | Agent 主动读 | -| agent-blackboard | SQLite + Ontology | SQLite 事务 | 本体条目 | 无 | Coordinator 分发 | -| **我们的方案** | **SQLite** | **SQLite 事务** | **Comment 线程** | **简化状态机** | **Daemon tick** | - -### 3.2 SQLite Schema - -```sql --- ===== 任务表 ===== -CREATE TABLE IF NOT EXISTS tasks ( - id TEXT PRIMARY KEY, -- task-001 - title TEXT NOT NULL, - description TEXT, - status TEXT NOT NULL DEFAULT 'pending', - CHECK (status IN ('pending','claimed','working','review','done','failed','blocked','cancelled')), - - -- 分配(谁领了或被指派) - assignee TEXT, -- agent id: zhangfei-dev - assigned_by TEXT, -- 谁分配的:pangtong-fujunshi / user - - -- 依赖 - depends_on TEXT, -- JSON array of task IDs - parent_task TEXT, -- 父任务(子任务分解时) - - -- 优先级和类型 - priority INTEGER NOT NULL DEFAULT 5, -- 1(最高)-10(最低) - task_type TEXT, -- coding/review/data/deploy/research/discuss - - -- 时间 - created_at TEXT NOT NULL DEFAULT (datetime('now')), - updated_at TEXT NOT NULL DEFAULT (datetime('now')), - claimed_at TEXT, - started_at TEXT, - completed_at TEXT, - deadline TEXT, - - -- 重试 - retry_count INTEGER NOT NULL DEFAULT 0, - max_retries INTEGER NOT NULL DEFAULT 2, - - -- must_haves 与风险等级(课题1设计决策) - must_haves TEXT, -- JSON: {truths: [], artifacts: [], constraints: []} - risk_level TEXT DEFAULT 'standard', -- high/standard/low/research - estimated_duration_minutes INTEGER -- 预估工时(续杯硬上限 = 3x 此值) -); - -CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); -CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee); -CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task); - --- ===== 评论线程表 ===== --- 参考 Hermes kanban_comment:追加写入,所有参与者可见 -CREATE TABLE IF NOT EXISTS comments ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task_id TEXT NOT NULL, - author TEXT NOT NULL, -- agent id 或 'user' - body TEXT NOT NULL, - mentions TEXT, -- JSON array: ["zhangfei-dev", "guanyu-dev"] - created_at TEXT NOT NULL DEFAULT (datetime('now')), - - FOREIGN KEY (task_id) REFERENCES tasks(id) -); - -CREATE INDEX IF NOT EXISTS idx_comments_task ON comments(task_id); -CREATE INDEX IF NOT EXISTS idx_comments_author ON comments(author); --- 注意:mentions 是 JSON 数组,无法直接建索引。daemon tick 查询用 json_each(mentions)。 --- 数据量小时够用,后续可拆 comment_mentions 关联表优化。 - --- ===== 产出表 ===== -CREATE TABLE IF NOT EXISTS outputs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task_id TEXT NOT NULL, - agent TEXT NOT NULL, -- 谁写的 - output_type TEXT NOT NULL, -- code/document/data/config/other - title TEXT NOT NULL, - content_path TEXT, -- 文件路径(产出物在 task 目录下) - summary TEXT, -- 一句话摘要 - metadata TEXT, -- JSON: {files_changed, lines_added, ...} - attempt_number INTEGER DEFAULT 1, -- 关联 task_attempts.attempt_number - created_at TEXT NOT NULL DEFAULT (datetime('now')), - - FOREIGN KEY (task_id) REFERENCES tasks(id) -); - -CREATE INDEX IF NOT EXISTS idx_outputs_task ON outputs(task_id); - --- ===== 决策记录表 ===== --- Agent 执行过程中的关键决策必须记录。哪怕是自己做的决策也要填一条。 -CREATE TABLE IF NOT EXISTS decisions ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task_id TEXT NOT NULL, - decider TEXT NOT NULL, -- 谁做的决策 - decision TEXT NOT NULL, -- 决策内容:"选 A 方案" - rationale TEXT NOT NULL, -- 为什么:"B 方案内存开销更大" - alternatives TEXT, -- JSON array: 被排除的选项 - created_at TEXT NOT NULL DEFAULT (datetime('now')), - - FOREIGN KEY (task_id) REFERENCES tasks(id) -); - -CREATE INDEX IF NOT EXISTS idx_decisions_task ON decisions(task_id); - --- ===== 观察表 ===== --- Agent 执行过程中发现的问题、风险、建议 -CREATE TABLE IF NOT EXISTS observations ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task_id TEXT NOT NULL, - observer TEXT NOT NULL, -- 谁观察到的 - severity TEXT NOT NULL DEFAULT 'info', - CHECK (severity IN ('blocking','warning','info','audit')), - body TEXT NOT NULL, - resolved_by TEXT, -- 谁处理的 - resolved_at TEXT, -- 何时处理的 - created_at TEXT NOT NULL DEFAULT (datetime('now')), - - FOREIGN KEY (task_id) REFERENCES tasks(id) -); - --- ===== 事件日志(审计追踪)===== -CREATE TABLE IF NOT EXISTS events ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task_id TEXT, - agent TEXT, - event_type TEXT NOT NULL, - detail TEXT, -- JSON - created_at TEXT NOT NULL DEFAULT (datetime('now')) -); - -CREATE INDEX IF NOT EXISTS idx_events_task ON events(task_id); -CREATE INDEX IF NOT EXISTS idx_events_time ON events(created_at); - --- 合法 event_type 清单: --- 任务:task_created, task_claimed, task_started, task_completed, task_failed, --- task_blocked, task_unblocked, task_reviewed, task_cancelled, task_retried --- 协作:comment_added, output_written, observation_added, decision_recorded --- Agent:agent_spawned, agent_completed, agent_zombie_detected --- Session:session_spawned, session_archived, session_cleanup --- 系统:daemon_tick, daemon_manual_tick - --- ===== Agent 注册表 ===== -CREATE TABLE IF NOT EXISTS agents ( - agent_id TEXT PRIMARY KEY, - role TEXT, - current_status TEXT DEFAULT 'idle', -- idle/working/offline - current_task TEXT, - last_active TEXT, - capabilities TEXT -- JSON array: ["coding", "review", "deploy"] -); - --- ===== 任务尝试记录(参考 Hermes task_runs)===== -CREATE TABLE IF NOT EXISTS task_attempts ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - task_id TEXT NOT NULL, - attempt_number INTEGER NOT NULL, - agent TEXT NOT NULL, - outcome TEXT NOT NULL, -- completed/blocked/crashed/timed_out/spawn_failed/reclaimed - exit_code INTEGER, - log_path TEXT, - summary TEXT, - 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' -``` - -**连接配置:** - -```python -def get_connection(): - conn = sqlite3.connect(str(DB_PATH)) - conn.row_factory = sqlite3.Row - conn.execute("PRAGMA journal_mode=WAL") - conn.execute("PRAGMA foreign_keys=ON") - conn.execute("PRAGMA busy_timeout=5000") - return conn -``` - -### 3.3 简化状态机 - -``` -pending → claimed → working → review → done - ↑ │ ├→ blocked ──┘ ├→ failed - │ │ └→ failed └→ cancelled - └─────────┘ - (review→pending: 审核不通过,打回重做) - (blocked→pending: 阻塞解除) - (failed→pending: 重试) -``` - -**与 v2.0 的区别:** v2.0 有 9 个状态(spawning, ready, reporting 等),v2.6 简化为 8 个。原因是 spawn 逻辑从状态机移到了 daemon--daemon tick 发现黑板需要某人介入就 spawn,不需要 spawning/ready 这些中间状态。 - -| 状态 | 含义 | 谁触发 | -|------|------|--------| -| pending | 待领取 | 任何 Agent 或用户创建 | -| claimed | 已认领 | Agent 自己或被指派 | -| working | 执行中 | Agent | -| review | 待审核 | Agent 完成产出 | -| blocked | 需要帮助 | Agent | -| done | 完成 | **审核通过且所有问题达成一致** | -| failed | 失败 | Agent 或 daemon | -| cancelled | 取消 | 用户 | - -**完整合法流转矩阵:** - -```python -VALID_TRANSITIONS = { - "pending": {"claimed", "cancelled"}, - "claimed": {"working", "pending", "cancelled"}, # pending: 放弃认领 - "working": {"review", "blocked", "failed", "cancelled"}, - "review": {"done", "pending", "failed", "cancelled"}, # pending: 审核不通过打回 - "blocked": {"pending", "cancelled"}, # pending: 阻塞解除 - "done": set(), # 终态 - "failed": {"pending"}, # pending: 重试 - "cancelled": set(), # 终态 -} -``` - -### 3.4 原子操作 - -**任务认领(claim)** - 原子 CAS,防止两个人同时领: - -```python -def claim_task(task_id: str, agent_id: str) -> bool: - conn = get_connection() - try: - cursor = conn.execute( - "UPDATE tasks SET status='claimed', assignee=?, claimed_at=datetime('now') " - "WHERE id=? AND status='pending' AND (assignee IS NULL OR assignee=?)", - (agent_id, task_id, agent_id) - ) - conn.commit() - return cursor.rowcount > 0 # 0 表示被别人抢了或不是指定分配给自己的人 - finally: - conn.close() -``` - -**产出写入** - SQLite 事务保证原子: - -```python -def write_output(task_id: str, agent_id: str, output: dict): - conn = get_connection() - try: - conn.execute("BEGIN IMMEDIATE") # 立即获取写锁 - conn.execute( - "INSERT INTO outputs (task_id, agent, output_type, title, content_path, summary, metadata) " - "VALUES (?, ?, ?, ?, ?, ?, ?)", - (task_id, agent_id, output['type'], output['title'], - output['path'], output['summary'], json.dumps(output.get('metadata', {}))) - ) - conn.execute( - "INSERT INTO events (task_id, agent, event_type, detail) VALUES (?, ?, 'output_written', ?)", - (task_id, agent_id, json.dumps({'output_id': output['title']})) - ) - conn.commit() - finally: - conn.close() -``` - -### 3.5 评论线程(讨论机制) - -参考 Hermes 的 `kanban_comment` 模式: - -```python -def add_comment(task_id: str, author: str, body: str, mentions: list = None): - conn = get_connection() - try: - conn.execute( - "INSERT INTO comments (task_id, author, body, mentions) VALUES (?, ?, ?, ?)", - (task_id, author, body, json.dumps(mentions or [])) - ) - conn.execute( - "INSERT INTO events (task_id, agent, event_type, detail) VALUES (?, ?, 'commented', ?)", - (task_id, author, json.dumps({'body_preview': body[:100], 'mentions': mentions})) - ) - conn.commit() - finally: - conn.close() -``` - -**讨论示例:** - -``` -[16:30 庞统] 张飞,你的实现方案我看了,回测数据量大时内存会爆。 - 关羽,从风控角度也看看? @关羽 @张飞 -[16:35 关羽] 同意。建议加分批加载机制,单批不超过 50 万条。 -[16:40 张飞] 收到,改成分批加载。预计 30 分钟。 -[16:55 庞统] @张飞 注意止损逻辑也需要同步改,分批后止损触发时机变了。 -[17:10 张飞] 完成。产出在 output-zhangfei-v2.md。 -``` - -**核心原则:评论都在黑板上,不在任何 agent 的 session 里。Agent 的 session 是临时的。** - -### 3.6 竞态解决 - -任务认领的竞态通过 SQLite 原子 CAS 解决(先到先得)。 - -职责冲突的解决(张飞和关羽都认为自己该做某个任务): -1. **默认:先到先得** - SQLite CAS,谁先 claim 谁做 -2. **升级:庞统仲裁** - 如果争议,评论中 @庞统 请求仲裁 -3. **最终:用户拍板** - @user 请求用户决定 - -不需要复杂的分布式共识--职责分工已经自然避免了大部分冲突。 - -### 3.7 黑板是索引不是仓库(AI Native 内容规范) - -**核心原则:黑板只存元数据 + 摘要 + 文件路径,不存大段文本内容。** - -设计推导(课题 2): -- Network-AI 的核心洞察:Agent 只读黑板摘要,详细数据在文件中 -- Claude Code 的 file reference 模式:不内联,只引用 -- agent-chorus 的 Context Pack 实验证明:结构化上下文让 Agent 文件打开量降 70%、token 消耗降 60%、零生产风险答案 -- Opal-Bridge 的 Fidelity 三档:无损/摘要/混合,传递时按需降档 -- 一个典型任务全量黑板信息 ~1100-1750 tokens,极端 ~4000 tokens——远小于 128K context -- 问题不是空间不够,而是**信号噪声比**:全量注入让 Agent 在无关信息上浪费注意力 - -**AI Native 内容规范——不做硬限制,做软引导:** - -传统做法是给每个字段设长度上限(如 comments.body ≤ 2000 字符),这是 CRUD 应用的思维。 -AI Native 的做法是:Agent 是智能体,有能力判断“这段分析应该写文件还是直接写评论”。规范是指导性的,不是强制性的。 - -- **不做硬限制**——不设字段长度上限,不截断,不报错 -- **做软引导**——Agent 的 Skill 中写“评论应简洁明了,大段分析写文件后在评论中给路径” -- **做传递优化**——L1 传递时自动截取(最近 3 条评论、每条 100 字符),这是传递层面的优化,不是存储层面的限制 -- **做信息分层**——黑板上的 comments 表存完整内容(不截断),但 L1 传递时只取摘要 - -**为什么这样做是 AI Native**: -1. Agent 是智能体,不是 API 客户端——它有能力判断“这段分析应该写文件还是直接写评论” -2. 如果硬限制导致信息丢失,Agent 会绕过限制(拆成多条评论、用文件存储),反而更混乱 -3. 真正需要控制的是传递时的信息量(L1 预算),不是存储时的信息量 - -**黑板上“必要信息”的定义(指导性)**: - -| 类别 | 上黑板 | 不上黑板 | -|------|--------|----------| -| 决策 | ✅ 谁、选了什么、为什么 | ❌ 完整备选方案对比表 | -| 产出 | ✅ title + summary + content_path | ❌ 代码全文、数据文件 | -| 状态 | ✅ 当前 status + 最新 observation | ❌ 完整事件日志(可归档) | -| 讨论 | ✅ 结论 + 关键论据 | ❌ 来回辩论的完整过程 | -| 风险 | ✅ severity + 一句话描述 | ❌ 详细影响分析报告 | - -**防爆炸机制**: -- 产出物只存路径(outputs.content_path) -- 事件日志有 TTL(events 表定期归档旧数据) -- 大段分析建议写文件,黑板只存摘要+路径 - -落地到 schema: -- `outputs` 表:`content_path` + `summary`,不存文件内容 -- `comments` 表:`body` 存完整内容(不截断),大段分析 Agent 自主决定是否写文件 -- `decisions` 表:`decision` + `rationale` 是结构化文本 -- `observations` 表:`body` 是风险描述 - -Agent 获取信息的分层策略(L1/L2/L3)详见 §4.4,对应 Opal-Bridge Fidelity 三档。 - ---- - -## 4. Daemon(管家)设计 - -### 4.1 Daemon 的角色定位 - -> **Daemon 是投递员,不是决策者。所有决策发生在黑板上,daemon 只执行。** - -Daemon 做三件事: -1. **读黑板** - 定期 tick,检查黑板状态 -2. **Spawn Agent** - 根据黑板上的指示,spawn 对应的 agent -3. **清理 Session** - agent 执行完后,存档 jsonl + 清理 sessions.json - -Daemon **不做**: -- ❌ 不决定谁做什么(agent 自己决定或庞统在黑板上分配) -- ❌ 不维护状态机(黑板就是状态) -- ❌ 不做业务逻辑(不解析产出、不做评审) - -**三层执行模型**: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、庞统纠错 | - -关键区别: -- L2 的 sub 是一次性、单任务的("帮我检查这个输出是否在 scope 内"),执行完就退出 -- L3 的 agent 是完整的黑板参与者(读全局、自主决策、写回多个表) - -**L2 与 L3 的区分标准**:是否读黑板全局。 -- L2:不读黑板全局上下文,只拿当前任务的特定字段做判断。spawn 时传递局部数据(如 scope_declaration 文本 + task.truths),sub 返回结果后退出。 -- L3:读黑板全局(tasks + comments + outputs + decisions + observations),做全局决策。spawn 时只传任务 ID + 触发原因,Agent 自己读黑板。 - -这个区分决定了 spawn 时的消息内容--L2 传数据,L3 传指针。 - -### 4.2 双层事件架构(课题 2 设计决策) - -#### D2-1:架构总览 - -> **设计推导**:v2.6 原设计为 60s polling tick,但 @mention 响应延迟、依赖解锁延迟、用户操作无法即时响应等痛点要求事件驱动。open-multi-agent 证明纯 EventEmitter 零基础设施即可实现,Network-AI 证明 file-backed 信号可实现跨进程通知。用户确认"事件驱动这块需要设计完一起实施"。 - -**双层架构**: - -``` -┌──────────────────────────────────────────────────────────────────┐ -│ Daemon (Python asyncio) │ -│ │ -│ Layer 1: EventBus(asyncio.Queue) │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ 进程内事件总线,~0ms 延迟 │ │ -│ │ • task_completed → 解锁下游依赖 + spawn 对应 Agent │ │ -│ │ • task_failed → 触发 retry 链(spawn 庞统) │ │ -│ │ • comment_added → @mention 检测 → spawn 被提及者 │ │ -│ │ • user_action → 即时响应 │ │ -│ │ • task_ready → 依赖满足 → spawn 对应 Agent │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ ↑ │ -│ Layer 2: Signal File Watcher(~500ms) │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Agent(外部进程)写 SQLite 后,同时写 signal file │ │ -│ │ Daemon 每 500ms 扫描 signal 目录 │ │ -│ │ 读取信号 → emit 到 EventBus → 即时处理 │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ ↑ │ -│ Layer 3: Tick(30s 简化版,兜底 + 健康检查) │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ • 僵尸检测、stale 任务回收 │ │ -│ │ • Signal 遗漏先底(万一 signal file 处理失败) │ │ -│ │ • 低优先级事件批量处理(task_created, output_written) │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -└──────────────────────────────────────────────────────────────────┘ -``` - -**不选的替代方案**: -- SQLite update_hook:~0ms 但需要 C API 绑定,且只能在 SQLite 操作时触发 -- Redis pub/sub:引入新依赖,v2.6 已去掉 Redis -- fswatch/watchdog:跨平台兼容性差,signal file 更简单 - -#### 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 | -| `user_action` | 直接 API 调用 | ~0ms | EventBus 即时处理 | -| `task_ready` | EventBus(内部事件) | ~0ms | EventBus 即时:spawn 对应 Agent | -| `task_created` | Signal File | ≤30s | Tick 批量处理 | -| `task_claimed` | EventBus(Daemon 内部) | ≤30s | Tick 批量处理 | -| `output_written` | Signal File | ≤30s | Tick 批量处理 | - -**关键洞察**:真正需要即时响应的场景只有 4 个(task_completed / task_failed / @mention / user_action),其他 60s 延迟完全可接受。 - -#### D2-3:依赖声明的并行/串行自动决策 - -> **设计推导**: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_ready 事件 - → spawn Agent B 执行 task-002 -``` - -**并行**:`depends_on` 为空且 assignee 不同的任务,自然并行(Daemon 分别 spawn)。不需要额外逻辑。 - -**不做 files_modified 冲突检测**(D2-4):Agent 通过黑板评论自然协调("我在改 main.py,你别碰"),不需要系统强制。Scope Guard(课题 1)作为兜底。 - -#### D2-5:Signal File 规范 - -```python -# Agent 操作黑板后写 signal file(CLI 自动完成) -SIGNAL_DIR = Path("~/.sanguo_projects/sanguo_moziplus_v2/signals") - -# Signal file 格式: {event_type}.signal -# 内容: {task_id}:{agent}:{timestamp} -# 示例: task_completed.signal → "task-001:zhangfei-dev:1715750400" - -# Daemon Watcher: 每 500ms 扫描 SIGNAL_DIR -async def watch_signals(): - while True: - for signal_file in SIGNAL_DIR.glob("*.signal"): - payload = signal_file.read_text() - parts = payload.split(":") - event_type = signal_file.stem - await event_bus.emit(Event( - type=EventType(event_type), - task_id=parts[0] or None, - agent=parts[1] or None, - )) - signal_file.unlink() # 处理完删除 - await asyncio.sleep(0.5) -``` - -**关键**:Signal file 写入由 `blackboard.py` CLI 自动完成,Agent 无需额外操作。任何 `blackboard.py` 的写操作(comment/output/claim/status update)都会同步写 signal file。 - -#### 与课题 1 的兼容性 - -| 课题 1 设计 | 事件驱动后变化 | 改善 | -|-----------|--------------|------| -| 续杯机制 | task_completed 事件即时触发依赖解锁 | @mention 从 ≤60s 降到 ≤1s | -| retry 由 AI 决策 | task_failed 事件即时触发 retry 链 | 庞统更快介入 | -| Guardrail 吹哨人 | observation 写入触发 signal file | Daemon 即时感知问题 | -| 三层执行模型 | 不变,事件处理仍按 L1/L2/L3 分层 | ✅ 一致 | - -### 4.3 Session 生命周期 - -``` -1. Daemon spawn - openclaw agent --agent zhangfei-dev --session-id \ - --message "请检查黑板 task-001..." - ↓ -2. Agent 执行 - - 读黑板(SQLite 查询) - - 做任务(编码/审核/数据分析) - - 写回黑板(产出、评论、状态更新) - ↓ -3. Agent 退出(自然结束) - ↓ -4. Daemon 清理 - - mv .jsonl → task-001/archive/ - - mv .trajectory.jsonl → task-001/archive/ - - 编辑 sessions.json 删除该 session 记录 -``` - -**技术验证结论:** -- `openclaw agent --agent --session-id ` 可创建完全隔离的 session ✅ -- 直接编辑 `sessions.json` 可安全删除 session 记录 ✅(已验证) -- Gateway WS `sessions.delete` 需要 `operator.admin` scope(token 模式不授予,不可用)❌ -- 回退方案:直接编辑 `sessions.json` 是安全可靠的 ✅ - -### 4.4 Agent Spawn 的上下文分层传递(课题 2 设计决策) - -> **设计推导**:GSD Wave Execution 证明隔离 session + 新鲜 context > 单一 session + 压缩。Claude Code 的 file reference 模式证明"引用而非内联"是最优策略。问题不是 context 不够大,而是信号噪声比。 - -**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 模板**: - -```python -def build_spawn_message_L1(task_id: str, agent_id: str, trigger: str) -> str: - task = get_task(task_id) - - # 依赖状态摘要(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 字符) - 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 ' (无依赖)'} - -最近评论: -{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-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,安全 | - -### 4.5 续杯与心跳 - -参考 v1.0 实践 + Hermes v0.13 Claim TTL。 - -**正常流(大多数情况):** -1. Agent spawn → 开始工作 -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 | - -**设计推导**: -- v1.0 实践证明:看结果不看过程(即使 CLI 报错/超时,产出文件存在且有效就算成功) -- 续命和重试是两个独立预算:续命(Agent有进度→无限续),重试(Agent真挂→有限次) -- Hermes 的 Claim TTL(默认15分钟)提供了超时回收的参考值 - -**timeout 的检测**:timeout 信号来自 `openclaw agent --agent ` 的返回值(阻塞调用)。Agent 在执行过程中通过写黑板 observations 维持活跃信号--Daemon tick 检查 observations 的最后写入时间,如果有新 observation 说明 Agent 还在工作。但最终判断 Agent 是否超时,以 agent run 的返回值为准。 - -reminder 后的硬时间上限:reminder 后如果超过 `estimated_duration_minutes` 仍未完成(从 reminder 时间算起),才回收任务。 - -### 4.6 AI 驱动的 Retry(纠错协商) - -参考 v1.0 _handle_blocked_node() + Hermes task_runs + Claude Code Teams "before retrying, answer what failed"。 - -**核心原则**:Retry 原因由 AI 判断,Daemon 只执行。 - -**流程:** - -1. Agent 失败(产出 status=failed 或 Daemon 检测到异常终止) -2. Daemon 不判断原因,只在黑板上记录这次 attempt(task_runs 模式,每次 attempt 独立记录) -3. Daemon spawn 庞统(L3)看黑板上的失败记录 + 之前所有 attempts -4. 庞统在黑板上写决策(四种选择之一): - - "同一 Agent 重试" + 失败原因分析 + 改进建议 - - "换 Agent 重试" + 为什么换 + 新 Agent 优势 - - "任务需要用户介入" + 卡在哪 + 建议 - - "任务无法完成,建议取消" + 为什么 -5. Daemon 读庞统决策,执行对应操作 -6. 如果重试后仍失败 → 新 attempt 记录 → 再次 spawn 庞统 -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) | - -**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),可追溯可审计 - -### 4.7 Guardrail 体系(吹哨人机制) - -参考 OpenAI Agent SDK OutputGuardrail + GSD must_haves + v1.0 M4 Guard 机制。 - -**核心原则**:Guardrail 是吹哨人不是终结者。检测到问题写黑板(observation),触发后续 AI 判断链。决策权在黑板上,执行权在 Daemon。 - -**三个 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 | -| **Format Guard** | Agent 写任何结构化数据时 | L1 JSON Schema 校验 | 格式错误直接打回重做 | - -**后续动作链(问题升级):** - -``` -Guardrail 检测到问题 → 写黑板 observation - ↓ -Daemon tick 读到 observation - ↓ -根据 severity 分级处理: - - blocking → L3 立即 spawn 庞统 - - warning → L3 spawn 庞统(下次 tick 统一处理) - - info → 只记录,不触发 - ↓ -庞统在黑板上写决策: - - "确认偏离,打回" → Daemon 改状态回 pending - - "方向扩展合理,批准继续" → 继续 - - "需要用户判断" → 通知用户 -``` - -**设计推导**: -- 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 阶段仍会检查方向正确性 - ---- - -## 5. Agent 与黑板的交互 - -### 5.1 Agent 被_spawn_后的工作流程 - -``` -Agent 被 spawn - ↓ -1. 读黑板 → 了解任务全局状态 - - 读 tasks 表:当前任务的状态、描述、依赖 - - 读 comments 表:讨论历史 - - 读 outputs 表:已有产出 - - 读 observations 表:已知风险 - ↓ -2. 想 → 根据自己的职责自主决策 - - 我是编码先锋,这个 pending 任务适合我 → claim - - 我是风控守将,这个 comment @ 我 → 回复 - - 我是副军师,这个任务需要分解 → 创建子任务 - - Agent claim 任务后、开始工作前,写 scope_declaration 到 decisions 表: - "我计划做什么,产出什么" - Scope Guard(L2 sub)会对比 scope_declaration vs task.truths - ↓ -3. 做 → 执行任务 - - 编码、审核、数据分析等 - - 过程中发现风险 → 写 observation - - 需要其他人协助 → 写 comment @mention - ↓ -4. 写回黑板 → 产出、评论、状态更新、决策记录 - - 写 outputs 表:产出文件路径 + 摘要 - - 写 comments 表:完成说明 - - 写 decisions 表:关键决策(哪怕自己的决策也要填一条) - - 更新 tasks 表:status → done/review - - must_haves 三件套(任务创建时由庞统定义): - - truths:用户视角的可观测行为("用户能看到回测结果"),不是实现步骤("编写回测脚本") - - artifacts:必须存在的产出文件 - - constraints:继承的约束(如"不超过500行"、"必须用vnpy") - ↓ -5. 退出 → daemon 自动清理 session -``` - -### 5.2 Agent 工具集 - -Agent 通过 `exec` 工具调用 CLI 命令操作黑板: - -```bash -# 读黑板(全部) -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py read --task task-001 - -# 读黑板(过滤:只读和自己相关的) -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py read --task task-001 --agent zhangfei-dev - -# 读黑板(过滤:只读最近 20 条) -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py read --task task-001 --last 20 - -# 读黑板(过滤:只读特定类型) -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py read --task task-001 --type comments - -# 认领任务 -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py claim --task task-001 --agent zhangfei-dev - -# 写产出 -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py output --task task-001 --agent zhangfei-dev \ - --type code --title "分批加载实现" --path task-001/output-zhangfei.md \ - --summary "实现分批加载,单批50万条" - -# 写评论 -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py comment --task task-001 --author zhangfei-dev \ - --body "完成分批加载实现" --mentions "[]" - -# 写观察 -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py observe --task task-001 --observer guanyu-dev \ - --severity warning --body "止损逻辑需适配分批模式" - -# 记录决策 -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py decide --task task-001 --decider zhangfei-dev \ - --decision "使用分批加载而非流式" --rationale "流式需要改底层框架,分批只需改回测模块" - -# 创建任务(任何 Agent 都可以创建) -python3 ~/.sanguo_projects/sanguo_moziplus/cli/blackboard.py create --title "分钟线数据下载" \ - --creator zhaoyun-data --task-type data -``` - ---- - -## 6. 关键场景流程 - -### 6.1 庞统规划 + Agent 领任务(事件驱动版) - -``` -用户 → 庞统(主session):"设计一个动量因子策略" - ↓ -庞统在黑板上写: - - 创建 task-001(数据准备,pending,无依赖) - - 创建 task-002(因子计算,pending,depends_on: [task-001]) - - 创建 task-003(回测验证,pending,depends_on: [task-002]) - - 评论:"建议赵云领 001,张飞领 002 和 003" - ↓ -庞统写 signal file: task_created - ↓ -Daemon EventBus 收到 task_created(低优先级) - → Tick 批量处理: spawn 赵云通知 task-001 - ↓ -赵云读黑板 → claim task-001 → 执行 → 写产出 → 更新 status→done - → 写 signal file: task_completed - ↓ -Daemon EventBus 即时收到 task_completed - → 查询 depends_on 包含 task-001 的 pending 任务 → task-002 - → task-002 的依赖全部满足 → 触发 task_ready - → spawn 张飞执行 task-002 - ↓ -(同理 task-002 done → 即时触发 task-003) -``` - -**对比 polling 版**:task-001 done 到 task-002 spawn 的延迟从 ≤60s 降到 ~0ms。 - -### 6.2 Agent 间协作讨论(事件驱动版) - -``` -张飞执行 task-002 时发现需要分钟线数据 - ↓ -张飞写评论:"@赵云 task-002 需要分钟线数据,能帮忙下载吗?" -张飞更新任务状态 → blocked - → 写 signal file: comment_added - ↓ -Daemon EventBus 即时收到 comment_added - → 解析 @mention → 赵云 - → spawn 赵云(L1 消息含评论摘要) - ↓ -赵云读黑板 → 看到评论 → 下载数据 → 写产出 -赵云写评论:"@张飞 数据就绪,可以继续" - → 写 signal file: comment_added - ↓ -Daemon EventBus 即时收到 → @mention → spawn 张飞 - ↓ -张飞读黑板 → 看到数据就绪 → 继续 task-002 -``` - -**对比 polling 版**:@mention 响应从 ≤60s 降到 ≤1s。 - -### 6.3 Agent 发现风险 - -``` -张飞在 task-002 中发现止损逻辑有 bug - ↓ -张飞写 observation(severity: warning): - "止损逻辑在分批模式下可能漏触发" -张飞写评论:"@关羽 止损逻辑需要你从风控角度确认" - ↓ -Daemon tick 发现 observation + 评论 @ 关羽 - ↓ -Daemon spawn 关羽 → 关羽读黑板 → 审查 → 写评论 + observation -``` - -### 6.4 用户直接参与 - -``` -用户读黑板 → 发现 task-002 进度慢 - ↓ -用户在黑板上写评论:"task-002 优先级提高,需要今天完成" - ↓ -Daemon tick 发现用户评论 → 如果张飞未 active → spawn 张飞通知 -``` - ---- - -## 7. Session 隔离与清理 - -### 7.1 技术实现 - -```python -class SessionManager: - def async_spawn_agent(self, agent_id: str, message: str) -> str: - """异步 spawn 隔离 session,不等待完成。返回 session_id。""" - session_id = str(uuid.uuid4()) - cmd = [ - "openclaw", "agent", - "--agent", agent_id, - "--session-id", session_id, - "--message", message, - "--json" - ] - # Popen 异步启动,不阻塞 daemon tick - subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - log_event(agent=agent_id, event_type='agent_spawned', detail={'session_id': session_id}) - return session_id - - def cleanup_session(self, agent_id: str, session_id: str, archive_dir: str): - """存档 jsonl + 文件锁保护下清理 sessions.json""" - sessions_dir = f"/Users/chufeng/.openclaw/agents/{agent_id}/sessions" - store_path = f"{sessions_dir}/sessions.json" - lock_path = f"{sessions_dir}/.cleanup.lock" - - # 1. 存档 jsonl 文件 - os.makedirs(archive_dir, exist_ok=True) - for ext in ['.jsonl', '.trajectory.jsonl', '.trajectory-path.json']: - src = f"{sessions_dir}/{session_id}{ext}" - if os.path.exists(src): - shutil.move(src, f"{archive_dir}/{session_id}{ext}") - - # 2. 文件锁保护下编辑 sessions.json(防止和 Gateway 并发写入冲突) - with open(lock_path, 'w') as lock_file: - fcntl.flock(lock_file, fcntl.LOCK_EX) - try: - with open(store_path) as f: - store = json.load(f) - - keys_to_remove = [k for k in store if session_id in k] - for k in keys_to_remove: - del store[k] - - with open(store_path, 'w') as f: - json.dump(store, f, indent=2) - finally: - fcntl.flock(lock_file, fcntl.LOCK_UN) - os.unlink(lock_path) -``` - -### 7.2 验证结论 - -| 验证项 | 结果 | -|--------|------| -| `openclaw agent --session-id ` 创建隔离 session | ✅ 通过 | -| 连续 spawn 多个 session 互不干扰 | ✅ 通过 | -| 并行 spawn 成功 | ✅ 通过 | -| 直接编辑 sessions.json 删除记录安全 | ✅ 通过 | -| jsonl 存档后从原目录删除 | ✅ 通过 | -| Gateway WS sessions.delete(需 admin scope) | ❌ 不可用 | -| `openclaw sessions cleanup --fix-missing --enforce` | ❌ 对 agent main session 报错 | -| Agent 主 session 对 CLI spawn 的 sub 完全无感 | ✅ 确认(设计如此)| - ---- - -## 8. Sanguo Mail:退役 - -v2.6 中 Mail 完全退役。黑板的两个操作替代了 Mail 的所有功能: - -| Mail 功能 | 黑板替代 | -|----------|--------| -| 庞统分配任务 | 庞统在黑板创建 task + 评论 @指定 agent | -| Agent 间通信 | 评论 @mention | -| 结果回传 | 产出写入 outputs 表 + 评论通知 | -| 讨论 | 评论线程 | - -黑板比 Mail 更可靠:信息集中在 SQLite(不分散在 mail 目录)、有状态追踪、评论线程保持上下文完整、SQLite 读写比 Mail poller 更可靠。 - -如果需要系统级通知(daemon 异常、Gateway 状态),在黑板上创建 `system` 类型任务处理。 - ---- - -## 9. 质量门控(任务完成标准) - -### 9.1 任务完成 = 司马懿评审通过 + 所有问题达成一致 + 修改完成 - -一个任务要标记为 `done`,必须满足: - -1. **产出已提交** - Agent 写入 outputs 表 -2. **决策已记录** - 关键决策写入 decisions 表(哪怕是自己的决策也要填一条) -3. **司马懿审核通过** - spawn 司马懿审核产出,评论中明确写"通过" -4. **所有问题达成一致** - 审核中提出的问题全部解决,讨论达成共识 -5. **修改已完成** - 审核问题对应的修改已写入产出 - -### 9.2 达成一致的原则 - -- **以用户意图为导向** - 任何人(包括司马懿、庞统)说的都不一定对,最终以用户的原始意图为准 -- **讨论达成共识** - 不同意见通过黑板评论讨论解决,不是谁职位高谁说了算 -- **用户有最终裁量权** - 讨论无法达成一致时,@user 请用户裁定 - -### 9.3 流程 - -``` -Agent 完成产出 → status: review - ↓ -Daemon tick → spawn 司马懿审核 - ↓ -司马懿读黑板(产出 + 决策 + 观察) - ↓ -司马懿写评论: - - "通过" → status: done - - "不通过,原因:XXX" → status: pending(打回重做)+ 评论说明问题 - ↓ -如果有争议: - - 评论中讨论 - - 讨论不清 → @user 请求裁定 -``` - -### 9.4 决策记录 - -Agent 执行过程中的每个关键决策都必须记录在黑板的 decisions 表中: - -| 字段 | 含义 | -|------|------| -| decider | 谁做的决策 | -| decision | 决策内容(选了什么) | -| rationale | 为什么这样选 | -| alternatives | 被排除的选项 | - -**哪怕是自己做的决策也要填一条。** 目的: -- 后续复盘时能追溯"当时为什么这样选" -- 审核时司马懿能理解决策背后的思考 -- 经验沉淀的原始素材 - -### 9.5 分级审查矩阵 - -不是所有任务都值得同等深度的审查。按任务风险等级决定审查深度。 - -| 风险等级 | 任务类型 | 审查深度 | 参与者 | -|---------|---------|---------|--------| -| **高风险** | 量化策略、生产部署、数据删除 | 三阶段审查(方案审查→Output Guardrail→产出审查)+ 可选多视角对抗 | 庞统+司马懿+对应执行者 | -| **标准** | 编码、数据处理、配置修改 | 二阶段(Output Guardrail + 产出审查) | 司马懿+执行者 | -| **低风险** | 调研报告、文档更新、日志查看 | 一阶段(Output Guardrail 机械检查) | Daemon 自动 | -| **调研** | 技术调研、方案探索 | 一阶段(庞统确认方向) | 庞统 | - -**风险等级**:庞统创建任务时标注。默认值为 `standard`。庞统的 Skill 中内置规则:创建 task_type 为 `strategy` 或 `deploy` 的任务时自动设为 `high`,`research` 类型自动设为 `research`。无需庞统手动判断。 - -**设计推导**: -- v1.0 实践:每个节点都要司马懿审查,简单任务过重 -- superpowers:三阶段审查(implementer → spec reviewer → code quality reviewer),不同阶段不同深度 -- Hermes:per-task retry budget,任务级别差异化 - ---- - -## 10. 产出物目录约定 - -``` -~/.sanguo_projects/sanguo_moziplus/artifacts/ -└── {task-id}/ - ├── outputs/ # Agent 产出物(代码、文档、数据) - ├── archive/ # session jsonl 存档 - └── data/ # 数据文件 -``` - -Agent 写产出时,`content_path` 指向此目录。Daemon 存档 session jsonl 时也写入 `archive/` 子目录。 - ---- - -## 11. 保留 v2.0 的设计 - -以下 v2.0 的设计在 v2.6 中保留: - -1. **SQLite WAL 模式** - 黑板数据库同样使用 WAL -2. **结构化产出规范** - output.md frontmatter + 结论 JSON(写在黑板 outputs 表中) -3. **观察机制** - v2.0 Report Watcher 的思路升级为 observations 表 -4. **证据原则** - 结论必须有证据(代码行号、日志、文件内容) -5. **审核流程** - 可通过黑板评论 + 状态机实现 - ---- - -## 12. Phase 规划(v2.6) - -### Phase 1: 黑板基础设施 -1. SQLite blackboard.db(5 表 + WAL) -2. blackboard.py CLI(读写操作 + signal file 写入) -3. Daemon 核心循环(EventBus + Signal File Watcher + Tick 兜底) -4. Session 管理(spawn + 存档 + 清理) -5. L1 spawn message 模板 - -### Phase 2: 事件驱动 + Agent 交互 -6. Agent 黑板操作 Skill -7. EventBus 即时处理(task_completed → 解锁下游、@mention → spawn) -8. 任务依赖自动推进(complete→auto-unlock) -9. 评论 + @mention 通知链路(即时版) -10. 健康检查(stale reclaim + zombie 检测) -11. L2/L3 分层读取 API(blackboard.py read --level) - -### Phase 3: 智能化 -12. 庞统 AI 规划(读需求 → 创建任务 + 分配建议 + must_haves) -13. Agent 自主领活(读黑板 → 匹配职责 → claim + scope_declaration) -14. 产出验证门禁(Output Guard + Scope Guard) -15. AI 驱动 Retry + Circuit breaker -16. 经验沉淀(observation → knowledge base) - ---- - -## 13. 技术选型 - -| 需求 | 参考系统 | 我们的方案 | 理由 | -|------|---------|-----------|------| -| 共享状态 | Hermes SQLite + Network-AI flock | SQLite WAL + 事务 CAS | 原子性 + 无外部依赖 | -| 讨论 | Hermes kanban_comment | comments 表 + @mention | 简单追加写入,所有人可见 | -| 事件驱动 | open-multi-agent EventEmitter | asyncio.Queue EventBus + Signal File | 零基础设施,进程内 ~0ms,跨进程 ~500ms | -| 调度 | Hermes Dispatcher 60s tick | EventBus 即时 + Signal File + 30s Tick 兜底 | 即时响应 + 健康检查 | -| 上下文传递 | GSD Wave Execution + Claude Code file ref | L1 必传 + L2/L3 按需读取 | 信号噪声比优化 | -| 通知 | Claude Code idle notification | Daemon spawn + L1 message | OpenClaw 原生能力 | -| 通信 | Hermes kanban_comment + Claude Code inbox | 黑板 comments + @mention | 替代 Sanguo Mail | -| 竞态 | Network-AI propose→validate→commit | SQLite CAS(first-commit-wins) | SQLite 事务足够 | -| Session | Hermes process-per-worker | openclaw agent --session-id | OpenClaw 原生隔离 | -| 清理 | 无参考 | 编辑 sessions.json | 已验证可行 | - ---- - -## 14. 风险和缓解 - -| 风险 | 概率 | 缓解 | -|------|------|------| -| Agent 上下文不足(隔离 session 没有历史)| 中 | spawn 时传递黑板关键信息 + agent 可主动读黑板 | -| Daemon 单点故障 | 低 | PM2 自动重启 + tick 无状态 | -| SQLite 并发写入 | 中 | WAL + busy_timeout + BEGIN IMMEDIATE | -| 黑板膨胀(大量评论/产出)| 低 | 定期 archive + agent 只读最近 N 条 | -| Agent 不知道该做什么 | 中 | Skill 指导 + 庞统 plan 评论 + daemon 消息含上下文 | -| Sanguo Mail 退役后的系统通知 | 低 | 黑板 system 类型任务替代 |