本文为「AI 辅助编程实战指南」第7篇,完整系列持续更新中。


前言

你可能遇到过这些情况:同一段代码,在新会话里让 AI 修改,质量明显比旧会话好;或者明明给了 AI 所有信息,它输出的代码却”忘了”你前面提过的规范;又或者对话超过 30 轮后,AI 开始重复之前已经试过的方案。

这些问题的根源都是同一个:上下文管理不到位

AI 的输出质量直接取决于你喂给它的上下文质量。给太多噪音,AI 会被干扰;给太少信息,AI 会猜错;上下文窗口快满了,AI 会”失忆”。上下文管理不是 Prompt 工程的附属品,它是 AI 编程场景下最重要的单一技能——比 Prompt 写法更重要,比工具选择更重要。

本篇学完你将掌握

  • 上下文窗口的运作机制和容量边界
  • 项目规则文件的正确写法和各工具配置差异
  • 精准上下文投喂的 @ 引用体系和最佳实践
  • 会话管理的黄金法则:何时压缩、何时重启
  • 上下文劣化的信号识别和应对策略
  • 环境工程化消除环境差异的完整方案

一、上下文窗口:理解 AI 的”工作台”

在讲管理策略之前,先搞清楚上下文窗口是什么、有多大、什么时候会出问题。

1.1 什么是上下文窗口

上下文窗口是 AI 在每次对话中能”看到”的全部信息——包括系统提示词、项目规则文件、你的提问、AI 的回答、引用的代码、对话历史等等。所有这些信息共享同一个有限的空间。

打个比方:上下文窗口就像 AI 的”工作台”。台面大小有限,你摆上去的文件越多,AI 能看到每一份文件的注意力就越分散。如果台面被塞满了,最早放上去的文件就会被挤出去。

1.2 容量边界与消耗速度

工具 / 模型 上下文窗口 大致容量 消耗示例
Claude Code (Opus/Sonnet) 200K tokens ~100 万 tokens 工作上下文 500 行 TypeScript ≈ 4,000 tokens
Cursor (Claude 4 Sonnet) 200K tokens 取决于模型 AI 一次详细回复 ≈ 1,500-3,000 tokens
GitHub Copilot 128K tokens 取决于模型 项目规则文件 ≈ 200-500 tokens
ChatGPT (GPT-4.1) 1M tokens 100 万 tokens 完整对话历史 + 文件引用

💡 提示:token 不等于字符数。粗略估算:1 个中文字 ≈ 1.5-2 个 token,1 个英文单词 ≈ 1-1.5 个 token。一行典型代码 ≈ 10-15 个 token。

1.3 上下文窗口的消耗结构

每次对话开始时,上下文窗口已经被”预占”了一部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
┌───────────────────────────────────────────┐
│ 系统提示词(工具内置,不可见) │ ~500-2,000 tokens
├───────────────────────────────────────────┤
│ 项目规则文件(自动加载) │ ~200-2,000 tokens
├───────────────────────────────────────────┤
│ MCP 工具定义(如已启用) │ ~0-67,000 tokens ← 容易被忽视的大户
├───────────────────────────────────────────┤
│ 引用的代码文件 │ 按需加载
├───────────────────────────────────────────┤
│ 对话历史(你的提问 + AI 的回答) │ 随对话增长
├───────────────────────────────────────────┤
│ 剩余可用空间 │ ← AI 的"思考空间"
└───────────────────────────────────────────┘

⚠️ 注意:MCP 工具是上下文消耗的大户。有用户记录到仅连接 4 个 MCP 服务器就消耗了 67,000 tokens——在你还没输入任何 Prompt 之前,这些空间就已经被占用了。如果你很少用某些 MCP 工具,建议禁用它们以释放上下文空间。

1.4 上下文满了会怎样

当上下文窗口接近饱和时,各工具有不同的应对机制:

工具 饱和行为 影响
Claude Code 自动压缩(auto-compact),在约 83.5% 容量时触发 早期对话细节被压缩摘要,可能丢失关键信息
Cursor 对话历史截断,早期消息被丢弃 上下文断裂,AI “忘记”之前的讨论
ChatGPT 自动压缩或提示”对话过长” 需要手动开启新对话

自动压缩虽然能延长对话寿命,但压缩过程本身会丢失信息——尤其是具体的代码片段、错误信息和决策细节。这些恰恰是 AI 后续工作最需要的上下文。


二、项目规则文件:每次对话自动加载的”宪法”

项目规则文件是解决上下文问题的第一道防线。它在每次新会话开始时自动加载到上下文中,确保 AI 始终知道你的项目规范和编码约定——不用每次手动重复说明。

