Claude Code 攻略 2 - 上下文是一切的基石

2025-12-16 | 101分钟 | yrobot | 上下文工程,Context Engineering,LLM 优化,Token 管理,Prompt Engineering,RAG,向量搜索

从一个真实问题说起

在深入学习 Claude Code 的过程中,我发现了一个很有意思的现象。同样是"修复登录功能的 bug"这个需求,有时候 AI 会给出很精准的解决方案,有时候却只能给出一些通用的、无法直接应用的建议。

后来我做了个实验。第一次,我只说"修复登录功能的 bug",Claude Code 给了我一些通用的排查建议,比如检查数据库连接、验证 JWT 配置等,但都不太适用。第二次,我换了个说法:"修复登录功能的 bug,项目使用 Next.js + Prisma + JWT,错误信息是 TypeError: Cannot read 'id' of undefined",这次 AI 直接定位到了问题所在,并给出了准确的修复方案。

这两次尝试的差异让我意识到:AI 的输出质量,很大程度上取决于我们提供的信息,也就是所谓的"上下文"(Context)。对于大型语言模型来说,上下文就像是它的"视野范围"和"知识来源"。你提供什么样的信息,它就基于什么样的信息来生成回答。

这篇文章,我会从 LLM 的工作机制讲起,系统地分析如何优化上下文的五个关键维度,帮助你在使用 Claude Code 时获得更好的输出质量。

LLM 的工作原理:为什么上下文是关键

反直觉的事实:LLM 并不"理解"你的问题

传统程序:
if (condition) {
    return action;  // 基于规则执行
}

LLM 的工作方式:
扫描上下文 → 计算概率分布 → 选择最可能的下一个词

核心机制

  • LLM 基于统计概率预测下一个最可能的词
  • 它的"理解"来自于上下文中的信息模式
  • 上下文越相关、越丰富,预测越准确

上下文窗口:LLM 的"视野范围"

┌─────────────────────────────────────┐
│         上下文窗口(200K tokens)      │
├─────────────────────────────────────┤
│ [系统提示词]                         │
│ [对话历史]                           │
│ [用户当前输入]                       │
│ [工具调用结果]                       │
│ [文件内容]                           │
└─────────────────────────────────────┘
         ↓
   这是 LLM 能"看到"的全部信息
         ↓
   基于这些信息生成回复

技术规格

  • Claude 3.5 Sonnet:200K tokens(约 40 万中文字符)
  • GPT-4 Turbo:128K tokens
  • 上下文窗口外的信息会被截断或遗忘

限制的影响

  • 信息超出窗口 → LLM 无法访问
  • 上下文质量差 → 输出质量差
  • 无关信息多 → 干扰判断

上下文工程的定义和目标

定义

上下文工程(Context Engineering):
在有限的 Token 窗口内,优化提供给 LLM 的信息,
以最大化输出质量和准确性的技术和方法论

核心目标

  • 提供足够的信息(让 LLM 理解任务)
  • 保持精简(不超出 Token 限制)
  • 确保相关(排除无关信息)
  • 结构清晰(便于 LLM 理解)

上下文工程的五个优化维度

维度 1:数量(Quantity)- 给多少信息?

问题:信息太少 vs 信息太多

信息太少 ←──── 最佳点 ────→ 信息太多
    ↓              ↓              ↓
LLM 无法理解   准确完成     Token 超限

实际案例对比

信息太少的例子:

用户:修复这个 bug
AI:什么 bug?请提供更多详细信息

适当的信息量:

用户:修复登录 bug
项目:Next.js + Prisma + PostgreSQL
错误:TypeError: Cannot read 'id' of undefined
位置:src/app/api/auth/login/route.ts:42
期望:正常登录返回 JWT token

信息过载的例子:

用户:修复登录 bug
[粘贴整个项目的 10 万行代码]
[包含完整的 git 历史记录]
[包含所有依赖包的源码]

优化策略

  1. 最小必要原则:只包含必要信息
  2. 分层提供:先摘要,后细节
  3. 按需扩展:根据 AI 的反馈补充信息

维度 2:质量(Quality)- 信息的准确性

高质量上下文的特征

  • 准确性:信息真实可靠,无错误
  • 具体性:细节明确,避免模糊
  • 时效性:信息是最新的
  • 完整性:包含必要的关联信息

质量优化实例

低质量的描述:

用户:网站有问题,帮我看看

高质量的描述:

用户:网站在用户登录后出现 500 错误
环境:生产环境
时间:昨天 20:30 开始
影响:所有新用户无法登录
日志:在 auth.service.ts:45 出现 TypeError
变更:昨天部署了 v2.1.0 版本

质量检查清单

  • 错误信息是否准确(复制粘贴,而非口头描述)?
  • 环境信息是否完整(开发/测试/生产)?
  • 复现步骤是否清晰?
  • 期望结果是否明确?
  • 相关变更是否说明?

