"AI 编程中的上下文管理:如何让 AI 真正理解你的代码库"

9 阅读8分钟

AI 编程中的上下文管理:如何让 AI 真正理解你的代码库

核心观点:AI 编程工具的上限不取决于模型大小,而取决于你喂给它的上下文质量。同样的 GPT-4o,上下文管理得当和随意提问,产出差距可以达到 5 倍以上。


一、问题:为什么 AI 助手总是"答非所问"

你肯定遇到过这些场景:

  • 让 AI 重构一个函数,它改完后引入了你项目里根本不存在的依赖
  • 问 AI 一个 bug 的原因,它给出的方案和你用的框架版本完全不匹配
  • 让 AI 写单元测试,它用的是另一种测试框架的 API

根本原因:AI 不知道你的项目长什么样。它看到的只是你粘贴的那几十行代码,加上训练数据里几百万个项目的统计规律。

我花了 3 个月时间,在 4 个不同规模的项目(从 2 万行到 50 万行)中测试各种上下文管理策略,最终总结出一套可复用的方法论。


二、策略一:项目级上下文文件(.cursorrules / .github/copilot-instructions.md)

这是效果最显著、实施成本最低的策略。

2.1 什么是上下文文件

现代 AI 编程工具(Cursor、Copilot、Windsurf)都支持在项目根目录放置一个配置文件,告诉 AI "我的项目是什么样的"。

Cursor 使用 .cursorrules,GitHub Copilot 使用 .github/copilot-instructions.md。内容结构类似,我统一用 .cursorrules 举例。

2.2 实战模板

这是我总结的模板,直接复制后按需修改:

# 项目上下文
- 项目类型:Node.js 全栈应用(Next.js 14 + Express 后端)
- 包管理器:pnpm(不是 npm 或 yarn)
- 语言:TypeScript(严格模式,tsconfig.json 中 strict: true)
- 数据库:PostgreSQL 16 + Prisma ORM
- 测试:Vitest + Testing Library(不是 Jest)
- 样式:Tailwind CSS + shadcn/ui 组件库
- 部署:Vercel(前端)+ Railway(后端 API)

# 代码规范
- 组件文件使用 .tsx 后缀,工具函数使用 .ts
- 所有组件必须是 React Server Component,除非显式使用 "use client"
- API 路由使用 App Router 的 route.ts 模式
- 错误处理统一使用 Result 模式(neverthrow 库),不使用 try-catch
- 环境变量通过 t3-env 类型安全地读取

# 禁止事项
- 不要使用 JavaScript,全部用 TypeScript
- 不要使用 class 组件,全部用函数组件 + hooks
- 不要手动拼接 SQL,使用 Prisma query API
- 不要使用 any 类型,用 unknown 或定义具体类型
- 不要使用 console.log 做日志,使用 winston logger

# 常用模式
- 数据获取:使用 Server Component 直接查询数据库
- 表单处理:使用 react-hook-form + zod 验证
- 认证:使用 NextAuth.js v5(Auth.js)
- 状态管理:优先用 URL search params,复杂状态用 Zustand

2.3 效果对比

我用同一个任务测试了有/无上下文文件的差异:

任务:「实现一个用户头像上传功能」

维度无上下文文件有上下文文件
生成的代码能用40%(需要大量修改)95%(微调即可)
使用正确依赖否(用了 multer)是(用了 Next.js Upload)
使用正确测试框架否(写了 Jest 测试)是(写了 Vitest 测试)
遵循代码规范部分完全
平均节省时间基准节省约 70%

三、策略二:按需注入相关文件(文件引用法)

上下文文件解决"全局认知"问题,但具体任务往往需要 AI 看到相关代码。

3.1 Cursor 中的 @ 引用

在 Cursor 的 Chat 或 Composer 中,用 @ 可以引用文件:

@src/lib/auth.ts @src/middleware.ts
帮我分析一下这两个文件的认证逻辑是否有漏洞

关键技巧:不要引用整个文件,只引用相关部分。

@src/lib/auth.ts:15-45
这段 token 刷新逻辑在并发请求时会出问题吗?

3.2 手动构建上下文块

对于不在 Cursor 中的场景(比如用 Claude Web 或 ChatGPT),我习惯手动构建上下文块:

## 相关代码

