---
title: 'Claude Code 上下文工程实战：从"碰运气"到"有体系"'
author: deletexiumu
pubDatetime: 2026-04-04T21:00:00+08:00
featured: false
draft: false
tags:
  - Claude Code
  - AI 编程
  - 效率
  - 教程
description: 'Claude Code 时灵时不灵？本文从四种上下文失败模式出发，介绍五层上下文分层体系和决策规则，帮你从碰运气变成有体系地管理 AI 编码助手的信息输入。'
---

![封面图](/blog/context-engineering-in-practice/cover.jpg)

同样一个任务——创建一个 Skill，上次 Claude Code 一次搞定，结构清晰、规范齐全。过了两天，我在一个已经聊了很久的会话里又让它做类似的事，结果来回改了三轮还是偏。

你开始怀疑是不是模型降级了。但更可能的原因是：上次碰巧给对了上下文，这次没有。

这就是本文要解决的问题。不靠运气，靠体系。

## 一句话理解上下文工程

Prompt engineering 优化"怎么问"，Context engineering 优化"AI 手边有什么信息"。

Thoughtworks 的 Birgitta Böckeler 在一篇发表于 martinfowler.com 的文章中引用了同事 Bharani Subramaniam 的定义：

> Context engineering is curating what the model sees so that you get a better result.

Anthropic 在 2026 Agentic Coding Trends Report 中强调，AI 协作并不等于完全委托——setup、监督、验证和人的判断仍然关键。换句话说，上下文准备的质量会直接影响协作效果。

类比一下：你不会只跟实习生说"去做 X"——你会给背景文档、代码库权限、注意事项清单。对 AI 也一样。区别在于，实习生能主动问你要材料，AI 只能用你塞给它的东西。

那么问题来了：上下文这么重要，它会怎么出错？

## 四种上下文失败模式——先会诊断，才能治

用 Claude Code 时间长了，你大概率踩过以下坑。我把它们归为四种失败模式：

### 污染：越修越偏

**症状**：错误像传染病，一个错误假设导致后续代码全基于错误前提。

我遇过一次典型场景：在创建 tech-article-creator 这个 Skill 时，早期会话里我随口说了一句"先按双版本写"，后来改了策略要求单版本，但 Claude Code 始终在按双版本的假设生成代码和配置。我越纠正，它越混乱——因为前面几十轮对话里的双版本痕迹太多了，新指令淹没在旧上下文里。

**急救**：`/clear` 开新会话。在一个被污染的会话里反复纠正，不如带着正确的上下文重新开始。

### 分心：忽视新指令

**症状**：你改了需求，它还在按旧方案干。

这在长会话中尤其常见。会话前半段讨论了方案 A，后来你说"换方案 B"，但 Claude Code 生成的代码里方案 A 的痕迹还在。不是它"不听话"，是前面的上下文太长，新指令的权重被稀释了。

**急救**：用 `/compact` 压缩历史，或把当前决策写进任务文件（spec/plan），让 Claude Code 从文件读取而非依赖会话记忆。

### 混乱：选错工具，跑偏方向

**症状**：MCP 工具（给 AI 接外部数据源和能力的协议接口）太多时，Claude Code 拿了错的那个。

我配了几十个 MCP 工具，有一次让它查个东西，它调了 Grok 搜索而不是直接读本地文件——因为工具列表太长，它的"注意力"分散了。Manav Ghosh 在个人实测中也发现类似现象：精简 MCP 连接后响应速度明显提升。

**急救**：缩减活跃 MCP 工具范围。默认保持 2-3 个核心 server（filesystem、git），按需添加专用 server，而不是一股脑全挂上去。

### 冲突：自相矛盾

**症状**：行为矛盾，一会儿用 TypeScript 一会儿用 Python。

CLAUDE.md 说"用 TypeScript"，但你在会话里说"这个用 Python 写"，Claude Code 就会在两者之间摇摆。或者全局 CLAUDE.md 和项目级 CLAUDE.md 的规则打架。它不是故意矛盾——而是收到了矛盾的信号。

**急救**：统一权威源。CLAUDE.md 里的规则应该是不矛盾的，如果需要特例，在会话中明确说明"本次覆盖 CLAUDE.md 中的语言选择规则"。

### 关于上下文退化的经验

