[English Version →](/en/lectures/lecture-12-why-every-session-must-leave-a-clean-state/)

> 本篇代码示例：[code/](https://github.com/walkinglabs/learn-harness-engineering/blob/main/docs/zh/lectures/lecture-12-why-every-session-must-leave-a-clean-state/code/)
> 实战练习：[Project 06. 搭建一套完整的 agent 工作环境](./../../projects/project-06-runtime-observability-and-debugging/index.md)

# 第十二讲. 每次会话结束前都做好交接

## 这节课要解决什么问题

你的 agent 跑了一下午，改了 20 个文件，提交了代码，会话结束。下一个 agent 会话开始，一上来就发现：构建失败了、测试红了、临时调试文件到处都是、功能清单没更新、进度完全不清楚。新会话的前 30 分钟全花在"搞清楚上一个会话到底干了什么"上。

OpenAI 和 Anthropic 都明确指出：**长期可靠性取决于操作纪律，不仅是单次运行的成功。** 每个会话结束时的状态质量，直接决定下一个会话的效率。这就像 Git 的最佳实践——每次提交应该是一个原子性的、可编译的变更，而不是一堆半成品代码的堆砌。

## 核心概念

- **清洁状态**：会话结束时系统满足五个条件——构建通过、测试通过、进度已记录、无过时工件、启动路径可用。缺一个都不算"做完"。
- **会话完整性**：类比数据库事务——要么全部提交并留下清洁状态，要么回滚到上一致状态。没有中间地带。
- **质量文档**：对每个模块的质量等级做持续记录的活跃工件。不是一次性评估，而是跟踪代码库是变强了还是变弱了。
- **清理循环**：定期的维护会话，目标是系统性减少代码库中的熵。不是紧急修复，而是常规运维。
- **harness 简化**：随着模型能力提升，定期移除不再必要的 harness 组件。今天必要的约束，三个月后可能是多余的开销。
- **幂等清理**：清理操作无论执行多少次都产生相同结果。确保清理在失败重试场景中仍然安全。

## 为什么会这样

### 熵增是默认状态

Lehman 的软件演化定律告诉我们：持续变更的系统，除非主动管理，否则复杂性必然增加。这对 AI 编码 agent 尤其成立——agent 每次会话都会引入变更，如果不在退出时清理，技术债务会指数级累积。

**agent 会复制仓库中已有的模式——即使那些模式是不均匀的或次优的。** 这是 OpenAI 在 5 个月的 Codex 实验中观察到的一个核心现象。随着时间的推移，这种复制必然导致漂移。

OpenAI 团队最初花每周五（20% 的工作时间）手动清理 "AI slop"。不出所料，这种方式不可扩展。他们的解决方案是：

1. **把"黄金原则"编码进仓库**：比如"优先使用共享工具包而非手写的 ad-hoc 辅助函数"（保持不变量集中）、"不要 YOLO 式地猜数据结构"（验证边界或依赖类型化 SDK）。这些原则是具体的、机械的、可自动检查的。
2. **建立周期性的清理流程**：一组后台 Codex 任务定期扫描偏差，更新质量评分，开针对性的重构 PR。大多数可以在一分钟内审查并自动合并。
3. **人类品味捕获一次，持续执行**：审查意见、重构 PR、用户侧 bug 都被转化为文档更新或直接编码到工具中。当文档不够用时，把规则提升为代码。

这个机制就像垃圾回收——技术债是高息贷款，持续小额还清几乎总是比攒到一次性爆发好得多。

> 来源：[OpenAI: Harness engineering: leveraging Codex in an agent-first world](https://openai.com/index/harness-engineering/)一个使用 agent 持续开发 12 周的项目，没有清洁策略的情况下：

- 第 1 周：构建通过率 100%，测试通过率 100%，新会话启动 5 分钟
- 第 4 周：构建 95%，测试 92%，启动 15 分钟
- 第 8 周：构建 82%，测试 78%，启动 35 分钟
- 第 12 周：构建 68%，测试 61%，启动 60+ 分钟

同样的项目，有清洁策略的情况下：

- 第 1 周：100%，100%，5 分钟
- 第 12 周：97%，95%，9 分钟

12 周后，构建通过率差 29 个百分点，新会话启动时间差 85%。这不是理论推导，是实际可观测到的差异。

### 五个维度的清洁状态

清洁状态不是单一的"代码能编译"，而是五个维度的综合：

**构建维度**：代码能无错构建？这是最基本的——下一个会话不应该先修构建错误。

**测试维度**：所有测试通过？包括会话之前就存在的测试——会话有责任不破坏已有功能。而且要在 CI 环境验证，不是"在我机器上通过"。

**进度维度**：当前进度已记录在机器可读的工件中？已完成的子任务和通过标准、进行中但未完成的子任务和当前状态、尚未开始的子任务。好的进度记录减少 60-80% 的会话启动诊断时间。

**工件维度**：无过时或歧义的临时工件？调试日志、临时文件、注释掉的代码、TODO 标记——这些都增加下一个会话的认知负担。

**启动维度**：标准启动路径可用？下一个会话能不能不人工干预就开始工作？环境初始化、代码库加载、上下文获取、任务选择——这些路径不能被破坏。

### "以后再清理"是永远不清理

最常见的心理陷阱是"这次来不及清理了，下次再弄"。但下次的 agent 不知道你上次留下了什么——它看到的是一堆混乱的代码和不确定的状态。它会花大量时间推断"这堆代码里哪些是有意的，哪些是临时的"。

更糟的是，每个会话都有自己的任务目标。新会话来的时候是要做新功能的，不是来清理上一个会话的烂摊子的。它会忽略混乱直接开始新工作，然后在混乱的基础上引入更多混乱。这是熵增的正反馈循环。

## 怎么做才对

### 1. 清洁状态作为完成的必要条件

在 harness 里明确定义：**会话完成 = 任务通过验证 AND 清洁状态检查通过。** 缺任何一个，会话不算完成。在 CLAUDE.md 里写：

```
## 会话退出检查清单
- [ ] 构建通过 (npm run build)
- [ ] 所有测试通过 (npm test)
- [ ] 功能清单已更新
- [ ] 无调试代码残留 (console.log, debugger, TODO)
- [ ] 标准启动路径可用 (npm run dev)
```

### 2. 双模式清理策略

结合两种清理模式：

**即时清理（每个会话结束时）**：清理本次会话创建的临时工件、更新功能清单状态、确保构建和测试通过。这是"引用计数式"清理。

**定期清理（每周一次）**：全系统扫描——处理累积的结构性问题、更新质量文档、运行基准测试检测漂移。这是"追踪式"清理。

### 3. 维护质量文档

质量文档是对每个模块持续评分的活跃工件：

```markdown
# 质量文档

## 用户认证模块 (质量: A)
- 验证通过: 是
- agent 可理解: 是
- 测试稳定性: 稳定
- 架构边界: 合规
- 代码规范: 遵循

## 支付模块 (质量: C)
- 验证通过: 部分（支付回调未测试）
- agent 可理解: 困难（逻辑分散在 3 个文件）
- 测试稳定性: 不稳定（2 个 flaky 测试）
- 架构边界: 有违规
- 代码规范: 部分遵循
```

新会话读这个文档就知道优先处理哪里。质量评分最低的模块先修。

### 4. 定期简化 harness

harness 里的每个组件之所以存在，是因为模型无法独立做好某件事。但随着模型改进，这些假设会过时。

Anthropic 的实验直接展示了这一点。他们最初的 harness 包含 sprint 拆分机制——把工作分成小块让 Sonnet 4.5 逐个完成。当 Opus 4.6 发布后，模型的原生能力已经可以自主处理工作分解，sprint 构造变成了不必要的开销。移除后，builder agent 能连续工作超过两小时而不会跑偏，反而更流畅。

但 evaluator 的情况不同。即使 Opus 4.6 能力更强，在任务接近模型能力边界时，evaluator 仍然提供了实际价值——捕获 generator 的遗漏功能和存根实现。这意味着 evaluator 不是一个固定的是/否决策，而是取决于任务难度相对于模型能力的位置。

**推荐做法**：每月挑一个 harness 组件，暂时禁用它，跑基准任务。如果结果没退化，永久移除。如果退化了，恢复或用更轻量的替代。

一个更具体的原则：**随着模型改进，harness 的有趣组合不是变少了，而是移动了。** 以前必须解决的问题被模型能力覆盖了，但新的能力边界打开了以前不可能的 harness 设计。AI 工程师的工作是持续找到下一个有价值的组合。

### 5. 高吞吐量改变了 merge 哲学

当 agent 的产出远超人类审查能力时，传统的 merge 哲学需要调整。

OpenAI 团队的经验：在一个 agent 每天开 3.5 个 PR（且后来增加到更多）的环境里，最小化阻塞式 merge gate 是正确的。PR 应该短命。测试 flake 通常用后续运行解决，而不是无限期阻塞进度。在一个修正成本很低、等待成本很高的系统里，快速前进 + 快速修正是比缓慢确认更好的策略。

**注意**：这在低产出环境里是不负责任的。但在 agent 产出远超人类注意力的环境里，这往往是正确的权衡。关键判断标准：**修正一个 bug 的平均成本 vs 等待人类审查一个 PR 的平均成本。** 前者低于后者时，快速合并是对的。

### 5. 清理操作必须幂等

清理脚本要能安全地重复执行：

```bash
# 幂等的清理操作
rm -f /tmp/debug-*.log  # -f 确保文件不存在时不报错
git checkout -- .env.local  # 恢复到已知状态
npm run test  # 验证清理未破坏功能
```

## 实际案例

一个使用 agent 持续开发的 Electron 应用，12 周演化过程的对比数据：

**无清洁策略**（对照组）：第 12 周，构建通过率 68%，测试通过率 61%，新会话启动 60+ 分钟，过时工件 103 个。

**有清洁策略**（实验组）：每个会话结束时执行完整清洁检查 + 每周清理循环。第 12 周，构建通过率 97%，测试通过率 95%，新会话启动 9 分钟，过时工件 11 个。

到第 12 周，实验组的构建通过率比对照组高 29 个百分点，测试通过率高 34 个百分点，新会话启动时间减少 85%。

## 关键要点

- **清洁状态是会话完成的必要条件**——不是可选的善后工作，是"完成定义"的一部分。
- **五个维度缺一不可**——构建、测试、进度、工件、启动，每个都要显式检查。
- **质量文档让代码库健康可追踪**——知道哪里在退化才能主动修复。
- **定期简化 harness**——随着模型能力提升，移除不再必要的约束。
- **"以后再清理"等于永远不清理**——熵增是默认状态，只有主动的清洁操作才能对抗它。

## 延伸阅读

- [Clean Code - Robert C. Martin](https://www.goodreads.com/book/show/3735293-clean-code) — 代码清洁性的系统化原则
- [Harness Engineering - OpenAI](https://openai.com/index/harness-engineering/) — 可重复性作为 harness 设计的核心要求
- [Effective Harnesses - Anthropic](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents) — 清洁会话退出对长期可靠性的关键作用
- [Programs, Life Cycles, and Laws of Software Evolution - Lehman](https://ieeexplore.ieee.org/document/1702314) — 软件演化定律，证明系统复杂性在无主动维护时必然增长

## 练习

1. **清洁状态检查表**：为你的代码库设计一个会话退出检查表，涵盖五个维度。在 5 个连续会话中应用，记录每个维度上的违反次数。

2. **基准对比实验**：固定任务集，两种 harness 变体（有/无清洁状态要求）各跑一遍。比较完成率、重试次数和缺陷逃逸率。

3. **harness 简化实践**：选一个 harness 组件，暂时禁用，跑基准任务。比较有无该组件的结果。决定保留、移除还是替换。
