# Project 08. 把你的工作流画成一张图

> 相关讲义：[L14. 从单循环到图工程](./../../lectures/lecture-14-graph-engineering/index.md)

## 你要做什么

这是从 "Loop" 到 "Graph" 的跃迁项目。上一讲你搭了一个 maker-checker loop——实现、验证、反馈、再实现，所有决策都发生在同一个 agent 的上下文窗口里。这一讲你要做的，是**把藏在循环里的结构显式地画出来**：节点、边、共享状态、路由规则，一个字一个字地写清楚。

你会做三个递进的实验：先把 P07 的 maker-checker loop 画成一张显式图，再给图加一个并行 fan-out/fan-in 节点，最后加一条条件回退边和一个人工审批节点。做完你会亲身感受到一件事：**图不是新发明，是当你的 loop 复杂到一定程度后，它自己变成的样子。**

## 用什么工具

- Claude Code 或 Codex
- Git
- 你在 P07 搭好的 maker-checker loop（或任何一个你能反复跑的 agent 工作流）
- 一个文本编辑器或绘图工具（画图不是为了好看，是为了把结构写清楚；`mermaid` 或手写 `graph.md` 都行）

## 具体步骤

### 准备工作

1. 从 P07 完成后的仓库出发，或者直接用你正在跑的任何 agent 工作流。
2. 创建三个分支：`p08-explicit-graph`、`p08-parallel`、`p08-human-in-the-loop`。
3. 准备一个 `state.md` 作为共享状态文件：需求、进度、验证结果都写在这里。这是图的"公共工作台"。

### 实验一：把 Loop 画成显式图

切到 `p08-explicit-graph` 分支。

1. **列出所有节点**：把 P07 maker-checker loop 里的每一步写成一个节点。每个节点写清楚：它的职责、它的输入、它的输出、它是 agent 还是确定性代码。
2. **画出所有边**：列出节点之间的每一条边。重点标注两条特殊边：
   - 条件边：验证通过/失败，走哪条
   - 回退边：失败回到哪个节点
3. **写共享状态**：明确列出状态里有哪些字段（需求、代码、测试结果、审查结论），谁读谁写。
4. **写路由规则**：用最简单的 if-then 语言写下"下一步去哪"的规则，比如：
   ```
   if 验证通过 → 合并节点
   if 验证失败 → 实现节点
   if 实现节点信息不足 → 研究节点
   ```
5. **写成 `graph.md`**：把以上内容整理成一份文档。用 mermaid 画一张图，附上节点表和路由规则。
6. **回答这个问题**：画完之后，找出至少一条**原来是隐式的边**——以前藏在 agent 上下文里、你自己都不知道它存在的决策路径。

### 实验二：加一个并行 Fan-out / Fan-in 节点

切到 `p08-parallel` 分支。

1. **选一个可以并行的点**：找任务里一个可以拆成两个独立部分的地方。比如：
   - 实现拆成两个独立模块，两个 agent 并行写
   - 验证拆成两个独立审查：一个跑测试和 lint，一个做代码审查（不同的指令、不同的关注点）
   - 研究拆成两个方向，两个 agent 各查一路
2. **写 fan-out 规则**：共享状态里记录"这个任务被拆成 N 个并行子任务"，每个子任务一个独立的 context、一个独立的节点。
3. **写 fan-in 规则**：所有子任务完成后，谁来合并结果？合并的标准是什么（比如：两个审查都通过才合并，还是有一个通过就行）？
4. **用 worktree 隔离**：每个并行子任务在独立的 git worktree 里跑，物理上避免文件碰撞（回顾第十三讲的 Worktree 原语）。
5. **跑一次并记录**：记录并行前后 wall-clock 时间、token 消耗、结果质量。并行真的更快吗？还是协调开销吃掉了省下的时间？

### 实验三：加一条回退边和一个人工审批节点

切到 `p08-human-in-the-loop` 分支。

这是三个实验里最重要的一个。你要在图上加两种节点：

1. **条件回退边**：给验证节点加一条"部分通过"的路径——不是全盘打回实现节点，而是带着具体反馈回到**产生问题的那个节点**。比如：测试全过但代码审查发现需求理解有误，回退到研究节点而不是实现节点。这要求你的共享状态里记录"问题出在哪一层"。
2. **人工审批节点（Human-in-the-loop）**：在合并节点之前加一个人工节点。走到这里，图**停下来**，等你在 `state.md` 里写"批准"或"打回"。审批节点可以有一个超时规则：N 小时后没响应，自动打回或自动升级。
3. **写 interrupt 的格式**：审批请求怎么写清楚——发生了什么、改了什么、为什么需要人、批准/打回的后果各是什么。
4. **跑至少 2 轮完整流程**：每一轮都走到人工审批节点，你自己批准或打回一次。记录：你的审批决策和验证节点的判断一致吗？审批节点拦住过什么验证节点没拦住的吗？

## 怎么衡量结果

| 指标 | 实验一（显式图） | 实验二（并行） | 实验三（人机协同） |
|------|----------------|--------------|------------------|
| 结构可见性 | 找出了几条隐式边？ | 共享状态能否支撑并行子任务？ | 回退边能否精确定位问题层？ |
| 失败定位 | 失败时能否直接指出是哪条边错了？ | 并行子任务失败时，能定位到哪一个？ | 审批打回时，能指出是哪一层的问题吗？ |
| 协作开销 | 写图花了多久？ | 并行省下的时间 vs 协调开销 | 审批等待时间 vs 拦住的问题价值 |
| 可观测性 | 每一步发生了什么，现在看得见了吗？ | 每个并行子任务的状态可见吗？ | 审批请求写得够清楚吗？ |
| 可靠性 | 图描述和实际运行一致吗？ | fan-in 合并标准靠谱吗？ | 超时/升级规则真的会触发吗？ |

## 要交什么

- `graph.md`（实验一的完整图描述：mermaid 图 + 节点表 + 边表 + 共享状态字段 + 路由规则）
- 实验一发现的隐式边清单（至少一条）
- 实验二的 fan-out/fan-in 规则和一次并行运行记录（时间/成本/质量对比）
- 实验三的回退边规则、审批节点格式和 2 轮人机协同记录
- 最终复盘：从 loop 到 graph，你的工作方式发生了什么变化？哪些任务值得画图，哪些不值得？

## 对应讲义

- [Lecture 14 — 从单循环到图工程](../../lectures/lecture-14-graph-engineering/index.md)
- [Lecture 13 — 从手动驱动到自动循环](../../lectures/lecture-13-loop-engineering/index.md)（你的 loop 就是图里的一个节点；这个项目是把节点的内部结构摊开）
- [Lecture 09 — 为什么 agent 会提前宣告完成](../../lectures/lecture-09-why-agents-declare-victory-too-early/index.md)（验证节点为什么必须独立于实现节点，在图中是结构问题）
- [Lecture 11 — 为什么可观测性属于 harness 的一部分](../../lectures/lecture-11-why-observability-belongs-inside-the-harness/index.md)（图越复杂，越需要看到每个节点在做什么）
