# 调研报告：事件驱动架构 + 上下文管理策略

**版本**: v1.0
**作者**: 庞统（副军师）
**日期**: 2026-05-15
**范围**: moziplus v2.6 AI Native DevOps 平台

---

## 课题 2：事件驱动架构 + 并行/串行决策

### 1. 已有经验（知识库/wiki）

在 `~/.openclaw/sanguo_projects/sanguo_moziplus/docs/design/` 中有完整的架构设计文档：

| 文档 | 关键内容 |
|------|----------|
| `architecture-v2.6.md` | 当前 v2.6 使用 60s polling tick 轮询黑板，Daemon tick 读取黑板状态→发现需要介入的→spawn agent |
| `technical-design-v2.6.md` | Daemon ticker.py 实现了 tick 循环主逻辑，含 @mention 解析、session 管理、健康检查 |

**当前痛点**：
- Agent 被 @mention 后最多等 60 秒才知道（polling 间隔）
- Daemon tick 是重量级操作（读全量黑板、检查所有任务、处理所有 mention）
- 没有即时响应能力，用户紧急操作只能靠手动触发 tick

### 2. 业界优秀实践对比表

| 项目 | 通知机制 | 事件类型 | 依赖解析 | 并行/串行决策 | 亮点 |
|------|----------|----------|----------|--------------|------|
| **open-multi-agent** | 事件驱动 TaskQueue（`task:ready` 事件自动触发下游） | `task:ready`, `task:complete`, `task:error` | 拓扑排序（topological sort），complete→自动解锁下游 pending 任务 | **依赖声明驱动**：depends_on 声明后自动判断并行/串行 | 3 个运行时依赖，零基础设施，纯 TypeScript EventEmitter |
| **Network-AI** | 原子黑板信号（propose→validate→commit + file-backed mutex） | `propose`, `validate`, `commit`, `rollback` | 无显式依赖图，通过原子提交保证一致性 | Agent 自行判断并行（信号锁机制防竞态） | 零外部依赖，251 个测试，12 框架适配器 |
| **Hermes Kanban** | Dispatcher 60s polling tick（与 v2.6 相同） | 状态变化 + comment + mention | 7 状态完整状态机 | Dispatcher 调度决定并行/串行 | 成熟稳定，但同样受限于 polling 延迟 |
| **Claude Code Agent Teams** | 共享任务列表 + 直接消息（SendMessage tool） | `task:claimed`, `task:completed`, message | 无显式依赖图 | Agent 自主认领（先到先得） | 每个 agent 独立 1M token context window，通过消息通信 |
| **GSD (Get-Shit-Done)** | Wave-based 执行，阶段式推进 | Plan 级事件（phase complete） | Plan 中声明 `depends_on` 和 `wave` 编号 | **Wave 执行**：同 wave 并行，跨 wave 串行 | 每个 executor 独立 200K token 新鲜上下文，消除 context rot |
| **Confluent 事件驱动模式** | Kafka 事件流 | `AgentTaskSubmitted`, `AgentResultPublished` | DAG 依赖声明 | Event Router 根据依赖图路由 | 4 种模式：链式、广播-聚合、动态路由、竞技 |
| **Azure Agent Patterns** | 多种：顺序/并发/群聊/交接 | 按模式定义 | Workflow pattern 支持依赖图 | **编排模式选择**：sequential vs concurrent vs group-chat | 最完整的模式分类 |

### 3. 重点项目深度分析

#### 3.1 open-multi-agent — 事件驱动 TaskQueue

**核心机制**：`TaskQueue` 是一个可变、事件驱动的队列，支持拓扑依赖解析。

```typescript
// queue.ts 核心逻辑
// Tasks enter in 'pending' state.
// Queue promotes them to 'blocked' when unresolved dependencies exist.
// When dependencies resolve → back to 'pending', firing 'task:ready'
// When task completes → auto-unlock downstream dependent tasks
```

