为什么有人用它效率翻十倍,有人却觉得不过如此?答案藏在它的工作原理里。
第一章:两个程序员的故事
先讲个我身边真实发生的事。
上个月,团队接到一个需求:把项目里所有 REST API 的鉴权方式从 session-based 迁移到 JWT。涉及十几个路由文件、中间件改造、测试用例更新——典型的中等规模重构。
程序员 A 的做法是这样的:
> 打开 src/middleware/auth.ts,把 session 验证逻辑替换成 JWT 验证
(Claude Code 改完了)
> 现在打开 src/routes/user.ts,把里面的 req.session.userId 改成从 JWT 中解析
(改完了,但报错了)
> 报错了,req.user 是 undefined,你帮我修一下
(修了,又报错了)
> 测试也挂了,帮我修测试...
两个小时后,A 终于改完了。过程中他发了 30 多条消息,每次都在告诉 Claude Code 下一步该做什么,像在操控一个遥控车——左转、右转、前进、停。
程序员 B 只发了一条消息:
> 将项目的认证方式从 session-based 迁移到 JWT。要求:
> 1. 使用 jose 库替代现有的 session 逻辑
> 2. 保持所有现有 API 的接口契约不变
> 3. 确保所有测试通过
> 4. 参考 CLAUDE.md 中的错误处理规范
Claude Code 进入了规划模式,先扫描了整个项目结构,列出了所有需要改动的文件,给出了迁移方案。B 审批后,它自主执行——读文件、改代码、跑测试、发现问题、自己修复——20 分钟搞定。
差距不在 prompt 技巧。
A 和 B 的区别在于:A 把 Claude Code 当作了一个"更聪明的自动补全",而 B 把它当作一个自主代理系统(Agentic System)。
这个区别至关重要。
想象一下:你的团队来了一位新同事。他是个资深工程师——能力极强、精力无限、学习速度惊人,但刚入职第一天,还不了解你们的代码库、规范和偏好。
你会怎么和他协作?
你绝对不会站在他身后,指着屏幕说"在第 42 行加一个 if 语句"。你会给他看架构文档、告诉他项目规范、描述要实现的目标,然后让他自己去探索、规划、执行。
Claude Code 就是这位新队友。
本文的一切,都是关于如何与这位新队友高效协作。我会拆解它的每一个核心工作机制,然后从机制推导出最佳实践。读完后,你不只知道"该怎么做",更知道"为什么要这么做"。
第二章:核心机制剖析
2.1 Agent Loop — 心跳循环
它不是搜索引擎,它是一个循环
大多数人第一次用 Claude Code,脑子里的模型是这样的:
输入 prompt → 获得输出
就像 Google 搜索一样,一问一答。
但 Claude Code 的真实工作方式完全不同。它的核心是一个 Agent Loop(代理循环):
flowchart LR
A["🎯 理解任务"] --> B["🔍 收集上下文"]
B --> C["📋 制定计划"]
C --> D["⚡ 执行行动"]
D --> E{"✅ 验证结果"}
E -- "通过" --> F["🏁 任务完成"]
E -- "失败/发现问题" --> B
style A fill:#4A90D9,color:#fff,stroke:none
style B fill:#7B68EE,color:#fff,stroke:none
style C fill:#E67E22,color:#fff,stroke:none
style D fill:#27AE60,color:#fff,stroke:none
style E fill:#F39C12,color:#fff,stroke:none
style F fill:#2ECC71,color:#fff,stroke:none
Agent Loop 的核心:不是"一问一答",而是"自主迭代直到完成"。失败后不会停下来等你——它会自己回到收集上下文阶段重新来过。
这个循环会一直转下去,直到任务完成或者需要你的输入。
一个看起来简单的用户请求——"给用户列表页面加个搜索功能"——在背后可能触发 50 次以上的工具调用:
sequenceDiagram
participant U as 👤 用户
participant CC as 🤖 Claude Code
participant FS as 📁 文件系统
participant T as 🧪 测试
U->>CC: "给用户列表加搜索功能"
rect rgb(240, 245, 255)
Note over CC,FS: 🔍 第一阶段:探索
CC->>FS: Glob("**/user*.*")
FS-->>CC: 找到 5 个相关文件
CC->>FS: Grep("UserList")
FS-->>CC: 定位组件位置
CC->>FS: Read(UserList.tsx)
FS-->>CC: 理解现有代码结构
end
rect rgb(240, 255, 240)
Note over CC,FS: ✏️ 第二阶段:执行
CC->>FS: Edit(UserList.tsx) — 添加搜索组件
CC->>FS: Edit(useUsers.ts) — 添加过滤逻辑
CC->>FS: Write(SearchBar.tsx) — 创建搜索栏组件
end
rect rgb(255, 245, 240)
Note over CC,T: 🧪 第三阶段:验证 + 自动修复
CC->>T: Bash("pnpm test")
T-->>CC: ❌ 类型错误
CC->>FS: Read(错误日志)
CC->>FS: Edit(types.ts) — 修复类型
CC->>T: Bash("pnpm test")
T-->>CC: ✅ 全部通过
end
CC->>U: "搜索功能已完成,所有测试通过 ✅"
整个过程用户只发了一条消息,Claude Code 自主完成了探索→执行→验证→修复→再验证的完整循环。
回到新队友的比喻:一个优秀的工程师拿到任务后,不会闷头就写代码。他会先看现有代码怎么写的,理解项目结构,想个方案,写代码,跑测试,发现问题再调整。Agent Loop 就是在模拟这个过程。
所以:用意图描述任务,而非指令式步骤
理解了 Agent Loop,你就明白为什么 B 程序员的做法更好了。
当你给出指令式步骤("打开这个文件,改第 42 行"),你实际上在短路 Agent Loop。你把一个能自主迭代的系统降级成了一个执行机器人。
当你给出意图式描述("迁移到 JWT,保持测试通过"),你在激活完整的 Agent Loop。Claude Code 会自主决定该读哪些文件、该以什么顺序修改、该怎么验证。
反例 ❌:
打开 src/auth.ts,找到第 23 行的 validateToken 函数,
把 jsonwebtoken 的 verify 调用换成 jose 的 jwtVerify,
然后打开 src/types.ts 更新类型定义...
正例 ✅:
将 token 验证从 jsonwebtoken 迁移到 jose 库。
要求:保持现有的 validateToken 接口不变,确保所有测试通过。
第二种写法更短,但效果更好。因为你把"怎么做"的决策权交给了 Agent Loop——它比你更清楚当前代码的具体状态。
口诀:说目的地,不说路线。
2.2 工具系统 — 十八般武艺
它带了一整套工具箱
你的新队友第一天上班,不是空手来的。他带了一整套专业工具箱,里面有十几种精挑细选的工具:
graph TB
subgraph explore["🔍 探索类 — 了解情况"]
Read["Read<br/>读文件"]
Glob["Glob<br/>找文件"]
Grep["Grep<br/>搜内容"]
end
subgraph modify["✏️ 修改类 — 改东西"]
Write["Write<br/>创建文件"]
Edit["Edit<br/>精确编辑"]
end
subgraph orchestrate["🎭 编排类 — 组织工作"]
Task["Task<br/>子代理"]
TaskCreate["TaskCreate<br/>任务跟踪"]
end
subgraph execute["⚡ 执行类 — 外界交互"]
Bash["Bash<br/>运行命令"]
Web["Web<br/>网络访问"]
MCP["MCP<br/>外部工具"]
end
style explore fill:#E8F4FD,stroke:#4A90D9,color:#333
style modify fill:#FDF2E8,stroke:#E67E22,color:#333
style orchestrate fill:#F0E8FD,stroke:#7B68EE,color:#333
style execute fill:#E8FDE8,stroke:#27AE60,color:#333
- 探索类:Read(读文件内容)、Glob(按模式匹配找文件,如
**/*.tsx)、Grep(搜索代码内容) - 修改类:Write(创建/覆写文件)、Edit(精确编辑文件片段,只发 diff)
- 编排类:Task / 子代理(派分身并行工作)、TaskCreate(任务列表跟踪进度)
- 执行类:Bash(跑测试、装依赖、Git 等)、WebFetch / WebSearch(网络访问)、MCP(连接外部工具)
关键洞察在这里:Claude Code 的系统提示中有明确的工具选择规则。 比如,它被要求"读文件用 Read 而不是 cat"、"搜索用 Grep 而不是 grep 命令"、"编辑用 Edit 而不是 sed"。这些不是随意的偏好——专用工具比通用 Bash 命令更可靠、更可预测、也更方便你审查。
而且,模型会根据任务自主编排工具链。当你说"找到所有使用废弃 API 的地方并更新",它自然会触发这样的链:
flowchart LR
A["Glob\n找候选文件"] --> B["Grep\n定位使用位置"]
B --> C["Read\n理解上下文"]
C --> D["Edit\n逐个替换"]
D --> E["Bash\n跑测试验证"]
style A fill:#E8F4FD,stroke:#4A90D9,color:#333
style B fill:#E8F4FD,stroke:#4A90D9,color:#333
style C fill:#E8F4FD,stroke:#4A90D9,color:#333
style D fill:#FDF2E8,stroke:#E67E22,color:#333
style E fill:#E8FDE8,stroke:#27AE60,color:#333
你不需要告诉它用哪个工具——它自己会选。
所以:用匹配工具能力的方式描述任务
知道队友会什么,你才能更好地给他派任务。
反例 ❌:
帮我手动检查这 20 个文件里有没有用 deprecated API
(这会让 Claude Code 一个个 Read,慢且低效)
正例 ✅:
找到项目中所有调用 oldApi.fetchData() 的地方,
替换为 newApi.getData(),并确保类型兼容
(这自然触发 Grep 批量搜索 → Edit 批量替换的高效路径)
再比如,如果你知道它有 WebSearch 工具,你可以这样:
使用 jose 库替换 jsonwebtoken 实现 JWT 验证。
如果你不确定 jose 的 API 用法,可以查阅其文档。
口诀:知道队友会什么,才能用好队友。
2.3 记忆系统 — 记忆宫殿
这是全文最重要的一节。如果你只记住一件事,就记住这个。
四层记忆体系
新队友的记忆不是铁板一块,它有层次。Claude Code 有一套精心设计的四层记忆体系:
graph TB
subgraph L1["🏛️ 第一层:CLAUDE.md — 长期记忆"]
direction LR
C1["📖 项目根目录 CLAUDE.md"]
C1D["会话启动时最先加载\n始终在上下文中,不会被压缩"]
end
subgraph L2["💬 第二层:对话上下文 — 工作记忆"]
direction LR
C2["🗣️ 当前会话交互"]
C2D["你说的话 + AI 回复 + 工具输出\n会过期,会被自动压缩"]
end
subgraph L3["📐 第三层:.claude/rules/ — 模块化规则"]
direction LR
C3["📏 条件加载的规则文件"]
C3D["处理 .tsx 时加载前端规范\n处理 .go 时加载 Go 规范"]
end
subgraph L4["📝 第四层:Auto-Memory — 自动记忆"]
direction LR
C4["🧠 AI 自己的学习笔记"]
C4D["跨会话持久化\n权重低于前三层"]
end
L1 --- L2 --- L3 --- L4
style L1 fill:#DCEEFB,stroke:#2980B9,stroke-width:3px,color:#333
style L2 fill:#E8F8F5,stroke:#27AE60,stroke-width:2px,color:#333
style L3 fill:#FEF9E7,stroke:#F1C40F,stroke-width:2px,color:#333
style L4 fill:#FDEDEC,stroke:#E74C3C,stroke-width:1px,color:#333
优先级从上到下递减:CLAUDE.md 的指示权重最高,Auto-Memory 最低。越上层越可靠,越持久。
用公司来类比:
| 记忆层 | 公司类比 | 持久性 | 可靠性 | 你能控制吗 |
|---|---|---|---|---|
| CLAUDE.md | 公司工程师手册 | ★★★★★ 永不丢失 | ★★★★★ | ✅ 完全控制 |
| 对话上下文 | 今天站会笔记 | ★★☆☆☆ 会被压缩 | ★★★★☆ | ⚠️ 部分控制 |
| .claude/rules/ | 特定场景 Runbook | ★★★★☆ 按需加载 | ★★★★☆ | ✅ 完全控制 |
| Auto-Memory | 员工个人笔记 | ★★★★☆ 跨会话 | ★★★☆☆ | ❌ AI 自主 |
CLAUDE.md:你 ROI 最高的投入
在所有四层中,CLAUDE.md 是你能控制的、影响最大的一层。 它之所以重要,是因为三个特性:
- 首先加载 — 在 Claude Code 做任何事情之前,它就已经读了 CLAUDE.md
- 始终在场 — 不管上下文怎么压缩、怎么 compact,CLAUDE.md 永远在
- 全局影响 — 它影响 Claude Code 在这个项目中的所有行为
而且它支持分层——就像 CSS 的层叠规则,越具体的越优先:
graph TB
subgraph scope["CLAUDE.md 分层加载机制"]
direction TB
G["🌍 ~/.claude/CLAUDE.md\n个人偏好(全局生效)\n例:偏好 Vim 键位、暗色主题"]
P["📦 项目根目录/CLAUDE.md\n项目规范(团队共享)\n例:技术栈、架构原则、代码规范"]
M["📂 src/api/CLAUDE.md\n模块规范(特定目录生效)\n例:API 设计规范、错误码定义"]
end
G -->|"被项目层覆盖"| P
P -->|"被模块层覆盖"| M
style G fill:#f0f0f0,stroke:#999,color:#333
style P fill:#DCEEFB,stroke:#2980B9,color:#333
style M fill:#D5F5E3,stroke:#27AE60,color:#333
style scope fill:#fff,stroke:#ddd,color:#333
越具体的层级优先级越高:如果项目 CLAUDE.md 说"用 tabs 缩进",但
src/api/CLAUDE.md说"用 2 spaces",那么在src/api/目录下工作时,2 spaces 生效。
很多人把 CLAUDE.md 写成了流水账,或者压根没有。这就像招了个资深工程师却不给他看任何文档,让他自己猜你们的规范——他当然也能干活,但效率和质量会大打折扣。
一个真实的 CLAUDE.md 示例
# Project: E-Commerce Platform
## Tech Stack
- TypeScript + React 18 + Next.js 14 (App Router)
- Tailwind CSS (no CSS modules)
- Prisma ORM + PostgreSQL
- Vitest for unit tests, Playwright for E2E
## Architecture Principles
- Feature-based directory structure: src/features/{feature}/
- Each feature has: components/, hooks/, api/, types.ts, index.ts
- Shared code goes in src/shared/ (not src/utils/ or src/common/)
- Server Components by default; only use "use client" when needed
## Code Conventions
- Prefer named exports over default exports
- Use Zod for all runtime validation (API inputs, form data, env vars)
- Error handling: use Result<T, E> pattern, never throw in business logic
- Database queries only in src/features/*/api/ (never in components)
## Testing Requirements
- Every new feature needs unit tests (Vitest)
- API routes must have integration tests
- Run tests before any commit: `pnpm test`
- E2E tests for critical flows: `pnpm test:e2e`
## Git Conventions
- Conventional commits: feat/fix/refactor/docs/test
- Branch naming: feature/xxx, fix/xxx, refactor/xxx
- Squash merge to main
## Common Gotchas
- Prisma needs `npx prisma generate` after schema changes
- Next.js middleware runs on edge runtime (no Node.js APIs)
- TailwindCSS v4 uses CSS-based config, not tailwind.config.js
注意几个要点:
- 50-200 行是理想长度 — 精炼但全面,不要写成万字文档
- 定义原则,不定义细节 — "使用 Zod 做校验" ✅,"Zod schema 用这种格式写" ❌
- 包含"常见坑" — 这些是新人最容易踩的,也是 Claude Code 最容易犯的
- 可以被 Git 追踪 — 把它当作项目文档的一部分,团队共享
所以:写宪法,而非写代码
如果你今天只做一件事来提升 Claude Code 体验,就是给你的项目写一份 CLAUDE.md。
这不是一次性工作。它应该随着项目演进持续更新——就像一份活的工程师手册。
当你发现 Claude Code 反复犯同一个错误,不要每次在对话里纠正它。把正确的做法写进 CLAUDE.md,一劳永逸。
反例 ❌:
> 记住,我们项目用 pnpm 不用 npm
> (下次新会话又得说一遍)
正例 ✅:
# CLAUDE.md
## Package Manager
- Use pnpm exclusively (never npm or yarn)
- Lock file: pnpm-lock.yaml
口诀:写好入职文档,新人自然好用。
2.4 子代理架构 — 分身术
它能分身
你的新队友有一项特殊能力:分身术。
当面临复杂任务时,Claude Code 可以派生出多个子代理(Sub-agents),每个子代理有独立的上下文窗口,互不干扰,并行工作。
目前有几种类型的子代理:
- Explore 代理 — 只读,专门用来快速探索代码库。不能修改文件,只做调查
- Plan 代理 — 设计方案。像架构师一样分析问题,输出结构化的实施计划
- 通用 Task 代理 — 能使用全部工具,执行具体任务
一个典型的场景:你报告了一个 bug,Claude Code 不确定根因在哪。它可以同时派出三个 Explore 代理:
sequenceDiagram
participant U as 👤 用户
participant M as 🤖 主代理
participant S1 as 🔍 子代理 1
participant S2 as 🔍 子代理 2
participant S3 as 🔍 子代理 3
U->>M: "订单金额计算有 bug"
par 三路并行调查
M->>S1: 调查数据库查询
Note right of S1: 独立上下文窗口<br/>读取 SQL、分析查询逻辑
and
M->>S2: 检查 API 数据转换
Note right of S2: 独立上下文窗口<br/>追踪数据流转过程
and
M->>S3: 检查前端状态管理
Note right of S3: 独立上下文窗口<br/>排查 race condition
end
S1-->>M: "数据库查询正常 ✅"
S2-->>M: "发现:货币转换丢失精度 ❌"
S3-->>M: "前端状态正常 ✅"
M->>U: "根因定位:API 层货币转换使用了<br/>浮点数运算导致精度丢失,建议改用 Decimal"
三个调查同时进行,最后主代理汇总结论,定位到问题所在。这比串行调查快了三倍。
每个子代理有自己的上下文窗口,这意味着主代理的上下文不会被大量调查结果污染。子代理完成后,只把结论汇报回来——就像团队开完调查后,在站会上各自汇报一句结论,而不是念自己的全部调查笔记。
所以:设计可并行化的任务
了解了分身术,你就可以主动设计适合并行处理的任务。
反例 ❌:
先查一下 userService 有没有问题,
然后再查 orderService,
最后查 paymentService
(这强制了串行,一个一个来)
正例 ✅:
调查以下三个服务中哪个导致了订单金额计算错误:
1. userService 中的折扣计算
2. orderService 中的价格汇总
3. paymentService 中的货币转换
分别检查后给出结论。
(Claude Code 可能会并行派出子代理调查)
不过要注意,不是所有任务都适合并行。如果步骤之间有依赖关系(后一步依赖前一步的结果),强行并行反而会出问题。
口诀:分而治之,并行调查。
2.5 上下文窗口管理 — 桌面大小问题
桌面就这么大
现在想象你队友的工作桌面。
这张桌面的面积是固定的——所有正在处理的信息都得放在上面:读取的文件内容、你们的对话记录、工具调用的输出、系统提示、CLAUDE.md……
这就是上下文窗口(Context Window)。
当桌面快满了,Claude Code 会自动做一件事:把最早的对话和工具输出压缩成摘要,推到桌面边缘。核心信息保留,但细节丢失了。
graph LR
subgraph before["😰 上下文快满了"]
direction TB
B1["📖 CLAUDE.md"]
B2["⚙️ 系统提示"]
B3["💬 早期对话(细节)"]
B4["📄 读取的文件内容"]
B5["💬 中期对话(细节)"]
B6["🔧 工具输出(大量)"]
B7["💬 最近对话"]
end
before -- "/compact" --> after
subgraph after["😊 压缩后腾出空间"]
direction TB
A1["📖 CLAUDE.md ← 不变"]
A2["⚙️ 系统提示 ← 不变"]
A3["📝 历史摘要(压缩)"]
A4["💬 最近对话"]
A5["🆓 空闲空间(可继续工作)"]
end
style before fill:#FFF5F5,stroke:#E74C3C,color:#333
style after fill:#F0FFF0,stroke:#27AE60,color:#333
style B1 fill:#DCEEFB,stroke:#2980B9,color:#333
style A1 fill:#DCEEFB,stroke:#2980B9,color:#333
style A5 fill:#E8FDE8,stroke:#27AE60,color:#333
你也可以主动管理桌面:
/compact— 手动压缩。把对话细节压缩成摘要,腾出空间。就像把散落的笔记整理成一张提纲/clear— 彻底清空。只保留 CLAUDE.md 和系统提示,其他全部丢弃。就像收拾好桌面开始全新工作
这里有一个关键细节:CLAUDE.md 永远不会被压缩或清除。 不管你 compact 还是 clear 多少次,CLAUDE.md 始终在场。这就是为什么它是记忆系统中最可靠的一层。
上下文窗口管理不当的后果很明显:
- 信息丢失 — 早期对话被压缩后,Claude Code 可能"忘记"之前讨论过的设计决策
- 性能下降 — 上下文塞得越满,模型的注意力越分散,输出质量下降
- 成本增加 — 更长的上下文意味着更多的 token 消耗
所以:保持"上下文卫生"
就像保持桌面整洁一样,上下文窗口需要主动维护。
原则一:一个对话处理一个逻辑任务
不要在同一个对话里又改 bug 又加功能又重构——这会把上下文搅成一锅粥。完成一个任务后,开新对话。
原则二:阶段间主动 /compact
如果一个任务确实需要多个阶段(比如先调查再实施),在调查完成、开始实施前,用 /compact 压缩调查阶段的细节,保留结论。
原则三:选择性读文件
不要让 Claude Code 读取整个大文件"了解一下"。先用 Glob + Grep 定位关键部分,再只读必要的片段。
反例 ❌:
读一下 src/ 目录下所有的文件,了解一下项目结构
(这会把上下文塞满文件内容,几个大文件就占了大半桌面)
正例 ✅:
项目使用 Next.js App Router 架构。
请找到与用户认证相关的路由和中间件文件,理解当前的认证流程。
(Claude Code 会用 Glob + Grep 精准定位,只读必要的文件)
原则四:关键信息放 CLAUDE.md
任何你不希望 Claude Code "忘记"的信息——项目规范、架构决策、常见陷阱——都应该放进 CLAUDE.md,而不是靠对话上下文记住。
口诀:保持桌面整洁,重要的东西钉在墙上(CLAUDE.md)。
2.6 权限模型 — 安全带
有风险的事会举手确认
你的新队友虽然能力强,但不是横冲直撞的莽夫。
Claude Code 内置了一套分级权限模型。工具按风险级别分类:
graph LR
subgraph low["🟢 低风险 — 自动放行"]
L1["Read"]
L2["Glob"]
L3["Grep"]
end
subgraph mid["🟡 中风险 — 可配置"]
M1["Edit"]
M2["Write"]
M3["Bash(已知命令)"]
end
subgraph high["🔴 高风险 — 必须确认"]
H1["rm -rf"]
H2["git push --force"]
H3["Bash(未知命令)"]
end
style low fill:#E8F5E9,stroke:#43A047,color:#333
style mid fill:#FFF8E1,stroke:#F9A825,color:#333
style high fill:#FFEBEE,stroke:#E53935,color:#333
当 Claude Code 要做有风险的事情时,它会暂停循环,举手确认:
Claude Code 想要执行: rm -rf build/
是否允许?[y/n]
你可以在 settings.json 中配置信任级别:
- 默认模式 — 大部分修改操作需要确认
- 信任项目 — 放宽常见操作(如 Edit、运行测试),但高危操作仍需确认
- Yolo 模式 — 几乎不需要确认(适合实验性项目,不建议用于生产代码)
系统提示中写得很明确:Claude Code 的行为准则是优先安全——它永远不会主动提交包含 .env 的文件、不会未经确认 force push、不会删除看起来像用户工作的分支。即使你授权了"推送代码",它也只认为这次授权有效,下次还会再问。
所以:信任但验证
对于成熟项目:在 settings 中放宽常见操作的权限——每次 Edit 都要确认会打断 Agent Loop 的流畅性,让你的队友干活缩手缩脚。
对于敏感操作:保留审批。数据库操作、部署脚本、Git push 等,永远值得多看一眼。
实用配置建议:
// .claude/settings.json
{
"permissions": {
"allow": [
"Edit",
"Write",
"Bash(pnpm test)",
"Bash(pnpm lint)",
"Bash(pnpm build)"
]
}
}
允许编辑文件和运行测试 / lint / 构建这类安全的命令,但其他 Bash 操作仍需确认。
口诀:配好信任级别,常规放行,敏感必审。
2.7 规划模式 — 先谋后动
让队友先戴上"架构师帽"
有时候你不想让队友直接动手改代码。你想先听听他的方案。
规划模式(Plan Mode) 就是这个"架构师帽"。用 Shift+Tab 即可切换。
进入规划模式后,Claude Code 的行为发生根本变化:
flowchart LR
subgraph plan["🎩 规划模式(Shift+Tab)"]
direction TB
P1["✅ Read — 读文件"]
P2["✅ Glob — 找文件"]
P3["✅ Grep — 搜内容"]
P4["✅ 分析 + 设计方案"]
P5["❌ Edit / Write"]
P6["❌ Bash"]
end
User["👤 用户"] -- "Shift+Tab\n进入规划" --> plan
plan -- "输出方案" --> Review{"👤 审批方案"}
Review -- "✅ 同意" --> Exec["⚡ Agent Loop 执行"]
Review -- "❌ 调整" --> plan
style plan fill:#FFF8E1,stroke:#F9A825,color:#333
style P5 fill:#FFEBEE,stroke:#E53935,color:#333
style P6 fill:#FFEBEE,stroke:#E53935,color:#333
style Exec fill:#E8F5E9,stroke:#43A047,color:#333
它变成了一个纯粹的分析者和规划者——只看不动手。
这特别适合两类场景:
场景一:大规模重构
"我想把项目从 Redux 迁移到 Zustand"——这种涉及几十个文件的变更,你绝对不想让它直接开干。先进规划模式,让它分析依赖关系、列出所有需要改动的地方、给出迁移步骤和风险评估。你审批方案后,再让它执行。
场景二:不确定的问题
"应用启动越来越慢,帮我分析原因"——你不确定问题在哪,让 Claude Code 先以只读方式调查,给出分析报告,然后你根据报告决定下一步。
规划模式的输出通常是结构化的:
## 迁移方案
### 影响范围
- 12 个文件需要修改
- 3 个 store 需要重写
- 所有 useSelector 调用需要替换
### 执行步骤
1. 安装 zustand,移除 redux 相关依赖
2. 将 Redux store 逐个转换为 Zustand store
3. 替换组件中的 useSelector/useDispatch
4. 更新测试
5. 运行全量测试验证
### 风险点
- middleware 逻辑需要手动重写(不能自动转换)
- 异步 action 的处理方式有差异
你审批这个方案后,Claude Code 就会按步骤执行,遇到问题还会回来汇报。
所以:超过 3 个文件的变更,先谋后动
这是一条简单有效的经验法则:
- 改 1-3 个文件 → 直接描述意图,让 Agent Loop 跑
- 改 3+ 个文件 → 先进规划模式,审批方案再执行
- 架构级变更 → 必须规划模式,甚至可以要求多轮规划
反例 ❌:
把所有的 class 组件重构成函数组件
(直接执行,可能改一半出问题,中间状态很难恢复)
正例 ✅:
[规划模式]
分析项目中所有的 class 组件,评估重构为函数组件的影响范围和风险,
给出分批重构的方案。
口诀:架构师帽先戴上,方案敲定再开工。
2.8 Hooks 系统 & MCP 集成 — 自动化与扩展
Hooks:自动化质量门禁
你可以为 Claude Code 的工具调用设置自动触发的脚本——就像 Git hooks,但更细粒度。
// .claude/settings.json
{
"hooks": {
"afterEdit": ["npx prettier --write $FILE"],
"beforeBash": ["echo '正在执行: $COMMAND'"],
"afterWrite": ["npx eslint --fix $FILE"]
}
}
每次 Claude Code 用 Edit 工具修改文件后,自动跑 Prettier 格式化。每次 Write 创建新文件后,自动跑 ESLint 修复。
Hooks 的价值在于一劳永逸。你不需要每次告诉 Claude Code "改完记得格式化"——配好 Hook,它自动就做了。
MCP:给队友开更多权限
MCP(Model Context Protocol) 是一个标准化协议,让 Claude Code 连接外部工具和服务。通过 MCP,你的新队友不再局限于本地文件操作,而是能触达完整的工作流:
- 连接 Jira / Linear — 直接读取和更新任务状态
- 连接 Slack — 发消息、查讨论
- 连接 数据库 — 查询数据辅助调试
- 连接 Figma — 读取设计稿信息
- 连接自定义内部工具 — 任何你能写 API 的东西
比如,你可以告诉 Claude Code:
看一下 JIRA-1234 的需求描述,然后实现它
它会通过 MCP 读取 Jira 任务,理解需求,然后在本地实现代码。
最佳实践
- 配置 Hooks 实现自动化质量门禁 — 格式化、Lint、类型检查,让它们自动在 Claude Code 操作后运行
- 通过 MCP 扩展 AI 的工具链 — 把你日常工作流中的工具都接进来,减少手动切换
口诀:Hooks 设了就忘,MCP 越多越强。
2.9 系统提示 — 隐形之手
110+ 条内置直觉
你的新队友受过优秀的工程教育。
Claude Code 的系统提示中有 110 多条精心设计的行为规则,覆盖方方面面:
安全规则:
- 永远不提交
.env、credentials.json等敏感文件 - 破坏性 Git 操作(force push、reset --hard)必须确认
- 不猜测或生成 URL,除非明确是编程辅助
工具偏好:
- 读文件用 Read,不用 cat
- 搜索用 Grep,不用 grep 命令
- 编辑用 Edit,不用 sed
- 这些规则确保操作可预测、可审查
代码风格:
- 修改前先读代码("不要改你没读过的代码")
- 优先编辑已有文件,避免创建不必要的新文件
- 避免过度工程化——只做要求的事情,不画蛇添足
- 不要在没改的代码上加注释、类型注解或 docstring
Git 操作规范:
- 优先创建新 commit,不 amend 已有的
- 用具体文件名 add,不用
git add -A - 提交前要看 diff 和 log
- 绝对不 skip hooks(
--no-verify)
这些规则你无法修改——它们是系统级别的。但好消息是:CLAUDE.md 可以扩展甚至覆盖部分行为。
比如系统提示说"不要主动提交",但你可以在 CLAUDE.md 里写:
## Workflow
- After completing a change, always commit with a descriptive message
Claude Code 会遵守你在 CLAUDE.md 里的指示,即使它和系统提示的默认行为不同。
但有些规则你不应该尝试覆盖——比如安全相关的规则。强行让 Claude Code 提交 .env 文件或 force push 到 main,它会拒绝或至少强烈警告。这些是安全底线。
所以:顺势而为,不要逆流
理解了系统提示的存在,你就能解释很多"奇怪"的行为:
- "为什么它总是先读文件再改?" — 因为系统提示要求"修改前先读"
- "为什么它不用 sed 而用 Edit?" — 因为系统提示规定了工具偏好
- "为什么它创建 commit 不用 --amend?" — 因为系统提示说"优先新 commit"
这些不是 bug,是特性。它们让 Claude Code 的行为更安全、更可预测。
反例 ❌:
用 sed 命令替换文件中的所有 oldFunction 为 newFunction
(你在要求它逆着系统提示的偏好工作,它可能还是会用 Edit)
正例 ✅:
把项目中所有的 oldFunction 调用替换为 newFunction
(让它自己选择最佳工具——它会用 Grep 找到所有位置,然后用 Edit 逐个替换)
口诀:借力不对抗,理解默认值。
2.10 透视实例 — 一次请求的完整生命周期
前面九节讲的都是"原理"。现在,我们把所有原理串成一条线——用一个真实例子,逐帧回放 Claude Code 处理一次请求时,到底发生了什么。
包括:发给大模型的数据结构长什么样、每一轮循环做了什么决策、你的 CLAUDE.md 如何影响行为。
场景设定
你在一个 Next.js 电商项目里,输入了这条消息:
用户列表页的搜索功能有 bug:输入中文后搜索结果为空。请修复。
项目根目录有一份 CLAUDE.md:
# E-Commerce Platform
## Tech Stack
- TypeScript + Next.js 14 (App Router)
- Prisma ORM + PostgreSQL
## Code Conventions
- Use Zod for runtime validation
- Error handling: use Result<T, E> pattern
## Testing
- Run `pnpm test` before finishing
下面是 Claude Code 背后真实发生的事情。
第 0 步:组装第一次 API 请求
你按下回车的那一刻,Claude Code 客户端并不是直接把你这句话扔给模型。它先组装一个完整的请求体。简化后大致长这样:
// 发送给 Claude API 的第一次请求
{
"model": "claude-sonnet-4-20250514",
"max_tokens": 16000,
"system": [
{
// 🔵 系统提示(2.9 节讲的"隐形之手",110+ 条规则)
"type": "text",
"text": "You are Claude Code, Anthropic's official CLI...\n
- Do NOT use Bash to run commands when a dedicated tool exists\n
- Read files with Read, not cat\n
- Edit files with Edit, not sed\n
- In general, do not propose changes to code you haven't read\n
- Avoid over-engineering...\n
..."
},
{
// 🟢 CLAUDE.md(2.3 节讲的"宪法",始终注入系统提示)
"type": "text",
"text": "<claude-md>\n# E-Commerce Platform\n## Tech Stack\n
- TypeScript + Next.js 14 (App Router)\n
- Prisma ORM + PostgreSQL\n
## Code Conventions\n- Use Zod for runtime validation\n
## Testing\n- Run `pnpm test` before finishing\n
</claude-md>"
}
],
// 🔧 工具定义(2.2 节讲的"工具箱",告诉模型它有哪些能力)
"tools": [
{
"name": "Read",
"description": "Reads a file from the local filesystem...",
"input_schema": {
"type": "object",
"properties": {
"file_path": { "type": "string" },
"offset": { "type": "number" },
"limit": { "type": "number" }
},
"required": ["file_path"]
}
},
{
"name": "Glob",
"description": "Fast file pattern matching...",
"input_schema": { "..." : "..." }
},
{
"name": "Grep",
"description": "Search tool built on ripgrep...",
"input_schema": { "..." : "..." }
},
{
"name": "Edit",
"description": "Performs exact string replacements in files...",
"input_schema": { "..." : "..." }
},
{
"name": "Bash",
"description": "Executes a bash command...",
"input_schema": { "..." : "..." }
},
{
"name": "Task",
"description": "Launch a new agent to handle complex tasks...",
"input_schema": { "..." : "..." }
}
// ... 共 12+ 种工具
],
// 💬 对话消息(2.5 节讲的"上下文窗口",此时只有用户这一条)
"messages": [
{
"role": "user",
"content": "用户列表页的搜索功能有 bug:输入中文后搜索结果为空。请修复。"
}
]
}
graph TB
subgraph req["📦 第一次 API 请求的组成"]
direction TB
SP["⚙️ system prompt\n系统提示 110+ 条规则"]
CM["📖 CLAUDE.md\n项目宪法(注入 system)"]
TL["🔧 tools\n12+ 工具定义(JSON Schema)"]
MS["💬 messages\n用户消息(目前只有 1 条)"]
end
style SP fill:#E8EAF6,stroke:#3F51B5,color:#333
style CM fill:#DCEEFB,stroke:#2980B9,color:#333
style TL fill:#FFF3E0,stroke:#FB8C00,color:#333
style MS fill:#E8F5E9,stroke:#43A047,color:#333
注意三个关键点:
- CLAUDE.md 在 system 层级,和系统提示平级。这就是为什么它"始终在场"——它不是对话消息,不会被压缩
- 工具以 JSON Schema 定义。模型看到这些定义后,就"知道"自己能做什么。这是 2.2 节说的"工具箱"
- messages 此刻只有用户的一条话。后续每轮循环都会往这里追加,这就是 2.5 节说的"上下文窗口越来越满"
第 1 轮:模型决定先探索(Agent Loop 启动)
Claude API 返回响应。模型没有直接开始改代码——它决定先了解情况(2.1 节说的"先看现有代码"):
// Claude API 的第一次响应
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "我来调查这个中文搜索的 bug。先定位搜索相关的代码。"
},
{
// 模型选择了 Grep 工具(不是 Bash + grep 命令!遵守系统提示的工具偏好)
"type": "tool_use",
"id": "tool_01",
"name": "Grep",
"input": {
"pattern": "search|filter|query",
"glob": "**/user*",
"output_mode": "files_with_matches"
}
},
{
// 并行调用!同时用 Glob 找相关文件(2.2 节:模型自主编排工具链)
"type": "tool_use",
"id": "tool_02",
"name": "Glob",
"input": {
"pattern": "src/**/search*.{ts,tsx}"
}
}
]
}
注意:一次响应中包含了两个并行的工具调用。模型判断这两个搜索互不依赖,所以同时发出。这不是偶然——系统提示明确要求"如果多个工具调用没有依赖关系,并行发出"。
Claude Code 客户端执行这两个工具,把结果追加到 messages 中:
// 客户端追加工具结果到 messages
{
"role": "user", // 工具结果以 user 角色返回
"content": [
{
"type": "tool_result",
"tool_use_id": "tool_01",
"content": "src/features/users/hooks/useUserSearch.ts\nsrc/features/users/components/UserList.tsx"
},
{
"type": "tool_result",
"tool_use_id": "tool_02",
"content": "src/features/users/components/SearchBar.tsx"
}
]
}
此时 messages 数组有 3 条消息:用户原始请求 → 模型的工具调用 → 工具执行结果。上下文窗口开始填充。
第 2 轮:精准读取关键文件
客户端把更新后的 messages 再次发送给 Claude API(这就是 Agent Loop 的"循环"——每一轮都是一次完整的 API 调用)。
模型看到搜索结果,决定读取最可疑的文件:
// 第二次 API 响应
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "找到了 3 个相关文件。先看搜索 hook 的实现。"
},
{
"type": "tool_use",
"id": "tool_03",
"name": "Read",
"input": {
"file_path": "/project/src/features/users/hooks/useUserSearch.ts"
}
}
]
}
客户端执行 Read,返回文件内容(假设是这样的代码):
{
"type": "tool_result",
"tool_use_id": "tool_03",
"content": " 1→import { useState, useMemo } from 'react'\n
2→\n
3→export function useUserSearch(users: User[]) {\n
4→ const [query, setQuery] = useState('')\n
5→\n
6→ const filtered = useMemo(() => {\n
7→ if (!query) return users\n
8→ const q = query.toLowerCase()\n
9→ return users.filter(u =>\n
10→ u.name.toLowerCase().includes(q) ||\n
11→ u.email.toLowerCase().includes(q)\n
12→ )\n
13→ }, [query, users])\n
14→\n
15→ return { query, setQuery, filtered }\n
16→}"
}
messages 数组已有 5 条消息。 文件内容全部进入上下文窗口。这就是为什么"选择性读文件"很重要——每读一个大文件,桌面空间就少一块。
第 3 轮:定位 Bug 并修复
模型分析了代码,发现了问题——toLowerCase() 对中文无效(中文没有大小写概念,但问题在于某些环境下 toLowerCase() 可能改变 Unicode 字符)。但更关键的是,真实 bug 可能在于搜索是前端过滤,而数据源中 u.name 的中文编码有问题。
模型决定进一步确认:
// 第三次 API 响应 — 继续调查
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "搜索逻辑看起来基本正确。但 toLowerCase() 对中文搜索没有意义,
而且可能受 locale 影响。让我检查数据获取端,
看是否有编码或 normalize 的问题。"
},
{
"type": "tool_use",
"id": "tool_04",
"name": "Grep",
"input": {
"pattern": "fetchUsers|getUsers|findMany.*user",
"glob": "src/features/users/api/**",
"output_mode": "content",
"-A": 5
}
}
]
}
Grep 返回了 API 层的代码,模型发现问题:
{
"type": "tool_result",
"tool_use_id": "tool_04",
"content": "src/features/users/api/getUsers.ts:
8→export async function getUsers(query?: string) {
9→ const where = query
10→ ? { name: { contains: query, mode: 'insensitive' } }
11→ : {}
12→ return prisma.user.findMany({ where })
13→}"
}
现在模型看清了全貌:搜索有两条路径——前端过滤(useUserSearch)和后端查询(getUsers)。前端的 includes 对中文实际上是有效的,问题大概率在后端这边——Prisma 的 contains 配合 mode: 'insensitive' 在 PostgreSQL 上对中文支持有问题(PostgreSQL 的 ILIKE 对非 ASCII 字符的行为取决于 locale 配置)。
第 4 轮:执行修复
模型确认了根因,现在开始修复。注意它如何遵守 CLAUDE.md 的规范:
// 第四次 API 响应 — 执行修复
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "找到根因了。问题在后端:Prisma 的 `contains` + `insensitive` 模式
在 PostgreSQL 上对中文不可靠。\n\n
修复方案:改用 Prisma 的原生查询进行 Unicode 安全的模糊搜索,
同时修复前端搜索使用 normalize 来确保一致性。"
},
{
"type": "tool_use",
"id": "tool_05",
"name": "Edit", // 系统提示要求用 Edit 而非 sed
"input": {
"file_path": "/project/src/features/users/api/getUsers.ts",
"old_string": " const where = query\n ? { name: { contains: query, mode: 'insensitive' } }\n : {}",
"new_string": " const where = query\n ? {\n OR: [\n { name: { contains: query } },\n { name: { contains: query.normalize('NFC') } },\n { email: { contains: query } },\n ],\n }\n : {}"
}
},
{
"type": "tool_use",
"id": "tool_06",
"name": "Edit", // 并行修复前端
"input": {
"file_path": "/project/src/features/users/hooks/useUserSearch.ts",
"old_string": " const q = query.toLowerCase()\n return users.filter(u =>\n u.name.toLowerCase().includes(q) ||\n u.email.toLowerCase().includes(q)\n )",
"new_string": " const q = query.normalize('NFC')\n return users.filter(u =>\n u.name.normalize('NFC').includes(q) ||\n u.email.normalize('NFC').includes(q)\n )"
}
}
]
}
这里模型做了两个关键决策:
- 用 Edit 而不是 Write — 系统提示偏好精确编辑而非覆写整个文件
- 两个 Edit 并行发出 — 两次编辑互不依赖,所以同时执行
第 5 轮:自动验证(遵守 CLAUDE.md)
修复完成后,模型没有停下来向你汇报——因为 CLAUDE.md 写了 Run pnpm test before finishing。这条规则被注入了 system 层级,模型会严格遵守:
// 第五次 API 响应 — 运行测试
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "两个文件已修复。按照项目规范,先跑一下测试。"
},
{
"type": "tool_use",
"id": "tool_07",
"name": "Bash",
"input": {
"command": "cd /project && pnpm test --filter='**/users/**'",
"description": "Run user module tests",
"timeout": 30000
}
}
]
}
假设测试通过了:
{
"type": "tool_result",
"tool_use_id": "tool_07",
"content": "✓ useUserSearch - filters by Chinese characters (3ms)\n
✓ useUserSearch - filters by email (2ms)\n
✓ getUsers - returns filtered results (15ms)\n
Tests: 3 passed, 3 total"
}
第 6 轮:汇报结果(循环结束)
测试通过,Agent Loop 终于结束。模型生成最终回复:
// 第六次 API 响应 — 最终回复(无工具调用 = 循环结束)
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "已修复中文搜索 bug。\n\n
**根因**:两个问题叠加\n
1. 后端 Prisma 的 `insensitive` 模式对中文不可靠,改为直接 `contains` 匹配\n
2. 前端的 `toLowerCase()` 对中文无意义,改为 `normalize('NFC')` 确保 Unicode 一致性\n\n
**改动文件**:\n
- `src/features/users/api/getUsers.ts` — 修复后端查询\n
- `src/features/users/hooks/useUserSearch.ts` — 修复前端过滤\n\n
所有相关测试已通过 ✅"
}
]
}
没有
tool_use块 = Agent Loop 终止。 这是循环结束的标志——模型认为任务完成了,不再需要调用任何工具。
全景回顾:一次请求背后的完整数据流
sequenceDiagram
participant U as 👤 你
participant CC as 🖥️ Claude Code 客户端
participant API as ☁️ Claude API
Note over CC: 组装请求:system prompt<br/>+ CLAUDE.md + tools + messages
U->>CC: "中文搜索 bug,请修复"
rect rgb(240, 245, 255)
Note over CC,API: 🔄 第 1 轮 — 探索
CC->>API: messages: [user_msg]
API-->>CC: Grep + Glob(并行)
Note right of CC: 执行工具,追加结果到 messages
end
rect rgb(240, 245, 255)
Note over CC,API: 🔄 第 2 轮 — 深入调查
CC->>API: messages: [user_msg, asst_1, tool_results_1]
API-->>CC: Read(useUserSearch.ts)
Note right of CC: 执行工具,追加结果到 messages
end
rect rgb(240, 245, 255)
Note over CC,API: 🔄 第 3 轮 — 追查根因
CC->>API: messages: [...之前所有, asst_2, tool_results_2]
API-->>CC: Grep(API 层代码)
Note right of CC: 执行工具,追加结果到 messages
end
rect rgb(255, 248, 240)
Note over CC,API: ✏️ 第 4 轮 — 修复代码
CC->>API: messages: [...之前所有, asst_3, tool_results_3]
API-->>CC: Edit × 2(并行)
Note right of CC: ⚠️ 可能触发权限确认
end
rect rgb(240, 255, 240)
Note over CC,API: 🧪 第 5 轮 — 运行测试(遵守 CLAUDE.md)
CC->>API: messages: [...之前所有, asst_4, tool_results_4]
API-->>CC: Bash("pnpm test")
end
rect rgb(245, 240, 255)
Note over CC,API: ✅ 第 6 轮 — 汇报结果(无工具调用 = 循环结束)
CC->>API: messages: [...之前所有, asst_5, tool_results_5]
API-->>CC: 纯文本回复(无 tool_use)
end
CC->>U: 展示修复结果 + 改动摘要
从这个例子中看到的所有原理
回顾一下这个例子中体现的全部机制:
| 原理 | 在例子中的体现 |
|---|---|
| Agent Loop | 6 轮 API 调用自主循环,从探索到修复到验证,用户只说了一句话 |
| 工具系统 | 模型自主选择 Grep→Read→Edit→Bash 的工具链;用 Edit 而非 sed(系统提示偏好) |
| 并行工具调用 | 第 1 轮 Grep+Glob 并行,第 4 轮两个 Edit 并行 |
| CLAUDE.md | 注入 system 层级;pnpm test 规则让模型在修复后自动跑测试 |
| 系统提示 | "修改前先读代码" → 模型先 Read 再 Edit;"用 Edit 不用 sed" → 遵守工具偏好 |
| 上下文窗口 | messages 每轮追加,从 1 条增长到 11 条;文件内容全部进入上下文 |
| 权限模型 | Edit 操作可能触发用户确认;Bash 执行测试命令需要权限放行 |
| 意图式描述 | 用户说"修复中文搜索 bug",没有指定步骤,模型自主完成全部决策 |
关键 takeaway:你看到的 Claude Code 界面上的每一行输出,背后都是一次完整的 API 往返。那个看起来"在思考"的光标闪烁,就是客户端在等待 API 响应、执行工具、把结果追加到 messages、再次发送……这就是 Agent Loop 的心跳。
第三章:范式总结 — 文档驱动开发
把前面所有机制和实践汇聚在一起,我们得到了一个统一的工作范式。
我叫它文档驱动开发(Document-Driven Development,DDD)。
旧模式 vs 新模式
旧模式:人写代码,AI 辅助片段。
你是司机,AI 是导航 GPS。你决定方向盘怎么打,AI 只是建议"前方 200 米左转"。写代码的主体还是你,AI 提供自动补全、代码建议、解答问题。
新模式:人定义"做什么",AI 实现"怎么做"。
你是工程经理,AI 是执行工程师。你定义目标、约束、标准和验收条件。AI 自主探索代码库、制定方案、编写代码、运行测试、迭代修复。
这不是偷懒或推卸责任。恰恰相反——定义好"做什么"比亲手"怎么做"更难。它要求你有清晰的架构思维、完善的规范体系、精准的需求描述能力。
角色转变
从 "使用 AI 的编码者" 到 "指挥 AI 的工程经理"。
工程经理不会亲手写每一行代码,但他确保:
- 团队有清晰的规范(CLAUDE.md)
- 任务被清晰定义(意图式描述)
- 方案在执行前被审批(规划模式)
- 执行过程有质量保障(Hooks + 权限模型)
- 产出被验证(测试 + 审查)
完整 DDD 工作流
flowchart TB
S1["📖 Step 1\n编写 CLAUDE.md"]
S2["🎯 Step 2\n意图式描述任务"]
S3{"📐 需要改 3+ 文件?"}
S3Y["🎩 Step 3\n进入规划模式\n审批方案"]
S4["⚡ Step 4\n让 Agent Loop 自主执行"]
S5{"✅ 结果满意?"}
S5N["💬 Step 5\n意图式反馈迭代"]
S6["🧹 Step 6\n/compact 或新对话\n更新 CLAUDE.md"]
S1 --> S2
S2 --> S3
S3 -- "是" --> S3Y
S3 -- "否" --> S4
S3Y --> S4
S4 --> S5
S5 -- "否" --> S5N
S5N --> S4
S5 -- "是" --> S6
S6 -. "下一个任务" .-> S2
style S1 fill:#DCEEFB,stroke:#2980B9,color:#333
style S2 fill:#E8F4FD,stroke:#4A90D9,color:#333
style S3 fill:#FEF9E7,stroke:#F1C40F,color:#333
style S3Y fill:#FFF8E1,stroke:#F9A825,color:#333
style S4 fill:#E8F5E9,stroke:#43A047,color:#333
style S5 fill:#FEF9E7,stroke:#F1C40F,color:#333
style S5N fill:#FDE8E8,stroke:#E74C3C,color:#333
style S6 fill:#F3E8FD,stroke:#8E44AD,color:#333
Step 1:编写优秀的 CLAUDE.md
项目开始的第一件事。定义技术栈、架构原则、代码规范、测试要求、常见陷阱。这是你 ROI 最高的时间投入。
Step 2:用意图式描述定义任务
不要说"打开文件 A,在第 X 行加 Y"。说"实现 Z 功能,确保满足 W 约束"。
Step 3:复杂任务先进规划模式
超过 3 个文件的变更,按 Shift+Tab 进入规划模式。审批方案后再让 Claude Code 动手。
Step 4:让 Agent Loop 自主执行
方案审批后,放手让它跑。它会自己读文件、改代码、跑测试、修 bug。不要中途打断——除非你发现方向性错误。
Step 5:审查结果、反馈迭代
Agent Loop 完成后,审查变更。如果有问题,用意图式描述反馈("这里的错误处理不符合我们的规范,请按 CLAUDE.md 中的 Result<T, E> 模式修改"),而不是手动指定修改。
Step 6:任务间管理上下文
一个任务完成后,/compact 或开新对话。保持上下文窗口干净。把本次工作中发现的重要模式更新到 CLAUDE.md。
第四章:速查表
10 对"机制→实践"的快速参考:
| 机制 | 核心洞察 | 最佳实践 | 一句话口诀 |
|---|---|---|---|
| Agent Loop | 它会自主迭代 | 意图式描述 | 说目的地,不说路线 |
| 工具系统 | 它有专业工具箱 | 匹配工具描述任务 | 知道队友会什么 |
| CLAUDE.md | 它先读手册 | 写宪法而非写代码 | 写好入职文档 |
| 子代理 | 它能分身 | 设计并行任务 | 分而治之 |
| 上下文窗口 | 桌面有限 | 上下文卫生 | 保持桌面整洁 |
| 权限模型 | 风险操作会确认 | 信任但验证 | 配好信任级别 |
| 规划模式 | 可以只看不动手 | 先谋后动 | 架构师帽先戴上 |
| Hooks | 支持自动化 | 自动化质量门禁 | 设了就忘 |
| MCP | 能用外部工具 | 扩展工具链 | 给它开权限 |
| 系统提示 | 有内置直觉 | 顺势而为 | 借力不对抗 |
快速行动清单:
- 给项目写一份 CLAUDE.md(今天就做)
- 下次需求描述从"打开文件改第 X 行"改为"实现 Y 功能"
- 尝试一次规划模式(
Shift+Tab) - 配置一个 Hook(比如 Edit 后自动格式化)
- 完成一个任务后试试
/compact
第五章:回到那两个程序员
现在回头看开篇的故事,你应该能解释一切了。
程序员 A 的问题不是 prompt 写得差,而是他的心智模型错了。他把 Claude Code 当成一个需要逐步指令的"遥控车",结果:
- 短路了 Agent Loop — 每条消息都在告诉它下一步做什么,剥夺了它自主迭代的能力
- 没有 CLAUDE.md — 每次新会话都要重新交代项目规范
- 没用规划模式 — 直接让它改跨多个文件的代码,没有方案审批就开工
- 上下文被污染 — 来回纠错的对话塞满了上下文,降低了后续输出的质量
程序员 B 做对了每一件事:
- 意图式描述 → 激活了完整的 Agent Loop
- 引用了 CLAUDE.md → 规范一开始就到位
- 不啰嗦 → 上下文保持干净
- 信任 Agent Loop → 给出目标后放手让它跑
差距不是 10% 的 prompt 优化,是 10 倍的范式升级。
最后一句话
最好的 prompt 根本不是 prompt——而是一份写得好的 CLAUDE.md、一个清晰的意图、和让 Agent Loop 自己跑起来的智慧。
现在就去给你的项目写一份 CLAUDE.md 吧。
这一个动作,比任何 prompt 技巧合集都更能改变你的 Claude Code 体验。