上下文的类型与层次
同样是"给 AI 背景信息",给法不同,效果天差地别。这章拆解上下文的分类方式,帮你在不同场景下做出正确选择。
为什么要分类?
上一章讲了上下文的基本原理——给 AI 项目信息,它就能给出更好的回答。但实际操作中你会发现,上下文不是一股脑塞进去就行的。
举个例子:你让 AI 帮你写一个订单查询接口。你把整个项目的技术栈文档、所有模块的业务规则、最近三个月的迭代记录全丢给它——结果 AI 反而写出了一坨不知所云的代码。
问题出在哪?你给的信息太多、太杂,AI 分不清哪些跟当前任务有关。
Anthropic 在 2025 年 9 月发布的《Effective Context Engineering for AI Agents》中提出了一个观点:上下文是有限资源,存在"注意力预算"(attention budget)。每多塞一个 token,AI 对其他 token 的关注度就会被稀释。所以关键不是"给多少",而是"给什么、怎么给"。
要做到这一点,先得理解上下文有哪些类型。
上下文的五个分类维度
稳定性: 静态上下文 vs 动态上下文 → 多久变一次?
范围: 全局上下文 vs 局部上下文 → 覆盖多大?
表达: 显式上下文 vs 隐式上下文 → 怎么传递?
来源: 项目上下文 vs 领域上下文 → 从哪来?
时效: 长期上下文 vs 临时上下文 → 有效期多长?这五个维度不是互斥的。一条信息可以同时属于多个类别——比如"项目用 React 18 + TypeScript",它是静态的、全局的、显式的、项目特定的、长期有效的。
理解这些分类,你就能针对不同场景选择最合适的上下文组合,而不是每次都把所有东西一股脑丢给 AI。
按稳定性分类
静态上下文
项目生命周期中基本不变的信息。技术选型定了就是定了,架构设计不会每周推翻重来,编码规范也不会朝令夕改。
这类信息变化频率低,以月甚至年为单位;可以提前准备、反复打磨;是所有 AI 对话的"地基"——没有它,AI 给的建议大概率跑偏。
为什么静态上下文这么重要?因为它决定了 AI 回答的"基调"。你告诉 AI "项目用 TypeScript",它后续所有代码都会用 TypeScript 写;你不说,它可能今天给你 JavaScript,明天给你 Python。
Claude Code 的 CLAUDE.md 文件就是典型的静态上下文载体——项目启动时写好,放在仓库根目录,AI 每次对话自动读取。Anthropic 官方把这种做法叫"naive drop":不做任何检索,直接把文件内容塞进上下文窗口。简单粗暴,但对静态信息来说够用了。
典型内容:
## 项目基础信息(静态上下文)
### 项目定位
- 项目名称:拉了么(Lamo)
- 项目类型:外卖订餐平台
- 目标用户:C端用户、商家、配送员
### 技术选型(确定后基本不变)
- 前端:React 18 + TypeScript
- 后端:Nest.js + Prisma
- 数据库:PostgreSQL
- 缓存:Redis
### 核心架构(不会频繁变动)┌─────────────┐ ┌─────────────┐ │ 前端应用 │ ──→ │ API 网关 │ └─────────────┘ └──────┬──────┘ │ ┌──────▼──────┐ │ 业务服务 │ └──────┬──────┘ │ ┌────────────┼────────────┐ │ │ │ ┌────▼───┐ ┌────▼───┐ ┌────▼───┐ │ 用户服务 │ │ 订单服务 │ │ 商品服务 │ └────────┘ └────────┘ └────────┘
### 编码规范(团队约定后稳定)
- 命名:camelCase / PascalCase / kebab-case
- 文件组织:按功能模块 / 按层次
- Git 提交:Conventional Commits管理建议:
- 写在 Wiki 的"项目概述"章节,或者 CLAUDE.md / .cursorrules 这类 AI 工具的配置文件里
- 项目启动时就确定,团队达成共识后固化
- 只在重大变更时更新(比如从 Redux 迁移到 Zustand)
- 作为所有 AI 对话的基础上下文——不管问什么问题,这些信息都应该在
一个判断标准:如果这条信息三个月后大概率还是对的,它就是静态上下文。
动态上下文
跟静态上下文相反,动态上下文是"活的"——它反映项目此刻的状态,过几天可能就变了。
当前在做什么迭代、有哪些已知 bug、这周的临时约定……这些信息变化快,但对 AI 理解"现在该做什么"同样重要。
你让 AI 帮你修 bug,如果它不知道这个 bug 的上下文(什么时候出现的、影响范围、已经试过哪些方案),它只能给你一个泛泛的排查建议。但如果你告诉它"#1024 订单列表加载慢,初步排查是 N+1 查询问题,已经试过 eager loading 但没效果",它就能给出更有针对性的方案。
动态上下文的难点在于维护成本。静态上下文写一次管半年,动态上下文可能每周都要更新。Microsoft Research 在 2026 年 ICLR 发表的 ACE(Agentic Context Engineering)框架就在尝试解决这个问题——让 AI 自己维护和更新上下文,把它当作"不断演化的剧本"(evolving playbooks),通过生成、反思、整理三个步骤自动积累和优化策略。
典型内容:
## 项目当前状态(动态上下文)
### 正在进行的任务
- 当前迭代:Sprint 12
- 正在开发:优惠券系统
- 下个版本:v2.3.0(预计下周五发布)
### 已知问题
- #1024: 订单列表加载慢(待优化)
- #1025: 支付回调偶尔失败(调查中)
- #1026: 库存扣减并发问题(方案讨论中)
### 临时约定
- 本周内:所有新功能必须写测试用例
- 代码冻结:v2.3.0 发布前不接受新功能
### 环境信息
- 开发环境:dev.example.com
- 测试环境:staging.example.com
- 生产环境:www.example.com
### 数据库版本
- PostgreSQL:15.2
- Redis:7.0
- 最新迁移:2024_02_15_add_coupon_tables.sql管理建议:
- 每周或每个迭代更新一次,跟站会节奏同步
- 放在 Wiki 的"当前状态"页面,或者项目看板的描述区域
- 用相对时间表述("本周""当前迭代"),避免写死日期——写"2024年2月19日"的信息过两周就成了误导
- 控制信息量,只写跟 AI 协作相关的内容。AI 不需要知道"小王请假了"
一个实用技巧:在动态上下文里标注"最后更新时间"。这样 AI 和团队成员都能判断信息是否过期。
静态 vs 动态:怎么选?
| 维度 | 静态上下文 | 动态上下文 |
|---|---|---|
| 变化频率 | 月/年 | 日/周 |
| 维护成本 | 低 | 高 |
| 信息类型 | 技术栈、架构、规范 | 任务、问题、临时约定 |
| 存放位置 | CLAUDE.md、Wiki 首页 | Wiki 状态页、项目看板 |
| 使用频率 | 每次对话 | 按需提供 |
实际项目中,两者配合使用。静态上下文是"底座",动态上下文是"补丁"。
按范围分类
全局上下文
适用于整个项目的上下文,不管你问 AI 什么问题,这些信息都可能用得上。
打个比方:全局上下文就像公司的员工手册。新人入职第一天就得看,不管他分到哪个部门。技术栈是什么、代码风格怎么定、错误处理用什么方案——这些信息跨模块通用。
Anthropic 在 context engineering 文章中提到,Claude Code 的 CLAUDE.md 就是全局上下文的典型实现。它被"naive drop"到每次对话的上下文窗口里,不做任何过滤。这种做法的前提是:全局上下文足够精简,不会浪费太多 token。
典型内容:
## 全局上下文示例
### 技术栈全局信息
所有开发都基于:
- 语言:TypeScript(前后端统一)
- 包管理:pnpm
- 代码风格:ESLint + Prettier
- Git 主干:master(生产)、develop(开发)
### 业务全局规则
- 用户认证:JWT + 刷新token机制
- 错误处理:统一用 CustomError
- 日志:用 Winston,级别为 info
- 时间:全部用 UTC 时间
### 全局常量
```typescript
// 全局适用的常量
export const APP_NAME = 'Lamo';
export const API_VERSION = 'v1';
export const MAX_UPLOAD_SIZE = 10 * 1024 * 1024; // 10MB全局命名规范
- 数据库表名:snake_case(如 user_profiles)
- API 路由:kebab-case(如 /api/user-profiles)
- TypeScript 接口:PascalCase + I 前缀(如 IUserProfile)
**应用场景**:
- 所有 AI 对话都包含——这是"默认装备"
- 放在项目 Wiki 的首页或"快速开始"章节
- 通过 CLAUDE.md、.cursorrules 或 Claude Projects 功能设置
- Token 预算建议:控制在 500-1500 tokens 以内,太长反而稀释注意力
### 局部上下文
只适用于特定模块、功能或问题的上下文。你在做订单模块的时候,不需要知道用户模块的密码加密策略;你在调支付接口的时候,不需要知道商品搜索的分词规则。
局部上下文的价值在于"精准"。全局上下文告诉 AI "这个项目长什么样",局部上下文告诉它"我现在在做的这个东西有什么特殊规则"。
Anthropic 在 context engineering 文章中把这种做法叫"just in time"策略——不提前把所有信息塞进去,而是在需要的时候才加载。Claude Code 就是这么干的:它不会一开始就读完整个代码库,而是用 glob 和 grep 按需检索文件,只把当前任务相关的代码拉进上下文。
**典型内容**:
```markdown
## 局部上下文示例
### 模块 A:用户管理
特定规则:
- 用户手机号必须唯一
- 密码必须加密存储(bcrypt)
- 用户删除是软删除
相关代码:
- src/modules/user/
- docs/api/user-api.md
### 模块 B:订单处理
特定规则:
- 订单状态机:pending → paid → preparing → delivering → completed
- 库存扣减时机:订单支付后
- 优惠券使用:每个订单限一张
相关代码:
- src/modules/order/
- docs/business/order-workflow.md
### 模块 C:支付系统
特定规则:
- 支付超时:15分钟
- 重试次数:3次
- 回调处理:幂等性保证
相关代码:
- src/modules/payment/
- docs/integration/payment-gateway.md应用场景:
- 只在讨论相关模块时提供——别把支付模块的规则塞给正在写用户注册的 AI
- 通过文档引用方式传递:"参考 docs/business/order-workflow.md"
- 可以有多个独立的局部上下文,互不干扰
全局 vs 局部:一张图看懂
全局上下文:
┌─────────────────────────────────┐
│ 适用于整个项目 │
│ - 技术栈 │
│ - 编码规范 │
│ - 通用业务规则 │
│ │
│ 使用频率:每次对话 │
└─────────────────────────────────┘
局部上下文:
┌───────────┐ ┌───────────┐ ┌───────────┐
│ 用户模块 │ │ 订单模块 │ │ 支付模块 │
│ 上下文 │ │ 上下文 │ │ 上下文 │
└───────────┘ └───────────┘ └───────────┘
使用频率:讨论相关模块时按表达方式分类
显式上下文
你主动写出来、明确告诉 AI 的信息。文档、配置文件、对话中的说明——这些都是显式上下文。
显式上下文的好处是"所见即所得":你写了什么,AI 就看到什么,不存在理解偏差。坏处是需要人工维护,写得不好或者过时了,AI 就会被误导。
Anthropic 在系统提示词设计上有个建议:用 XML 标签或 Markdown 标题把不同类型的信息分隔开,比如 <background_information>、<instructions>、## Tool guidance。这样 AI 能快速定位到相关章节,而不是在一大段文字里"大海捞针"。
形式 1:文档
# 技术栈文档(显式上下文)
## 前端
- React 18
- TypeScript 5.0
- Vite 4.3
## 后端
- Node.js 18
- Nest.js 9.0
- Prisma 4.15形式 2:配置文件
// package.json(隐式上下文,但是显式文件)
{
"name": "lamo-frontend",
"dependencies": {
"react": "^18.2.0",
"typescript": "^5.0.0"
}
}形式 3:对话中的说明
你:帮我写一个用户注册功能
项目信息:
- 框架:Nest.js
- 数据库:PostgreSQL
- ORM:Prisma
- 密码加密:bcrypt优势:
- 清晰明确,AI 直接读到,不需要猜
- 可以用 Git 版本管理,变更可追溯
- 适合团队协作——大家都看得到
隐式上下文
不用你专门写,AI 从代码本身"看出来"的信息。目录结构透露了架构风格,变量命名暴露了编码习惯,import 语句显示了依赖关系。
隐式上下文是"免费的午餐"——不需要额外维护,代码改了它自动同步。但这不意味着它完美无缺:AI 可能误解代码意图,也可能看不出一些隐含约定。比如你约定"所有异步函数名以 fetch 开头",但代码里没写,AI 就不知道。
Anthropic 的 Claude Code 大量依赖隐式上下文。它不是靠你喂文档,而是自己去读代码、看结构、分析 import 路径。这种"自主探索"方式的好处是实时准确——代码改了它立刻知道;坏处是可能漏掉一些不成文的规则。
来源 1:代码结构
src/
├── modules/
│ ├── user/
│ │ ├── user.controller.ts
│ │ ├── user.service.ts
│ │ └── user.entity.ts
│ └── order/
│ ├── order.controller.ts
│ ├── order.service.ts
│ └── order.entity.ts
AI 推断:
- 项目采用模块化组织
- 每个模块有 controller/service/entity 三层来源 2:代码注释
/**
* 用户服务
*
* 负责用户相关的业务逻辑:
* - 用户注册/登录
* - 用户信息查询/更新
* - 密码加密和验证
*/
class UserService {
// ...
}
AI 推断:
- UserService 的职责
- 主要功能有哪些来源 3:命名规范
// 文件名:user.controller.ts
// 类名:UserController
// AI 推断:这是用户模块的控制器
// 文件名:IUser.ts
// 接口名:IUser
// AI 推断:这是用户的类型定义来源 4:配置文件
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true
}
}
AI 推断:
- 项目使用严格模式
- 支持 ES 模块导入优势:
- 不需要额外维护,代码即文档
- 代码改了自动同步,不会过时
- 反映真实情况,不是"理想中的规范"
劣势:
- 可能不够完整,只看代码看不出设计意图
- AI 需要推断,可能误解
- 表达能力有限——代码写不出"为什么这么设计"
最佳实践:显式 + 隐式结合
显式上下文负责"告诉 AI 项目是什么",隐式上下文负责"让 AI 看到项目怎么做"。两者互补。
Anthropic 的 Claude Code 就是这个思路:CLAUDE.md 提供显式的项目规范(技术栈、目录结构约定、团队规则),同时 AI 自己读取代码获取隐式上下文(实际的函数签名、import 关系、代码风格)。只靠显式,AI 写不出跟现有代码完美融合的代码;只靠隐式,AI 不知道那些"不成文的规则"。
按来源分类
项目上下文
来自你项目本身的信息。技术栈、架构设计、代码规范、业务规则——这些是"这个项目特有的"。
项目上下文的问题是不能跨项目复用。你在这个项目花了大量时间整理的上下文文档,换个项目大概率用不上。但它也是最有价值的——AI 知道了这些,才能写出"符合这个项目"的代码。
示例:
# 项目上下文
## 项目名称
拉了么(Lamo)
## 项目类型
外卖订餐平台
## 技术栈
(具体的技术选型)
## 业务规则
(外卖平台的特定规则)领域上下文
来自行业或技术领域的通用知识。行业标准和最佳实践、技术框架的使用方式、设计模式和架构模式、安全规范和合规要求——这些都是跨项目复用的。
特点:
- 可跨项目复用——学一次,到处用
- 相对稳定,不会频繁变化
- AI 已经知道大部分——这是关键
应用策略:
AI 的训练数据包含了海量的技术文档、代码示例、最佳实践。React 怎么用、JWT 是什么、RESTful API 的设计原则——这些领域知识它早就烂熟于心。
所以给 AI 提供上下文时,问自己三个问题:
- 这是不是行业通用知识? → 是就不用写
- 这是不是项目特定的约定? → 是就必须写
- 这个领域 AI 训练数据里有多少? → 主流技术(React、Vue、Python)不用写,小众框架可能需要简单说明
举个例子:"JWT 认证怎么实现"——不用写,AI 知道。"我们项目用 JWT,token 存在 localStorage,有效期 24 小时,刷新接口是 /api/auth/refresh"——必须写,这是项目特定的。
按时效分类
这个维度跟"稳定性"有点像,但关注点不同。稳定性看"多久会变",时效看"多久失效"。
长期上下文
在长时间内(月、年级别)保持有效的上下文。项目定位、技术选型、架构设计——这些不会因为发布了一个新版本就改变。
长期上下文应该"一次写入,长期有效"。它的价值在于提供稳定的背景信息,让 AI 的每次回答都有统一的基调。比如你告诉 AI "项目用 TypeScript",它会在后续所有代码生成中保持这个约定。
管理:
- 写在 Wiki 或 CLAUDE.md
- 只在重大变更时更新(比如技术栈迁移)
- 作为所有 AI 对话的基础上下文
临时上下文
只在短期内有效(天、周级别)。当前迭代任务、临时约定、已知问题——这些信息下周可能就变了。
临时上下文的关键是"明确标注时效"和"及时清理"。你写"本周内所有新功能必须写测试用例",得标注"本周"。过了这周还不删,AI 还在遵守这条规则,就可能导致问题。
Anthropic 在 context engineering 文章中提到一个技巧:在动态上下文里标注"最后更新时间"。这样 AI 和团队成员都能判断信息是否过期。
示例:
## 临时上下文(2024年2月第三周)
### 当前冲刺
- Sprint 12(2月19日 - 3月1日)
- 重点:优惠券系统
### 本周约定
- 所有 PR 必须经过至少一人审查
- 新功能必须包含单元测试
### 已知问题(本周内解决)
- #1024: 订单列表性能问题
- #1025: 支付回调失败
### 下周计划
- 开始 v2.4.0 需求评审
- 技术分享:RAG 在项目中的应用上下文层次结构
前面讲了五个分类维度,但实际使用时不是每条信息单独处理,而是形成一个层次结构。
金字塔模型
可以把项目上下文想象成一个金字塔:底层是全局静态信息,顶层是最具体的代码上下文。中间层是模块特定的、临时的、领域相关的信息。
这种层次的好处是"渐进式细化":AI 先理解项目整体,再理解当前模块,最后看具体代码。每往下一层,信息更具体、更相关。
┌──────────────┐
│ 全局静态 │ ← 项目基础
│ 上下文 │
└──────┬───────┘
│
┌──────────────────┼──────────────────┐
│ │ │
┌──────▼───────┐ ┌──────▼───────┐ ┌──────▼───────┐
│ 模块上下文 │ │ 领域上下文 │ │ 临时上下文 │
│ (局部静态) │ │ (可复用) │ │ (动态) │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└──────────────────┼──────────────────┘
│
┌──────▼───────┐
│ 代码上下文 │ ← 隐式上下文
│ (最具体) │
└──────────────┘使用策略
从上到下,逐层细化:给 AI 提供上下文时,按金字塔顺序来。先全局,再模块,再看代码,最后说具体问题。
这种顺序符合人类认知习惯——先了解整体,再关注局部。对 AI 来说也一样,全局上下文帮它建立"心理模型",模块上下文缩小范围,代码上下文提供具体参考。
Field Guide to AI 在 context engineering 章节中把这种策略叫"分层上下文构建"(layered context construction)——不是一次性塞所有信息,而是根据任务需要逐层加载。
第1层:全局静态上下文(基础)
"这是一个外卖平台,用 React + Nest.js"
第2层:模块上下文(具体)
"现在要开发订单模块"
第3层:代码上下文(实现)
"参考订单服务的现有代码"
第4层:当前问题(目标)
"帮我写订单创建的 API"实战:构建上下文层次
场景:开发支付功能
步骤 1:提供全局上下文
项目信息:
- 拉了么外卖平台
- React + Nest.js + PostgreSQL
- JWT 认证
- 统一错误处理步骤 2:提供模块上下文
支付模块特点:
- 集成微信支付和支付宝
- 需要处理异步回调
- 要求幂等性
- 金额用分(避免浮点)步骤 3:提供代码上下文
参考代码:
- src/modules/payment/payment.service.ts
- src/modules/payment/wechat-pay.service.ts步骤 4:提供具体需求
需求:
- 实现支付宝支付
- 参考微信支付的实现方式对比:不同层次的效果
只有全局上下文:
你:帮我实现支付宝支付
AI:好的,支付宝支付的一般实现步骤是...
(给出通用实现,可能不符合项目)完整的层次上下文:
你:帮我实现支付宝支付
项目:[全局上下文]
模块:[支付模块上下文]
参考:[现有代码]
AI:明白了,我会参考微信支付的实现方式,
为支付宝创建类似的服务...
(给出符合项目的实现)上下文组合策略
知道上下文有哪些类型还不够,关键是知道"什么情况下用哪些类型"。
策略 1:最小有效集
Anthropic 在 context engineering 文章中强调:上下文越多不一定越好。多了会稀释 AI 的注意力,导致性能下降——这就是"context rot"。
最小有效集的原则是"只提供必要的上下文"。必要的定义是:没有这条信息,AI 就无法完成任务或给出正确答案。
❌ 过度提供:
提供整个项目的所有文档(50+ 文件)
✅ 最小有效:
提供 3-5 个最相关的文档策略 2:渐进式补充
别一开始就堆所有上下文。先给基础的,观察 AI 输出,不够再加。
这种"测试-补充"循环能帮你找到真正的最小有效集。同时也能节省 token——如果第一次就能解决,就不需要把那些"备用"信息塞进去了。
Claude Code 的"just in time"策略就是这个思路:先给你轻量级的信息(文件路径、目录结构),需要时再深入读取文件内容。
策略 3:上下文模板
为常见场景准备上下文模板,能减少重复思考的时间。新功能开发用哪些信息、Bug 修复需要哪些资料、代码审查看哪些文件——这些是可以标准化的。
但要注意:模板是参考,不是铁律。每次使用前想想,这次任务真的需要这么多上下文吗?
总结
核心要点
上下文可以从五个维度分类
- 稳定性:静态 vs 动态——多久变一次?
- 范围:全局 vs 局部——覆盖多大?
- 表达:显式 vs 隐式——怎么传递?
- 来源:项目 vs 领域——从哪来?
- 时效:长期 vs 临时——有效期多久?
这五个维度不是互斥的。一条信息可以同时是静态的、全局的、显式的、项目特定的、长期有效的。理解这些分类,才能在具体场景下做出正确的选择。
不同类型有不同的管理方式
- 静态上下文:写在 Wiki 或 CLAUDE.md,长期维护,作为所有对话的基础
- 动态上下文:定期更新,标注时效,反映项目当前状态
- 全局上下文:所有 AI 对话都包含,但控制 token 量(500-1500 tokens)
- 局部上下文:按需提供,只在讨论相关模块时才塞进去
层次化提供上下文比一股脑塞更有效
- 从全局到局部:先项目整体,再具体模块
- 从抽象到具体:先技术栈,再代码示例
- 从文档到代码:先读规范文档,再看实际代码
Field Guide to AI 把这叫"分层上下文构建"——不是一次性塞所有信息,而是根据任务需要逐层加载。
最佳实践
好的上下文管理:
✅ 分层组织(全局/模块/代码)
✅ 分类清晰(静态/动态)
✅ 按需提供(最小有效集)
✅ 持续更新(保持同步)
✅ 显式隐式结合(文档 + 代码)数据来源
本文档内容参考:
- Anthropic《Effective Context Engineering for AI Agents》(2025年9月)
- Microsoft Research《Agentic Context Engineering》(ICLR 2026)
- Field Guide to AI《Context Engineering: Beyond Prompt Engineering》(2026年2月)
- LangChain《State of Agent Engineering Report》(2025年)
下一步
理解了上下文的类型和层次后,继续学习:
- Wiki 系统最佳实践 → 如何组织上下文内容
- 让 AI 使用上下文的技巧 → 实际操作方法