21 KiB
经验卡片集 — 批次2 司马懿纠正 + 庞统经验混合
数据源:151 个片段(庞统经验 21 条 + 司马懿纠正 122 条 + Sanguo Mail 纠正 8 条) 归纳时间:2026-05-26 覆盖时间段:2026-05-06 ~ 2026-05-26
汇总表
| # | 分类 | 严重度 | 频率 | 来源 | 核心教训 |
|---|---|---|---|---|---|
| 1 | 代码评审 | high | 5+ | simayi-correction | 评审必须验证最终代码,不能只审方案 |
| 2 | 代码评审 | high | 3+ | simayi-correction | 状态机/枚举值不一致是高频 Bug 根源 |
| 3 | 系统设计 | high | 3 | simayi-correction, experience | 评审者自我纠正:承认判断错误比坚持错误更有价值 |
| 4 | 系统设计 | high | 4+ | simayi-correction | 设计文档-代码一致性审查不能省 |
| 5 | 系统设计 | medium | 2+ | experience | "一键三连"闭环标准:文档→代码→最终确认 |
| 6 | 系统设计 | high | 3 | simayi-correction | Counter/锁的生命周期必须贯穿完整调用链 |
| 7 | 系统设计 | high | 2 | simayi-correction | 进程退出 ≠ 资源释放:on_complete 回调时序是关键 |
| 8 | 编排调度 | high | 5+ | simayi-correction | 续杯(retry)机制是最大的假死来源 |
| 9 | 编排调度 | medium | 3 | simayi-correction | 广播路径与单播路径必须行为一致 |
| 10 | 编排调度 | medium | 3+ | simayi-correction | E2E 测试要用真实环境,不能只测单元 |
| 11 | Agent 行为 | medium | 4+ | simayi-correction | Agent 认领任务前必须检查角色匹配 |
| 12 | Agent 行为 | high | 2 | simayi-correction | inform 类型邮件不应触发完整 Agent 执行 |
| 13 | 沟通协作 | medium | 3 | pangtong-correction, simayi-correction | 回答用户问题要直接,不要绕弯子 |
| 14 | 系统设计 | medium | 2 | simayi-correction | stdout JSON 解析路径必须实测验证 |
| 15 | 经验总结 | low | 2 | experience | 跨项目调研的实践对照表要做落地映射 |
卡片 1:评审闭环必须包含最终代码确认
---
category: "代码评审"
tags: [review, 闭环, 最终代码]
severity: "high"
frequency: 5
sources: ["simayi-correction", "experience"]
---
场景
多步骤开发中,方案评审通过后,实现阶段可能有微调。如果评审者只确认了方案而没看最终代码,Bug 可能被遗漏。
错误做法
庞统在 M2 阶段让司马懿 review 了 Checkpoint 和 Hooks 的方案,但实现后只说"已采纳建议",没发最终代码让司马懿确认。用户发现后指出:
"一键三连最终肯定是以司马懿 review 完你的最终成果物收尾的,不是他 review 完你的方案就算完事" [pangtong/experience]
正确做法
一键三连 = 改文档 → 改代码 → 司马懿确认最终代码片段。每个方案落地后,必须把最终代码(不是方案描述)发给评审者确认。司马懿在评审中多次明确引用代码行号做交叉验证,这种精度只有看最终代码才能做到。
关键细节
- "已采纳"不等于"已验证"——采纳后的代码可能引入新问题
- 司马懿多次在代码评审中发现方案评审没暴露的 Bug(如
_do_retry续杯失效) - 续杯评审中,司马懿看到最终代码才发现 on_complete=None 导致幻觉门控丢失
反面教训
未确认最终代码导致 Checkpoint 实现与设计不一致,返工修复。
卡片 2:状态机枚举值不一致是高频 Bug 根源
---
category: "代码评审"
tags: [状态机, 枚举, 一致性]
severity: "high"
frequency: 3
sources: ["simayi-correction"]
---
场景
系统有多处引用任务/节点状态值(数据库查询、状态转换、恢复逻辑),如果枚举定义与实际使用不一致,会导致静默失败。
错误做法
M1 遗留 Bug P0-2:get_all_executing_tasks SQL 查询用 'executing',但实际枚举值是 'working',导致重启恢复时 working 节点被遗漏。
"启动恢复查询用节点状态包含 'executing',但实际节点状态枚举中无此值(应为 'working')" [pangtong/simayi-review]
E2E 测试发现 failed→pending 转换不清 assignee,与另一路径 ticker._transition_status 的行为不一致。
正确做法
- 状态枚举集中定义,所有引用点从枚举取值,硬编码字符串零容忍
- 状态转换函数只保留一个入口(如
_transition_status),禁止分散在多个模块 - 评审时重点检查:新代码中的状态值是否与枚举定义一致
关键细节
- 司马懿在 counter v2.1 评审中发现
max_per_agent=2vs 设计文档的1,也是同类问题 - auto-sync 可能静默修改配置文件,需要与设计文档对照
反面教训
状态不一致导致任务永久卡住(P0-1)和重启恢复失败(P0-2)。
卡片 3:评审者自我纠正是高质量评审的标志
---
category: "代码评审"
tags: [自我纠正, 评审质量, 诚实]
severity: "high"
frequency: 3
sources: ["simayi-correction", "mail"]
---
场景
评审者在审查代码时可能做出错误判断。高质量的处理不是掩盖,而是主动承认并修正。
错误做法
无。此处记录的是正确做法的范例。
正确做法
庞统在评审 spawner-monitor 时发现两处自己之前的判断有误,主动发邮件给司马懿修正:
"修正 1: 问题4 recent_compact 不是死代码,是设计实现遗漏" — 原判断"建议删除",修正为"设计文档 §B2/B3 明确要求" [pangtong/mail]
司马懿回复:
"你说得对,我判断错了。设计文档 §B2/B3 明确要求区分 compact 进行中和进程卡死" [simayi/mail]
关键细节
- 评审者翻回设计文档交叉验证,是发现误判的有效手段
- 庞统和司马懿都在同一次评审中做了自我纠正——这说明交叉验证机制在工作
- 修正邮件明确标注"修正"而非静默修改,保留了审计轨迹
反面教训
如果不主动修正,错误判断会被当作已确认结论传播,后续实现可能基于错误假设。
卡片 4:设计文档-代码一致性审查不可省
---
category: "系统设计"
tags: [设计文档, 代码一致性, 三层审查]
severity: "high"
frequency: 4
sources: ["simayi-correction"]
---
场景
迭代开发中设计文档可能更新不及时,或者代码实现偏离设计。需要 PRD→设计→代码的三层一致性审查。
错误做法
spawner-monitor 实现中,设计文档 §B2(compact 进行中继续等)在代码中完全遗漏。司马懿初评时也未发现,直到庞统重新读设计文档才暴露:
"代码只实现了 B1/B3/B4,B2 遗漏了。recent_compact 是 B2 实现的数据基础" [pangtong/mail]
正确做法
- 每次代码评审前,先对设计文档逐条检查实现覆盖度
- 设计文档用明确编号(§B1/B2/B3)便于逐条追踪
- 庞统安排了 "背靠背一致性审查":PRD→设计→代码全覆盖审计
- 司马懿的核心职责就是做这种三层对照
关键细节
- 庞统专门发了 #311 邮件请求"PRD→设计→代码三层一致性审查"
- 司马懿在 counter 生命周期评审中发现设计说 crash 3 次标 failed,但代码只 release counter 无计数
反面教训
设计-代码不一致导致假死检测失效,系统在 compact 后无法区分"还在跑"和"卡死了"。
卡片 5:方案确认的完整闭环标准
---
category: "系统设计"
tags: [闭环, 一键三连, 确认标准]
severity: "medium"
frequency: 2
sources: ["experience"]
---
场景
多方案并行开发时,哪些方案算"完成"容易模糊。
错误做法
庞统在 M2 阶段同时推进多个方案,只跟踪了"方案评审"状态,没跟踪"最终代码确认"状态。用户追问才发现 Checkpoint 和方案 C 的代码未闭环。
正确做法
一键三连收尾标准(用户明确定义):
- 改文档(设计/方案)
- 改代码(实现)
- 司马懿 review 并确认最终代码片段
每步完成都要有明确证据(邮件编号、代码片段引用)。
关键细节
- 状态跟踪表要包含三列:方案评审 / 最终代码确认 / 状态
- 司马懿的确认必须是具体的("代码片段与实际改动一致"),不是笼统的"通过"
反面教训
未闭环的方案被标记为"已完成",实际遗漏了代码审查环节。
卡片 6:Counter/锁的生命周期必须贯穿完整调用链
---
category: "系统设计"
tags: [counter, 锁, 生命周期, 资源管理]
severity: "high"
frequency: 3
sources: ["simayi-correction"]
---
场景
Agent 并发控制需要 counter/锁机制。如果 counter 的 acquire-release 不成对,会导致永久占满或双重释放。
错误做法
spawner _handle_exit 中 retry 路径提前调 on_complete("retry_release") 释放 counter,但续杯 spawn 时 counter 已释放,导致同一 Agent 被并发 spawn 多次:
"retry 路径提前调 on_complete("retry_release") 释放 counter,导致续杯 spawn 时 counter 已空" [simayi/mail]
司马懿在评审中发现 _do_retry 中 counter 仍被占用但 on_complete=None,导致续杯永远无法 acquire。
正确做法
- Counter 贯穿 retry 链:acquire 在 spawn 前,release 在最终退出(done/failed)后
- Retry 不释放 counter,而是复用同一个 counter slot
- 司马懿建议的 cooldown 机制:release 后短期冷却,防止立即 re-acquire 导致抖动
- 三层控制:cooldown → global limit → per-agent → per-session
关键细节
- 所有
release调用都要带 session_id(counter v2.1 的教训) - on_complete 回调的时序:进程退出 ≠ 回调完成
- 广播 spawn 路径也要 catch AgentBusyError
反面教训
counter 提前释放导致 zhipu API 429(rate limit 被打爆),Gateway 假死。修复后 counter 泄漏导致续杯死循环。
卡片 7:进程退出 ≠ 资源释放
---
category: "系统设计"
tags: [进程管理, 回调时序, on_complete]
severity: "high"
frequency: 2
sources: ["simayi-correction"]
---
场景
异步系统中,子进程退出和回调执行不是原子操作。如果假设进程退出时资源已释放,会出现竞态条件。
错误做法
spawner 在 retry 时:进程退出 → on_complete 未调用 → counter 仍占用 → spawn_full_agent 的 can_acquire 返回 False → AgentBusyError → 续杯永远不会成功。
正确做法
- 在
_do_retry中手动释放 counter,并将 on_complete 设为 None 防止 double release - 资源释放应该有明确的触发点,不能依赖"进程退出自然释放"
- 司马懿在评审中强调:需要确认每条退出路径都有对应的资源释放
关键细节
- on_complete=None 后续杯 spawn 完成无幻觉门控,靠 ticker 超时兜底——影响可接受但需要记录
- 安装目录同步是必须的检查项(司马懿每次评审都验证)
反面教训
未处理回调时序导致续杯死循环,任务永远无法完成。
卡片 8:续杯(retry)机制是最大假死来源
---
category: "编排调度"
tags: [续杯, retry, 假死, 死循环]
severity: "high"
frequency: 5
sources: ["simayi-correction"]
---
场景
任务执行超时后需要 retry("续杯")。如果 retry 机制本身有 Bug,会导致无限重试或永久卡住。
错误做法
多个 Bug 叠加导致续杯死循环:
- retry_count 在续杯中永远不变(retry_count=1/3),续杯永不停
- Mail 续杯用 RETRY_PROMPT(含 review 标记指令),Agent 标了 review,但 _mail_auto_complete 只认 done
- 续杯创建新 session 而非复用 main session,每次重试都是全新上下文,丢失之前工作
正确做法
- 续杯模板必须专用(MAIL_RETRY_PROMPT),明确禁止状态转换命令
- retry_count 必须在每次续杯时递增,max_retries 兜底
- 续杯应复用 session 保持上下文连续性
- 司马懿在 Bug-7 评审中确认:retry 应复用 main session,每次重试不创建新 session
关键细节
- 续杯模板的"不要执行状态转换"指令是关键——Agent 容易自作主张标 done
- 司马懿在 Bug-8 评审中发现 use_main_session 在三处(主 dispatch、legacy broadcast、retry)必须统一
反面教训
续杯死循环阻塞 tick,导致整个调度停滞。PM2 restart 后旧 session 仍在续杯,新 session 又被创建,资源爆炸。
卡片 9:广播路径与单播路径行为必须一致
---
category: "编排调度"
tags: [广播, 单播, 路径一致性]
severity: "medium"
frequency: 3
sources: ["simayi-correction"]
---
场景
任务调度有两条路径:指定 Agent 的单播和广播认领。如果两条路径的行为不一致,某些任务类型会系统性地出问题。
错误做法
广播路径 ticker._broadcast_claim 调 spawn_full_agent 时没传 task_id 和 db_path,导致续杯时无法查询任务状态,retry_count 永远不变:
"广播路径不传 task_id/db_path → 续杯时 retry_count=1/3 永远不变" [simayi/mail]
正确做法
- 所有 spawn 路径(单播、广播、retry)必须传递完整的上下文参数
- 评审时重点检查:新功能是否覆盖了所有 spawn 路径
- 司马懿多次提醒:广播 spawn 路径也要 catch AgentBusyError
关键细节
- Mail 变广播导致所有 Agent 假死的事件就是路径不一致的典型案例
- 司马懿在 v2.7.2 Pipeline 重构评审中建议统一 TickResult 返回值 + 方法注册
反面教训
广播路径缺失参数导致续杯死循环,影响所有通过广播认领的任务。
卡片 10:E2E 测试必须用真实环境
---
category: "编排调度"
tags: [E2E测试, 真实环境, 集成测试]
severity: "medium"
frequency: 3
sources: ["simayi-correction"]
---
场景
单元测试只能验证单个模块逻辑。编排系统的 Bug 往往出在模块交互(spawn → 执行 → 续杯 → 状态转换),只有真实环境 E2E 能暴露。
错误做法
早期只跑了单元测试,部署后发现大量中间状态卡住的任务。用户发现:
"dashboard的任务中,大量的停在了中间阶段" [user/simayi-correction]
正确做法
- E2E 测试走真实 Ticker + 真实 Agent spawn,不手动推动状态
- 测试用例覆盖完整生命周期:创建→调度→执行→续杯→完成/失败
- 司马懿独立跑 E2E 测试并做根因分析,与庞统的修复做交叉验证
- 每次修复后全量重跑 E2E(不是只跑失败的用例)
关键细节
- 司马懿的 E2E 报告格式:通过/失败计数 + 每个失败用例的根因分析
- 测试从 6/10 → 8/10 → 9/10 → 10/10 的渐进修复过程证明 E2E 驱动开发的有效性
反面教训
未做 E2E 导致假死问题在生产环境中才暴露,排查成本远高于测试阶段。
卡片 11:Agent 认领任务前必须检查角色匹配
---
category: "Agent 行为"
tags: [认领, 角色匹配, 任务分配]
severity: "medium"
frequency: 4
sources: ["simayi-correction"]
---
场景
黑板广播任务时,所有 Agent 都能看到。如果审查者(司马懿)认领了编码任务,会导致角色错配。
错误做法
simayi-challenger(审查者)认领了 coding 类型任务:
"问题1:Agent 角色错配(P1)— simayi-challenger(审查者)认领了 coding 任务" [pangtong/mail #337]
数据中有大量司马懿被广播认领 E2E coding 任务的记录(frag_0076, frag_0305, frag_0320 等),说明这是系统性问题。
正确做法
- 任务模板中明确角色匹配规则:只认领符合专长的任务
- 评审/审查类角色不应认领编码任务
- 任务描述中包含"只认领符合你专长的任务"的提示,但 Agent 仍然会忽略
关键细节
- 这个问题出现了 20+ 次(大量 E2E 广播任务被司马懿认领)
- 根因是黑板没有角色过滤机制,完全靠 Agent 自律
反面教训
角色错配导致编码任务被审查者执行,产出质量不符合预期。
卡片 12:inform 类型邮件不应触发完整 Agent 执行
---
category: "Agent 行为"
tags: [邮件, inform, 资源浪费]
severity: "high"
frequency: 2
sources: ["simayi-correction", "mail"]
---
场景
Agent 之间的邮件有两种:需要回复的(request)和纯通知的(inform)。如果 inform 也触发完整 Agent 执行,会浪费大量 token 和 counter 资源。
错误做法
庞统的 daemon 用 openclaw agent --agent simayi-challenger --timeout 300 处理 inform 邮件,Agent 被完整 spawn 执行,310s 超时后重新投递:
"daemon 用 openclaw agent --agent simayi-challenger --timeout 300 处理 inform 类型邮件,310s 超时后重新投递" [simayi-correction]
正确做法
- Mail 类型简化为两种:inform(通知)和 request(需要回复)
- inform 类型由 ticker 直接标 done,或用轻量 prompt("读完标 done")让 Agent 感知但不做完整执行
- 默认类型是 request,inform 是显式指定的特殊场景
关键细节
- 庞统和用户讨论后确认:inform 仍让 Agent 看到内容(可能包含重要信息),但 prompt 告诉它不需要回复
- 这种设计比 ticker 直接标 done 更合理
反面教训
inform 触发完整执行 + 超时重投递,形成死循环,消耗大量 API 调用和 token。
卡片 13:回答用户问题要直接,不要绕弯子
---
category: "沟通协作"
tags: [沟通, 直接回答, 效率]
severity: "medium"
frequency: 3
sources: ["pangtong-correction", "experience"]
---
场景
用户提出具体问题时,Agent 有时回避核心问题,用相关信息绕弯子。
错误做法
庞统在讨论 compact 卡死问题时,反复讨论"compact 发生的概率"和"v1 vs v2 的区别",而用户已经明确说了"集中讨论 compact 发生后如何处理":
"你说得对,我一直在说废话。子进程就是
openclaw agent,等子进程就是等openclaw agent执行完" [pangtong/experience]
"别绕了,我都说过了,请你集中在 compact 发生之后如何处理" [user]
正确做法
- 先直接回答用户的问题(哪怕答案是"不能/不知道")
- 不确定时说"不能",然后说明可以做什么
- 庞统最终的模式值得学习:"处理方式就三个问题:超时后怎么处理、重试用什么 session、重试几次后放弃。这就是全部。没有更复杂的了。"
关键细节
- "不能区分超时原因"本身就是一个有用的答案
- 不需要区分原因也能给出处理方案——区分原因只对监控有意义
反面教训
绕弯子浪费多轮对话,用户反复追问同一问题。
卡片 14:stdout JSON 解析路径必须实测验证
---
category: "系统设计"
tags: [JSON解析, stdout, 实测]
severity: "medium"
frequency: 2
sources: ["simayi-correction"]
---
场景
openclaw agent --json 的输出结构可能随版本变化。如果解析路径是猜的而非实测的,会导致静默失败。
错误做法
spawner 代码取 data.response.meta.transport,但实际 openclaw agent --json 的顶层结构是 { response: { meta: { transport, ... } } }:
"P0:_parse_stdout_json 解析路径错误(根因)— openclaw agent --json 输出格式是 { response: { meta: { transport, ... } } } 但代码取的路径不对" [pangtong/mail]
正确做法
- 解析外部命令输出前,先用实际命令验证输出格式
- 评审时要求看到实测输出样例
- 司马懿在 Spawner v3.0 评审中指出 JSON 解析路径需验证:
data.result.meta.executionTrace是新路径,需确认
关键细节
- 这个 Bug 从第一天就存在("从第一天就存在的根因 bug")
- 静默失败比报错更危险——解析不到数据时走了 fallback,掩盖了问题
反面教训
解析路径错误导致 stdout 信息丢失,所有依赖 stdout 判定的功能(如幻觉门控)失效。
卡片 15:跨项目调研的实践对照要做落地映射
---
category: "经验总结"
tags: [调研, 对照表, 落地映射]
severity: "low"
frequency: 2
sources: ["experience"]
---
场景
Agent 调研多个开源项目的最佳实践后,需要将发现映射到自己的项目架构中。
错误做法
庞统调研了 OpenAI Agent SDK、LangGraph、Claude Code 三个项目,产出了详细的对照表,但部分条目只停留在"可借鉴"层面,没有明确"怎么做"。
正确做法
- 调研产出必须包含"moziplus 可借鉴点"列,明确优先级(M2 直接借鉴 / 够用 / 暂不需要)
- 标注哪些是可直接复用的模式(如 Lifecycle Hooks → on_node_start/end),哪些需要适配
- 司马懿在评审 Pipeline 重构时引用了业界调研,确认"Temporal 模式最接近我们"
关键细节
- 调研本身就是 Agent 经验声明的一种形式
- 庞统的对照表格式(优秀实践 / 来源 / 核心模式 / 可借鉴点)是好的模板
反面教训
没有落地映射的调研容易变成"资料搬运",无法转化为架构改进。