这四种失败不是孤立的，它们都会随着上下文占用率上升而加剧。我的日常体感是：上下文占用率高了之后精度会明显下降，到了很高的时候响应就不太稳定了。Claude Code 在接近上限时会触发自动压缩（auto compaction），但被动压缩难免丢信息。更好的做法是主动管理——在上下文膨胀之前就把信息放到正确的位置。

## 从诊断到治理

识别了失败模式，对应的治理动作：

| 失败模式 | 治理动作 |
|---------|---------|
| 污染 | `/clear` 开新会话，或 `/compact` 清理累积噪声 |
| 分心 | 用任务工件（spec/plan/session notes）明确当前任务边界 |
| 混乱 | 缩减 MCP 工具范围，按需加载而非全量 |
| 冲突 | 统一权威源到 CLAUDE.md，消除矛盾指令 |

但这只是应急处理。长期方案是搭一套分层体系——让每条信息待在它该在的地方。

## 五层上下文体系——信息该放哪？

很多人知道 CLAUDE.md，但 CLAUDE.md 只是上下文体系的一层。完整的体系是五层金字塔——底部是每次会话自动加载的，顶部是用完即弃的，排列依据是"加载频率"：

```
┌───────────────────────────────────┐
│     临时对话层（会话窗口）          │  ← 当前对话，用完即弃
├───────────────────────────────────┤
│   任务工件层（spec/plan/notes）    │  ← 任务级文件，跨会话但随任务结束归档
├───────────────────────────────────┤
│     持久记忆层（Memory）           │  ← 自动学习偏好和修正，跨会话持久
├───────────────────────────────────┤
│     按需知识层（Skills）           │  ← 专业知识包，用时才加载
├───────────────────────────────────┤
│     长期指令层（CLAUDE.md）        │  ← 项目宪法，每次自动读取
└───────────────────────────────────┘
```

关键问题是：拿到一条信息时，怎么判断它该放哪层？以下是我用的决策流程：

1. **这条信息每次会话都需要吗？** → 是 → 放 CLAUDE.md
2. **只在特定工作流中需要？** → 是 → 做成 Skill
3. **是从使用中学到的偏好或修正？** → 是 → 存 Memory（自动或手动触发）
4. **是当前任务的上下文？** → 是 → 写进任务工件（spec/plan/session 文件）
5. **只在当前对话中有用？** → 是 → 直接在会话中说

每层配一个我的实际用法：

**CLAUDE.md——精简为上**

我的全局 CLAUDE.md 只有 30 多行，核心是"指针而非内容"。比如：

```markdown
## 全局规则（每次自动加载）
- 通用经验 → rules/lessons-learned.md
- Skill 开发偏好 → rules/skill-development.md

## 按需参考（涉及相关任务时用 Read 读取）
- 服务器信息 → ~/.claude/refs/servers.md
- 数据库连接 → ~/.claude/refs/database-connections.md
```

"全局规则"每次加载，"按需参考"只在涉及相关任务时才读。这样 CLAUDE.md 不会膨胀，也不会让不相关的信息占用上下文。Claude Code 官方文档建议 CLAUDE.md 文件保持精简，避免过长导致遵从度下降——这也是为什么要用指针引用而非塞全文。

还有一个细节：我在 CLAUDE.md 里写了"回答前喊一声哥"。这不是搞笑——这是一个极低成本的行为锚点。如果它连这个都忘了，说明上下文可能已经丢失或被压缩，是时候检查会话状态了。

**Skills——按需加载，不占常驻上下文**

我目前有 80 多个 Skill，覆盖内容创作、发布分发、数据分析、开发工具等场景。关键设计原则是"用时才加载"。

以 tech-article-creator 为例，它的目录结构是：

```
tech-article-creator/
├── SKILL.md          # 主文件：流程定义（约 400 行）
├── config.yaml       # 可配置项模板
└── references/       # 详细指南（SKILL.md 通过路径引用）
    ├── writing-and-review-guide.md
    ├── image-guide.md
    ├── material-collection-guide.md
    └── ...            # 及其他参考文件
```

SKILL.md 保持流程骨架，详细规范放在 references/ 目录里按需读取。这避免了 SKILL.md 膨胀到不可维护的程度，也避免了一次性把所有内容塞进上下文。