### auth.ts (第 15-45 行)
```typescript
async function refreshAccessToken(refreshToken: string) {
  const decoded = jwt.verify(refreshToken, REFRESH_SECRET) as RefreshPayload;
  const user = await prisma.user.findUnique({
    where: { id: decoded.userId }
  });
  if (!user) throw new UnauthorizedError();
  
  return generateTokens(user);
}

middleware.ts (完整)

export default authMiddleware((req) => {
  // ...
});

问题

当用户同时发起 3 个 API 请求,其中 2 个触发了 401,这 3 个请求会并发调用 refreshAccessToken。 这会导致什么后果?如何修复?


### 3.3 上下文注入的"黄金比例"

经过大量实验,我总结出一个经验值:

- **最佳上下文量**:200-500 行代码
- **太少**(< 50 行):AI 缺少足够信息,给出泛泛建议
- **太多**(> 1000 行):关键信息被稀释,AI 注意力分散

**实操方法**:先给核心代码(50-100 行),再给相关的 1-2 个依赖文件的关键部分。

---

## 四、策略三:上下文分层策略

不是所有信息都需要每次都喂给 AI。我采用三层架构:

┌─────────────────────────────────┐ │ 第三层:任务级上下文 │ ← 每次对话时注入 │ (当前文件 + 相关代码片段) │ ├─────────────────────────────────┤ │ 第二层:模块级上下文 │ ← 切换模块时注入 │ (模块约定 + 公共类型 + 工具函数)│ ├─────────────────────────────────┤ │ 第一层:项目级上下文 │ ← 打开项目时注入一次 │ (.cursorrules / 技术栈 / 规范) │ └─────────────────────────────────┘


### 4.1 实际工作流

**场景**:我要给「用户模块」加一个「批量导入」功能。

**第一步**:确认第一层上下文已加载(.cursorrules 已存在)

**第二步**:切换到用户模块目录,告诉 AI 模块约定:

用户模块约定

  • 所有用户相关操作在 src/modules/user/ 下
  • 使用 Repository 模式封装数据库操作
  • 模块间通过事件解耦(使用 EventEmitter)
  • DTO 定义在 src/modules/user/dtos.ts

**第三步**:开始具体任务,注入任务级上下文:

@src/modules/user/repository.ts @src/modules/user/dtos.ts

实现批量导入功能:

  1. 接收 CSV 文件上传
  2. 解析并验证每行数据
  3. 批量创建用户(使用 Prisma $transaction)
  4. 返回成功/失败统计

### 4.2 为什么分层有效

| 分层 | 解决的问题 | 类比 |
|------|-----------|------|
| 项目级 | "这个项目用什么技术栈" | 新员工入职手册 |
| 模块级 | "这个模块的内部约定" | 部门工作规范 |
| 任务级 | "当前要做什么" | 具体任务说明书 |

没有分层,AI 就像第一次来你公司的实习生——什么都得从头解释。

---

## 五、策略四:利用 RAG 思想构建代码知识库

对于大型项目(> 10 万行代码),仅靠手动注入上下文不够。我尝试了一种更自动化的方法。

### 5.1 自动生成上下文摘要

写一个简单脚本,为每个模块生成 AI 友好的摘要:

```typescript
// scripts/generate-module-context.ts
import fs from 'fs';
import path from 'path';

interface ModuleContext {
  name: string;
  description: string;
  exports: string[];
  dependencies: string[];
  keyTypes: string[];
}

function analyzeModule(modulePath: string): ModuleContext {
  const files = getAllTsFiles(modulePath);
  
  return {
    name: path.basename(modulePath),
    description: extractJSDoc(files),
    exports: extractExports(files),
    dependencies: extractImports(files),
    keyTypes: extractTypeDeclarations(files),
  };
}

// 为每个模块生成 JSON 上下文
const modules = fs.readdirSync('src/modules')
  .filter(f => fs.statSync(`src/modules/${f}`).isDirectory());

const contexts = modules.map(m => analyzeModule(`src/modules/${m}`));

fs.writeFileSync(
  '.module-contexts.json',
  JSON.stringify(contexts, null, 2)
);

5.2 在提示词中使用摘要

## 模块上下文(自动生成)

