跳到正文

双实例计划工作流

使用两个具有不同角色的 Claude 实例:一个负责计划和审查(Claude Zero),一个负责实现(Claude One)。职责分离提高了计划质量并减少了实现错误。


目录

  1. TL;DR
  2. 何时使用此模式
  3. 配置
  4. 完整工作流
  5. 计划模板
  6. 成本分析
  7. 技巧与故障排查
  8. 参见

TL;DR

Plain
1. 启动 Claude Zero(计划者):探索、撰写计划、审查
2. 启动 Claude One(实现者):读取计划、编写代码、提交
3. 人工把关:在实现前批准计划
4. 计划目录:Review/ → Active/ → Completed/
5. 费用:~$100-200/月(vs Boris 水平模式的 $500-1K)

最适合:独立开发者、规范密集型工作、质量优先于速度、预算 <$300/月


何时使用此模式

适合使用的情况

  • 复杂规范:需要通过访谈式问答来澄清需求
  • 质量关键功能:安全、支付、数据迁移
  • 学习阶段:新代码库、不熟悉的模式
  • 产品设计师写代码:非开发背景,需要计划的严格性
  • 预算有限:$100-200/月(vs 并行多实例的 $500-1K)
  • 规范密集型工作流:详细需求、多种边界情况

不适合使用的情况

  • 简单改动:错别字修复、简单重构(使用单实例)
  • 探索性编码:问题空间未知(计划开销不值得)
  • 时间紧迫:速度优先于质量(接受修正循环)
  • 高并发功能:使用 Boris 模式(第 9.17 节)替代
  • 极少预算:<$100/月(使用 Sonnet,单实例)

与其他模式的对比

模式扩展维度月费用最适合
单实例$50-100大多数开发者,通用用途
双实例(Jon)垂直(计划 ↔ 实现)$100-200规范密集、质量优先
多实例(Boris)水平(5-15 并行)$500-1,000团队、高并发交付

配置

步骤 1:创建目录结构

Bash
cd ~/projects/your-project
mkdir -p .claude/plans/{Review,Active,Completed}

目录职责

  • Review/ — 等待人工批准的计划
  • Active/ — 已批准、正在实现的计划
  • Completed/ — 已归档的计划(学习资源)

添加到 .gitignore

Bash
# .gitignore
.claude/plans/Review/
.claude/plans/Active/
# 可选:提交 Completed/ 供团队学习

步骤 2:启动 Claude Zero(计划者)

终端 1

Bash
cd ~/projects/your-project
claude

首条消息(角色强制):

Plain
你是 Claude Zero(计划者)。

你的职责:
- 使用计划模式(按两次 Shift+Tab)探索代码库
- 就需求向用户提问
- 将详细计划写入 .claude/plans/Review/
- 在 Claude One 完成实现后审查
- 绝不直接编辑代码
- 绝不提交变更

请先确认你的角色。

Claude Zero 确认:"明白。我是 Claude Zero(计划者)。我将探索、计划和审查,但绝不接触代码。"

步骤 3:启动 Claude One(实现者)

终端 2(新会话):

Bash
cd ~/projects/your-project
claude

首条消息(角色强制):

Plain
你是 Claude One(实现者)。

你的职责:
- 从 .claude/plans/Active/ 读取已批准的计划
- 严格按照规范实现
- 每完成一个逻辑步骤后提交变更
- 向用户报告完成情况
- 绝不创建计划
- 绝不跳过批准步骤

请先确认你的角色。

Claude One 确认:"明白。我是 Claude One(实现者)。我只执行已批准的计划。"


完整工作流

阶段一:计划(Claude Zero)

步骤 1.1:启动计划

(发给 Claude Zero):

Plain
# 进入计划模式(按两次 Shift+Tab),然后:

为 API 实现 JWT 认证:
- 访问令牌(15 分钟过期)
- 刷新令牌(7 天过期)
- 保护路由的中间件
- 退出登录功能(撤销刷新令牌)

步骤 1.2:Claude Zero 探索

Claude Zero(在计划模式中):

  • 阅读现有认证代码
  • 搜索代码库中的认证模式
  • 识别依赖项(库、环境变量)

步骤 1.3:Claude Zero 向你提问

