aider 实战实录:用对话式编程读懂陌生仓库并完成 CSS 下拉菜单弹跳动画练习
这是一篇对 aider 官方示例聊天实录的深度解读与复现指南。示例发生在 The Odin Project 的 CSS Exercises 开源练习仓库中,目标是为
animation/03-dropdown-menu的下拉菜单补上"弹跳式展开"动画。文章完整保留并逐段剖析实录中的每一次交互,说明aider如何通过文件清单理解陌生仓库、用/add命令加入练习说明、在获得许可后把目标 CSS/JS 文件纳入会话,并最终以aider: ...前缀的自动 git 提交收尾;同时结合本仓库源码解释这些行为背后的实现位置,并给出可直接照做的复现步骤。
这篇实录的定位与读法
本篇文章的讨论对象是仓库中的 css-exercises.md,它是 aider 官方维护的示例聊天总览页中"Example chat transcripts"系列的一份。总览页把这类文章定位为"展示用 aider 编程是什么体验"的对话记录:用户既可能是写全新代码,也可能是在一个陌生仓库里探索、理解与修改既有代码,css-exercises 属于后者——它演示了"读懂一个陌生开源练习仓库,并按其 README 的要求完成动画练习"的完整闭环。
在阅读这类实录之前,总览页给出了一套约定,本篇文章中每一段对话都可以对照这套约定去解析:
>开头(灰底引用)是 aider 工具自身的输出,例如文件加入会话、补丁应用、git 提交等通知;####开头的是 用户输入的消息(在终端里每行都带有####前缀);- 其余正文是 LLM 的回复,其中常包含彩色高亮的"edit block"(编辑块),用来精确描述对代码的修改;
- 每当 LLM 提出一个代码修改建议,aider 都会把它自动应用到源文件,随后用一句描述性提交信息自动提交到 git(详见该页"HISTORY 说明"一节的约定文字)。
第一轮对话:先让 aider 读懂一个完全陌生的仓库
实录的第一句用户提问非常朴素:what is this repo?(这是什么仓库?),随后 LLM 基于启动时提供的文件清单给出了概括——该仓库收集了一组 CSS/HTML 练习、解答与示例,覆盖 Flexbox、Grid、Animation、Foundations、Margin & Padding 等主题,并包含练习用图片等资源。
这轮对话的价值在于它揭示了 aider 的使用姿势之一:打开会话时把整个目录交出去,先建立"仓库地图",再定位到具体练习。这里 LLM 判断依据是会话开始时的文件列表,而非打开任意文件——aider 会结合版本库结构构建一个供模型理解的仓库概览,让模型在修改前先对项目全貌形成认识。这一点在后续轮次中体现得更清楚:模型能立刻报出练习目录的路径(animation/03-dropdown-menu/)与相关文件命名(style.css、script.js),正是因为它先掌握了仓库布局。
第二轮对话:用 /add 把练习说明放进会话上下文
#### /add animation/03-dropdown-menu/README.md
> Added animation/03-dropdown-menu/README.md to the chat
用户使用 /add 命令把练习说明加入会话,aider 返回 "Added ... to the chat" 确认。/add 是 aider 会话控制的核心命令,它在源码中的职责定义是:
"Add files to the chat so aider can edit them or review them in detail"(把文件加入对话,以便 aider 编辑或详细审查它们)
其实现位于 aider/commands.py 中的 cmd_add:命令支持相对/绝对路径、目录展开与 glob 通配;只把真正存在的文件纳入会话,并对被 aiderignore 或 --subtree-only 排除、位于 git 仓库之外等情形给出提示。一个关键前提是:LLM 只能看到并编辑被"加入会话"的文件——这正是整段实录中反复出现 add 通知的原因。
README.md 入会后,LLM 立即读懂了练习要求:为下拉菜单加入"展开到接近最终状态时产生回弹(bounce)错觉"的动画;期望效果以 GIF 展示;hint 提示使用 transform-origin 属性,并在 @keyframes 规则里加入一个中间帧来制造回弹效果。这展示了 README 即需求文档的常见打法:把练习说明文本喂给模型,由它反推实现要点,再由用户确认是否动手。
第三轮对话:让 aider 动手改代码
用户提出 can you make the changes suggested in the readme?(能按 README 的建议做修改吗)。此时模型没有直接改文件,而是做出了一个非常"人味"的回应:
我需要看
animation/03-dropdown-menu/style.css和animation/03-dropdown-menu/script.js的内容,请提供这两个文件。
这正是 aider 的权限模型的体现:文件只有先进入会话,模型才能读取与修改。当模型主动要求查看文件时,aider 会询问用户是否授权加入,实录中出现的交互即为此机制:
> animation/03-dropdown-menu/style.css
> animation/03-dropdown-menu/script.js
> Add these files to the chat? y
用户输入 y 授权后,模型看到两个文件的真实内容,随即提出如下编辑方案(这就是上文提到的"edit block"):
animation/03-dropdown-menu/style.css
<<<<<<< ORIGINAL
.visible {
display: block;
}
=======
.visible {
display: block;
animation: expand 0.3s ease-out;
transform-origin: top;
}
@keyframes expand {
0% {
transform: scaleY(0);
}
80% {
transform: scaleY(1.1);
}
100% {
transform: scaleY(1);
}
}
>>>>>>> UPDATED
随后 aider 输出两条关键通知:
> Applied edit to animation/03-dropdown-menu/style.css
> Commit bb3a813 aider: Added bounce animation to dropdown menu.
第一条说明编辑块被自动应用到目标文件(带文件路径前缀 + ORIGINAL/UPDATED 分隔的编辑块格式,正是示例总览页中讲解的 transcript 编辑块写法);第二条说明改动已被自动提交,提交信息以 aider: 前缀开头。
第四轮对话:验证与收尾
用户反馈 that worked!(成功了),模型确认改动生效并说明随时可以继续协助。整段实录在"提出需求 → 授权文件 → 自动改码 → 自动提交 → 人工验证通过"的正反馈里结束——这也是用 aider 做小步迭代修改的标准闭环。
自动提交的背后:改动如何变成一次 git 提交
"Applied edit" 与 "Commit" 几乎同时出现并非巧合,这是 aider 的 auto-commit(自动提交)机制。在源码 aider/coders/base_coder.py 的 auto_commit 中可以看到完整链路:
- 当编辑被应用后,aider 调用
self.repo.commit(fnames=edited, context=context, aider_edits=True, coder=self); - 提交成功后在工具输出区展示结果(对应实录中的
Commit bb3a813 ...); - 若提交失败(如当前目录并非 git 仓库或发生 git 错误),会打印 "Unable to commit: ..." 并继续,而不是中断会话;
- 之后用户仍可通过
/undo撤销并丢弃每一次 aider 自动提交(详见 base_coder.py 中的提示逻辑)。
在 aider/repo.py 的 commit 方法中,aider_edits 参数会改变提交消息与署名语义:当改动由 aider(LLM)生成时,提交信息会自动加上 aider: 前缀(见 repo.py 中 commit_message = "aider: " + commit_message 一行),这正是实录中 "aider: Added bounce animation to dropdown menu." 这一提交信息的来源。
需要说明适用前提:auto-commit 依赖工作目录是一个 git 仓库,且相关文件已被 git 跟踪——示例中的 CSS Exercises 练习仓库满足该条件,因此 /add 与自动提交都畅通无阻。
CSS 技术要点拆解:如何实现"弹跳式展开"
抛开对话外壳,这段练习本身也值得单独剖析,它演示了 README 的 hint 如何一步步转化为真实动画代码。练习要求"下拉菜单展开到接近最终状态时产生回弹",模型给出的实现由三个 CSS 知识点构成:
-
animation: expand 0.3s ease-out;——给元素挂上名为expand的关键帧动画,时长 0.3 秒,缓动曲线为ease-out(先快后慢,模拟"展开落定"的物理感); -
transform-origin: top;——这是 README 明确 hint 的属性。下拉菜单通常挂在触发按钮正下方、自上而下展开,因此把变换原点设在顶部top,让scaleY缩放以顶边为轴进行,视觉上才是"从顶部撑开"; -
@keyframes expand的中间帧——README hint 的另一半。完整序列是:0%:scaleY(0),高度收缩为 0,隐藏状态;80%:scaleY(1.1),先"过冲"到 110% 高度;100%:scaleY(1),回落定格到标准高度。
"过冲再回弹"(overshoot-and-return)是制造 bounce 错觉的经典手法:物体不会直接停在终点,而是越过终点再弹回来。配合
.visible { display: block; }(原本通过切换 display 显隐菜单)与新加的 transform 动画,菜单每次出现都会自带一次轻微的弹跳手感。
最终生效的样式相当于:
.visible {
display: block;
animation: expand 0.3s ease-out;
transform-origin: top;
}
@keyframes expand {
0% { transform: scaleY(0); }
80% { transform: scaleY(1.1); }
100% { transform: scaleY(1); }
}
说明:动画属性只会作用于"添加 class 触发显示"的那一次显现;
display的显隐切换本身不参与过渡,这正是需要把transform而非height作为动画目标的原因——transform可以单独流畅插值,而display是不可动画属性。
复现这段练习:从克隆仓库到跑通一次对话
如果你希望亲自体验与实录完全一致的流程,可以按以下步骤操作(以 CSS Exercises 开源练习仓库为例):
- 准备一个 git 仓库环境,把 The Odin Project 的 CSS Exercises 练习仓库克隆到本地并进入
animation/03-dropdown-menu/目录(aider 的自动提交功能要求工作在 git 仓库内); - 确认
style.css、script.js与README.md就位,它们就是这次练习的载体; - 在该目录启动
aider会话; - 依次发起与实录相同的操作:
- 直接提问
what is this repo?,观察 aider 基于仓库文件清单给出的概括; - 输入
/add animation/03-dropdown-menu/README.md,把练习说明加入会话; - 输入
can you make the changes suggested in the readme?,当 aider 请求查看style.css与script.js时回复y授权加入;
- 直接提问
- 等待 aider 输出 edit block 并自动应用,随后在浏览器/测试环境确认下拉菜单出现了"回弹展开"效果,即用人工验证兜住模型输出。
运行 aider 需要先完成安装与模型配置,通用安装方式参见仓库文档(例如 install.md 系列);示例练习的具体安装方式以 CSS Exercises 仓库自身说明为准。
从这段实录提炼出的通用工作流
虽然表面是一道 CSS 练习题,但整个对话其实浓缩了一套可复用的"AI 结对改代码"范式,适用于任何陌生/既有代码库:
| 阶段 | 实录中的体现 | aider 侧机制 |
|---|---|---|
| 建立仓库认知 | "what is this repo?" 基于文件清单概括项目 | 会话开始即载入仓库结构概览 |
| 引入需求文档 | /add .../README.md |
cmd_add 把文件加入会话上下文 |
| 补全必要上下文 | 模型主动索要 style.css、script.js,用户 y 授权 |
权限模型:LLM 只能读写已入会话的文件 |
| 让模型产出改动 | edit block(ORIGINAL/UPDATED 分隔)描述对 style.css 的修改 |
aider 自动应用编辑 |
| 留下可回退的痕迹 | Commit bb3a813 aider: Added bounce animation... |
auto_commit + repo.py 的 aider: 前缀提交,可 /undo 回退 |
| 人类验收 | "that worked!" | 人工确认效果即会话闭环 |
如果你对这种"transcript 式"的学习材料感兴趣,仓库还提供了多个同类示例,例如对既有 JS 游戏仓库的探索与修改、跨文件协调的复杂改动与调试,以及语义化的搜索替换改造。它们与本文的区别只在于任务领域,交互范式——"读懂 → 加文件 → 请求改动 → 授权 → 自动应用 → 自动提交 → 验证"——是完全一致的,值得对照阅读。
总而言之,css-exercises 实录是一段小而完整的"从零理解并修改真实仓库"示范:模型并没有凭经验瞎写,而是先读练习 README、再向用户申请查看实现文件、最后把 hint 翻译成一段 20 行的 CSS。理解这段对话,也就理解了 aider 的会话权限模型、自动提交约定与 edit block 的形态,而这恰恰是把 aider 用于任何真实项目前最值得补的一课。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00