Aider 的第一个“Hello World”:从hello.md示例会话理解 AI 结对编程的最小闭环
【免费下载链接】aideraider is AI pair programming in your terminal项目地址: https://gitcode.com/GitHub_Trending/ai/aider
aider是一款运行在终端中的 AI 结对编程工具。本文将以仓库中 hello.md 这份“最简单的示例会话记录(chat transcript)”为核心,逐行还原一个把print("hello")改成print("goodbye")的完整交互闭环,并结合仓库源码剖析其背后的编辑块(edit block)语法、自动应用编辑、自动生成 git 提交等核心机制。读完本文,你将能读懂 aider 的示例会话、看懂工具输出格式,并亲自复现第一次 AI 结对编程体验。
一、hello.md 是什么:aider 世界里的“Hello World”
在aider的官方文档体系中,hello.md 归属于aider/website/examples/目录下的一组“示例对话转录”(Example chat transcripts),它的 front matter 中声明了parent: Example chat transcripts。从文件开头那句说明可以看出它的定位:
Here is the simplest possible "hello world" example of using aider.
它记录的就是一次真实的(或按真实交互整理的)aider 使用过程——用户只提出了一句需求,aider 就完成了“理解 → 修改文件 → 自动应用 → 自动 git 提交”的全部工作。文档正文没有理论说教,只有一段可以直接“照葫芦画瓢”的最小转录。
这一目录下还有其他循序渐进、主题各异的转录,例如:
- hello-world-flask.md:从空文件开始让 aider 搭建带多个端点的 Flask 应用;
- README.md:汇总介绍了 2048 游戏改造、多文件复杂变更、黑盒测试用例、遵循 NO_COLOR 规范等多种真实任务转录。
hello.md之所以被称为“最简单的示例”,是因为它只涉及单个文件、单行代码、一次修改,非常适合用来建立对 aider 工作流的整体直觉。如果你希望先看一个更完整的“从零建项目”流程,建议紧接着阅读 hello-world-flask.md。
二、完整会话逐行拆解:从 “hello” 到 “goodbye”
下面是 hello.md 中转录的核心内容,我们逐部分解读。
1. 用户的请求(####开头的行)
#### change hello to goodbye在 aider 的所有示例转录中,####前缀的行表示用户发送给助手的自然语言指令。这里用户的诉求非常简洁:把程序输出的 “hello” 改成 “goodbye”。
2. 模型的编辑方案与编辑块(edit block)
紧接着,AI 助手先用一段自然语言说明思路(示例中略去了冗长解释),然后给出一个带语言标注的代码块:
hello.py <<<<<<< ORIGINAL print("hello") ======= print("goodbye") >>>>>>> UPDATED这就是 aider 最核心的编辑块。它看起来像一次“代码上的 diff”,由四个关键部分组成:
| 组成 | 含义 |
|---|---|
首行文件名hello.py | 本次修改的目标文件,独立成行、逐字给出路径 |
<<<<<<< ORIGINAL(或实现中的SEARCH) | 编辑块起始标记 |
| 中间的原文片段 | 需要在文件中精确查找的旧代码 |
======= | 原文与替换内容的分隔线 |
>>>>>>> UPDATED(或实现中的REPLACE) | 编辑块结束标记,其上方为替换后的新代码 |
需要特别指出的是:示例转录为了让读者直观理解,采用了ORIGINAL / UPDATED这样的措辞(仓库中 benchmarks.md 也这样描述该格式:“每个编辑是一个围栏代码块,指定文件名以及一段 ORIGINAL 与 UPDATED 代码”);而在当前源码与提示词模板中,同一语义的编辑块以SEARCH / REPLACE标记组织(见下文源码剖析)。两者本质相同——给出“在文件中查找什么”,再给出“把它替换成什么”。
3. aider 的工具输出:自动应用与自动提交
转录最后两行是 aider 工具本身打印的状态信息(转录中以>引用块呈现):
> Applied edit to hello.py > Commit 672ae42 aider: Changed output from "hello" to "goodbye" in hello.py.> Applied edit to hello.py:表示这个编辑块已被 aider自动应用到磁盘文件。对应源码在 base_coder.py:if self.dry_run: self.io.tool_output(f"Did not apply edit to {path} (--dry-run)") else: self.io.tool_output(f"Applied edit to {path}")可以看到,只有在
--dry-run(预演)模式下才不会真正写入文件;正常模式下aider会直接修改源文件。> Commit 672ae42 aider: ...:表示 aider 已把这些改动自动创建为一次 git 提交。提交信息采用 “aider:+ 对改动的概括” 的固定前缀格式,对应 repo.py 中的实现:if prefix_commit_message: commit_message = "aider: " + commit_message因此可以推断:你完全可以在命令行里用
git log --oneline快速筛选出所有由 aider 代劳的提交记录,便于复盘或回滚。
这就是一次完整的“最小闭环”:用户一句话 → 模型产出编辑块 → aider 解析并写入文件 → aider 提交 git。
三、读懂示例转录的排版约定
首次接触示例转录的人常被其中混杂的角色搞混。其实 examples/README.md 用一节的篇幅专门解释了转录排版约定(Transcript formatting),归纳如下:
- 以
>引用块开头的行,是aider 工具本身的输出,例如> Applied edit to hello.py、> Commit ...,以及“文件已被加入/移出会话”等通知。 - 以
####开头的行,是用户手写的聊天消息。 - 其余普通段落(在网页上以蓝色字体呈现)是LLM 的回复,其中往往内嵌着“上色高亮”的编辑块代码。
hello.md与hello-world-flask.md都通过<div class="chat-transcript">容器承载转录,正是为了在网页渲染时套用这套统一样式。
此外,examples/README.md 还说明了示例转录背后共同遵循的几条重要规则:
- 每当 LLM 建议一处代码改动,aider 都会自动把它应用到源文件;
- 应用编辑后,aider 会以描述性的提交信息自动提交到 git;
- LLM 只能看到并编辑“已加入本次会话(added to the chat session)”的文件。用户既可以在启动时通过命令行参数传入文件(如
aider app.py),也可以在会话中用/add命令加入。若 LLM 主动要求查看文件,aider 会先征得用户同意再将其加入会话——这正是示例转录里频繁出现文件添加/移出通知的原因。
在 hello-world-flask.md 的开头可以看到这一机制的现场表现:
> $ aider app.py > Creating empty file app.py > Added app.py to the chat也就是说:用户启动时把app.py交给了 aider,aider 便自动为它创建了会话入口,后续所有编辑都围绕该文件展开。
四、编辑块的底层实现:从解析到容错替换
为什么 LLM 输出一段看似普通的代码块,aider 就能可靠地改文件?关键在于一套“先解析、再精确定位、最后柔性替换”的源码机制,主要落在 editblock_coder.py 与 search_replace.py 两个文件中。
1. 编辑块的解析
在 editblock_coder.py 中,LLM 返回的内容会先交给find_original_update_blocks()做结构化解析,从中提取出“目标文件、原文片段、替换内容”三元组:
edits = list( find_original_update_blocks( content, self.fence, self.get_inchat_relative_files(), ) )解析器用正则识别编辑块的三个关键标记(editblock_coder.py):
HEAD = r"^<{5,9} SEARCH>?\s*$" # 起始标记,如 <<<<<<< SEARCH DIVIDER = r"^={5,9}\s*$" # 分隔线 ======= UPDATED = r"^>{5,9} REPLACE\s*$" # 结束标记,如 >>>>>>> REPLACE可见标记符允许 5~9 个</>/=连续字符,具备一定容错;若出现格式不完整的编辑块,解析器会抛出诸如Expected >>>>>>> REPLACE的ValueError,从而引导模型修正输出。
2. 从“精确替换”到“柔性匹配”
search_replace.py 提供了一个关键的flexible_search_and_replace()函数,它按“由严格到宽松”的顺序尝试多种替换策略:
editblock_strategies = [ (search_and_replace, all_preprocs), # 1. 最字面的整段文本替换 (git_cherry_pick_osr_onto_o, all_preprocs), # 2. 用 git cherry-pick 近似合入 (dmp_lines_apply, all_preprocs), # 3. 基于 diff-match-patch 的行级补丁 ]这意味着即便模型给出的 SEARCH 片段与实际文件存在空白差异、缩进差异(RelativeIndenter 会先把双方转换为“相对缩进”再比对),aider 仍有较高概率把改动正确落到目标位置。而对于“新建文件”这种常见场景,提示词模板(editblock_prompts.py)要求 LLM 提供一个 SEARCH 段为空的编辑块——即“查找空内容,替换为新文件内容”,此时需要新增的文件同样不需要任何磁盘前提。
3. 对模型的强约束
为了保证可解析性,提示词模板在 editblock_prompts.py 中对编辑块提出了一系列硬性规则:
- 首行必须是完整文件路径,单独成行、不加粗不转义;
- 每个
SEARCH段必须与现有文件内容逐字符精确一致(含注释与 docstring); - 编辑块默认只替换第一处匹配,如需多处修改应拆分多个编辑块,并让每个 SEARCH 段足够独特以便唯一定位;
- SEARCH 段应尽量精简,只包含改动行及其必要上下文,不要夹带大段未改动代码;
- 只允许对已加入会话的文件创建编辑块。
理解这些约束,也就理解了示例转录中编辑块为什么总是“短小、精准、直击要害”。
4. 应用编辑后的自动提交
编辑应用成功后,base_coder.py 中的auto_commit()会接管后续流程:它把本次改动的文件名与对话上下文一起交给repo.commit()(开启aider_edits=True以标记改动由 AI 生成),并由self.repo.commit(...)生成“aider: 改动概述”格式的提交信息。提交是否真正发生由auto_commits开关控制——在 base_coder.py 中该参数默认值为True。仓库的提交模块(repo.py)还支持通过--attribute-committer、--attribute-co-authored-by等参数控制提交署名归属(如把提交者标注为“用户名 (aider)”,或为提交信息追加Co-authored-by: aider尾注),方便与同事协作时区分 AI 生成的改动。
五、亲自复现:把 “hello” 变成 “goodbye”
读完源码机制后,你也可以在自己的终端里复现这第一次体验。前提与步骤大致如下:
- 准备一个 git 仓库:aider 的自动提交依赖 git,建议先执行
git init(aider 仅在检测到 git 仓库时启用自动提交逻辑,参见 repo.py 中aider_edits=True的分支处理)。 - 创建一个
hello.py,内容为print("hello")。 - 启动 aider 并把文件加入会话,方式与 hello-world-flask.md 一致:
$ aider hello.py > Added hello.py to the chat - 输入与示例相同的请求:
change hello to goodbye模型会返回一个编辑块,aider 随后打印
> Applied edit to hello.py,并给出一次> Commit ... aider: ...提交记录。 - 验证:查看
hello.py内容已是print("goodbye"),再执行git log即可看到带aider:前缀的提交;若想回退,可在会话中配合/undo撤销并丢弃对应的 aider 提交(该提示信息同样出现在 base_coder.py 的实现中)。
安装环节请参考仓库的安装指引:docs/install.md 以及 website/install.sh。
六、从 “Hello” 出发,继续探索
hello.md的价值在于用一行代码展示了 aider 的全部核心流程;如果你想看到同样的机制在更复杂任务上的表现,仓库 aider/website/examples/ 目录中还有大量配套转录,建议按此顺序阅读:
- hello-world-flask.md:从零创建 Flask 应用,演示“新增端点、带 URL 参数的求和接口、斐波那契数列接口、删除已有端点”四连击——每一轮都完整展示了编辑块 → 应用 → 提交的过程;
- 2048-game.md:进入一个现有开源仓库,先让 aider 理解代码再动手修改;
- complex-change.md:跨多个源码文件的复杂改动与调试;
- add-test.md:在无法看到被测方法源码的情况下,借助 ctags 生成的仓库地图编写“黑盒”测试用例。
当你对这些示例转录的“语言”足够熟悉后,再回到编辑块的源码(editblock_coder.py、search_replace.py)深入研读,会发现示例中每一行看似简单的输出背后,都是一套为“可靠自动改代码”而精心设计的解析、匹配与提交流水线——这正是aider作为终端 AI 结对编程工具的立身之本。
【免费下载链接】aideraider is AI pair programming in your terminal项目地址: https://gitcode.com/GitHub_Trending/ai/aider
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考