Aider 源码研究:Repo Map、Edit Format 与 Git-aware 修复循环
Aider 很适合用来观察“模型输出怎样真正变成代码改动”。阅读时先跟踪编辑格式的解析,再看文件修改、Git 和测试反馈如何连接。它与以通用工具调用为中心的系统不完全相同,这个差别贯穿全文。
2026-10-25:当前源码入口与阅读练习
本节固定到公开仓库提交 5dc9490bb35f9729ef2c95d00a19ccd30c26339c(提交时间 2026-05-22T14:02:20Z)。只对下面列出的文件和机制重新核对;后面的历史长文继续按各自快照阅读,不把新 HEAD 当作全部旧结论的重新验证。
这次远端 HEAD 与上次记录相同,仍是 5dc9490bb35f9729ef2c95d00a19ccd30c26339c。如实保留这一点:重新核验不等于项目一定发布了新功能,也不能从提交没有变化推断项目已经停止维护。
学习入口仍可选 base_coder.py 的 run_one 和消息装配相关方法。给自己一个小任务:画出“用户消息—可见文件—模型响应—编辑处理”的数据流,再找到不同 edit format 如何接入。这个练习比把某种补丁格式说成所有 Coding Agent 的标准更可靠。
本节的核验依据
2026-10-25 查阅。下面的链接支持本节的机制说明;练习场景和选型建议是本教程的教学设计。
以下为历史快照研究。涉及路径、默认值和产品行为时,请同时查看上面的本次核对范围。
版本与资料依据
last_verified:2026-08-24version_scope:5dc9490bb35f9729ef2c95d00a19ccd30c26339csource_type:official-repository + source-auditstability:mature / active
2026-09-20 增量核对:现在从哪里读
本轮证据固定在 5dc9490bb35f,入口为 aider/coders/base_coder.py。下文旧快照与旧核验日期保留;本节不是对全部历史结论的重新背书。
本轮核对 base_coder.py:仍可沿 run、run_one、send_message 和 send 追踪用户输入到模型请求。阅读 Aider 时,先把对话组织与具体 edit format 分开:主流程准备材料、发送请求,具体 coder 决定怎样解释并应用修改。
它的教学价值在于把“模型输出一段建议”和“文件真的被修改”分成两步。练习时可选一个很小的仓库,查看提交前后的 diff,运行测试,再故意制造一个定位不匹配的编辑来观察反馈。本次是固定源码的静态核对,不代表所有模型适配和编辑格式已执行验证。
1. 定位
- 官方仓库:Aider-AI/aider
- 固定快照:
5dc9490 - 主体:Python CLI、Git-aware pair programming、以文件编辑和验证为中心。
Aider 与通用 tool-calling Agent 的核心差异是:主动作协议不是任意 Tool Registry,而是受约束的 Edit Format。 模型输出被 parser 转成文件修改,由 Git、lint、test 和 reflection 形成闭环。
2. 总体链路
主要入口是 aider/coders/base_coder.py 的 Coder。run() 负责交互输入,run_one() 管理一次请求和 reflection,send_message() 管理 prompt/response/edit/validation,send() 才进入模型 API。
3. Context:把仓库压缩成可选择的证据
一次模型请求通常包含:
- system/edit-format instructions;
- 对话历史;
- 用户明确加入 chat 的文件全文;
- read-only files 或图片等附件;
- Repo Map;
- Git/diff、lint/test 错误等反馈。
3.1 Repo Map
aider/repomap.py 的 RepoMap 使用 tree-sitter tags 提取定义/引用,再依据文件关系与用户当前关注点做排名,并受 token budget 约束。
Repo Map 不是向量数据库,也不是完整 AST;它是针对 Coding Agent 的结构化检索/压缩层。它的目标是让模型知道“哪些符号在哪里、哪些文件相关”,再决定是否把某文件加入全文 context。
4. Edit Format:Output Parser 就是动作协议
Aider 支持多种 coder/edit format,例如 whole-file、search/replace edit block、unified diff、patch,以及 architect/editor 双模型流程。共同模式是:
- prompt 明确要求一种可解析格式;
- parser 提取目标路径、old/new 区块或 patch;
- executor 验证文件存在性、匹配唯一性与路径;
- 应用成功后记录 changed files;
- parser/apply 失败形成可供模型修正的错误。
4.1 Search/Replace 的关键不变量
- SEARCH 必须在目标文件中找到;
- 通常要求唯一匹配,否则模型需补充更多上下文;
- REPLACE 只替换该块,不接受模糊意图;
- 文件创建、删除和重命名需要明确协议;
- 模型文字说明不能被误当代码 patch。
这种协议比任意 shell 命令更容易做 diff review 和失败修复,但能力边界也更窄。
5. Reflection Loop
Coder.max_reflections = 3。当 edit parser、apply、lint 或 test 产生可恢复失败时,Aider 把错误作为新反馈再请求模型;达到上限后停止自动反思。
reflection 与 provider retry 不同:provider retry 处理网络/限流;reflection 是把任务级失败证据交还模型重新决策。两者的计数、backoff 和日志应分开。
6. Git 是状态与审计边界
Aider 的 Git 集成负责:
- 识别 repository、tracked/dirty files;
- 在修改前后形成 diff;
- 可选自动提交;
- 用 commit message 记录本轮变更;
- 避免把用户已有 dirty work 静默混成 Agent commit;
- 支持 undo/恢复工作流。
自动 commit 是运行配置,不是模型能力。dry_run、auto_commits、repository dirty state 与用户显式 git 操作共同决定真实行为。
7. Lint 与 Test 闭环
auto_lint 默认开启,auto_test 默认关闭。修改后:
- 只对相关文件或配置的 linter 执行检查;
- lint 失败可触发 reflection;
- test 命令由用户/配置决定;
- test 输出裁剪后回填,避免无限放大 context;
- 成功结果与失败结果都要对应本轮 changed files。
正确性边界:lint 通过不等于测试通过,测试通过也不等于任务完成。Aider 提供执行反馈层,但最终 acceptance 仍需要项目特定的验证门。
8. Architect/Editor 双模型
ArchitectCoder 先用 architect model 形成解决方案,再由 editor model 按可执行 edit format 落地。它体现了“规划文本”和“补丁协议”的分离:
- Architect 擅长推理、范围与方案;
- Editor 接收方案和文件 context,负责严格格式;
- 结果仍进入同一 apply/lint/test/Git 链路。
这不是通用多 Agent 调度:它更像固定两阶段 pipeline,没有任意任务图、共享黑板或动态 subagent topology。
9. 模型适配
Aider 的 model metadata 决定 context window、edit format、reasoning/stream 参数、provider 设置与 Repo Map token 策略。模型名称相同并不保证 provider 行为完全一致,因此 source audit 应检查:
- model settings 来源和覆盖顺序;
- prompt/edit format 是否与模型能力匹配;
- tool/function calling 与文本 patch 是否混用;
- token/cost 与 cache metadata;
- truncated response 对 parser 的影响。
10. UI/命令层
CLI commands 处理 /add、/drop、/read-only、/diff、/undo、/test、/lint、/commit 等控制面动作。命令层改变 context 或运行配置,不应伪装成普通用户 message 交给模型解释。
11. 错误分类
| 错误 | Owner | 正确恢复方式 |
|---|---|---|
| provider/network | model client | retry/backoff/换模型 |
| output parse | edit-format parser | reflection,要求重发合法 patch |
| block 不匹配 | edit executor | 返回目标文件证据后 reflection |
| Git dirty/conflict | GitRepo/user | 显式处理工作区,不覆盖 |
| lint/test failure | validation runner | 结构化回填模型 |
| context overflow | context builder | 缩减 map/files/history |
12. 源码索引
| 文件 | 阅读问题 |
|---|---|
aider/coders/base_coder.py |
主 loop、context、reflection、lint/test/commit |
aider/repomap.py |
tag graph 与 token-budget Repo Map |
aider/coders/editblock_coder.py |
search/replace parser 与 apply |
aider/coders/udiff_coder.py |
unified diff 变体 |
aider/coders/architect_coder.py |
architect/editor pipeline |
aider/repo.py |
Git repository 与 commit 边界 |
aider/linter.py |
language-aware lint |
aider/models.py |
model metadata/配置 |
13. 与 Tool-calling Agent 的对照
| 维度 | Aider | 通用 Tool Agent |
|---|---|---|
| 动作空间 | 主要是 edit format + CLI control | 任意 registry tools |
| Repository context | Repo Map 是核心 | 实现差异大 |
| 文件修改 | parser + deterministic apply | edit tool 调用 |
| 修复循环 | reflection 上限明确 | 通常依赖 Agent Loop |
| Git | 一等工作流 | 可能只是 shell tool |
| 多 Agent | architect/editor 固定 pipeline | 可动态 spawn/delegate |
14. 值得学习与限制
值得学习
- Repo Map 将代码结构检索与 token budget 结合。
- Edit Format 把自由文本变成确定性修改协议。
- parser/apply/lint/test 失败进入有限 reflection。
- Git diff/commit/undo 是工作流主干。
- 明确区分 provider retry 与任务反思。
限制
- edit format 对复杂非文件工具工作流不如通用 registry 灵活。
- Repo Map 的静态关系不等于动态调用和运行时证据。
- 自动提交策略需适应团队分支/CI 规则。
- reflection 上限避免死循环,但不保证最后一次修改正确。
15. 未验证项
- 所有 provider/model 对每种 edit format 的当前质量;
- 超大 monorepo 中 Repo Map 的延迟、缓存和排名效果;
- 不同语言 linter/test runner 的完整覆盖;
- 用户已有复杂 dirty state、submodule/worktree 下的所有 Git 边界。
16. 最终心智模型
Repository → Repo Map + selected files
→ model response constrained by Edit Format
→ parser → deterministic patch apply
→ Git diff/commit
→ lint/test evidence
→ bounded reflection
Aider 展示了一条与“模型随意调用 shell”不同的 Coding Agent 路线:缩小动作协议,强化 repository context、补丁确定性与验证反馈。