**关键设计**：
1. **事件类型**：`task:ready`（依赖满足）、`task:complete`（任务完成）、`task:error`（任务失败）
2. **自动解锁**：当 task complete 时，自动检查所有依赖于它的 pending 任务，如果依赖全部满足，触发 `task:ready`
3. **并行决策**：纯依赖声明驱动——没有依赖关系的任务自然并行执行
4. **零基础设施**：纯 EventEmitter，不依赖 Redis/Kafka/数据库

**对我们的启示**：
- **complete→auto-unlock** 是核心模式，替代 polling tick 的"检查依赖是否满足"
- 依赖声明优于 Agent 自行判断并行性
- 事件驱动不一定要引入消息队列基础设施

#### 3.2 Network-AI — 原子黑板信号

**核心机制**：propose→validate→commit 三阶段原子提交，file-backed mutex 防竞态。

```
1. Agent 调用 propose(key, value) → 写入 .proposed 文件
2. validate() → 检查约束条件（其他 agent 没有冲突 propose）
3. commit() → 原子性写入最终状态
4. 失败 → rollback() → 清理 .proposed 文件
```

**关键设计**：
1. **信号机制**：通过文件系统信号（`.proposed`、`.committed`）通知其他 Agent
2. **原子性保证**：flock 文件锁 + 三阶段提交 = 无竞态
3. **零外部依赖**：不需要 Redis/数据库做分布式锁
4. **251 个测试**：竞态条件覆盖充分

**对我们的启示**：
- 我们的 SQLite CAS（claim_task 的原子 UPDATE WHERE）已经实现了类似功能
- 三阶段提交模式适合"产出审核"场景（propose 产出 → 庞统 validate → commit 到黑板）
- 文件系统信号可以作为轻量级通知机制的灵感

#### 3.3 Hermes Kanban — 当前 v2.6 的参考

**核心机制**：Dispatcher 60s tick + SQLite 黑板 + 7 状态机。

```
Dispatcher loop (every 60s):
  1. Reclaim stale claims（超时回收）
  2. Promote ready tasks（依赖满足 → 推进状态）
  3. Atomically claim（原子认领）
  4. Spawn assigned profiles（spawn agent）
```

**与 v2.6 的对比**：我们的设计直接参考了 Hermes，但 Hermes 本身也有 polling 延迟问题。Hermes 提供了 `Nudge dispatcher` 手动触发来缓解。

### 4. 事件类型定义

基于所有调研项目，我们需要的核心事件类型：

| 事件类型 | 触发条件 | 消费者 | 优先级 |
|---------|---------|--------|--------|
| `task_created` | 任何 Agent 创建任务 | Daemon（检查是否需要 spawn） | 中 |
| `task_claimed` | Agent 认领任务 | Daemon（更新 agent 状态） | 低 |
| `task_completed` | Agent 完成任务 | Daemon（解锁下游依赖 + spawn 下一环） | **高** |
| `task_failed` | Agent 任务失败 | Daemon（重试逻辑 + 通知庞统） | 高 |
| `task_blocked` | Agent 请求帮助 | Daemon（spawn 被提及的人） | 高 |
| `comment_added` | 评论写入 | Daemon（检查 @mention） | **高** |
| `output_written` | 产出写入 | Daemon（通知相关方） | 中 |
| `@mention` | 评论中提及 Agent | Daemon（立即 spawn 被提及者） | **最高** |
| `user_action` | 用户在黑板上的操作 | Daemon（立即响应） | **最高** |

### 5. 通知机制对比

