Agent 在大代码库里的主要任务不是写代码,而是先找到要改的那几行
问题规模
主流大模型当前的上下文窗口在 100K 到 1M token 之间。听起来很大,但放到真实代码库面前并不够用:
| 代码库 | 大致行数 | 估计 token 数 |
|---|---|---|
| 小型项目 | 1-5 万 | 0.5-2M |
| 中型项目(典型业务系统) | 10-50 万 | 5-20M |
| 大型项目(Django、React 等) | 50-200 万 | 20-100M |
| 超大型项目(Chromium、Linux kernel) | 1000 万+ | 数百 M |
即使最大的上下文窗口也装不下一个中型项目。所以 Code Agent 在真实项目里工作时,主要的工作不是写代码,而是先定位到要看哪几个文件、要改哪几行。
几种定位策略
1. 关键词搜索(grep-based)
最直接,也最实用:
grep -r "UserAuthService" --include="*.py" ./src
适合 Agent 已经知道要找的具体符号名、变量名、错误信息时使用。SWE-agent 的 search_file / search_dir 工具本质上就是 grep 的封装。
优点:精确、快、易理解。 缺点:不能处理语义上相似但用词不同的情况。
2. 文件树浏览
把目录结构展示给 Agent,让它根据文件名和路径推测哪些文件相关:
src/
├── auth/
│ ├── service.py
│ ├── middleware.py
│ └── handlers.py
├── models/
│ ├── user.py
│ └── session.py
└── api/
└── auth_routes.py
Agent 看到 "auth" 相关目录,会优先去那里看。适合熟悉的项目结构、命名规范明确的项目。
3. 语义检索(Embedding-based)
对代码库做向量索引:把每个函数、类、文件转成 embedding,按语义相似度检索。
query = "处理用户登录失败的逻辑"
results = vector_db.search(embed(query), top_k=5)
# 返回最相关的 5 段代码
适合 Agent 描述的是功能性需求,而不是具体符号名。
工具:
- Cody(Sourcegraph):商业产品,基于代码 embedding 检索
- Cursor:编辑器内置,对工作目录建索引
- Codebase Indexing(Continue.dev 等):开源方案
代价:索引需要预先构建,代码改动后需要增量更新,存储开销不小。
4. 调用图分析(AST-based)
用语言服务器(LSP)或 AST 分析工具构建调用图:
函数 A 被这些地方调用:
- module_x.py:45
- module_y.py:120
- tests/test_a.py:30
函数 A 调用了:
- helpers.format_date
- models.User.get_by_id
适合需要追踪"改这个函数会影响哪些地方"的修改任务。SWE-agent、Aider 等工具会用 LSP 提供这类信息。
5. 历史变更(git-based)
通过 git blame、git log 找到与某段代码相关的历史:
git log --all --source --remotes -- src/auth/service.py
git blame src/auth/service.py
适合需要理解"这段代码为什么是这样写的"的场景。最近修改过相关文件的提交,往往和当前问题相关。
实际工作流的组合
成熟的 Code Agent 通常不是只用一种策略,而是按场景组合:
[阶段 1:粗筛]
关键词搜索 + 文件树浏览
→ 锁定候选文件(10-30 个)
[阶段 2:精读]
对候选文件做语义检索或直接读取
→ 锁定候选函数(5-10 个)
[阶段 3:理解依赖]
调用图分析
→ 理解修改的影响范围
[阶段 4:编辑]
精确编辑 + 跑相关测试
每个阶段都在收窄信息范围。如果跳过粗筛直接读所有文件,上下文很快就会爆。
窗口内的信息组织
定位到了相关代码,怎么放到上下文里?
完整文件 vs 片段
完整文件:信息完整,但占 token 多。 片段(按行号范围):节省 token,但容易丢失上下文(比如类定义的开头被截掉了)。
实际做法通常是:
- 当前编辑的目标文件:完整放入
- 相关的其他文件:只放相关函数或类
- 更远的依赖:只放签名(函数名、参数、返回类型)
摘要 vs 原文
对于大文件,可以先生成摘要:
[文件摘要:src/services/user_service.py]
- 提供用户相关的业务逻辑
- 主要类:UserService(管理用户 CRUD)、AuthService(认证)
- 关键方法:
- UserService.create_user(...)
- UserService.update_profile(...)
- AuthService.login(...)
- 依赖:models.User, repositories.UserRepository
让 Agent 先看摘要决定要不要进一步查看完整代码。Cursor、Aider 等工具内部都有类似机制。
代价:摘要可能丢失关键细节,而且摘要的生成本身也要花 LLM 调用。
状态保持
SWE-agent 的 ACI 设计里专门强调了"当前打开的文件、当前浏览的行数"这类状态。把这些信息显式放在 prompt 里,可以让 Agent 不会"迷路"。
当前状态:
打开的文件:src/auth/service.py
当前浏览位置:第 245-310 行
最近编辑:修改了 line 280-285 的 login() 方法
跨文件依赖的处理
修改一个函数往往会影响调用它的地方。Agent 需要识别这种依赖。
静态分析
用 LSP 或 tree-sitter 找出调用链:
def find_references(symbol_name, codebase_path):
# 用 LSP 找到所有引用
references = lsp_client.references(symbol_name)
return [
{"file": ref.file, "line": ref.line, "context": ref.surrounding_code}
for ref in references
]
把这些引用信息放入 prompt,Agent 修改函数时就能同步更新调用点。
动态运行测试
修改之后跑测试,让测试来告诉 Agent 哪里坏了:
修改:src/auth/service.py 的 login() 方法
跑测试:pytest tests/test_auth.py
结果:
tests/test_auth_handlers.py::test_login_endpoint FAILED
- 错误:TypeError: login() missing 1 required argument: 'remember_me'
测试错误信息直接告诉了 Agent 漏改了哪些地方。
实际做法是两者结合:静态分析帮忙找候选影响点,动态测试验证。
缓存与增量更新
代码库不是静态的,频繁修改后索引会过期。处理方式:
文件级缓存失效:每个文件的索引带时间戳或哈希,文件修改时只重建该文件的索引,不重建整个库。
懒加载:不预先索引整个库,按需建立索引(用户查询到时才计算 embedding)。
多级缓存:
- L1:最近访问的文件(内存,几十个)
- L2:项目的高频文件(磁盘,几百个)
- L3:完整代码库索引(向量数据库)
每一级都有 hit 时跳过下一级。
不同规模的策略选择
| 代码库规模 | 推荐策略 |
|---|---|
| 万行以内 | 全部放入上下文,无需特殊设计 |
| 万到十万行 | 文件树 + 关键词搜索 + 按需读取 |
| 十万到百万行 | 上述 + 语义检索 + LSP 调用图 |
| 百万行以上 | 完整索引系统 + 摘要 + 多级缓存 |
规模越大,预处理和工程投入越多,纯靠"把代码塞给 LLM"越不可行。
工程实践的几个观察
精确比全面重要:给 Agent 30 个相关文件,不如给 3 个真正相关的文件。前者容易让 Agent 注意力分散,后者反而效果好。
结构化优于自由文本:用明确的格式(文件名 + 行号 + 内容)比把代码段堆在一起更利于 Agent 处理。
让 Agent 自己控制:与其预先决定给它看什么,不如提供工具让 Agent 自己按需查询。SWE-agent 的设计就是这种思路——给工具,不给数据。
上下文管理是迭代过程:Agent 看完一些代码后,会发现需要再看另一些代码。这种动态查询比一次性"给齐所有相关材料"更接近真实开发过程。
小结
大代码库的上下文管理是 Code Agent 从 demo 走向实际可用的关键工程问题之一。它不是某个算法能解决的,而是几个组件的组合:
- 多种检索方式(关键词、语义、AST、git)
- 信息组织策略(完整 / 片段 / 摘要 / 签名)
- 跨文件依赖处理(静态 + 动态)
- 缓存与增量更新
模型的上下文窗口在变大,但代码库的规模也在变大,工程上的"按需检索 + 智能裁剪"在可预见的将来仍然是必要的。
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:16. 大代码库的上下文管理:Agent 如何在百万行代码里找路
本文链接:https://www.sshipanoo.com/blog/ai/code-agent-harness/16-大代码库的上下文管理/
本文最后一次更新为 天前,文章中的某些内容可能已过时!