Aider — 架构与原理
30 秒导读: Aider 是一个在终端里跑的「AI 结对编程」工具。你把几个文件加进会话、说一句"把 X 改成 Y",它把你的代码 + 一张全仓库地图发给 LLM,LLM 回一段带文件名的 SEARCH/REPLACE 补丁,Aider 把补丁容错地应用到磁盘、跑 lint/测试、并自动 git 提交——出错就把错误喂回模型让它自己改。
1. 这是什么(零基础也能懂)
一句话定义: Aider 是一个命令行工具,让你用自然语言驱动 LLM 修改你本地 git 仓库里的真实代码。
解决什么问题 / 给谁用: 假设你在终端里维护一个几百个文件的项目,想让 AI 帮你"给 app.py 的 get_factorial() 换成 math.factorial"。直接把整个仓库贴给 ChatGPT 既超上下文又难把回复落回文件。Aider 解决的就是这"最后一公里"——让模型的输出能被机器可靠地应用到磁盘,并且让模型不用看到全部代码也知道仓库里有什么。
它能做什么:
- 接收自然语言改动请求,产出对多个文件的精确编辑。
- 自动把编辑写盘、
git commit,可/undo回退。 - 给大仓库生成一张「重要符号地图」(repo map),让模型有全局观。
- 自动跑 linter / 测试,把错误反馈回模型让它自纠。
- 支持几乎任意 LLM(通过 litellm),并按模型能力切换编辑格式。
用起来什么样: 一段真实的终端交互(示意):
$ aider mathweb/flask/app.py
> Change get_factorial() to use math.factorial
# 模型回复里夹着一个 SEARCH/REPLACE 块:
mathweb/flask/app.py
```python
<<<<<<< SEARCH
return str(factorial(n))
=======
return str(math.factorial(n))
>>>>>>> REPLACE
```
Applied edit to mathweb/flask/app.py
Commit a1b2c3d Change get_factorial to use math.factorial
上面那段 <<<<<<< SEARCH ... ======= ... >>>>>>> REPLACE 就是 Aider 的核心"编辑语言"——它长得像 git 冲突标记,模型最熟悉、最不容易写错。
一句话直觉/类比: 把 LLM 当成一个只会说话、看不见你磁盘的资深程序员。Aider 是它的「手和眼」:
- 眼=把相关代码 + 一张仓库地图念给它听;
- 手=把它口述的"把这几行换成那几行"容错地落到真实文件,并用 git 兜底。
2. 顶层全景(它大概怎么转)
主要部件
| 部件 | 干什么 | 在哪 |
|---|---|---|
Coder(基类) | 主循环、上下文组装、反思自纠、提交编排 | aider/coders/base_coder.py |
各 *Coder 子类 | 实现一种编辑格式的解析与应用(diff / udiff / 整文件…) | aider/coders/editblock_coder.py 等 |
RepoMap | 用 tree-sitter 抽符号 + PageRank 排重要性,生成仓库地图 | aider/repomap.py |
GitRepo | 暂存、生成提交信息、按规则改作者/提交者归属 | aider/repo.py |
Model | 把模型名映射到能力(默认编辑格式、缓存、提醒位置…) | aider/models.py |
Commands | 斜杠命令(/add /undo /test …) | aider/commands.py |
InputOutput | 终端 IO、确认提示、读写文件 | aider/io.py |
主线走一遍(高层)
你打一句话
│
▼
┌──────────────────────────────────────────────────────────┐
│ Coder.run_one (base_coder.py:924) │
│ 预处理:识别斜杠命令 / 文件提及 / URL │
└───────────────┬────────────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ format_chat_chunks → 组装上下文: │
│ 系统提示 + 例子 + repo map + 只读文件 + 会话文件 + 历史 │
│ (chat_chunks.py 决定拼接顺序与缓存点) │
└───────────────┬────────────────────────────────────────────┘
▼
send → LLM(litellm,流式)
▼
┌──────────────────────────────────────────────────────────┐
│ 回复文本 = 解释 + 若干 SEARCH/REPLACE 块 │
│ get_edits 解析出 (文件, 旧文本, 新文本) │
│ apply_edits 容错地把旧文本定位并替换(多级降级匹配) │
└───────────────┬────────────────────────────────────────────┘
▼
成功?──否──► reflected_message = 错误详情 ──┐
│是 │ 回灌给模型
▼ │ 再来一轮
git auto-commit → lint → test │ (≤3 次)
│ │
└── lint/test 失败也可触发反思 ────────────┘
这张图就是 Aider 的灵魂:一个"发请求 → 落编辑 → 验证 → 出错就把错误喂回去再来一轮"的有限次自纠循环。循环上限是 3 次(base_coder.py:101 max_reflections = 3)。
三个最值得理解的设计点
- 编辑即语言。 模型不调用"写文件"工具,而是在普通回复里夹一段约定格式的补丁;Aider 负责解析与落地。
- 容错匹配是核心难点。 模型"记忆"的旧代码几乎从不和磁盘逐字一致,所以应用补丁要一层层降级匹配(见第 2 章)。
- 反思替代多智能体。 没有复杂的 agent 编排——靠"把 lint/test/匹配失败的报错原样回灌"形成一个朴素但有效的自纠环。
3. 阅读地图(建议顺序)
这是大型项目,拆成四章,由浅入深:
| 顺序 | 文件 | 讲什么 | 适合谁 |
|---|---|---|---|
| 1 | 01-edit-formats.md | LLM 怎么"说出"一次改动:三种编辑格式 + 解析 | 想懂"模型输出长啥样、怎么被切出来" |
| 2 | 02-apply-and-match.md | 把模型口述的旧代码容错地落到真实文件:多级降级匹配 | 想懂"为什么改不准也能改对"——精华所在 |
| 3 | 03-repo-map.md | tree-sitter 抽符号 + PageRank 排序,压出仓库地图 | 想懂"模型 没看全部代码却有全局观" |
| 4 | 04-loop-and-git.md | 主循环 / 反思自纠 / 上下文与缓存 / git 提交与归属 | 想懂"端到端怎么转、怎么兜底" |
建议至少读 1 → 2:这两章是 Aider 区别于"套壳聊天"的真正工程含量所在。
4. 代码地图(导航索引)
| 主题 | 文件 | 关键符号 |
|---|---|---|
| 主循环 / 反思 | aider/coders/base_coder.py | run_one、send_message、max_reflections、reflected_message |
| 编辑格式工厂 | aider/coders/base_coder.py | Coder.create |
| SEARCH/REPLACE 解析 | aider/coders/editblock_coder.py | find_original_update_blocks、find_filename |
| 容错匹配 | aider/coders/editblock_coder.py | replace_most_similar_chunk、replace_part_with_missing_leading_whitespace、try_dotdotdots |
| udiff 应用 | aider/coders/udiff_coder.py、aider/coders/search_replace.py | find_diffs、flexible_search_and_replace、udiff_strategies |
| 仓库地图 | aider/repomap.py | RepoMap.get_ranked_tags、get_ranked_tags_map_uncached、get_tags_raw |
| 上下文组装 / 缓 存 | aider/coders/base_coder.py、aider/coders/chat_chunks.py | format_chat_chunks、ChatChunks.all_messages、add_cache_control_headers |
| git 提交与归属 | aider/repo.py | GitRepo.commit、get_commit_message |
| 模型能力映射 | aider/models.py | Model.configure_model_settings、edit_format |