| 方案 | 延迟 | 复杂度 | 依赖 | 适用场景 |
|------|------|--------|------|----------|
| **Polling（当前）** | ≤60s | 最低 | 无 | 简单场景，容忍延迟 |
| **SQLite update_hook** | ~0ms（进程内） | 低 | sqlite3 C API | Daemon 内部事件触发 |
| **文件系统 watch（inotify/FSEvents）** | ~ms | 中 | OS 原生 | 跨进程通知 |
| **SQLite WAL file watch** | ~ms | 中 | fswatch/watchdog | 跨进程 SQLite 变更通知 |
| **Unix socket / Named pipe** | ~ms | 中 | 无 | 本地进程间通信 |
| **Redis pub/sub** | ~ms | 中 | Redis | 分布式场景 |
| **Signal file + polling** | ≤1s | 最低 | 无 | 混合方案 |
| **asyncio.Event（进程内）** | ~0ms | 最低 | 无 | Daemon 进程内部 |

### 6. 推荐方案：分层事件驱动（结合 AI Native 目标）

#### 6.1 核心思路：不引入重依赖，进程内事件 + 轻量跨进程信号

```
┌─────────────────────────────────────────────────┐
│                Daemon (Python asyncio)           │
│                                                   │
│  ┌─────────────┐    ┌──────────────────────┐    │
│  │ EventBus    │    │ Tick Loop (fallback)  │    │
│  │ (asyncio)   │    │ 30s 轮询兜底          │    │
│  └──────┬──────┘    └──────────────────────┘    │
│         │                                         │
│  Agent 操作黑板时：                                │
│  1. 写入 SQLite（当前逻辑不变）                    │
│  2. 写入 signal file（通知 daemon）                │
│  3. Daemon 检测到信号 → 立即触发事件处理            │
└─────────────────────────────────────────────────┘
```

#### 6.2 具体实现

**Layer 1：进程内 EventBus（asyncio）**

```python
import asyncio
from enum import Enum
from dataclasses import dataclass
from typing import Callable, Awaitable

class EventType(str, Enum):
    TASK_CREATED = "task_created"
    TASK_CLAIMED = "task_claimed"
    TASK_COMPLETED = "task_completed"
    TASK_FAILED = "task_failed"
    TASK_BLOCKED = "task_blocked"
    COMMENT_ADDED = "comment_added"
    OUTPUT_WRITTEN = "output_written"
    USER_ACTION = "user_action"

@dataclass
class Event:
    type: EventType
    task_id: str | None
    agent: str | None
    detail: dict | None

class EventBus:
    def __init__(self):
        self._handlers: dict[EventType, list[Callable]] = {}
        self._queue: asyncio.Queue[Event] = asyncio.Queue()
    
    def on(self, event_type: EventType, handler: Callable):
        self._handlers.setdefault(event_type, []).append(handler)
    
    async def emit(self, event: Event):
        await self._queue.put(event)
    
    async def start(self):
        """主事件循环"""
        while True:
            event = await self._queue.get()
            handlers = self._handlers.get(event.type, [])
            for handler in handlers:
                try:
                    await handler(event)
                except Exception as e:
                    logger.error(f"Event handler error: {e}")
    
    async def emit_from_blackboard_op(self, event_type: EventType, task_id: str, 
                                       agent: str, detail: dict = None):
        """黑板操作后触发事件"""
        await self.emit(Event(type=event_type, task_id=task_id, agent=agent, detail=detail))
```

**Layer 2：Signal File 跨进程通知**

```python
import os
from pathlib import Path

SIGNAL_DIR = Path("~/.sanguo_projects/sanguo_moziplus_v2/signals")

async def write_signal(event_type: str, task_id: str = None, agent: str = None):
    """Agent（外部进程）写入信号文件"""
    signal_file = SIGNAL_DIR / f"{event_type}.signal"
    payload = f"{task_id or ''}:{agent or ''}:{time.time()}"
    signal_file.write_text(payload)

async def watch_signals():
    """Daemon 监听信号文件"""
    while True:
        for signal_file in SIGNAL_DIR.glob("*.signal"):
            if signal_file.exists():
                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,
                    detail=None
                ))
                signal_file.unlink()  # 处理完删除
        await asyncio.sleep(0.5)  # 500ms 检查间隔（比 60s 好 120 倍）
```

**Layer 3：Fallback Tick（30s 兜底）**

