# #04 黑板协作模型设计 > 版本: v1.1 > 日期: 2026-05-30 > 作者: 庞统(副军师) > 状态: ✅ 已完成(@mention + mention_queue 已实现) > 前置: #02 Main Session + Delegation, #03 Prompt 进化 --- ## 一、问题陈述 当前黑板有 7 种信息类型(Task/Comment/Output/Event/Review/Decision/Observation),全部通过 `task_id` 平铺关联。E2E 测试暴露了三个设计缺陷: ### 问题 1:assignee 和 @mention 功能重叠 | 机制 | 触发方式 | 路由行为 | |------|---------|---------| | assignee 字段 | 创建任务时传 `assignee: "zhangfei-dev"` | 确定性路由 | | @mention | Comment 中 `mentions: ["zhaoyun-data"]` | mention_queue → spawn | **问题**:两者都能触发"找人做事",语义不同但边界模糊。 - Agent 不知道什么时候用 assignee,什么时候用 @ - assignee 是单人的,但任务可能需要多人协作 - @mention 需要额外传 `mentions` 数组,容易遗漏 ### 问题 2:一个任务只能有一个 assignee 当前 `assignee` 是单个字符串。但现实中: - 一个数据准备任务可能需要赵云(获取)+ 关羽(风控审核) - 一个部署任务可能需要姜维(部署)+ 关羽(安全检查) - 庞统创建子任务时需要同时指定多人 ### 问题 3:信息组织是平铺的,缺乏结构化视图 当前 `expand=all` 只展开当前 task 的子表,不递归子任务。用户想看"数据准备子任务的所有 comments 和成果物",需要: 1. 先查父任务,找到子任务 ID 2. 再逐个查每个子任务的 `expand=all` 信息之间的关联(比如 Output #3 是 Comment #2 的结果)无法表达。 --- ## 二、优秀实践调研 ### 2.1 项目管理工具的共识 **Jira / Linear / Asana 共同模式**: | 洞察 | 来源 | 启示 | |------|------|------| | 单表存所有任务 + 类型字段区分 | Jira `issuetype` | 不需要为不同任务类型建不同表 | | `parent_id` + `topmost_id` 实现层级 | Jira | 父子关系用指针,不是嵌套 | | Project 是逻辑隔离边界 | Jira/Linear | 一个 Project 一个黑板 DB | | 一个 Task 可属于多个 Project | Asana | 多对多关系(cross-project) | ### 2.2 AI Agent 编排系统的共识 **LangGraph / CrewAI / AutoGen 共同模式**: | 洞察 | 来源 | 启示 | |------|------|------| | 子任务隔离 + 结果摘要回传 | LangGraph Subgraph | 子任务有独立状态,完成后折叠 | | 共享 Memory + Crew 边界 | CrewAI | 同一 Crew 共享记忆 | | 对话历史即上下文 | AutoGen | 不需要额外机制,消息本身就是上下文 | | 扁平 Handoff + Context Variables | OpenAI Swarm | 最简模型,适合简单场景 | ### 2.3 学术和实践前沿 | 洞察 | 来源 | 启示 | |------|------|------| | **共享产出物 > 共享消息** | O'Reilly 2026 | 围绕 artifact 协作,不是围绕消息 | | **Phase gates + shared artifacts + final supervisor** | O'Reilly 2026 | 2026 存活系统的共同特征 | | **共享工作区 + 结构化产出 > 消息传递** | Claude Code 实践 | 文件系统 + JSON 接口 | | **对话历史传递 surprisingly effective** | OpenAI Handoff | 转交时携带完整上下文 | | **bMAS 迭代收敛到共识** | arXiv:2507.01701 | Agent 轮流行动直到黑板达成共识 | | **propose→validate→commit 原子写入** | Network-AI | 消除 split-brain | | **Auftragstaktik 任务式指挥** | ClawTeam #10 | Intent→End State→Constraints,不指定步骤 | ### 2.4 核心设计原则(从调研提炼) 1. **黑板是唯一真相源** — 所有 Agent 通过黑板共享信息 2. **产出物 > 消息** — 围绕共享产出物协作,不是围绕消息传递 3. **结构对称** — 不把任何 Agent 当"主",Canonical IR 原则 4. **单一职责** — 每种信息类型只表达一件事 5. **可追溯** — 不可变事件日志,写入即审计 6. **任务式指挥** — Intent→End State→Constraints,Agent 自主决定怎么做 --- ## 三、设计方案 ### 3.1 统一路由:assignee 降级为显示字段,路由统一走 @mention **核心决策**:保留 `assignee` 字段作为「负责人」显示字段,但路由触发统一走 @mention。 | 之前 | 之后 | |------|------| | 创建任务传 `assignee` → 确定性路由 | 创建任务时在 description 中 `@zhangfei-dev` → daemon 自动推断 assignee + 路由 | | Agent 不知道用 assignee 还是 @mention | 只有一种路由入口:@ | | assignee 是单人的 | @ 可以 @ 多人 | **为什么保留 assignee 字段(不取消)**: 1. **前端展示**:「这个任务谁负责」是刚需 2. **Mail 特殊处理**:Mail 的 assignee 是收件人,不能取消 3. **向后兼容**:存量任务已有 assignee 值 4. **查询效率**:`WHERE assignee=?` 比扫描 description 中的 @ 快 **assignee 从「路由入口」变为「路由结果」**: - API 调用方不再直接设置 assignee(废弃) - daemon 从 description/comment 中的 @mention 自动推断 assignee - router 快速路径保持不变(仍然读 assignee 字段,只是赋值来源变了) #### 迁移方案 **阶段 1(#04 Phase 1)**:双轨并行 - 创建任务时仍接受 `assignee` 参数(向后兼容,标记为 deprecated) - 新增:daemon 从 description 中提取 @mention → 如果有匹配 → 自动覆盖 assignee - router 快速路径保持不变(读 assignee 字段路由) - 无 assignee 且无 @mention → 广播认领 **阶段 2(#04 Phase 2)**:全面切换 - API 不再接受 `assignee` 参数(返回 deprecation warning) - assignee 完全由 daemon 从 @mention 推断 - router 快速路径不变(仍然读 assignee 字段,只是赋值来源变了) **阶段 3(未来)**:清理 - 移除 API 的 assignee 参数 - 存量任务:assignee 值保留不动(已经是正确的负责人信息) **代码影响评估**: | 文件 | 影响 | 改动 | |------|------|------| | router.py L155-160 | assignee 快速路径 | ✅ 保持不变(仍然读 assignee 字段) | | dispatcher.py L427-446 | assignee 作为 dispatch 依据 | ✅ 保持不变 | | ticker.py _transition_status | pending 时清空 assignee | ✅ 保持不变 | | API POST /tasks | 接受 assignee 参数 | Phase 1 保留,Phase 2 废弃 | | ticker.py _tick_project | 新增:创建后扫描 description 提取 @mention | 新代码 | **API 变化**: ```python # Phase 1:两种方式都支持,@mention 优先 POST /tasks { "title": "写 hello.py", "description": "@zhangfei-dev 写一个 hello.py" } # daemon 自动提取 assignee=zhangfei-dev # 也可以旧方式:assignee="zhangfei-dev"(deprecated) # Phase 2:只用 @mention POST /tasks { "title": "写 hello.py", "description": "@zhangfei-dev 写一个 hello.py" } ``` ### 3.2 @mention 语义增强 **当前问题**:Comment 需要**同时**写 `body` 中的 `@zhaoyun-data` **和** `mentions` 数组。Agent 容易遗漏。 **改进方案**:daemon 自动从 `body` 中提取 `@Agent` 模式,自动填充 `mentions`。 ```python # Agent 只需要写 body POST /comments { "author": "pangtong-fujunshi", "body": "@zhaoyun-data 你来获取沪深300行情数据,@guanyu-dev 数据到了你做风控检查" } # daemon 自动提取 → mentions: ["zhaoyun-data", "guanyu-dev"] # 写入 mention_queue → 两人都收到 mention spawn ``` **提取规则**(D4 决策:只支持 @agent-id 格式): - 正则 `@([a-z]+-[a-z]+-[a-z]+)` 匹配已知 Agent ID 列表 - 匹配到的 Agent 写入 `mentions` 字段(如果前端也传了 `mentions`,取并集) - 不认识的 @ 目标忽略(可能是 @文档 @链接) - **不支持中文昵称**(@张飞)—— agent-id 是系统唯一标识,无歧义。未来如需支持,加 alias 映射即可 ### 3.3 多人协作模式 @ 多人 ≠ 多人同时执行同一任务。而是**每人收到 mention spawn,自主协调**: | @ 模式 | 含义 | Daemon 行为 | |--------|------|------------| | `@zhangfei-dev` | 指定张飞做这个任务 | 确定性路由给张飞 | | `@zhaoyun-data @guanyu-dev` | 需要两人协作 | 创建两个子任务,分别路由 | | `@所有人` | 不知道谁合适 | 广播认领 | | 无 @ | 不需要特定人 | 广播认领 | **@多人 → 自动拆子任务**(Phase 2,暂不实现): ``` 庞统创建任务:@zhaoyun-data 获取数据,@zhangfei-dev 写策略代码 Daemon 自动拆解: ├── 子任务 1: 获取数据 → assignee: zhaoyun-data └── 子任务 2: 写策略代码 → assignee: zhangfei-dev, depends_on: [子任务 1] ``` Phase 1 只做:@多人 → 每个人收到 mention spawn,各自决定如何协作。 ### 3.4 信息关联模型重构 **当前**:7 种信息平铺挂在 `task_id` 上,互相之间无关联。 **改进**:引入 `parent_id` 串联信息流。 #### Output 关联 Comment ```python # 当前 POST /outputs {agent, content_type, summary} # 产出物和讨论没有关联 # 改进:output 关联到触发它的 comment POST /outputs { agent: "zhaoyun-data", content_type: "data", summary: "沪深300日频行情", triggered_by_comment: 42 # ← 新字段,关联到 @赵云 的那条 comment } ``` #### 反向索引 ```sql CREATE INDEX IF NOT EXISTS idx_outputs_triggered_by ON outputs(triggered_by_comment); ``` 支持查询「这条 comment 触发了哪些 outputs」。 #### Review 关联 Output 当前 `Review.output_id` 已有关联,保持不变。 #### 信息流视图 ``` Comment #1: "@zhaoyun-data 获取沪深300行情" └── mention_queue → spawn 赵云 └── Comment #2: "数据已获取,见附件" └── Output #1: content_path=/data/market.csv, triggered_by_comment=#1 └── Review #1: verdict=approved, output_id=#1 ``` ### 3.5 层级查询 API **当前痛点**:想看"数据准备子任务的所有信息"需要多次查询。 **改进**:新增聚合查询 API(D3 决策:Phase 2 实施,含子任务的完整版 Phase 3)。 #### Phase 2:单任务 timeline ``` GET /api/projects/{pid}/tasks/{task_id}/timeline?limit=50&offset=0 返回: { "task": {...}, "timeline": [ { "task": {...}, "comments": [...], "outputs": [...], "reviews": [...] } ], "timeline": [ {"ts": "...", "type": "comment", "author": "pangtong", "body": "@zhaoyun-data ..."}, {"ts": "...", "type": "mention", "agent": "zhaoyun-data", "status": "notified"}, {"ts": "...", "type": "status", "from": "pending", "to": "claimed"}, {"ts": "...", "type": "comment", "author": "zhaoyun-data", "body": "数据已获取"}, {"ts": "...", "type": "output", "agent": "zhaoyun-data", "summary": "沪深300行情"}, {"ts": "...", "type": "review", "verdict": "approved"} ], "total": 42, "has_more": true } ``` - 只聚合当前任务(不含子任务)的 comments + outputs + reviews + events + mentions - 支持 `limit` + `offset` 分页 - 按 `created_at` DESC 排序 #### Phase 3:含子任务的完整 timeline 聚合子任务信息,考虑 materialized view 或 cache 优化性能(WARN-3)。 --- ## 四、实施计划 ### Phase 1(与 #02/#03 一起验证) | 改动 | 影响 | |------|------| | daemon 自动从 body 提取 @mention | Agent 不再需要手动传 `mentions` 数组 | | claim prompt 补充完整 API(RC-2) | Agent 知道怎么写产出物 | | assignee 保留但降级为显示字段 | 向后兼容 | ### Phase 2(#04 独立实施) | 改动 | 影响 | |------|------| | 创建任务时从 description 提取 @ → 自动 assignee | 统一路由入口 | | API assignee 参数废弃(返回 deprecation warning) | 向后兼容过渡 | | @mention 自动提取(blackboard_routes.py) | Agent 不再需要手动传 mentions | | Output 新增 triggered_by_comment 字段 + 索引 | 信息关联 | | /timeline 聚合查询 API(单任务版) | 结构化视图 | ### Phase 3(未来) | 改动 | 影响 | |------|------| | @多人自动拆子任务(LLM 辅助) | 复杂协作 | | @所有人 广播语法 | 统一广播入口 | | /timeline 含子任务完整版 + materialized view | 全景视图 | | Context Folding(子任务完成后折叠) | 上下文管理 | | Fidelity 三档信息路由 | 按 Agent 角色分档展示 | --- ## 五、设计决策(已确认) | # | 决策 | 结论 | 理由 | |---|------|------|------| | D1 | assignee 是否完全取消? | **保留为显示字段,路由统一走 @mention** | 前端展示/Mail/向后兼容/查询效率 | | D2 | @多人 Phase 1 是否自动拆子任务? | **不自动拆,Phase 3 再做** | daemon 无法可靠推断依赖关系 | | D3 | timeline API 是否 Phase 1 就做? | **Phase 2 做(单任务版)** | 先让 E2E 跑通 | | D4 | @ 模式支持中文昵称? | **只支持 @agent-id** | 无歧义,低维护成本 | --- ## 附录:调研来源 - Jira 数据库设计(单表 + issuetype + parent_id) - Linear/Asana 层级模型(Workspace 隔离 + 逻辑分组) - LangGraph Subgraph 模式(子任务隔离 + State 映射回传) - CrewAI 共享 Memory(Crew 边界) - bMAS 黑板架构(Control Unit 动态路由 + 迭代收敛) - O'Reilly 2026(共享产出物 > 共享消息 + Phase gates) - OpenAI Handoff(对话历史传递 surprisingly effective) - Network-AI(propose→validate→commit 原子写入) - ClawTeam #10(Auftragstaktik 任务式指挥) - Opal-Bridge(Canonical IR + Fidelity 三档)