### user 模块
- 导出:UserService, UserRepository, UserType, UserDTO
- 依赖:database, events, validators
- 关键类型:
  ```typescript
  interface UserDTO {
    id: string;
    email: string;
    name: string;
    role: 'admin' | 'user' | 'viewer';
    createdAt: Date;
  }

任务

在 user 模块中增加「用户角色变更」功能,要求:

  1. 只有 admin 可以变更角色
  2. 变更时触发 role_changed 事件
  3. 记录变更日志

### 5.3 进阶:向量检索

对于真正的大型项目,可以用简单的向量检索:

```bash
# 使用 openai 或本地 embedding 模型
# 将每个函数/类的签名和文档字符串向量化
# 查询时检索最相关的 5-10 个代码块

pip install openai chromadb
# 简化版 RAG 上下文检索
import openai
import chromadb

def get_relevant_context(query: str, top_k: int = 5) -> str:
    """根据问题检索最相关的代码上下文"""
    client = chromadb.PersistentClient(path=".code-db")
    collection = client.get_collection("code_contexts")
    
    results = collection.query(
        query_texts=[query],
        n_results=top_k
    )
    
    return "\n---\n".join(results['documents'][0])

# 使用示例
context = get_relevant_context("如何实现用户权限检查")
prompt = f"""## 相关代码上下文\n\n{context}\n\n## 任务\n帮我实现一个权限中间件..."""

实际效果:在 50 万行代码的项目中,RAG 检索的上下文相关度比随机选取高 3 倍。


六、策略五:上下文验证与迭代

最容易被忽视的一步:检查 AI 是否真的理解了上下文

6.1 快速验证法

在给 AI 下发任务之前,先让它复述理解:

## 上下文
[粘贴项目约定 + 相关代码]

## 验证
在开始之前,请先回答:
1. 这个项目使用什么测试框架?
2. 错误处理使用什么模式?
3. 数据库 ORM 是什么?

确认理解后再继续。

如果 AI 回答错了,说明上下文注入不够清晰,需要补充。

6.2 上下文迭代日志

我在项目中维护一个简单的上下文迭代日志:

# 上下文迭代日志

## 2026-04-20
- 问题:AI 生成的测试用了 Jest 而不是 Vitest
- 原因:.cursorrules 中测试框架描述不够突出
- 修复:在 .cursorrules 的"禁止事项"中明确写出"不要使用 Jest"
- 效果:后续测试生成正确率从 60% 提升到 95%

## 2026-04-22
- 问题:AI 在重构时引入了不必要的抽象层
- 原因:缺少"保持简单"的指导原则
- 修复:在 .cursorrules 中加入"优先使用简单方案,除非有明确的扩展需求"
- 效果:重构代码的复杂度评分降低 40%

6.3 上下文健康检查清单

每周花 10 分钟检查:

  • .cursorrules 是否反映了最新的技术栈变化?
  • 模块级上下文是否过期?
  • 最近 AI 生成的代码有多少需要大幅修改?
  • 有没有新的"禁止事项"需要加入?

七、总结:上下文管理的优先级

按投入产出比排序:

优先级策略投入时间效果提升
⭐⭐⭐⭐⭐项目级 .cursorrules30 分钟+40%
⭐⭐⭐⭐按需引用相关文件每次 2 分钟+25%
⭐⭐⭐⭐上下文分层一次设置+20%
⭐⭐⭐模块摘要/RAG2-4 小时+15%(大项目)
⭐⭐⭐上下文验证每次 1 分钟+10%

核心原则

  1. 上下文 > 提示词技巧:好的上下文让普通提示词也能产出好结果
  2. 精确 > 全面:50 行精准上下文胜过 500 行模糊描述
  3. 持续维护:上下文文件不是一次性的,需要随项目演进更新
  4. 验证闭环:定期检查 AI 是否真的理解了你的上下文

八、行动清单

如果你只记住三件事:

  1. 今天就创建 .cursorrules:花 30 分钟写一份项目上下文文件,明天你的 AI 助手就会好用一倍
  2. 引用文件而不是粘贴代码:用 @文件名 或行号引用,保持上下文和代码同步
  3. 每周检查上下文健康度:10 分钟的维护,换来每天节省 30 分钟的修改时间

本文所有策略均在真实项目中验证过。如果你有更好的上下文管理方法,欢迎在评论区分享。