2.1 各工具的规则文件对比

工具 规则文件 加载方式 共享方式
Cursor .cursor/rules/*.md(新版)或 .cursorrules(旧版) 每次对话自动加载 随项目 Git 提交,团队共享
Claude Code CLAUDE.md(项目根目录 + 子目录) 每次对话自动加载,子目录按需加载 随项目 Git 提交
Qoder AGENTS.md(项目根目录) 每次对话自动加载 随项目 Git 提交
Copilot .github/copilot-instructions.md 每次对话自动加载 随项目 Git 提交
OpenAI Codex AGENTS.md(项目根目录) 每次对话自动加载 随项目 Git 提交

2.2 规则文件该写什么

规则文件的核心是回答三个问题:项目是什么、代码怎么写、怎么验证。用一个简洁的框架:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 项目:ShopFront — 电商平台后台

Next.js 16 App Router、TypeScript strict、Prisma ORM、Stripe 支付。

## 常用命令
- `npm run dev` — 开发服务器(端口 3000)
- `npm test` — Jest 测试套件
- `npm run lint` — ESLint 检查
- `npm run db:migrate` — Prisma 数据库迁移

## 目录结构
- `/app` — Next.js App Router 页面
- `/components/ui` — 共享 UI 组件(Tailwind,禁止自定义 CSS 文件)
- `/lib` — 工具函数和业务逻辑
- `/prisma` — 数据库 Schema 和迁移

## 编码规范
- 使用具名导出(named exports),禁止默认导出
- 禁止 `any` 类型,用 `unknown` + 类型收窄
- 2 空格缩进,必须加分号

## 安全红线
- 禁止提交 .env 文件
- Stripe webhook 必须验证签名
- 所有数据库查询通过 Prisma,禁止裸 SQL
- 修改 /lib 下的文件后必须运行 `npm test`

💡 提示:以上示例只有约 30 行——这就够了。社区实测数据显示:具体的规则(”用 2 空格缩进”)遵守率约 89%,而模糊的指令(”写干净的代码”)遵守率只有 35%。更关键的是,规则文件越长,所有规则的遵守率都会下降——因为 AI 的注意力预算是有限的。

2.3 规则文件的长度控制

文件位置 建议长度 内容定位
全局规则(~/.claude/CLAUDE.md < 50 行 个人偏好:缩进风格、回复语言、注释语言
项目根规则(./CLAUDE.md < 300 行 项目规范:技术栈、编码规范、安全红线
子目录规则(.claude/rules/*.md 按需 模块特定规范,只在相关文件操作时加载
所有规则文件总计 < 2,000 tokens 超过这个量级,规则遵守率显著下降

2.4 渐进式展开:不要把所有规则塞进一个文件

当规则内容很多时,使用渐进式展开策略——把详细规则拆到独立文件中,在主规则文件中只放简短描述和引用路径:

1
2
3
4
5
6
7
8
9
10
# CLAUDE.md(主文件,保持精简)

## 编码规范
- 详见 docs/coding-standards.md

## API 设计约定
- 详见 docs/api-conventions.md

## 部署流程
- 详见 docs/deployment.md

AI 在执行相关任务时会按需读取这些文件,而不是在会话开始时就全部加载。这就是第4篇提到的渐进式展开(Progressive Disclosure)在上下文管理中的应用。

2.5 规则文件的常见错误

错误 原因 正确做法
用否定句:”不要使用分号” 否定句反而激活了”分号”这个概念 用肯定句:”使用 no-semicolons ESLint 规则”
全文加粗:”IMPORTANT” 10 条规则都标重要 = 没有重要的 只给真正关键的 1-2 条加粗
@引用大文件@docs/full-api.md 整个文件被嵌入上下文,浪费数千 tokens 只写文件路径描述,让 AI 按需读取
规则太长:500+ 行 超出 AI 的注意力预算,所有规则的遵守率都下降 控制在 300 行以内,详细内容拆到子目录

💡 建议:规则文件应该随着项目演进持续更新。每次发现 AI 犯了一个错误,就修一下规则文件让它不再重犯。几周后,你的规则文件就会变成项目经验的精华浓缩。


三、精准上下文投喂:只给 AI 它需要的

规则文件解决了”持久化规范”的问题,但在具体任务中,你还需要给 AI 提供与当前任务直接相关的上下文。核心原则是:只给相关的,不给全部的

3.1 Cursor 的 @ 引用体系

Cursor 提供了最丰富的显式上下文引用机制:

引用类型 语法 什么时候用 示例
文件 @Files 需要引用某个具体文件的完整内容 @src/services/auth.py 参考这个文件的错误处理模式
目录 @Folders 需要引用整个目录的结构 @src/api/v1 检查这个目录有没有缺少认证的接口
代码符号 @Code 只需要引用某个函数/类 @useUserData 把这个 hook 从 useState 改为 React Query
文档 @Docs 引用外部库的官方文档 @React Router Docs 用文档中的方式实现路由守卫
Web @Web 搜索最新信息 @Web FastAPI 0.110 有什么新特性
Git @Git 引用提交历史或 diff @Commit 帮我生成 commit message
Linter @Linter Errors 让 AI 修复 lint 错误 修复所有 @Linter Errors 中的问题

最佳实践

1
2
3
4
5
6
# 好的做法:精准引用
@src/components/Button.tsx 参考这个文件的组件写法,
创建一个同样风格的 Link.tsx 组件。

# 不好的做法:让 AI 自己猜
帮我创建一个 Link 组件,风格跟项目里的其他组件保持一致。

💡 提示@Code(代码符号引用)是最精准的引用方式——它只引入你指定的函数或类,不会把整个文件都塞进去。当你只需要参考某个函数的写法时,优先用 @Code 而不是 @Files

3.2 Claude Code 的上下文引用

Claude Code 主要通过文件路径引用和对话内引用来管理上下文:

1
2
3
4
5
6
# 引用文件路径(AI 按需读取)
读取 src/auth/middleware.py,理解当前的认证流程,
然后设计一个支持多租户的认证方案。

# 引用目录结构
查看 src/api/v2/ 目录结构,分析接口组织的合理性。

Claude Code 的 Agent 模式会自动分析代码库,识别相关文件和模式。但在复杂项目中,显式指定文件路径比让 AI 自己搜索更可靠。

3.3 通用策略:片段引用 vs 全文件引用

策略 适用场景 上下文消耗
粘贴代码片段 只需要参考某几行代码 最低(仅引用片段)
@符号引用函数/类 需要参考某个完整的函数或类 低(仅引用符号)
@文件引用 需要理解整个文件的结构和逻辑 中等(整个文件)
@目录引用 需要理解目录结构和文件关系 较高(目录下所有文件)

实操建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 最佳:只粘贴相关的代码片段
我们的 API 统一响应格式如下:
{
"code": 200,
"message": "success",
"data": { ... }
}
按照这个格式,实现"修改密码"接口。

# 次佳:引用具体函数
@Code getUserById 参考这个函数的错误处理模式,
实现 getUserOrders 函数。

# 一般:引用整个文件
@src/services/user.py 参考这个文件,
新增一个 order service。

3.4 上下文投喂的反面案例

反面做法 问题 改进方案
“帮我优化整个项目的性能” 范围太大,AI 会随意发挥 “优化 /api/products 接口的查询性能,当前响应时间 500ms”
把整个 2000 行的文件粘贴到对话中 浪费上下文空间,AI 注意力分散 只粘贴需要修改的函数 + 相关上下文
让 AI “参考项目里的写法” AI 可能参考了错误的文件 显式指定要参考的文件路径
在对话第 25 轮时还在修改同一个功能 上下文已严重污染 开新会话,带上关键上下文重新提问

四、会话管理:何时续命,何时重启

会话管理是上下文管理中最容易被忽视的环节。很多开发者习惯在同一个会话里做所有事情——结果对话越来越长,AI 的输出质量越来越差。

4.1 会话的生命周期

1
2
3
4
5
6
7
8
9
10
11
┌──────────────────────────────────────────────┐
│ 会话开始 │
│ ├─ 规则文件自动加载 │
│ ├─ 你提出任务 │
│ ├─ AI 读取相关文件 → 上下文逐渐增长 │
│ ├─ AI 生成代码 → 上下文继续增长 │
│ ├─ 你追问/修改 → 对话历史累积 │
│ ├─ ⚠️ 上下文接近 70% → 应该主动压缩 │
│ ├─ ⚠️ 上下文接近 83.5% → 自动压缩触发 │
│ └─ ❌ 上下文满了 → 信息开始丢失 │
└──────────────────────────────────────────────┘

4.2 会话边界原则:一个会话 = 一个任务范围

最核心的会话管理原则:一个会话应该有且只有一个明确的任务范围

1
2
3
4
5
6
7
8
# 好的做法:一个会话 = 一个明确任务
会话1:"实现商品列表的分页查询"
会话2:"为分页查询添加缓存"
会话3:"修复分页在空数据时的 Bug"

# 不好的做法:一个会话 = 多个不相关任务
会话1:"先实现分页查询,再加个缓存,顺便帮我看看登录接口有没有 Bug,
最后帮我把 README 更新一下"

💡 提示:即使上下文预算还有剩余,切换到完全不同的任务时也应该开新会话。新鲜的上下文是免费的,被污染的上下文是昂贵的。

4.3 两个关键命令

Claude Code 的上下文管理命令

命令 作用 什么时候用
/compact 压缩对话历史,保留关键信息 当前任务还没做完,但对话太长
/compact "保留认证模块的修改和测试结果" 带焦点的压缩 明确告诉 AI 哪些信息必须保留
/clear 完全清除上下文 切换到完全不同的任务

使用时机判断

1
2
3
4
5
6
7
当前任务完成了吗?
├─ 是 → 切换任务了吗?
│ ├─ 是 → 用 /clear 开新会话
│ └─ 否 → 不需要操作
└─ 否 → 对话超过 20 轮了吗?
├─ 是 → 用 /compact 压缩
└─ 否 → 继续当前会话

Cursor 的会话管理

Cursor 没有直接的 /compact 命令,但可以通过以下方式管理上下文:

  • 关闭当前 Chat 窗口,开启新的 Chat
  • 在 Agent 模式下,完成一个功能后提交 commit,然后开新对话
  • 使用 @Past Chats 引用历史对话中的关键信息

4.4 主动压缩 vs 被动压缩

社区的最佳实践是在上下文用到 70-75% 时就主动压缩,而不是等到 83.5% 的自动触发阈值:

1
2
3
4
5
6
// Claude Code 设置:自定义自动压缩阈值
{
"env": {
"CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "75"
}
}

为什么主动压缩更好?因为自动压缩是在上下文已经很满时触发的,此时 AI 可能已经开始出现”上下文劣化”的症状(见下一节)。主动压缩让你在 AI 输出质量还很高的时候就释放空间。

4.5 跨会话上下文传递

当任务需要跨越多个会话时,用以下方式传递关键上下文:

方法 适用场景 具体做法
PROGRESS.md 中长期功能开发 维护进度文件,新会话让 AI 读取(详见第6篇
CHANGE_SPEC.md 有明确规格文档的任务 新会话引用规格文件继续工作
git log 快速了解已完成的工作 让 AI 阅读最近的 commit 历史
代码注释 标记待完成的工作 在代码中留 // TODO: 下一步实现 XX
1
2
3
4
5
6
7
# 新会话的标准开场 Prompt
请先阅读以下文件了解当前状态:
1. changes/add-bulk-import/CHANGE_SPEC.md — 功能目标
2. PROGRESS.md — 当前进度
3. 最近的 5 个 git commit — 已完成的工作

然后继续实现"文件上传 API 接口"。

五、上下文劣化:信号识别与应对

上下文窗口满了会触发自动压缩,但在满之前,上下文质量其实已经在悄悄劣化。识别这些早期信号,才能在问题恶化之前采取行动。

5.1 四大劣化信号

信号 表现 原因
重复 AI 建议你已经试过的方案 对话历史太长,早期的尝试被压缩但没被完全丢弃
漂移 AI 的代码风格变了,不再遵守你的规范 规则文件的优先级被后续的对话内容淹没
幻觉增加 AI 编造不存在的函数名或 API 上下文噪音太多,AI 的”搜索”能力被干扰
遗忘 AI 忘了前面定义的变量、接口或约束 早期信息被挤出上下文窗口

5.2 快速诊断方法

如果你怀疑上下文已经劣化,用以下方式快速诊断:

1
2
3
4
5
6
7
# 诊断方法1:让 AI 复述项目规范
请复述我们项目的编码规范和安全红线。
→ 如果 AI 答错或答不全,说明规则文件已被"淹没"

# 诊断方法2:让 AI 总结当前进度
请总结我们在这个会话中已经完成了哪些工作。
→ 如果 AI 遗漏了重要步骤,说明对话历史已被压缩

5.3 应对策略

1
2
3
4
发现劣化信号
├─ 轻度(只是代码风格漂移)→ /compact 压缩,提醒 AI 遵守规则
├─ 中度(出现重复建议)→ /compact 带焦点压缩
└─ 重度(幻觉频繁、遗忘关键信息)→ /clear 开新会话

⚠️ 注意:不要试图”坚持用下去”。当你发现 AI 的输出质量明显下降时,硬撑只会让情况更糟——你会花更多时间修复 AI 的错误输出,而不是开一个新会话重新开始。


六、环境工程化:消除”在 AI 那边能跑,在我这跑不了”

上下文管理不只关乎对话内容,还包括开发环境的一致性。如果 AI 不知道你的 Python 版本、操作系统、依赖版本,它生成的代码可能在你这里跑不起来。

6.1 为什么环境差异会影响 AI 输出

差异类型 翻车案例
Python 版本 AI 用 match/case(Python 3.10+),你用的是 3.9
包版本 AI 用 Pydantic v1 的写法,你的项目用 v2
操作系统 AI 生成 os.path.join(),你的项目要求用 pathlib
数据库 AI 生成 MySQL 方言 SQL,你用的是 PostgreSQL

6.2 在规则文件中声明环境

最简单的环境工程化方式是在规则文件中明确声明运行环境:

1
2
3
4
5
## 运行环境
- Python 3.12、FastAPI 0.110+、SQLAlchemy 2.0
- PostgreSQL 16、Redis 7.2
- 操作系统:Ubuntu 22.04(生产环境)/ macOS 15(开发环境)
- 包管理:uv(禁止使用 pip 直接安装)

6.3 使用 DevContainer 锁定环境

更彻底的方案是用 VS Code DevContainer 或 Docker 锁定整个开发环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// .devcontainer/devcontainer.json
{
"name": "ShopFront Dev",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
}
},
"postCreateCommand": "uv sync && npm install",
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python"
},
"extensions": [
"ms-python.python",
"cursor.cursor"
]
}
}
}

在规则文件中引用环境配置

1
2
3
4
## 开发环境
- 使用 DevContainer 开发,环境定义见 .devcontainer/devcontainer.json
- 所有依赖通过 uv.lock 和 package-lock.json 锁定
- 禁止在 DevContainer 外直接安装依赖

6.4 环境工程化的完整方案

1
2
3
4
devcontainer.json(锁定 OS + 语言版本 + 系统依赖)
+ uv.lock / package-lock.json(锁定包版本)
+ 规则文件中的环境声明(让 AI 知道环境配置)
= AI 生成的代码直接兼容你的运行环境

💡 建议:对于团队协作项目,DevContainer 的 ROI 非常高。一次配置好环境,所有团队成员(和 AI)都在同一个环境中工作,”在我这能跑”的问题基本消失。


七、踩坑记录:对话 40 轮后 AI 开始”鬼打墙”

现象
在一个会话中连续开发商品管理模块。前 20 轮一切正常,但到第 30 轮左右,AI 开始反复建议已经试过的方案。比如之前已经因为性能问题放弃了嵌套子查询,但 AI 在第 35 轮又提出了同样的嵌套子查询方案。更诡异的是,AI 在第 38 轮生成的代码引用了一个不存在的函数 validate_product_data()——这个函数从来没有在项目中定义过。

原因

  1. 对话历史过长(40 轮 ≈ 60,000+ tokens 的对话内容)
  2. 自动压缩在第 32 轮时触发,早期讨论细节被摘要化
  3. AI 丢失了”已经试过嵌套子查询但放弃”的关键决策信息
  4. 上下文噪音过多,AI 开始”幻觉”——编造不存在的函数名

解决方案

  1. 立即 /clear,开新会话
  2. 在新会话中,用 PROGRESS.md + git log 恢复上下文
  3. PROGRESS.md 中明确记录”已尝试但放弃的方案”,避免 AI 重复提出

避坑建议

  • 对话超过 20 轮时,主动执行 /compact(不要等自动触发)
  • 重要的决策信息(如”为什么放弃了方案 A”)要记录在文件中,而不是只在对话中讨论
  • 如果 AI 开始重复建议或出现幻觉,不要试图纠正——直接开新会话,比纠正更快更可靠
  • 每个会话开始前,花 30 秒想一下”这个会话的目标是什么”,完成后立即结束会话

总结与回顾

核心要点 关键结论
上下文窗口 共享的有限资源,系统提示 + 规则文件 + MCP + 对话历史共享
规则文件 控制在 300 行以内,具体规则遵守率 89%,模糊指令只有 35%
精准投喂 用 @ 引用精准定位,优先引用函数而非整个文件
会话管理 一个会话 = 一个任务范围,完成后 /clear 开新会话
主动压缩 70-75% 时主动 /compact,不等 83.5% 的自动触发
劣化信号 重复、漂移、幻觉、遗忘——出现任一信号就该处理
环境工程化 DevContainer + lock 文件 + 规则声明 = 消除环境差异
核心原则 上下文质量决定输出质量,管理上下文比写好 Prompt 更重要

延伸阅读


本文为「AI 辅助编程实战指南」第7篇,完整系列持续更新中。