保留简化版 tick 循环，30s 一次（从 60s 降为 30s），只处理：
- 健康检查（zombie 检测、stale 任务回收）
- 信号遗漏兜底（万一 signal file 处理失败）

#### 6.3 事件处理优先级

```python
# 高优先级事件：立即 spawn
HIGH_PRIORITY = {
    EventType.TASK_COMPLETED,    # 解锁下游
    EventType.TASK_FAILED,       # 触发重试
    EventType.TASK_BLOCKED,      # 请求帮助
    EventType.COMMENT_ADDED,     # 可能含 @mention
    EventType.USER_ACTION,       # 用户操作
}

# 低优先级事件：排队处理
LOW_PRIORITY = {
    EventType.TASK_CREATED,
    EventType.TASK_CLAIMED,
    EventType.OUTPUT_WRITTEN,
}
```

### 7. 并行/串行决策推荐

#### 7.1 决策矩阵

| 场景 | 并行/串行 | 决策依据 | 示例 |
|------|----------|---------|------|
| 无依赖任务 | **并行** | `depends_on` 为空 | 赵云下载数据 + 庞统写方案 |
| 有依赖任务 | **串行** | `depends_on` 声明 | 先下载数据 → 再回测 |
| 同一任务冲突 | **串行**（先到先得） | SQLite CAS | 张飞和关羽抢同一个 review |
| 产出审核 | **串行**（完成→审核→通过） | 状态机 | 张飞完成 → 司马懿审核 |
| 独立研究 | **并行** | 无交集的子任务 | 多个因子独立调研 |
| 同文件修改 | **串行** | 文件路径冲突检测 | 不能两人同时改同一个文件 |

#### 7.2 推荐策略：**依赖声明优先，Daemon 辅助仲裁**

1. **显式依赖**：任务创建时声明 `depends_on`（庞统/创建者负责声明）
2. **自动并行**：`depends_on` 为空且 `assignee` 不同的任务，自动并行 spawn
3. **自动串行**：有 `depends_on` 的任务，上游完成事件触发下游 spawn
4. **冲突检测**：如果两个任务的 `files_modified` 有交集，Daemon 警告并建议串行
5. **庞统仲裁**：争议场景 spawn 庞统决定

```python
async def on_task_completed(event: Event):
    """任务完成 → 解锁下游依赖"""
    task_id = event.task_id
    
    # 查找所有依赖于该任务的 blocked 任务
    downstream = db.query(
        "SELECT * FROM tasks WHERE status='pending' AND depends_on LIKE ?",
        (f'%{task_id}%',)
    )
    
    for task in downstream:
        deps = json.loads(task['depends_on'])
        # 检查所有依赖是否都完成了
        all_done = all(
            db.query("SELECT status FROM tasks WHERE id=?", (d,))[0]['status'] == 'done'
            for d in deps
        )
        if all_done:
            # 自动解锁：触发 task:ready
            await event_bus.emit(Event(
                type=EventType.TASK_READY,
                task_id=task['id'],
                agent=task['assignee'],
            ))
            # 立即 spawn 对应 agent
            await spawn_agent(task['assignee'], f"任务 {task['id']} 依赖已满足，请查看并认领。")
```

---

## 课题 10：上下文管理策略

### 1. 黑板信息量具体测算

基于 `architecture-v2.6.md` 中的 SQLite Schema，逐项测算：

#### 1.1 一个任务基础信息（tasks 表）

```
字段                    典型内容                              估算 tokens
─────────────────────────────────────────────────────────────────────
id                     "task-001"                            1
title                  "动量因子策略回测"                       5
description            "对动量因子进行历史回测，验证策略有效性"  20
status                 "working"                             1
assignee               "zhangfei-dev"                        2
assigned_by            "pangtong-fujunshi"                   2
depends_on             ["task-001", "task-002"]              5
parent_task            "task-000"                            1
priority               5                                     1
task_type              "coding"                              1
created_at             "2026-05-15 09:00:00"                 3
updated_at             "2026-05-15 10:30:00"                 3
claimed_at             "2026-05-15 09:05:00"                 3
started_at             "2026-05-15 09:10:00"                 3
deadline               "2026-05-16 18:00:00"                 3
retry_count            0                                     1
─────────────────────────────────────────────────────────────────────
小计（结构化格式）                                            ~50-60 tokens
```