维度 3:结构(Structure)- 信息的组织方式

为什么结构化更好?

我之前也习惯用一段话把需求全说完,后来发现这样效果很差:

无结构的描述:

用户:用户登录功能需要邮箱密码验证还要检查账户状态是否激活如果是管理员要给管理员权限还要记录登录日志...

这种方式下,LLM 需要自己去提取和整理关键信息,很容易遗漏细节。

结构化的描述:

# 用户登录功能需求

## 输入验证

- 邮箱格式验证
- 密码强度检查(至少 8 位)

## 业务逻辑

1. 检查账户存在
2. 验证密码
3. 检查账户状态(激活/禁用)
4. 识别用户角色

## 输出

- 普通用户:JWT token + user info
- 管理员:JWT token + user info + admin permissions

## 附加功能

- 记录登录日志(IP、时间、设备)
- 限制登录尝试次数

使用结构化描述后,LLM 可以直接识别各个部分的作用,准确率明显提高。

结构化模板

# 任务概述

[简要描述要解决的问题]

## 背景

[问题的来源和影响]

## 技术栈

[使用的技术和版本]

## 现状

[当前实现情况]

## 需求

[具体要实现的功能]

## 约束

[限制条件和注意事项]

## 期望结果

[成功的标准]

维度 4:时序(Temporal)- 信息的时间顺序

LLM 的"近因偏差"(Recency Bias)

上下文窗口:
┌───────────────────────┐
│ [很早的信息]           │ ← LLM 容易忽略
│ [中间的信息]           │
│ [最近的信息]           │ ← LLM 重点关注
│ [当前输入]             │ ← LLM 最关注
└───────────────────────┘

Claude Code 的时序优化

  1. 系统提示词:总是在开头(定义行为)
  2. CLAUDE.md:每次对话注入(项目规则)
  3. 用户输入:最新信息(最重视)

时序优化策略

# 优化前的上下文(不推荐)

[长篇的背景介绍...]
[详细的历史对话...]
[前面的技术讨论...]
用户:现在帮我实现用户认证

# 优化后的上下文(推荐)

# 当前任务:实现用户认证功能

## 立即需要的信息

- 项目:Next.js + Prisma + PostgreSQL
- 已有:User 模型、基础 API 结构
- 需求:JWT 认证 + 角色权限

## 背景信息

[简要的项目背景...]

用户:现在帮我实现用户认证

维度 5:相关性(Relevance)- 信息的相关程度

相关性判断实例

任务:修复登录 bug

高相关的信息:

  • src/auth/auth.service.ts(直接相关)
  • src/auth/login.controller.ts(业务逻辑)
  • 错误日志(问题现象)
  • package.json(依赖版本)

无关的信息:

  • src/utils/formatDate.ts(工具函数)
  • README.md(项目介绍)
  • tests/e2e/(E2E 测试)
  • .gitignore(忽略文件)

Claude Code 的相关性过滤机制

// 智能文件选择流程
1. Glob: 查找相关文件模式
   - **/*auth*.*, **/*login*.*

2. Grep: 搜索关键词
   - "authentication", "login", "jwt"

3. Read: 只读取关键部分
   - 导出的函数和类
   - 错误处理逻辑
   - 配置项

相关性优化技巧

  1. 关键词提取:从任务描述中提取关键技术词
  2. 文件模式匹配:使用 Glob 模式快速筛选
  3. 内容预览:先读取文件头部和尾部,判断相关性
  4. 依赖分析:分析文件间的依赖关系

抽象 vs 具体:如何选择上下文的抽象级别

核心原则:根据任务类型选择

不是越抽象越好,也不是越具体越好。需要根据任务类型选择合适的抽象级别:

任务类型 推荐抽象级别 原因
架构设计 高度抽象 需要关注整体结构和模式
代码实现 中等具体 平衡设计思路和实现细节
Bug 修复 高度具体 需要精确的错误信息和代码
性能优化 中等具体 需要性能数据和代码实现
代码审查 中等抽象 关注设计原则和代码质量

实际案例对比

场景 A:架构设计(需要抽象)

过于具体的描述:

帮我设计用户系统,具体实现:
- User 类要有 id, name, email 字段
- 使用 class User { constructor() {...} }
- 数据库用 MySQL,表名 users...

适度抽象的描述:

帮我设计用户系统的架构:

技术背景:
- Node.js + TypeScript 后端
- 10 万用户规模
- 需要支持第三方登录(Google, GitHub)

需求:
- 用户注册登录
- 角色权限管理(普通用户/管理员)
- 账户安全(2FA, 密码重置)

场景 B:Bug 修复(需要具体)

过于抽象的描述:

用户登录功能有问题,帮我修复

高度具体的描述:

