---
title: 'Cookbook解读｜Plan、Goal、Spec 为什么不能互相替代'
description: '结合 OpenAI Cookbook、Claude Code 与 GitHub Spec Kit 的官方资料，拆开 Plan Mode、执行计划、Goal、Spec、Skill 和仓库规则各自负责的工程边界。'
pubDate: 2026-08-05
slug: plan-goal-spec-agent-contracts
tags: [agent, Codex, SDD, Cookbook解读]
lang: zh-CN
draft: false
---

给 Coding Agent 一个 Spec，让它先做 Plan，再开一个 Goal，最后还要准备 Skill 和 `AGENTS.md`——是不是把同一件事换了五种写法？

这个疑问很合理。它们都以自然语言出现，也都可能写着“必须运行测试”“不要改公共 API”。如果只看文件内容，确实像一叠互相抄作业的 Markdown。

问题在于，我们把不同层级的控制对象放进了同一个抽屉。OpenAI Cookbook 的 [Using PLANS.md for multi-hour problem solving](https://developers.openai.com/cookbook/articles/codex_exec_plans) 和 [Using Goals in Codex](https://developers.openai.com/cookbook/examples/codex/using_goals_in_codex)，恰好从“路径”和“终点”两侧把这个抽屉拆开；GitHub Spec Kit 又补上了更上游的需求契约。

先说结论：

> Spec 定义“要构建什么，以及不能破坏什么”；Goal 定义“当前任务凭什么可以停止”；Plan 记录“从现状走到目标的路径”；Skill 封装“同类任务以后怎样重复做”；`AGENTS.md` 或 `CLAUDE.md` 保存“在这个环境里长期遵守什么”。Validation 与 Eval 则提供证据，防止前面几份文档最后只剩下措辞正确。

它们会引用彼此，却不能互相替代。一个写得很细的 Plan 仍可能在实现错误需求；一个验收条件清晰的 Goal 也不会自动知道数据库迁移应该先做哪一步。

> **数据快照**
>
> - 最后核验：2026-08-04
> - 主要对象：OpenAI Cookbook 的 ExecPlan 与 Codex Goal、OpenAI Codex 官方文档、Anthropic Claude Code 官方文档、GitHub Spec Kit 官方文档
> - 产品门槛：Codex Goals 从 `0.128.0` 起可用；Claude Code `/goal` 文档要求 `2.1.139` 或更高版本
> - 证据边界：本文比较公开的控制机制，不提供不同工作流的成功率、成本或质量排名

## 第一个坑：Plan Mode、Plan 和 `PLANS.md` 不是一件事

讨论 Plan 之前，先要把三个同名对象分开。

### Plan Mode 是交互边界

Claude Code 的 [Plan Mode](https://code.claude.com/docs/en/permission-modes#analyze-before-you-edit-with-plan-mode) 允许 Claude 读取文件、运行探索命令并提出修改方案，但不编辑源码；用户批准后才切换到实施阶段。Codex 的官方命令文档也把 [`/plan`](https://learn.chatgpt.com/docs/developer-commands#built-in-slash-commands) 描述为“在实现开始前提出执行计划”。

所以 Plan Mode 首先是一种**交互与权限状态**：先调查和设计，把修改推迟到审阅之后。它可以产出一份 Plan，但“现在处于 Plan Mode”和“仓库里存在一份长期计划文档”不是同一句话。

### Plan 是当前任务的路径

普通 Plan 回答的是：基于现在看到的代码，准备改哪些模块，按什么顺序推进，怎样验证，哪里有风险。

它可以很短：

```text
1. 找出旧 OAuth 回调与 Session 写入位置
2. 增加 Provider Adapter，保留旧登录路径
3. 迁移 GitHub 回调并补集成测试
4. 运行认证测试与回归测试
```

路径依赖调查结果，因此允许改变。第二步发现用户表无法表达多个身份源，Plan 就应该更新，而不是为了证明自己“计划得很准”继续撞墙。

### `PLANS.md` 定义长期计划应该怎样写

OpenAI Cookbook 的 ExecPlan 又多了一层。`PLANS.md` 不是某个功能的具体计划，而是对**计划文档本身的仓库级约定**：什么时候需要 ExecPlan，它必须包含什么，执行过程中怎样维护。

Cookbook 要求 ExecPlan 自包含、面向不了解仓库的新手，并持续更新 `Progress`、`Surprises & Discoveries`、`Decision Log` 与 `Outcomes & Retrospective`。它既是设计文档，也是多小时任务的状态载体。文章甚至要求只拿到当前工作树和这一份 ExecPlan，也能继续推进。

这是一种适合长任务的 Cookbook 工作法，不是所有 Codex Plan 的强制格式。原文还带有当时的模型推荐；本文只采用它的计划模式，不把那条推荐当成 2026-08-04 的模型选择结论。

到这里可以先得到一个小结：Plan Mode 决定“现在先不修改”，Plan 决定“这次准备怎么改”，`PLANS.md` 决定“本仓库的长计划应该怎样写和维护”。三者相关，但作用域完全不同。

## Spec 与 Plan 的分界：先决定做对的东西，再决定怎样做

GitHub Spec Kit 的官方流程是 [Spec → Plan → Tasks → Implement](https://github.github.com/spec-kit/)。它的命令定义也刻意把两步拆开：[`/speckit.specify`](https://github.com/github/spec-kit#available-slash-commands) 定义 Requirements 与 User Stories，`/speckit.plan` 才加入技术栈和实现方案。

这条边界比“Spec 更大、Plan 更细”准确：

- Spec 约束产品行为、范围、非目标、兼容性和验收标准；
- Plan 根据现有代码与技术约束，选择实现路径；
- Tasks 再把路径切成可以执行和跟踪的工作单元。

例如“增加 GitHub OAuth 登录”，Spec 应该先回答：哪些用户能用，原有密码登录是否保留，账号冲突怎样处理，哪些场景不支持，什么行为算验收通过。至于使用哪一个 OAuth Library、用户表是否增加 Identity 表、Callback Route 放在哪个 Module，是 Plan 的问题。

如果把后者直接写进 Spec，技术方案一变，需求也跟着抖；如果把前者留给 Plan，Agent 可能交付一个实现精致、产品含义却完全不对的 GitHub 登录。

Spec 也不是越厚越好。一个只改错误文案的小任务，Prompt 里的两条约束已经可以充当 Spec-lite。只有当需求会跨团队、跨多轮或需要长期追踪时，独立 Spec 才开始值回维护成本。GitHub Spec Kit 展示的是一套完整 SDD 流程，不是每次提交都必须举行的开工仪式。

## Goal 与 Plan 的分界：一个固定终点，一个允许改路

Goal 最容易被误认为“更坚定的 Plan”。实际上，它不需要规定步骤。

OpenAI Cookbook 把 [Codex Goal](https://developers.openai.com/cookbook/examples/codex/using_goals_in_codex) 定义为跨 Turn 持续存在的目标：结果应该是什么，用什么证据检查，哪些约束必须保持。路径不确定时，Codex 可以依据新证据继续选择下一步；完成条件成立、预算耗尽或遇到真实阻塞时，循环才结束。

因此，两者对变化的态度正好相反：

- Goal 尽量稳定。测试失败不能靠降低门槛“解决”；
- Plan 必须能变。新发现应该推动路线修订；
- Evidence 每轮刷新。文件、测试、Benchmark 与产物决定离终点还有多远。

Claude Code 的 [`/goal`](https://code.claude.com/docs/en/goal) 也体现了同一分工：当前 Agent 每完成一轮，独立的小模型根据 Goal 与对话证据回答 Yes 或 No，未满足就发起下一轮。它要求的不是步骤表，而是可验证的 Completion Condition。Claude 的 Plan Mode 则负责先研究和提出改法，二者可以同时使用，并不冲突。

Codex 与 Claude 的 Goal 如何判定完成，上一篇[《Codex Goal 如何把“继续”变成完成协议》](/posts/codex-goals-completion-contract/)已经单独拆过。这里真正需要记住的是：**Plan 可以因为证据改变，Goal 只能因为需求改变。** 如果只是道路封闭，就换路线；如果连目的地都换了，那应该让用户重新确认任务，而不是悄悄更新计划。

## Skill 与仓库规则为什么放不进这条流水线

把 Spec、Goal 和 Plan 画成一条从需求到执行的链路还算自然，但 Skill 与 `AGENTS.md` 并不在链路的下一站。它们从侧面影响很多任务。

OpenAI 的 [Codex 定制文档](https://learn.chatgpt.com/docs/customization/overview#skills) 将 Skill 定位为可复用能力：`SKILL.md` 可以带脚本、参考资料与资源，在匹配到某类任务时按需加载。一个“数据库迁移 Skill”可以规定先备份、再 Dry Run、记录 Schema Diff、执行迁移并检查回滚；下次迁移仍然能用。

`AGENTS.md` 则保存持久工作约定。官方的 [`AGENTS.md` 文档](https://learn.chatgpt.com/docs/agent-configuration/agents-md) 用包管理器、测试命令和添加生产依赖前确认等规则举例。这类约定会影响许多任务，却不描述某一个功能的需求，也不会因为某次任务完成而自动消失。Claude Code 里的 `CLAUDE.md` 在概念上承担相近的长期上下文角色。

一个简单判断是：

- “这个 OAuth 功能必须保留密码登录”放进 Spec；
- “所有认证改动必须运行 `pnpm test:auth`”放进 `AGENTS.md`；
- “以后做身份源迁移都按这套审计流程”做成 Skill；
- “这一次具体修改哪些文件”写进 Plan；
- “所有验收项满足且回归测试通过才停”写成 Goal。

如果同一句规则确实同时出现在两处，不一定是坏事。关键是确认它在每个位置承担什么责任：Spec 中的“不能改公共 API”是产品约束，Goal 中再次引用它是停止条件，Plan 中提到它是实施提醒，验证器则要真正检查它。

## 六个对象如何在一次任务中配合

把这些对象放回一次真实工程任务，关系会比定义更清楚。

**图 1：Spec、Goal 与 Plan 组成任务主循环；Skill 和仓库规则横向约束工作方式，Validation/Eval 把实现状态反馈给 Goal**

```mermaid
flowchart LR
  S["Spec<br/>行为、边界、验收"] --> G["Goal<br/>当前完成条件"]
  S --> P["Plan<br/>实现路径"]
  G --> P
  P --> W["实施与调查"]
  W --> V["Validation / Eval<br/>测试、审阅、产物"]
  V --> D{"Goal 成立？"}
  D -->|"否"| P
  D -->|"是"| C["完成"]
  A["AGENTS.md / CLAUDE.md<br/>长期环境规则"] -.约束.-> P
  A -.约束.-> W
  K["Skill<br/>可复用工作流"] -.提供方法.-> P
  K -.提供方法.-> W
```

这张图不是强制流程。小任务可以把 Spec 和 Goal 压缩进一句 Prompt，也可以不创建持久 Plan。图里真正不能省略的是最后的证据回边：没有 Validation 或 Eval，Goal 只能听 Agent 自己描述进度，Spec 与 Plan 也无法知道实现是否偏离。

**表 1：截至 2026-08-04 的职责对照；“生命周期”描述典型作用域，不代表所有工具都使用相同存储实现**

| 对象                      | 核心问题               | 典型生命周期               | OAuth 示例                                | 不能替代什么         |
| ------------------------- | ---------------------- | -------------------------- | ----------------------------------------- | -------------------- |
| Spec / SDD                | 要构建什么，边界是什么 | 功能或产品演进期间         | 保留密码登录，不做账号自动合并            | 实现路线、运行时续跑 |
| Goal                      | 什么证据成立时才可以停 | 当前 Task / Session        | 认证验收与回归测试全部通过                | 产品需求、详细步骤   |
| Plan                      | 基于现状准备怎样实现   | 当前任务，随发现更新       | Adapter、Migration、Callback、Test 的顺序 | 需求决策、长期规则   |
| Task List                 | 下一批可执行单元是什么 | 一个 Milestone 或迭代      | 拆出 Schema、Route、Test 工作项           | 整体设计与完成协议   |
| Skill                     | 同类任务以后怎样重复做 | 跨 Task 复用               | 身份迁移的审计与回滚流程                  | 本次功能需求与终态   |
| `AGENTS.md` / `CLAUDE.md` | 在这个环境里长期守什么 | Repository、目录或用户范围 | 包管理器、测试命令、禁改目录              | 某个功能的 Spec      |

表里没有把 Validation/Eval 单列成一种文档，因为它更像证据层。测试、静态检查、人工 Review、Benchmark 和验收脚本可以被 Spec、Goal 与 Plan 同时引用，却不能被任何一段自然语言替代。

## 不同规模的任务，最小组合也不同

这些对象不是集邮项目。更实用的选择方式，是从任务风险与反馈周期反推最小组合。

### 一次性小改动：Prompt + 仓库规则 + 验证

改文案、修一个明确的 Null Pointer、补一条小测试，通常不值得先维护独立 Spec 与 ExecPlan。Prompt 说清楚预期和边界，Agent 遵守 `AGENTS.md`，最后运行对应检查即可。

### 中型功能：Spec-lite + Plan + 验收

OAuth、缓存切换或一个跨模块 API，已经有多种合理实现。先写清用户行为、非目标和验收项，再让 Agent 在 Plan Mode 调查代码并提交方案。只要实现仍能由人掌控下一次决策，未必需要 Goal 自动续跑。

### 长任务且路径不确定：Spec + Goal + Living Plan + Eval

大型迁移、性能调优、间歇性故障和研究复现，终点可以定义，路径却会被每轮证据改写。这正是 Goal 与 ExecPlan 同时有价值的场景：Goal 固定完成协议，Living Plan 保存当前路线、发现与决策，Eval 提供继续或停止的依据。

### 反复出现的任务：把稳定部分提炼成 Skill

当第三次复制同一套发布、审计或迁移步骤时，再把稳定方法抽成 Skill。Skill 应复用流程，不应把上一次任务的业务目标一起封存。否则“可复用能力”很快会变成一份过期 Plan。

## 最容易踩的四个替代错误

第一，用 Plan 代替 Spec。Agent 把文件、函数和步骤写得很具体，看起来已经想清楚了，但“用户到底要什么”仍然由实现者临场决定。

第二，用 Goal 代替 Plan。“所有测试通过”可以防止过早停止，却不会告诉 Agent 怎样迁移数据、怎样回滚，以及先验证哪个高风险假设。

第三，用 `AGENTS.md` 堆所有知识。长期规则会被一次性需求污染，真正每次都该遵守的命令反而淹没在大段功能背景里。

第四，把 Skill 当成完成证明。Skill 只能提高流程复用和执行一致性；它被正确调用，不代表本次产物已经通过验收。操作手册翻到了最后一页，机器不一定真的修好了。

## 总结

Plan、Goal 与 Spec 看起来相似，是因为它们都需要描述目标、约束和验证；真正的区别不在 Markdown 语法，而在**谁读取它、何时生效、允许怎样变化**。

Spec 是需求契约，应该在需求变化时更新；Goal 是当前任务的停止协议，应该在证据成立时完成；Plan 是可修订的路线，应该在新发现出现时改变。Skill 保存跨任务可复用的方法，`AGENTS.md` 或 `CLAUDE.md` 保存跨任务持续生效的环境规则。Validation 与 Eval 则负责让这些自然语言最终碰到现实。

下一次再遇到一个长任务，可以先问五个问题：用户行为是否已经写清，完成是否有可检查证据，路径是否需要先调查，流程以后会不会重复，哪些规则应该对整个仓库长期生效。答案会自然落到 Spec、Goal、Plan、Skill 和 `AGENTS.md`，而不是先建五个文件再往里填内容。

导航、终点、合同、操作手册和交通规则都很有用。麻烦通常不是缺少其中一个，而是拿着交通规则当地图，然后期待它告诉你什么时候已经到家。

## 参考资料

- [OpenAI Cookbook：Using PLANS.md for multi-hour problem solving](https://developers.openai.com/cookbook/articles/codex_exec_plans)
- [OpenAI Cookbook：Using Goals in Codex](https://developers.openai.com/cookbook/examples/codex/using_goals_in_codex)
- [OpenAI Codex：Developer commands](https://learn.chatgpt.com/docs/developer-commands)
- [OpenAI Codex：Customization / Skills](https://learn.chatgpt.com/docs/customization/overview#skills)
- [OpenAI Codex：Custom instructions with AGENTS.md](https://learn.chatgpt.com/docs/agent-configuration/agents-md)
- [Anthropic：Choose a permission mode](https://code.claude.com/docs/en/permission-modes)
- [Anthropic：Keep Claude working toward a goal](https://code.claude.com/docs/en/goal)
- [GitHub Spec Kit](https://github.github.com/spec-kit/)
- [GitHub Spec Kit：Specification-Driven Development](https://github.com/github/spec-kit/blob/main/spec-driven.md)