**一个任务基础信息 ≈ 50-60 tokens**

#### 1.2 评论（10 条，comments 表）

```
每条评论典型内容：
  "张飞，你的实现方案我看了，回测数据量大时内存会爆。关羽，从风控角度也看看？
   @关羽 @张飞"
  + author + created_at + mentions JSON
  ≈ 30-50 tokens/条

10 条评论 ≈ 300-500 tokens
```

#### 1.3 产出（5 个，outputs 表）

```
每个产出典型内容：
  output_type: "code"
  title: "分批加载实现"
  content_path: "task-001/output-zhangfei-v2.md"
  summary: "实现分批加载，单批50万条"
  metadata: {"files_changed": 3, "lines_added": 150}
  + agent + created_at
  ≈ 30-50 tokens/个

5 个产出 ≈ 150-250 tokens
```

#### 1.4 事件日志（10 条，events 表）

```
每条事件：
  event_type: "task_claimed"
  agent: "zhangfei-dev"
  detail: {"from": "pending", "reason": null}
  + created_at
  ≈ 15-25 tokens/条

10 条事件 ≈ 150-250 tokens
```

#### 1.5 决策记录（3 条，decisions 表）

```
每条决策：
  decision: "使用分批加载而非流式"
  rationale: "流式需要改底层框架，分批只需改回测模块"
  alternatives: ["流式加载", "内存映射"]
  ≈ 40-80 tokens/条

3 条决策 ≈ 120-240 tokens
```

#### 1.6 观察记录（3 条，observations 表）

```
每条观察：
  severity: "warning"
  body: "止损逻辑在分批模式下可能漏触发"
  ≈ 20-30 tokens/条

3 条观察 ≈ 60-90 tokens
```

#### 1.7 总计

| 组件 | 数量 | 估算 tokens |
|------|------|-------------|
| 任务基础信息 | 1 个 | 50-60 |
| 评论 | 10 条 | 300-500 |
| 产出 | 5 个 | 150-250 |
| 事件日志 | 10 条 | 150-250 |
| 决策记录 | 3 条 | 120-240 |
| 观察记录 | 3 条 | 60-90 |
| **总计** | | **830-1390 tokens** |
| + JSON 格式开销（花括号、引号） | | ~150-200 tokens |
| + 提示词格式（标题、分隔符） | | ~100-150 tokens |
| **实际传给 LLM 的总量** | | **~1100-1750 tokens** |

**关键结论：一个典型任务的全量黑板信息约 1100-1750 tokens。**

极端情况（30 条评论、10 个产出、50 条事件）：
- 评论：30 × 40 = 1200 tokens
- 产出：10 × 40 = 400 tokens
- 事件：50 × 20 = 1000 tokens
- 总计约 3000-4000 tokens

**即使极端情况也在 4000 tokens 以内，远小于 200K context window。**

但是——如果有多个任务（比如庞统规划了 5 个子任务），5 个任务 × 1500 tokens = 7500 tokens，仍然可控。

**真正的问题不是单个任务的黑板信息，而是**：
1. 产出物文件内容（code diff、分析报告）可能很大
2. 长讨论线程（30+ 评论来回讨论）
3. Agent 的 system prompt + SOUL.md + skill 文件已经占用大量 context

### 2. 业界优秀实践对比表

