auto-sync: 2026-05-15 13:37:58

This commit is contained in:
cfdaily
2026-05-15 13:37:58 +08:00
parent fe5b61f80d
commit a72ea6f509
+87 -77
View File
@@ -18,20 +18,20 @@
| 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需后续课题解决
### 课题 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-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-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 内部状态 |
| 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 |
@@ -465,25 +465,25 @@ def add_comment(task_id: str, author: str, body: str, mentions: list = None):
- Claude Code 的 file reference 模式:不内联,只引用
- agent-chorus 的 Context Pack 实验证明:结构化上下文让 Agent 文件打开量降 70%、token 消耗降 60%、零生产风险答案
- Opal-Bridge 的 Fidelity 三档:无损/摘要/混合,传递时按需降档
- 一个典型任务全量黑板信息 ~1100-1750 tokens,极端 ~4000 tokens——远小于 128K context
- 一个典型任务全量黑板信息 ~1100-1750 tokens,极端 ~4000 tokens--远小于 128K context
- 问题不是空间不够,而是**信号噪声比**:全量注入让 Agent 在无关信息上浪费注意力
**AI Native 内容规范——不做硬限制,做软引导:**
**AI Native 内容规范--不做硬限制,做软引导:**
传统做法是给每个字段设长度上限(如 comments.body ≤ 2000 字符),这是 CRUD 应用的思维。
AI Native 的做法是:Agent 是智能体,有能力判断这段分析应该写文件还是直接写评论。规范是指导性的,不是强制性的。
AI Native 的做法是:Agent 是智能体,有能力判断"这段分析应该写文件还是直接写评论"。规范是指导性的,不是强制性的。
- **不做硬限制**——不设字段长度上限,不截断,不报错
- **做软引导**——Agent 的 Skill 中写评论应简洁明了,大段分析写文件后在评论中给路径
- **做传递优化**——L1 传递时自动截取(最近 3 条评论、每条 100 字符),这是传递层面的优化,不是存储层面的限制
- **做信息分层**——黑板上的 comments 表存完整内容(不截断),但 L1 传递时只取摘要
- **不做硬限制**--不设字段长度上限,不截断,不报错
- **做软引导**--Agent 的 Skill 中写"评论应简洁明了,大段分析写文件后在评论中给路径"
- **做传递优化**--L1 传递时自动截取(最近 3 条评论、每条 100 字符),这是传递层面的优化,不是存储层面的限制
- **做信息分层**--黑板上的 comments 表存完整内容(不截断),但 L1 传递时只取摘要
**为什么这样做是 AI Native**:
1. Agent 是智能体,不是 API 客户端——它有能力判断这段分析应该写文件还是直接写评论
1. Agent 是智能体,不是 API 客户端--它有能力判断"这段分析应该写文件还是直接写评论"
2. 如果硬限制导致信息丢失,Agent 会绕过限制(拆成多条评论、用文件存储),反而更混乱
3. 真正需要控制的是传递时的信息量(L1 预算),不是存储时的信息量
**黑板上必要信息的定义(指导性)**:
**黑板上"必要信息"的定义(指导性)**:
| 类别 | 上黑板 | 不上黑板 |
|------|--------|----------|
@@ -542,82 +542,82 @@ Daemon **不做**:
这个区分决定了 spawn 时的消息内容--L2 传数据,L3 传指针。
### 4.2 事件驱动架构课题 2 设计决策
### 4.2 事件驱动架构(课题 2 设计决策)
#### 设计推导过程
**三个参考系统的做法**
**三个参考系统的做法**:
| 系统 | 架构 | 事件通知方式 | 启示 |
|------|------|------------|------|
| **open-multi-agent** | 单进程 TypeScript | 纯 EventEmitter——`queue.on('task:ready', handler)`。TaskQueue 内部维护 listeners Mapcomplete() 时同步触发 emit。零基础设施 | 和我们的黑板同构TaskQueue.complete() = 我们的任务完成unblockDependents() = 我们的依赖解锁 |
| **agent-chorus** | 多进程Claude/Codex/Gemini 各自独立 | 本地 JSONL 文件队列——`chorus send` 写入 `.agent-chorus/messages/<target>.jsonl``chorus messages --agent <self> --clear` 读并清空。纯文件系统无网络 | Standup+Conclude 模式Agent 开始时读 inbox结束时广播状态。JSONL inbox 做跨进程通信 |
| **Edict** | 分布式API Gateway + Orchestrator + Agent Pool | Redis Streams Event Bus——`task.created` 等主题 + WebSocket 推送 Dashboard | 我们是单机单进程不需要 Redis |
| **open-multi-agent** | 单进程 TypeScript | 纯 EventEmitter--`queue.on('task:ready', handler)`。TaskQueue 内部维护 listeners Map,complete() 时同步触发 emit。零基础设施 | 和我们的黑板同构:TaskQueue.complete() = 我们的任务完成,unblockDependents() = 我们的依赖解锁 |
| **agent-chorus** | 多进程(Claude/Codex/Gemini 各自独立) | 本地 JSONL 文件队列--`chorus send` 写入 `.agent-chorus/messages/<target>.jsonl`,`chorus messages --agent <self> --clear` 读并清空。纯文件系统,无网络 | Standup+Conclude 模式:Agent 开始时读 inbox,结束时广播状态。JSONL inbox 做跨进程通信 |
| **Edict** | 分布式(API Gateway + Orchestrator + Agent Pool) | Redis Streams Event Bus--`task.created` 等主题 + WebSocket 推送 Dashboard | 我们是单机单进程,不需要 Redis |
**推导结论**
1. open-multi-agent 证明单进程内 EventEmitter 完全够用但它是单进程我们是跨进程
2. agent-chorus 证明跨进程通信用 JSONL 文件就行不需要 HTTP/Redis/MQ
3. Edict 的 Redis Streams 是分布式场景所需我们不需要
4. **真正需要即时响应的场景只有 4 个**task_completed / task_failed / @mention / user_action。其他 ≤30s 延迟完全可接受
5. **60s Tick 本身不是问题问题是 Tick 的效率**——应该 Tick 是核心加速器可选
**推导结论**:
1. open-multi-agent 证明:单进程内 EventEmitter 完全够用,但它是单进程,我们是跨进程
2. agent-chorus 证明:跨进程通信用 JSONL 文件就行,不需要 HTTP/Redis/MQ
3. Edict 的 Redis Streams 是分布式场景所需,我们不需要
4. **真正需要即时响应的场景只有 4 个**:task_completed / task_failed / @mention / user_action。其他 ≤30s 延迟完全可接受
5. **60s Tick 本身不是问题,问题是 Tick 的效率**--应该 Tick 是核心,加速器可选
**用户反馈与设计迭代**
- 初始设计Signal File 跨进程通知 → 用户质疑"Signal File 存在的意义是什么"
- 第二版HTTP 端点 → 用户要求"基于优秀实践推导不是拍脑袋换方案"
- 最终版Tick 核心 + Inbox JSONL 加速agent-chorus 模式)——基于三个参考系统的实际代码推导
**用户反馈与设计迭代**:
- 初始设计:Signal File 跨进程通知 → 用户质疑"Signal File 存在的意义是什么"
- 第二版:HTTP 端点 → 用户要求"基于优秀实践推导,不是拍脑袋换方案"
- 最终版:Tick 核心 + Inbox JSONL 加速(agent-chorus 模式)--基于三个参考系统的实际代码推导
#### D2-1Tick 核心 + Inbox 加速最终方案
#### D2-1:Tick 核心 + Inbox 加速(最终方案)
```
┌──────────────────────────────────────────────────────────────────┐
│ Daemon (Python asyncio) │
│ │
│ 核心Tick Loop30s 主循环
│ 核心:Tick Loop(30s 主循环)
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 读黑板全量状态SQLite 查询 │ │
│ │ 发现需要处理的mention / blocked / done → pending │ │
│ │ 执行对应操作spawn / 通知 / 清理 │ │
│ │ 健康检查zombie / stale / heartbeat │ │
│ │ 读黑板全量状态(SQLite 查询) │ │
│ │ 发现需要处理的(mention / blocked / done → pending) │ │
│ │ 执行对应操作(spawn / 通知 / 清理) │ │
│ │ 健康检查(zombie / stale / heartbeat) │ │
│ │ │ │
│ │ 设计推导Hermes 60s tick 证明 polling 可靠稳定。 │ │
│ │ 我们从 60s 降到 30s因为黑板查询比 Hermes 轻量。 │ │
│ │ 设计推导:Hermes 60s tick 证明 polling 可靠稳定。 │ │
│ │ 我们从 60s 降到 30s,因为黑板查询比 Hermes 轻量。 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ↑ │
│ 加速Inbox JSONLagent-chorus 模式
│ 加速:Inbox JSONL(agent-chorus 模式)
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Agent 写黑板后可选追加一行 JSON 到 daemon inbox │ │
│ │ Agent 写黑板后,可选:追加一行 JSON 到 daemon inbox │ │
│ │ Daemon 主循环每 1s 检查 inbox 是否有新内容 │ │
│ │ 有新内容 → 立即执行一次 mini-tick只处理触发的事件 │ │
│ │ 有新内容 → 立即执行一次 mini-tick(只处理触发的事件) │ │
│ │ 处理完清空 inbox │ │
│ │ │ │
│ │ 设计推导agent-chorus 用 JSONL inbox 做跨 Agent 通信 │ │
│ │ 设计推导:agent-chorus 用 JSONL inbox 做跨 Agent 通信, │ │
│ │ 我们用 JSONL inbox 做 Agent→Daemon 通知。同理同构。 │ │
│ │ inbox 是加速器不是核心。Tick 兜底所有场景。 │ │
│ │ inbox 是加速器,不是核心。Tick 兜底所有场景。 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ↑ │
│ 恢复启动时全量扫描 │
│ 恢复:启动时全量扫描 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Daemon 重启后立即做一次完整 TickPM2 自动重启 │ │
│ │ Daemon 重启后立即做一次完整 Tick(PM2 自动重启) │ │
│ │ 消除重启后的 30s 空窗 │ │
│ │ 不需要 EventBus 持久化——黑板SQLite是唯一真相源 │ │
│ │ 不需要 EventBus 持久化--黑板(SQLite)是唯一真相源 │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
**为什么不选的替代方案**
- EventBus + Signal File初始设计):Signal File 需要额外的扫描/读/删循环增加了耦合链
- HTTP 端点第二版):引入网络依赖Daemon 需要跑 HTTP 服务不够简单
- Redis pub/subEdict 方案):引入新依赖v2.6 已去掉 Redis我们不需要分布式
- SQLite update-hook需要 C API 绑定
- fswatch/watchdog跨平台兼容性差
**为什么不选的替代方案**:
- EventBus + Signal File(初始设计):Signal File 需要额外的扫描/读/删循环,增加了耦合链
- HTTP 端点(第二版):引入网络依赖,Daemon 需要跑 HTTP 服务,不够简单
- Redis pub/sub(Edict 方案):引入新依赖,v2.6 已去掉 Redis;我们不需要分布式
- SQLite update-hook:需要 C API 绑定
- fswatch/watchdog:跨平台兼容性差
**Inbox JSONL 具体实现**参考 agent-chorus `chorus send` 模式):
**Inbox JSONL 具体实现**(参考 agent-chorus `chorus send` 模式):
```python
# blackboard.py 写完 SQLite 后可选追加一行 JSON
# blackboard.py 写完 SQLite 后,可选追加一行 JSON
INBOX_PATH = Path("~/.sanguo_projects/sanguo_moziplus_v2/inbox/daemon.jsonl")
# 写入格式参考 agent-chorus message schema: from/to/timestamp/content/cwd
# 写入格式(参考 agent-chorus message schema: from/to/timestamp/content/cwd)
async def notify_daemon(event_type: str, task_id: str, agent: str):
line = json.dumps({
"from": agent,
@@ -634,50 +634,50 @@ async def check_inbox():
if not INBOX_PATH.exists():
return
lines = INBOX_PATH.read_text().strip().split('\n')
INBOX_PATH.unlink() # 原子读取+删除参考 agent-chorus --clear 模式
INBOX_PATH.unlink() # 原子读取+删除(参考 agent-chorus --clear 模式)
for line in lines:
msg = json.loads(line)
await handle_event(msg['event'], msg['task_id'], msg['from'])
```
**Daemon 主循环**
**Daemon 主循环**:
```python
async def daemon_main_loop():
# 启动时全量扫描
await full_tick()
while True:
# 1. 检查 inbox每 1s
# 1. 检查 inbox(每 1s)
await check_inbox() # 有内容则立即执行 mini-tick
# 2. 定期 Tick每 30s
# 2. 定期 Tick(每 30s)
if time.time() - last_tick > 30:
await full_tick()
last_tick = time.time()
await asyncio.sleep(1)
```
#### D2-2依赖声明的并行/串行自动决策
#### D2-2:依赖声明的并行/串行自动决策
> **设计推导**open-multi-agent 的 TaskQueue.complete() → unblockDependents() 是核心模式——complete→auto-unlock纯依赖声明驱动。其 scheduler.ts 还提供了 4 种调度策略round-robin / least-busy / capability-match / dependency-first
> **设计推导**:open-multi-agent 的 TaskQueue.complete() → unblockDependents() 是核心模式--complete→auto-unlock,纯依赖声明驱动。其 scheduler.ts 还提供了 4 种调度策略(round-robin / least-busy / capability-match / dependency-first)
**串行触发链**Tick + Inbox 加速版):
**串行触发链**(Tick + Inbox 加速版):
```
Agent A 完成 task-001
→ 写黑板 outputs + 更新 status → done + 写 handoff comment
→ 通知 Daemoninbox JSONL
→ Daemon 下次循环~1s 内收到通知 → mini-tick
→ 通知 Daemon(inbox JSONL)
→ Daemon 下次循环(~1s 内)收到通知 → mini-tick:
查询所有 depends_on 包含 task-001 的 pending 任务
→ task-002 depends_on: [task-001]检查 task-001 done ✅
→ task-002 depends_on: [task-001],检查 task-001 done ✅
→ spawn Agent B 执行 task-002
如果 inbox 通知丢失 → 30s Tick 兜底补上
(如果 inbox 通知丢失 → 30s Tick 兜底补上)
```
**并行**`depends_on` 为空且 assignee 不同的任务自然并行Daemon 分别 spawn。不需要额外逻辑。
**并行**:`depends_on` 为空且 assignee 不同的任务,自然并行(Daemon 分别 spawn)。不需要额外逻辑。
**不做 files_modified 冲突检测**D2-4):Agent 通过黑板评论自然协调"我在改 main.py你别碰"),不需要系统强制。Scope Guard课题 1作为兜底。实际覆盖depends_on 覆盖 80%+ 的显式依赖场景边角场景通过黑板评论 + 庞统仲裁补充。
**不做 files_modified 冲突检测**(D2-4):Agent 通过黑板评论自然协调("我在改 main.py,你别碰"),不需要系统强制。Scope Guard(课题 1)作为兜底。实际覆盖:depends_on 覆盖 80%+ 的显式依赖场景,边角场景通过黑板评论 + 庞统仲裁补充。
#### 与课题 1 的兼容性
@@ -686,7 +686,7 @@ Agent A 完成 task-001
| 续杯机制 | task_completed 通知加速依赖解锁 | @mention 从 ≤60s 降到 ≤1s |
| retry 由 AI 决策 | task_failed 通知加速 retry 链 | 庞统更快介入 |
| Guardrail 吹哨人 | observation 写入后通知 Daemon | Daemon 即时感知问题 |
| 三层执行模型 | 不变Tick/inbox 处理仍按 L1/L2/L3 分层 | ✅ 一致 |
| 三层执行模型 | 不变,Tick/inbox 处理仍按 L1/L2/L3 分层 | ✅ 一致 |
### 4.3 Session 生命周期
@@ -714,11 +714,21 @@ Agent A 完成 task-001
- 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 模式证明"引用而非内联"是最优策略。Opal-Bridge 的 Fidelity 三档提供了理论框架。agent-chorus 的 Context Pack 实验证明结构化上下文让 Agent 效率提升 60-70%。问题不是 context 不够大而是信号噪声比。
**D2-5:三层上下文传递(L1 必传 / L2 按需 / L3 按需)**
**L1/L2/L3 对应 Opal-Bridge Fidelity 三档**
| Opal-Bridge Fidelity | 我们的映射 | 场景 |
|---------------------|----------|------|
| Mode A:无损(完整上下文) | L1 + L2 + L3 | 复杂任务,Agent 需要完整了解讨论历史和产出 |
| Mode BLLM 摘要 | L1 + L2 | 标准任务,核心信息 + 扩展摘要 |
| Mode C:混合保留最近N条 | L1 | 简单任务,只传核心,Agent 按需取更多 |
Agent 自己决定用哪个 Fidelity 档位——收到 L1 后判断信息是否足够,不够就 L2/L3。
**D2-5:三层上下文传递(L1 必传 / L2 按需 / L3 按需)**
| 层级 | 内容 | Token 估算 | 谁决定 |
|------|------|-----------|--------|