Manav Ghosh 在他的 Medium 文章中提到，Skills 按需加载相比把所有内容塞进 CLAUDE.md，上下文占用大幅下降（他个人实测的数据是节省约 60-70%，具体效果因项目而异）。我自己的体感类似：把配置和规范从 CLAUDE.md 拆到 Skills 之后，不相关任务的上下文明显干净了。

**Memory——从修正中自动学习**

Memory 存的是"从代码和 git 推导不出来"的信息。比如我纠正过一次"文章不做双版本"之后，Claude Code 自动存了一条 feedback 类型的 memory：

```markdown
---
name: 文章版本策略偏好
description: 技术文章 Blog 版和公众号版内容保持一致，仅做平台格式适配
type: feedback
---
虽然配置了双版本，但 Blog 和公众号版内容尽量保持一致。
**Why:** 我观察到跨平台跳转很少，双版本降级意味着一半读者永远只看到空洞内容。
**How to apply:** 写作阶段只产出一份内容，发布时仅做平台格式适配。
```

每条 memory 都有 Why 和 How to apply，确保未来能正确应用而非盲从。这比在每个新会话里重新解释一遍高效得多。

**任务工件——跨会话但不永久**

本文就是一个活生生的例子。大纲、原始素材、写作规范——这些都是任务级文件，多个会话可以共享，但任务完成后就归档了。它们不需要写进 CLAUDE.md 或做成 Skill，因为它们是一次性的。

**会话窗口——用完即弃**

临时调试指令、一次性的格式要求，直接在对话里说就行。不值得持久化的信息不要持久化，否则就是在制造噪声。

### SubAgent：用隔离换上下文空间

除了把信息放对层，还有一个减轻上下文压力的技巧：用 SubAgent（子代理）做探索性工作。SubAgent 在独立的上下文窗口中运行，完成后只返回精炼结果给主会话，探索过程中的大量中间信息不会污染主会话的上下文。Manav Ghosh 在他的实践中提到，一次代码探索任务通过 SubAgent 处理后，返回给主会话的信息量远小于直接在主会话中操作的开销。

### 上下文 vs Hook：一条分界线

不是所有问题都能靠上下文解决。有些规则必须 100% 执行，不能依赖模型"理解并遵守"。这时候需要 Hook（在固定生命周期事件自动执行的脚本，比如工具调用前后）。

| 场景 | 用上下文（软约束） | 用 Hook（硬约束） |
|------|-----------------|-----------------|
| 代码风格偏好 | CLAUDE.md 规则 | — |
| 禁止 force push | — | PreToolUse hook 拦截 |
| 测试必须通过才能提交 | — | PostToolUse hook 检查 |
| API 调用默认参数 | CLAUDE.md 或 Skill | — |
| 文件格式化 | — | PostToolUse format-on-save hook |

**原则**：能靠上下文解决的，用上下文——灵活、可调；必须 100% 执行的，用 Hook——确定性、不依赖模型理解。

比如我有一个 PostToolUse hook 专门修复 Skill 安装后的 symlink 路径错误——这个问题靠上下文提醒是没用的，因为路径解析是系统层面的事。简单说：CLAUDE.md 是建议，模型可能偶尔忽略；Hook 是代码，每次必定执行。

## 复杂任务的升级打法——Spec 作为可复用上下文

当任务复杂到一个会话搞不定时，写一份 spec.md 的目的是给每个新会话一份完整的任务上下文，而不只是为了文档化。

**什么时候值得写 spec**：

- 预计会跨多个会话
- 涉及多文件、多步骤
- 失败成本高（比如涉及生产环境或数据迁移）

**什么时候不需要**：

- 单文件修改
- 一次性脚本
- 探索性对话

一个实用的 spec 只需要三块内容：目标（做什么、不做什么）、约束（技术栈、兼容性要求、性能指标）、验收标准（怎么算完成）。每次开新会话时让 Claude Code 先读 spec 文件，它就能快速进入状态，而不需要你重新解释一遍背景。

关于 Spec-Driven Development 更完整的方法论，可以参考[《别让 AI 乱写代码：我的 Claude Code 工作流》](/posts/claude-code-plan-before-code/)。

## 改造案例——从"碰运气"到"有体系"

以我构建 tech-article-creator 这个 Skill 的过程为例，展示上下文工程如何把"碰运气"变成"有体系"。

**改造前的三次典型失误**：