| 项目 | 上下文策略 | 核心机制 | 优点 | 缺点 |
|------|-----------|----------|------|------|
| **Claude Code** | Auto-compact + file reference | 1) 自动压缩：接近 context limit 时先清 tool output，再 summarize 对话 2) `/compact` 手动压缩 3) `@file` 引用而非内联 4) CLAUDE.md 持久记忆 | 成熟稳定，官方支持 | 压缩可能丢失细节；单一 session 内累积 |
| **Claude Code Agent Teams** | 每个 Agent 独立 1M token context | 隔离 context window + 共享任务列表 + SendMessage 直接通信 | 天然隔离，无 context rot 问题 | 跨 agent 通信开销 |
| **GSD (Get-Shit-Done)** | Wave Execution：每个 plan 独立新鲜 200K context | 1) Plan 分 wave 执行 2) 每个 executor 新鲜 context 3) 原子 git commit 4) 主 context 保持 30-40% | 彻底消除 context rot | 需要精确的 plan 分解 |
| **Network-AI** | 原子黑板（数据在黑板，不在 context） | Agent 只读黑板摘要，详细数据在文件中 | context 极小 | 需要额外读取操作 |
| **Hermes Kanban** | kanban_show() 按需读取 | Agent 只看当前任务看板，不全量读取 | 简单有效 | 可能遗漏全局信息 |
| **Agent Chorus** | Checkpoint + 跨 Agent 消息 | Standup drain inbox + conclude broadcast + checkpoint 状态广播 | 跨框架兼容 | 复杂度较高 |
| **Opal-Bridge** | Cross-agent session translator | Claude Code ↔ Codex CLI 格式转换 | 多工具协作 | 范围有限 |
| **MindStudio** | 三层内存：工作/短期/长期 | Working（当前会话）+ Short-term（任务级）+ Long-term（项目级） | 分层清晰 | 需要额外基础设施 |

### 3. 重点项目深度分析

#### 3.1 Claude Code — Auto-compact + File Reference

**核心机制**：

1. **自动压缩（Auto-compact）**：
   - 当 context 使用接近 limit 时，先清除旧 tool output
   - 然后自动 summarize 对话历史
   - 用户可通过 CLAUDE.md 自定义压缩策略（如 "压缩时保留修改文件列表和测试命令"）
   - `/compact` 手动触发，`/compact "保留所有类型定义"` 可带自定义指令

2. **文件引用（@-reference）**：
   - 用 `@file_path` 引用文件内容，而非内联到对话中
   - LLM 按需读取，避免全量加载

3. **CLAUDE.md 持久记忆**：
   - 项目级（`CLAUDE.md`）+ 用户级（`~/.claude/CLAUDE.md`）
   - 每次 session 启动自动加载
   - 相当于 L1 核心信息

**对我们的启示**：
- 产出的详细内容不应放在黑板 context 中，只放摘要 + 文件路径引用
- Agent 读取产出时应按需 read 文件，不全量注入 context

#### 3.2 GSD (Get-Shit-Done) — Wave Execution

**核心机制**：

```
/gsd:execute-phase N
├── 分析 plan 依赖关系
├── Wave 1（无依赖的 plan）：
│   ├── Executor A（新鲜 200K context）→ commit
│   └── Executor B（新鲜 200K context）→ commit
├── Wave 2（依赖 Wave 1）：
│   └── Executor C（新鲜 200K context）→ commit
└── Verifier（检查所有产出）
```

**关键数据**：
- 主 context 始终保持在 30-40%（因为重活在 subagent 中做）
- 每个 executor 独立 200K token，不做压缩（新鲜 context 不需要）
- 每个 plan 一个原子 git commit（可回滚）

**对我们的启示**：
- **我们的 Agent spawn 模式天然就是 Wave Execution**：Daemon spawn 隔离 session，每个 agent 独立 context
- 关键是 spawn 时传多少上下文——传太多浪费，传太少丢信息
- 产出写入黑板摘要 + 文件路径，下一个 agent 按需读取

#### 3.3 Opal-Bridge — Cross-Agent Session Translator

**核心机制**：将 Claude Code 的 session 格式转换为 Codex CLI 的格式，实现跨工具接力。