登录功能报错:

错误信息:

TypeError: Cannot read property 'id' of undefined at AuthService.validateUser (src/auth/auth.service.ts:42:15)


相关代码:
```typescript
// src/auth/auth.service.ts:40-45
async validateUser(email: string, password: string) {
    const user = await this.userRepository.findByEmail(email);
    return user.id; // Line 42: user is undefined
}

测试用例:

  • 输入:valid@example.com / password123
  • 期望:返回用户对象
  • 实际:user 为 undefined

数据库查询结果:

  • 查询:SELECT * FROM users WHERE email = 'valid@example.com'
  • 结果:返回空数组

### 最佳实践:分层上下文策略

```markdown
# 阶段 1:理解需求(抽象层)
高层目标:
- 构建电商网站的用户认证系统
- 支持邮箱注册和社交登录
- 实现角色权限管理

业务需求:
- 用户注册/登录/登出
- 管理员后台管理
- 第三方登录集成

# 阶段 2:设计方案(中等层)
技术选型:
- Next.js 14 + TypeScript
- NextAuth.js 处理认证
- Prisma ORM + PostgreSQL
- JWT token + session 混合模式

架构设计:
- API Routes:/api/auth/*
- 数据库模型:User, Account, Session
- 前端组件:LoginForm, RegisterForm, Profile

# 阶段 3:实现代码(具体层)
现有代码:
- src/app/api/auth/[...nextauth]/route.ts
- prisma/schema.prisma

具体实现:
- 修改 User 模型添加 role 字段
- 实现自定义认证逻辑
- 添加权限中间件

# 阶段 4:测试验证(非常具体)
测试用例:
- 测试用户注册流程
- 验证权限控制
- 检查第三方登录

错误处理:
- 数据库连接失败
- 邮箱重复注册
- Token 过期处理

相关的 AI 优化知识领域

1. 提示工程(Prompt Engineering)

核心技巧

Zero-shot(零样本)

直接描述任务,不提供示例
"帮我实现一个用户认证系统"

Few-shot(少样本)

提供示例,让 LLM 学习模式
"帮我实现认证系统,像这样:
示例:用户登录 → 验证密码 → 返回 token
现在实现:用户注册 → ??? → 返回用户信息"

Chain-of-Thought(思维链)

让 LLM 分步思考
"实现用户认证系统:
1. 分析需求
2. 设计数据模型
3. 实现认证逻辑
4. 添加安全措施
请按这个思路执行"

2. RAG(检索增强生成)

Claude Code 的实现

检索:Grep + Glob + Read → 找到相关代码
增强:将检索结果加入上下文
生成:基于增强的上下文生成回复

优化策略

  • 建立代码索引(Grep 数据库)
  • 使用语义搜索(而非仅关键词)
  • 分块检索(避免 Token 超限)

3. In-Context Learning(上下文学习)

原理

  • LLM 在上下文中"学习"模式,无需重新训练
  • 提供示例 → LLM 自动遵循相同风格

实际应用

// 提供代码风格示例
// 现有代码风格:
export const getUserById = async (id: string): Promise<User | null> => {
  try {
    return await userRepository.findById(id);
  } catch (error) {
    throw new Error(`Failed to get user: ${error}`);
  }
};

// 请按照相同风格实现:
export const createUser = async (data: CreateUserDto): Promise<User> => {
  // LLM 会自动遵循相同的错误处理和返回类型
};

4. Embedding 和向量搜索

应用场景

  • 语义相似度搜索("找所有用户认证相关的代码")
  • 代码重复检测
  • 智能代码推荐

Claude Code 的应用

  • Skills 的触发机制(基于语义匹配)
  • Explore Agent 的智能文件选择

5. Fine-tuning vs Prompt Engineering

维度 Fine-tuning Prompt Engineering
成本 高(训练成本) 低(优化输入)
灵活性 低(需要重新训练) 高(实时调整)
控制度 中(模型内部改变) 高(精确控制)
适用场景 大规模、固定任务 灵活、多变化任务

Claude Code 的选择:Prompt Engineering

  • 任务灵活多变
  • 需要实时调整
  • 成本控制考虑

实战应用:优化 Claude Code 的上下文策略

策略 1:提供分层上下文

# 背景(抽象层)

开发电商网站,需要用户认证系统,支持邮箱注册和社交登录。

# 技术栈(中等层)

- Next.js 14 + TypeScript + Tailwind CSS
- Prisma ORM + PostgreSQL
- NextAuth.js 处理认证
- 部署在 Vercel

# 具体需求(具体层)

1. 用户注册:邮箱验证 + 密码强度检查
2. 用户登录:JWT token + 记住登录状态
3. 社交登录:Google OAuth + GitHub OAuth
4. 权限管理:普通用户/管理员/超级管理员

# 现有代码(具体层)

- User 实体:src/lib/prisma.ts
- 认证配置:src/pages/api/auth/[...nextauth].ts
- 前端组件:src/components/auth/

策略 2:使用 CLAUDE.md 预设上下文

# CLAUDE.md

## 项目上下文

### 技术栈

- Next.js 14 + TypeScript
- Tailwind CSS + Headless UI
- Prisma ORM + PostgreSQL
- NextAuth.js + JWT

### 代码风格

- 函数式组件(React)
- camelCase 命名
- TypeScript 严格模式
- ESLint + Prettier

### 项目结构

src/ ├── app/ # App Router ├── components/ # React 组件 ├── lib/ # 工具函数 ├── types/ # TypeScript 类型 └── prisma/ # 数据库模型


### 工作流程
1. 先 Plan Mode 设计方案
2. 实现核心功能
3. 添加测试用例
4. 更新文档

### 常见命令
```bash
npm run dev          # 开发服务器
npm run build        # 生产构建
npm run test         # 运行测试
npx prisma studio    # 数据库管理

### 策略 3:善用工具提供具体上下文

**❌ 低效方式:**
```text
用户:登录报错了
用户:[手动复制粘贴错误日志]
用户:[手动复制粘贴相关代码]

✅ 高效方式:

用户:登录报错,错误日志在 logs/error.log,相关代码在 src/auth/
Claude Code:
- [自动读取] logs/error.log
- [自动读取] src/auth/login.ts
- [自动读取] src/auth/auth.service.ts
- [分析] 发现是数据库连接问题
- [解决] 更新数据库配置

策略 4:动态上下文管理

智能上下文压缩

// 长对话自动总结
if (conversationLength > 50) {
  await summarizeConversation(); // 压缩历史对话
}

// 相关文件动态加载
if (taskRelatesTo("auth")) {
  await loadRelevantFiles(["src/auth/*", "tests/auth/*"]);
}

// 无关信息自动过滤
filteredContext = removeIrrelevantInfo(context, currentTask);

上下文优先级排序

优先级 1:当前任务相关文件
优先级 2:最近修改的文件
优先级 3:用户明确提到的文件
优先级 4:项目配置文件
优先级 5:通用工具函数

上下文工程的质量评估

评估维度

完整性评分

  • 任务背景是否清晰?
  • 技术栈信息是否完整?
  • 具体需求是否明确?
  • 约束条件是否说明?

相关性评分

  • 是否包含必要的错误信息?
  • 是否提供相关代码?
  • 是否排除无关信息?

结构性评分

  • 信息组织是否清晰?
  • 是否使用合适的格式?
  • 逻辑层次是否合理?

自动化检查工具

// 上下文质量检查函数
function validateContext(context: TaskContext): QualityReport {
  const issues = [];

  // 检查必要信息
  if (!context.error && context.type === "bugfix") {
    issues.push("Bug 修复任务缺少错误信息");
  }

  // 检查技术栈
  if (!context.techStack) {
    issues.push("缺少技术栈信息");
  }

  // 检查文件相关性
  const irrelevantFiles = detectIrrelevantFiles(context.files);
  if (irrelevantFiles.length > 0) {
    issues.push(`包含无关文件:${irrelevantFiles.join(", ")}`);
  }

  return {
    score: calculateScore(issues),
    issues,
    suggestions: generateSuggestions(issues),
  };
}

写在最后

通过这段时间对上下文工程的学习和实践,我对如何更好地使用 Claude Code 有了更深的理解。

我的几点体会

关于 LLM 的认知: 一开始我把 LLM 想象成一个真正"理解"我需求的智能助手,但实际上,它更像是一个基于概率和模式匹配的预测引擎。它能给出什么样的答案,完全取决于我提供了什么样的信息。

关于信息的提供方式: 我现在习惯在描述问题时,按照"背景 - 技术栈 - 具体需求 - 约束条件"这样的结构来组织信息。这样不仅让我自己的思路更清晰,也让 AI 更容易抓住重点。

关于抽象层次的把握: 这是我踩过最多坑的地方。做架构设计时提供太多细节,Bug 修复时又描述得太抽象,导致 AI 给出的方案总是偏离预期。现在我会根据任务类型来调整描述的具体程度,效果好了很多。

实践建议

如果你也在使用 Claude Code,我建议:

  1. 建立一套适合自己项目的上下文模板,每次使用时稍作调整即可
  2. 在项目的 CLAUDE.md 中写清楚技术栈、代码风格、常见命令等信息
  3. 充分利用 Claude Code 的工具能力,让它自己去读取文件、运行命令,而不是手动复制粘贴

上下文工程听起来是个很技术化的概念,但本质上就是"如何更清楚地表达自己的需求"。这个能力不仅对使用 AI 工具有帮助,在日常的团队协作中同样重要。