**失误一：污染。** 在一个已经讨论了其他 Skill 的长会话里继续创建 tech-article-creator，结果 Claude Code 把之前 Skill 的结构和命名习惯带了进来，生成的 SKILL.md 混入了不相关的配置模式。我改了两轮才发现根源——不是 Claude Code 不行，是我给它的上下文里有太多干扰信号。

**失误二：信息放错层。** 早期我把所有配置都塞进全局 CLAUDE.md——写作规范、发布流程、评审标准全在里面。结果做其他任务时（比如写代码或查数据），Claude Code 还在参考写作规范，偶尔冒出不相关的格式建议。CLAUDE.md 越长，不相关任务受到的干扰越大。

**失误三：没有持久记忆。** 每次开新会话做这个 Skill，我都要花好几分钟重新解释项目背景：用什么写作风格、单版本还是双版本、评审流程是什么。说过的话下次还要再说一遍。

**改造后用什么层治理**：

1. **识别污染信号 → `/clear` 开新会话。** 现在我养成了习惯：切换不同类型的任务时主动开新会话，而不是在一个会话里干到底。这一个动作就消除了大部分"越改越偏"的问题。

2. **配置从 CLAUDE.md 移到 Skill。** 把写作规范、评审模板、素材收集指南全部移到 `tech-article-creator/references/` 目录下，SKILL.md 通过路径引用。全局 CLAUDE.md 恢复精简，只保留真正"每次会话都需要"的规则。

3. **Memory 自动记住偏好。** "单版本策略"、"grok-mcp 超时用 180 秒"这类通过修正学到的偏好，Memory 自动存了。下次开新会话不用再解释，Claude Code 启动时就知道。任务级的进度和决策写进 spec/plan 文件，跨会话可追溯。

**效果**（基于我最近十几次使用这个 Skill 的体感）：返工频率明显降低，新会话不再需要重新解释背景，token 消耗也因为不再有无关信息挤占上下文而下降。

## 三件事，现在就能做

**第一，今晚就审查你的 CLAUDE.md。** 打开文件，用前面的决策规则逐行过一遍：只有"每次会话都需要"的信息才该留。特定工作流的内容移到 Skill，偏好和修正交给 Memory，任务级的上下文放到 spec/plan 文件。目标：精简到核心规则 + 指针引用。

**第二，下次 Claude Code "变笨"时先做诊断。** 不要急着重新发 prompt——先判断属于哪种失败模式（污染、分心、混乱、冲突），然后对症下药。最常见的情况是污染，`/clear` 一下就好了。

**第三，挑一条总被忽视的规则，改成 Hook。** 找一个你在 CLAUDE.md 里写了但 Claude Code 不是每次都遵守的规则——比如 format-on-save、禁止 force push——把它做成 PostToolUse 或 PreToolUse hook。十分钟就能搞定，效果立竿见影。

---

**延伸阅读**

- [Anthropic - 2026 Agentic Coding Trends Report](https://resources.anthropic.com/2026-agentic-coding-trends-report)
- [Birgitta Böckeler - Context Engineering for Coding Agents](https://martinfowler.com/articles/exploring-gen-ai/context-engineering-coding-agents.html)
- [Claude Code 官方文档 - Memory](https://code.claude.com/docs/en/memory)
- [Claude Code 官方文档 - Best Practices](https://code.claude.com/docs/en/best-practices)
- [Manav Ghosh - Mastering Context Management in Claude Code](https://medium.com/@manavghosh/mastering-context-management-in-claude-code-8-tips-that-changed-my-workflow-9ce88ca4db39)
- [Thomas Landgraf - Context Engineering for Claude Code](https://thomaslandgraf.substack.com/p/context-engineering-for-claude-code)

---

## 相关阅读

- [同样的话跟 Claude Code 说了八遍，是时候让它自己记住了](/posts/claude-code-memory-rules/) — Memory 机制详解，本文五层体系中"持久记忆层"的深入展开
- [别让 AI 乱写代码：我的 Claude Code 工作流](/posts/claude-code-plan-before-code/) — Spec-Driven Development 的前身，本文"升级打法"章节的完整版
- [Claude Code 安全三道防线](/posts/claude-code-safety-three-defenses/) — Hook 机制的完整实战，本文"上下文 vs Hook"分界线的延伸