**Fidelity 概念**（从 cross_agent_session_resumer 项目借鉴）：
- **Native fidelity**：保留原始格式的完整信息
- **Lossy export**：转换为通用格式时丢失部分信息
- **Checkpoint**：关键节点快照

**对我们的启示**：
- Agent 之间的"接力"需要定义标准化的交接格式
- 不是所有信息都需要完整传递——关键是决策、产出摘要、未完成事项

### 4. 推荐方案：分层传递策略

#### 4.1 三层信息架构

```
┌─────────────────────────────────────────────────────┐
│  L1: 核心信息（必须传入，~200-400 tokens）            │
│  ─────────────────────────────────────────────────── │
│  • 任务 ID + 标题 + 状态                              │
│  • 任务描述（description）                            │
│  • 我的角色 + 触发原因（为什么 spawn 我）              │
│  • 依赖任务的状态摘要（1 行/任务）                     │
│  • 最近 3 条评论摘要                                  │
│                                                       │
│  传递方式：spawn message 中直接写入                    │
│  保证：任何 Agent 都能在 L1 信息下开始工作              │
├─────────────────────────────────────────────────────┤
│  L2: 扩展信息（按需读取，~500-1500 tokens）           │
│  ─────────────────────────────────────────────────── │
│  • 完整评论线程                                       │
│  • 产出摘要列表（title + summary，不含详细内容）       │
│  • 决策记录                                          │
│  • 观察记录                                          │
│  • 其他相关任务摘要                                   │
│                                                       │
│  传递方式：Agent 通过 CLI 按需读取                     │
│  CLI: blackboard.py read --task task-001 --level L2   │
├─────────────────────────────────────────────────────┤
│  L3: 全量信息（按需读取，不限制大小）                  │
│  ─────────────────────────────────────────────────── │
│  • 产出物文件完整内容                                  │
│  • 完整事件日志                                      │
│  • 所有子任务详情                                     │
│                                                       │
│  传递方式：文件路径引用，Agent 用 read 工具读取         │
│  黑板只存 content_path，不存文件内容                   │
└─────────────────────────────────────────────────────┘
```

#### 4.2 Agent Spawn 时的上下文模板

```python
def build_spawn_message_L1(task_id: str, agent_id: str, trigger: str) -> str:
    """L1 核心：~200-400 tokens，直接写入 spawn message"""
    task = get_task(task_id)
    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']}")
    
    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"
    
    return f"""黑板任务通知（L1）：
任务：{task['title']}（{task['id']}）
状态：{task['status']}
类型：{task['task_type']}
触发原因：{trigger}
描述：{task['description'] 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
"""
```

#### 4.3 黑板上的信息分层规则

| 信息类别 | 存储位置 | 黑板上展示 | 说明 |
|---------|---------|-----------|------|
| 任务元数据 | 黑板 tasks 表 | 完整 | ID、标题、状态、描述、分配、依赖 |
| 评论 | 黑板 comments 表 | 完整 | 所有评论保留，L2 读取 |
| 产出摘要 | 黑板 outputs 表 | title + summary + path | 详细内容在文件中 |
| 产出详细内容 | 文件系统 | 仅文件路径 | Agent 按需 read |
| 决策记录 | 黑板 decisions 表 | 完整 | L2 读取 |
| 观察记录 | 黑板 observations 表 | 完整 | L2 读取 |
| 事件日志 | 黑板 events 表 | 仅最近 10 条 | L3 按需查询 |

#### 4.4 后接 Agent 无缝接力的关键

1. **产出物标准化**：每个产出必须包含 `summary`（一句话摘要）+ `content_path`（文件路径），不存大段文本
2. **决策必须记录**：Agent 的关键决策写入 decisions 表，后继者可通过 L2 了解"为什么这么做"
3. **未完成事项显式化**：Agent 结束前在评论中写 "未完成：XXX"，后继者一目了然
4. **触发原因明确**：Daemon spawn 时必须说明为什么 spawn（@mention / 依赖满足 / 用户指令）

