第34讲|大型项目中的 AI 上下文管理:如何让 AI 记住百万行代码

3 阅读1分钟

金句:上下文是 AI 编程的稀缺资源。掌握上下文管理,就是掌握了 AI 时代的注意力经济。


一、大型项目的上下文挑战

对于小型项目(< 10 个文件),直接告诉 AI 相关文件就够了。

对于大型项目(> 100 个文件,> 10 万行代码),问题变得复杂:

  • 单次对话无法加载所有代码
  • AI 不知道哪些文件与当前任务相关
  • 代码依赖关系复杂,局部修改可能影响全局

本讲给出系统性的大型项目上下文管理策略。


二、代码库地图(Codebase Map)

核心思路:为 AI 准备一份"导游图",让它快速了解项目全貌。

生成项目地图

# generate_codebase_map.py
import os
import ast
from pathlib import Path

def generate_codebase_map(root_dir: str, output_file: str = "CODEBASE_MAP.md"):
    """生成代码库地图,帮助 AI 快速理解项目结构"""
    
    map_content = ["# 代码库地图\n"]
    map_content.append("## 项目概览\n")
    
    # 统计基本信息
    file_count = 0
    total_lines = 0
    languages = {}
    
    for root, dirs, files in os.walk(root_dir):
        # 跳过不重要的目录
        dirs[:] = [d for d in dirs if d not in [
            'node_modules', '.git', '__pycache__', 
            'dist', 'build', '.next', 'coverage'
        ]]
        
        for file in files:
            filepath = os.path.join(root, file)
            ext = Path(file).suffix
            
            if ext in ['.ts', '.tsx', '.js', '.jsx', '.py']:
                try:
                    with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
                        lines = len(f.readlines())
                    file_count += 1
                    total_lines += lines
                    languages[ext] = languages.get(ext, 0) + 1
                except:
                    pass
    
    map_content.append(f"- 总文件数:{file_count}\n")
    map_content.append(f"- 总代码行数:{total_lines:,}\n")
    map_content.append(f"- 语言分布:{languages}\n\n")
    
    # 生成目录树(只到第三层)
    map_content.append("## 目录结构\n\n```\n")
    map_content.append(generate_tree(root_dir, max_depth=3))
    map_content.append("```\n\n")
    
    # 提取关键模块说明
    map_content.append("## 核心模块说明\n\n")
    modules = extract_module_descriptions(root_dir)
    for module, description in modules.items():
        map_content.append(f"### `{module}`\n{description}\n\n")
    
    # 提取 API 端点
    map_content.append("## API 端点清单\n\n")
    endpoints = extract_api_endpoints(root_dir)
    for endpoint in endpoints:
        map_content.append(f"- `{endpoint['method']} {endpoint['path']}`:{endpoint['description']}\n")
    
    # 提取数据库模型
    map_content.append("\n## 数据库模型\n\n")
    models = extract_database_models(root_dir)
    for model in models:
        map_content.append(f"- **{model['name']}**:{model['fields']}\n")
    
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(''.join(map_content))
    
    print(f"✅ 代码库地图已生成:{output_file}")

def generate_tree(root_dir: str, max_depth: int = 3, prefix: str = "") -> str:
    """生成目录树"""
    result = []
    entries = sorted(os.scandir(root_dir), key=lambda e: (not e.is_dir(), e.name))
    
    for i, entry in enumerate(entries):
        if entry.name.startswith('.') or entry.name in ['node_modules', '__pycache__', 'dist']:
            continue
        
        is_last = (i == len(entries) - 1)
        connector = "└── " if is_last else "├── "
        result.append(f"{prefix}{connector}{entry.name}")
        
        if entry.is_dir() and max_depth > 1:
            new_prefix = prefix + ("    " if is_last else "│   ")
            result.append(generate_tree(entry.path, max_depth - 1, new_prefix))
    
    return "\n".join(result)

# 使用
generate_codebase_map("./src")

在 .cursorrules 中引用地图

## 代码库地图
请在回答关于项目结构的问题前,先参考 @CODEBASE_MAP.md 获取项目全貌。

## 上下文引用规范
- 需要了解某个模块时,使用 @目录 引用整个目录
- 需要了解某个接口时,使用 @接口文件 引用具体文件
- 需要了解数据模型时,使用 @prisma/schema.prisma

三、智能上下文注入策略

策略一:任务驱动的文件选择

# smart_context_selector.py
# 根据当前任务,智能选择需要加载的文件

def select_context_files(task_description: str, all_files: list) -> list:
    """基于任务描述,选择最相关的文件"""
    
    # 使用 AI 分析任务,找出相关文件
    response = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": f"""
项目文件列表:
{chr(10).join(all_files)}

当前任务:{task_description}

请列出完成此任务最相关的文件(最多10个),
按相关程度排序,只输出文件路径,每行一个:"""
        }]
    )
    
    selected_files = response.content[0].text.strip().split('\n')
    return [f.strip() for f in selected_files if f.strip()]

策略二:渐进式上下文加载

第一轮:提供项目摘要(CODEBASE_MAP.md)
       → AI 了解整体结构

第二轮:AI 指出需要哪些具体文件
       → 加载这些文件

第三轮:AI 开始工作,可能需要更多文件
       → 按需加载

这样避免一开始就把所有文件塞进上下文

四、大型项目的专项提示词设计

跨文件重构提示词

【大型重构任务】

目标:将项目中的直接 Prisma 调用从 Service 层移到 Repository 层

背景(请先阅读):
@CODEBASE_MAP.md  # 项目全貌
@src/services/    # 当前 Service 层(需要重构)

重构范围:
仅处理 src/services/user/ 目录下的文件。

重构原则:
1. Service 层不再直接 import PrismaClient
2. 所有数据库操作通过新建的 UserRepository 类
3. UserRepository 放在 src/repositories/user.repository.ts

验收标准:
- [ ] Service 层无 PrismaClient 引用
- [ ] Repository 层有完整的 CRUD 方法
- [ ] 原有测试仍然通过
- [ ] 类型检查通过(tsc --noEmit)

请先告诉我你计划修改哪些文件,等我确认后再开始执行。

五、上下文压缩技术

当需要传递大量代码时,可以先让 AI 压缩上下文:

请阅读以下代码库的所有文件,生成一份"压缩摘要":
- 每个文件一行简介(文件名 + 主要职责 + 关键函数名)
- 主要数据流描述(请求如何从 Controller → Service → Repository)
- 关键依赖关系

这份摘要将被用作后续对话的上下文参考。

章节小结:大型项目的上下文管理是 Vibe Coding 在企业场景落地的关键技能。核心策略是:用代码库地图提供全局视角,用智能文件选择提供局部精度,用渐进式加载保持对话效率。这不是 AI 的局限,而是提示词工程的艺术。