Claude Zero 提出澄清问题:

Plain
在起草计划前,我需要澄清以下问题:

1. 是否支持每个用户多个并发会话?
   (例如,用户同时在手机和笔记本上登录)

2. 刷新令牌存储在哪里?
   - 数据库表
   - Redis
   - 其他

3. 哪些路由需要保护?
   - 所有 /api/* 路由?
   - 特定路由?

4. 是否需要对登录尝试进行速率限制?

5. "完成"的成功标准是什么?
   - 测试通过?
   - Postman 集合?
   - 文档更新?

你回答,Claude Zero 细化理解。

步骤 1.4:Claude Zero 撰写计划

Claude Zero 创建 .claude/plans/Review/auth-jwt.md

Markdown
# 计划:JWT 认证

**创建日期**:2026-02-04
**作者**:Claude Zero
**估算工作量**:3-4 小时
**风险级别**:中(安全关键)

## 摘要
实现基于 JWT 的认证,采用访问令牌/刷新令牌模式。
支持每个用户多个并发会话。
刷新令牌存储在数据库中,支持撤销功能。

## 需求澄清
- 每用户多会话:是
- 刷新令牌存储:数据库(新建表)
- 保护路由:除 /api/auth/* 外的所有 /api/*
- 速率限制:是(每 15 分钟 5 次)
- 成功标准:测试通过 + Postman 集合

## 待创建文件

### 1. src/auth/jwt.ts(约 120 行)
**用途**:JWT 工具函数

**导出**
- `generateAccessToken(userId: string): string`
  - 负载:{ userId, type: 'access' }
  - 过期:15 分钟
  - 用 JWT_SECRET 签名

- `generateRefreshToken(userId: string): string`
  - 负载:{ userId, type: 'refresh', jti: uuid() }
  - 过期:7 天
  - 用 JWT_REFRESH_SECRET 签名
  - jti = 用于撤销的唯一令牌 ID

- `verifyAccessToken(token: string): { userId: string } | null`
  - 验证签名
  - 检查过期
  - 返回负载或 null

- `verifyRefreshToken(token: string): { userId: string, jti: string } | null`
  - 验证签名
  - 检查过期
  - 检查是否已撤销(数据库查询)
  - 返回负载或 null

**依赖**:jsonwebtoken、uuid

### 2. src/middleware/auth.ts(约 60 行)
**用途**:认证中间件

**导出**
- `requireAuth(req, res, next)`
  - 从 Authorization 头提取令牌(Bearer 格式)
  - 使用 verifyAccessToken() 验证
  - 将 userId 附加到 req.userId
  - 无效/缺失时返回 401

**依赖**:jwt.ts

### 3. src/db/migrations/YYYYMMDD_create_refresh_tokens.ts(约 40 行)
**用途**:刷新令牌数据库表

**Schema**
```sql
CREATE TABLE refresh_tokens (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  jti UUID NOT NULL UNIQUE,
  created_at TIMESTAMP DEFAULT NOW(),
  expires_at TIMESTAMP NOT NULL,
  revoked_at TIMESTAMP
);
CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id);
CREATE INDEX idx_refresh_tokens_jti ON refresh_tokens(jti);

待修改文件

1. src/routes/api.ts

位置:第 23 行(导入后)改动:为除 /auth/* 外的所有路由添加 requireAuth 中间件

之前

TypeScript
router.get('/profile', profileController);
router.post('/posts', createPostController);

之后

TypeScript
import { requireAuth } from '../middleware/auth';
router.get('/profile', requireAuth, profileController);
router.post('/posts', requireAuth, createPostController);

2. src/routes/auth.ts

位置:创建新文件或添加到现有认证路由改动

  • POST /auth/login → 返回 { accessToken, refreshToken }
  • POST /auth/refresh → 用刷新令牌换取新的访问令牌
  • POST /auth/logout → 撤销刷新令牌

3. src/config/env.ts

位置:第 15 行(现有密钥后)添加

TypeScript
JWT_SECRET: process.env.JWT_SECRET || '',
JWT_REFRESH_SECRET: process.env.JWT_REFRESH_SECRET || '',

4. .env.example

添加

Plain
JWT_SECRET=your-secret-here-min-32-chars
JWT_REFRESH_SECRET=your-refresh-secret-here-min-32-chars

实现步骤(顺序执行)

  1. 安装依赖

  2. 创建 JWT 工具(jwt.ts)

    • 实现全部 4 个函数
    • 添加错误处理(verify 用 try/catch)
  3. 运行数据库迁移(refresh_tokens 表)

    • 测试迁移的升降级
  4. 创建认证中间件(auth.ts)

    • 实现 requireAuth
    • 用模拟令牌测试
  5. 创建/更新认证路由(auth.ts 路由)

    • POST /auth/login
    • POST /auth/refresh
    • POST /auth/logout
  6. 保护现有路由(api.ts)

    • 为所有 /api/* 路由应用 requireAuth
  7. 将 JWT 密钥添加到 .env

    • 生成安全随机字符串(64 字符)
  8. 编写测试

    • jwt.ts 函数的单元测试
    • 认证流程的集成测试
    • 测试令牌过期
    • 测试撤销
  9. 创建 Postman 集合

    • 登录 → 获取令牌
    • 用访问令牌访问受保护路由
    • 刷新访问令牌
    • 退出登录 → 撤销刷新令牌
    • 验证已撤销的令牌被拒绝

成功标准

  • [ ] POST /auth/login 返回 accessToken + refreshToken

  • [ ] 受保护路由在没有有效访问令牌时返回 401

  • [ ] 受保护路由在有有效访问令牌时返回 200

  • [ ] POST /auth/refresh 用刷新令牌换取新的访问令牌

  • [ ] POST /auth/logout 撤销刷新令牌

  • [ ] 已撤销的刷新令牌在 /auth/refresh 时被拒绝

  • [ ] 已过期的访问令牌被拒绝

  • [ ] 每个用户的多会话正常工作(不同的刷新令牌)

  • [ ] 所有测试通过(npm test)

  • [ ] Postman 集合端到端可用

安全清单

  • [ ] JWT 密钥在 .env 中(从不提交)

  • [ ] JWT 密钥 ≥32 字符

  • [ ] 刷新令牌存储在数据库(不仅仅是 JWT)

  • [ ] 刷新令牌有唯一的 jti 用于撤销

  • [ ] 访问令牌过期时间较短(15 分钟)

  • [ ] Authorization 头已验证(Bearer 格式)

  • [ ] 令牌验证错误已捕获(无崩溃)

风险与缓解

风险影响缓解
JWT 密钥泄露.env 在 .gitignore 中,从不记录密钥
令牌过期时间过长15 分钟访问令牌,7 天刷新令牌(足够短)
登录无速率限制添加速率限制(每 15 分钟 5 次)
刷新令牌表无限增长添加清理任务(删除过期令牌)

给实现者(Claude One)的问题

如果在实现过程中遇到以下情况:

  1. 现有用户登录流程:与现有登录逻辑集成,不要替换整个认证系统
  2. 数据库 ORM:使用现有 ORM(Prisma/TypeORM/Knex)创建 refresh_tokens 表
  3. 错误消息:返回通用的"令牌无效"(不要泄露令牌是已过期还是签名无效)

估算工作量分解

  • JWT 工具:45 分钟
  • 数据库迁移:15 分钟
  • 中间件:30 分钟
  • 认证路由:60 分钟
  • 保护现有路由:15 分钟
  • 测试:90 分钟
  • Postman 集合:15 分钟

总计:约 4 小时


计划是否批准? → 移动到 .claude/plans/Active/auth-jwt.md

Plain

### 阶段二:人工审查

**你审查** `.claude/plans/Review/auth-jwt.md`:

**检查清单**:
- [ ] 所有需求是否都已覆盖?
- [ ] 方案是否适合该代码库?
- [ ] 安全考虑是否已处理?
- [ ] 估算工作量是否合理?
- [ ] 成功标准是否清晰且可测试?
- [ ] 待创建/修改的文件路径是否正确?

**若批准**:
```bash
mv .claude/plans/Review/auth-jwt.md .claude/plans/Active/

若需要修改,请 Claude Zero 修订:

Plain
(发给 Claude Zero):请更新计划:
- 将刷新令牌过期时间改为 30 天(而非 7 天)
- 将密码重置流程纳入范围

阶段三:实现(Claude One)

(发给 Claude One):

Plain
实现 .claude/plans/Active/auth-jwt.md

严格按照计划执行。每完成一个逻辑步骤后提交。
完成后向我汇报。

Claude One:

  1. 阅读计划文件
  2. 安装依赖
  3. 创建 jwt.ts
  4. 创建数据库迁移
  5. 运行迁移
  6. 创建认证中间件
  7. 更新路由
  8. 添加环境变量
  9. 编写测试
  10. 创建 Postman 集合

Claude One 在每步后提交

Plain
feat: add JWT utility functions
feat: create refresh_tokens table migration
feat: add auth middleware
feat: protect API routes with JWT auth
test: add JWT auth flow tests

阶段四:验证(Claude Zero)

(发给 Claude Zero):

Plain
审查 Claude One 刚完成的 JWT 实现。
对照 .claude/plans/Active/auth-jwt.md 中的计划检查。

Claude Zero 审查:

  • 代码结构是否与计划匹配?
  • 所有成功标准是否满足?
  • 安全清单是否已完成?
  • 测试是否通过?
  • 是否有代码异味或问题?

Claude Zero 报告

Plain
审查完成:auth-jwt.md

代码质量:9/10
- 所有文件均按计划创建
- 成功标准满足(9/9)
- 安全清单已完成
- 测试通过(15/15)

轻微建议:
1. 考虑添加刷新令牌轮换(安全最佳实践)
2. 为 jwt.ts 函数添加 JSDoc 注释
3. 考虑将魔法数字(15 分钟、7 天)提取到配置

关键问题:无

可以将计划归档到 Completed/。

阶段五:归档

若批准

Bash
mv .claude/plans/Active/auth-jwt.md .claude/plans/Completed/

计划已归档,供未来参考和团队学习。


计划模板

将此模板保存到 .claude/plan-template.md 以保持计划结构一致:

Markdown
# 计划:[功能名称]

**创建日期**:[日期]
**作者**:Claude Zero
**估算工作量**:[小时数]
**风险级别**:低 | 中 | 高

## 摘要
[2-3 句话概述本计划的实现内容]

## 需求澄清
[通过访谈确认的需求列表]
- 需求 1:[答案]
- 需求 2:[答案]

## 待创建文件

### 1. [文件路径](约 [行数] 行)
**用途**:[此文件的功能]

**导出**
- `functionName(params): returnType`
  - [功能说明]
  - [关键实现细节]

**依赖**:[库、其他文件]

## 待修改文件

### 1. [文件路径]
**位置**:第 [N] 行([上下文:在什么之后、什么之前])
**改动**:[改动内容]

**之前**
```[language]
[现有代码片段]

之后

Plain
[修改后的代码片段]

实现步骤(顺序执行)

  1. [步骤名称]

    • [子步骤]
    • [子步骤]
  2. [步骤名称]

    • [子步骤]

成功标准

  • [ ] [可测试的标准 1]

  • [ ] [可测试的标准 2]

安全清单(如适用)

  • [ ] [安全项目 1]

  • [ ] [安全项目 2]

风险与缓解

风险影响缓解
[风险][高/中/低][如何预防/处理]

给实现者(Claude One)的问题

如果在实现过程中遇到以下情况:

  1. [场景]:[指导建议]

估算工作量分解

  • [任务 1]:[时间]
  • [任务 2]:[时间]

总计:[小时数]


计划是否批准? → 移动到 .claude/plans/Active/[filename].md

Plain

---

## 成本分析

### 双实例 vs 带修正循环的单实例

| 场景 | 单实例 | 双实例 | 节省 |
|----------|----------------|---------------|---------|
| **简单功能**(登录表单) | 1 次会话 × $5 = **$5** | 2 次会话 × $3 = $6 | +$1(单实例胜出) |
| **中等功能**(认证系统) | 1 次会话 × $15 + 2 次修正 × $10 = **$35** | 2 次会话 × $12 = $24 | **节省 $11** |
| **复杂功能**(模糊规范) | 1 次会话 × $20 + 3 次修正 × $15 = **$65** | 2 次会话 × $18 = $36 | **节省 $29** |

**盈亏平衡点**:需要 ≥2 次修正循环的功能 → 双实例更经济。

### 月度预算估算

**假设**:
- 每月 20 个工作日
- 每天 2 个功能(简单与复杂混合)
- Opus 4.5 定价(约 $15/1M 输入,$75/1M 输出)

| 用户类型 | 每月功能数 | 单实例 | 双实例 | 节省 |
|---------|----------------|----------------|---------------|---------|
| **轻度用户** | 20 个简单功能 | $100 | $120 | -$20(单实例胜出) |
| **中度用户** | 30 个混合功能(60% 中等,40% 简单) | $650 | $480 | **节省 $170** |
| **重度用户** | 40 个复杂功能 | $2,000 | $1,200 | **节省 $800** |

**建议**:
- 仅简单功能 → 单实例
- 中等/复杂功能 → 双实例既省钱又省时

---

## 技巧与故障排查

### 角色强制执行

**问题**:Claude Zero 开始编辑代码。

**解决方案**:在每次请求中提醒:

(发给 Claude Zero):记住:你是 Claude Zero(仅计划者)。不要编辑代码。将计划写入 .claude/plans/Review/

Plain

**预防措施**:使用 CLAUDE.md 强制角色:

```markdown
# .claude/CLAUDE.md

## 如果你是 Claude Zero(计划者):
- 所有探索使用计划模式(按两次 Shift+Tab)
- 将所有计划保存到 .claude/plans/Review/[feature].md
- 绝不编辑代码
- 绝不提交变更
- 在 Claude One 完成实现后审查

## 如果你是 Claude One(实现者):
- 从 .claude/plans/Active/ 读取计划
- 严格按照规范实现
- 每完成一个逻辑步骤后提交
- 绝不创建计划

上下文污染

问题:Claude One 的上下文被计划讨论污染。

解决方案:使用独立的终端会话(独立上下文):

  • 终端 1 = Claude Zero(计划上下文)
  • 终端 2 = Claude One(实现上下文)

绝不在 Claude Zero 和 Claude One 之间共享上下文。

计划偏移

问题:Claude One 在实现过程中偏离了计划。

解决方案:在计划中包含这些内容:

Markdown
## Claude One 的实现规则

- 按顺序执行计划步骤(不要跳过或重新排序)
- 如果遇到阻断,停止并报告(不要自行创新解决)
- 每步后提交(保持细粒度历史)
- 如有不清楚的地方,询问用户(不要猜测)

管理开销

问题:在目录之间移动文件的手动开销。

解决方案:创建 bash 别名:

Bash
# 添加到 ~/.bashrc 或 ~/.zshrc

# 将计划移至 Active(批准)
approve-plan() {
    mv ".claude/plans/Review/$1.md" ".claude/plans/Active/"
    echo "已批准:$1.md → Active/"
}

# 将计划移至 Completed(归档)
complete-plan() {
    mv ".claude/plans/Active/$1.md" ".claude/plans/Completed/"
    echo "已完成:$1.md → 已归档"
}

# 按状态列出计划
plans() {
    echo "待审查:"
    ls -1 .claude/plans/Review/ 2>/dev/null || echo "  (空)"
    echo ""
    echo "进行中:"
    ls -1 .claude/plans/Active/ 2>/dev/null || echo "  (空)"
    echo ""
    echo "已完成:"
    ls -1 .claude/plans/Completed/ 2>/dev/null | tail -5 || echo "  (空)"
}

用法

Bash
plans                     # 列出所有计划
approve-plan auth-jwt     # 批准计划
complete-plan auth-jwt    # 归档已完成的计划

参见

  • 主指南:第 9.17.1 节 — 概述与对比
  • 计划模式:「plan-driven.md」 — 计划工作流的基础
  • 多实例(Boris):第 9.17 节 — 水平扩展替代方案
  • 成本优化:第 8.10 节 — 预算管理

外部资源


来源:飞书 · AI Spark 知识库 | 原文(最新版):https://lcnniolukk80.feishu.cn/wiki/Jo0Pwf5Aei61rIk3Hz1ctaFanQf | 归档:2026-06-04