### 5. Context 预算分配建议

假设使用 128K context window 的模型（如 gpt-4o / claude-3.5）：

| 组件 | 预算 | 说明 |
|------|------|------|
| System Prompt + SOUL.md + IDENTITY.md | ~3000-5000 tokens | 固定开销 |
| Skills + AGENTS.md | ~2000-4000 tokens | 固定开销 |
| L1 spawn message | ~300-500 tokens | 任务核心信息 |
| L2 黑板扩展信息（按需） | ~500-1500 tokens | 完整讨论、决策 |
| L3 产出物文件（按需） | ~2000-10000 tokens | 代码/报告内容 |
| 工作空间（Agent 思考+输出） | ~30000-50000 tokens | 预留给 Agent 实际工作 |
| **总计** | ~40K-70K tokens | 远小于 128K，安全 |

**关键结论**：我们的黑板信息量远小于 context window 限制，**不需要做复杂的压缩/摘要**。核心策略是：

1. **L1 必传**：~300-500 tokens，任何场景都负担得起
2. **L2 按需**：Agent 自己决定是否需要深入了解讨论/决策
3. **L3 文件引用**：大内容只在文件中，黑板只存路径

---

## 总结与行动建议

### 课题 2 行动建议（事件驱动）

| 优先级 | 行动 | 工作量 |
|--------|------|--------|
| P0 | 实现 asyncio EventBus 进程内事件总线 | 1 天 |
| P0 | 实现 Signal File 跨进程通知（Agent→Daemon） | 0.5 天 |
| P1 | 事件处理：task_completed → 解锁下游依赖 | 0.5 天 |
| P1 | 事件处理：comment_added → @mention 检测 | 0.5 天 |
| P2 | 保留 30s fallback tick（健康检查） | 0 天（简化现有 tick） |
| P2 | files_modified 冲突检测 | 1 天 |

**预期效果**：
- @mention 响应从 ≤60s 降到 ≤1s
- 任务依赖解锁从 ≤60s 降到 ~0ms（进程内事件）
- 不引入任何新依赖

### 课题 10 行动建议（上下文管理）

| 优先级 | 行动 | 工作量 |
|--------|------|--------|
| P0 | 定义 L1/L2/L3 分层读取 API | 0.5 天 |
| P0 | 实现 L1 spawn message 模板 | 0.5 天 |
| P1 | 产出物只存摘要+路径的规范落地 | 0 天（已在 schema 中） |
| P2 | blackboard.py read --level L2 实现 | 0.5 天 |
| P2 | Agent 规范：结束前写未完成事项 | 0 天（文档规范） |

**核心原则**：
- 黑板是索引（做什么 + 在哪找），不是仓库（详细内容）
- 产出物在文件中，黑板只存路径
- Agent spawn 时传最小充分上下文（L1），按需获取更多（L2/L3）
- 不做复杂压缩——信息量本身就很小

---

## 参考项目索引

| 项目 | URL | 关键参考价值 |
|------|-----|-------------|
| open-multi-agent | github.com/JackChen-me/open-multi-agent | 事件驱动 TaskQueue + 依赖自动解锁 |
| Network-AI | github.com/jovanSAPFIONEER/Network-AI | 原子黑板 propose→validate→commit |
| Hermes Kanban | github.com/NousResearch/hermes-agent | 60s tick + SQLite 黑板 + 状态机 |
| GSD (Get-Shit-Done) | github.com/gsd-build/get-shit-done | Wave Execution + 新鲜 context |
| Claude Code | code.claude.com | Auto-compact + file reference + agent teams |
| Agent Chorus | github.com/cote-star/agent-chorus | 跨 Agent checkpoint + 消息传递 |
| Azure Agent Patterns | learn.microsoft.com | 编排模式分类（sequential/concurrent/handoff） |
| Confluent 事件驱动 | confluent.io/blog | 4 种事件驱动多 Agent 模式 |
