Aider:终端里的AI结对编程助手
Aider 是一个革命性的终端工具,它让你能够与先进的大语言模型(LLMs)直接“结对编程”。无论你是想从零开始一个新项目,还是对现有代码库进行修改、重构或调试,Aider 都能理解你的需求,并以代码块、差异(diff)或完整文件的形式,直接将修改应用到你本地的代码中。它就像一位精通所有编程语言的资深工程师,随时待命,与你并肩作战。
功能特性
- 广泛的模型支持:支持与数十种主流大语言模型无缝集成,包括 OpenAI (GPT-4o, o1, o3-mini)、Anthropic (Claude 3.5/3.7 Sonnet, Opus)、Google Gemini、DeepSeek 等。你也可以通过 OpenRouter 或本地运行的其他模型来使用 Aider。
- 智能代码编辑:Aider 能理解你发出的自然语言指令,并直接在正确的文件中做出修改。它支持多种编辑格式(如
diff、whole、search/replace),以确保修改的准确性。 - 强大的终端交互:在熟悉的终端环境中工作,无需离开你的开发流程。Aider 提供了命令自动补全、语法高亮、多行编辑等现代化终端体验。
- 内置 Git 集成:自动为每次成功的修改创建 git 提交,让你可以轻松地跟踪 AI 所做的更改,并使用
/undo命令随时回滚到之前的状态。 - 实时 Diff 预览:在 AI 生成修改的过程中,Aider 会以动态 diff 的形式实时显示即将发生的代码变化,让你对改动一目了然。
- 语音输入支持:你可以直接使用语音向 Aider 下达指令,解放双手,让沟通更加自然流畅。
- 智能代码库映射:对于大型项目,Aider 能够智能地分析整个代码库的结构和文件关系,在需要时只向模型发送最相关的代码片段,从而高效地处理复杂问题,并有效管理 token 消耗。
- 聊天记录管理:当对话历史过长时,Aider 会自动智能地总结之前的对话,确保模型始终在有效的上下文窗口内工作,避免信息丢失。
- 便捷的 Web 抓取:你可以直接向 Aider 提供一个网页 URL,它会自动抓取内容并将其转化为上下文,让模型能够基于网页信息进行编程。
安装指南
Aider 推荐通过 Python 的包管理器 pip 进行安装。请确保你的系统已安装 Python 3.8 或更高版本。
1. 基础安装
打开你的终端,执行以下命令即可安装 Aider:
python -m pip install aider-chat
2. 安装额外功能支持
Aider 支持一些可选功能,你可以根据需要安装对应的依赖:
- 语音支持:如需使用语音输入功能,请安装:
python -m pip install 'aider-chat[voice]' - 网页抓取支持:如需使用网页抓取功能,请安装 Playwright:
python -m pip install 'aider-chat[playwright]' # 然后安装 Chromium 浏览器 playwright install --with-deps chromium
3. 配置 API 密钥
Aider 本身是免费的,但它需要调用大语言模型的 API,因此你需要配置相应的 API 密钥。
你可以在终端中设置环境变量,或者在项目的根目录下创建一个 .env 文件。例如,要使用 OpenAI 的模型:
# 设置 OpenAI API 密钥
export OPENAI_API_KEY="你的 OpenAI API 密钥"
如果你想使用 Anthropic 的 Claude 模型,则设置:
export ANTHROPIC_API_KEY="你的 Anthropic API 密钥"
如果你有多个密钥,可以在启动 Aider 时通过 --api-key 参数指定。
使用说明
快速开始
-
进入你的项目目录:
cd /path/to/your/project -
启动 Aider,并指定你想要使用的模型:
# 使用 OpenAI 的 GPT-4o 模型 aider --model gpt-4o # 使用 Anthropic 的 Claude 3.7 Sonnet 模型 aider --model sonnet # 使用 DeepSeek aider --model deepseek/deepseek-chat -
首次启动时,如果当前目录是一个 git 仓库,Aider 会询问你是否允许它创建提交。建议允许,以便更好地管理 AI 的修改。
-
现在,你就可以在 Aider 的提示符 (
>) 下开始提问或下达指令了。
典型使用场景
- 新建功能:在提示符下输入“创建一个新的 Python 函数,用于计算斐波那契数列,并保存在
utils.py文件中”。Aider 会创建文件并写入代码。 - 修改代码:输入“将
app.py中的hello函数改为接受一个name参数,并输出 'Hello, {name}!'”。Aider 会找到对应代码并进行修改。 - 代码解释与提问:输入“
/ask解释一下src/models/user.py中的User类是如何工作的”。Aider 会分析代码并给出解释。 - 添加文件到对话:输入“
/add src/main.js” 将main.js文件加入当前对话,这样 AI 就能看到并编辑它。 - 执行命令:AI 有时会建议你运行一些 shell 命令(如安装依赖、运行测试),你可以在 Aider 中直接输入
!pip install requests来执行。 - 查看差异:在 AI 生成修改的过程中,你会看到实时的代码差异,修改完成后,你可以输入
/commit来提交这些更改。
API 概览
Aider 的核心是 Coder 类,它封装了与不同模型交互、处理文件、管理 git 仓库和编辑代码的逻辑。Aider 为不同的任务定义了多种“Coder”:
AskCoder:主要用于问答,不会修改文件。EditBlockCoder:使用搜索/替换块来精确修改代码,是最常用的 Coder 之一。WholeFileCoder:通过提供完整的更新后文件内容来进行修改。UnifiedDiffCoder:使用类似diff -U0的统一 diff 格式来应用修改。ArchitectCoder:一种双模型模式,一个模型负责设计架构,另一个负责执行编辑。
这些 Coder 通过 main.py 中的 main() 函数进行调度和管理。Aider 还包含 io 模块用于处理输入输出,commands 模块用于处理 / 开头的特殊命令,以及 repo 模块用于与 git 仓库交互。
核心代码
以下是从项目中提取的几个核心模块,展示了 Aider 的关键机制:
1. 核心 Coder 基类 (aider/coders/base_coder.py - 简化示例)
所有 Coder 类型的基类,定义了与 LLM 交互、管理消息、处理文件修改的基础流程。
# aider/coders/base_coder.py (概念性展示)
from aider import prompts
from aider.llm import litellm
class Coder:
def __init__(self, main_model, io, **kwargs):
self.main_model = main_model
self.io = io
self.abs_fnames = set() # 当前对话中的文件绝对路径
self.done_messages = [] # 已完成的对话历史
self.cur_messages = [] # 当前轮次的对话
def run(self, with_message=None):
"""主运行循环,获取用户输入,发送给 LLM,并处理响应"""
if with_message:
user_message = with_message
else:
user_message = self.io.get_input() # 从终端获取用户输入
# 将用户消息添加到当前对话
self.cur_messages.append(dict(role="user", content=user_message))
# 构建发送给 LLM 的消息(包括系统提示、文件内容、历史记录等)
messages = self.format_messages_for_llm()
# 调用 LLM 并处理流式响应
generator = self.main_model.streaming_completion(messages)
self.partial_response_content = ""
for chunk in generator:
self.partial_response_content += chunk
# 实时展示响应(如 diff)
self.show_intermediate_response()
# 完成响应后,解析并应用修改
self.reply_completed()
def reply_completed(self):
"""LLM 回复完成后调用,用于解析和应用修改"""
edits = self.get_edits() # 从回复中提取编辑操作(由子类实现)
if edits:
self.apply_edits(edits) # 应用编辑(由子类实现)
if self.repo: # 如果有 git 仓库,自动提交
self.repo.commit()
def format_messages_for_llm(self):
"""构建完整的消息列表,供 LLM 使用"""
# 包括系统提示、只读文件内容、可编辑文件内容、对话历史等
chat_chunks = ChatChunks()
chat_chunks.system = [{"role": "system", "content": self.gpt_prompts.main_system}]
chat_chunks.readonly_files = self.get_readonly_files_content()
chat_chunks.chat_files = self.get_editable_files_content()
chat_chunks.done = self.done_messages
chat_chunks.cur = self.cur_messages
return chat_chunks.all_messages()
2. 搜索/替换编辑块实现 (aider/coders/editblock_coder.py)
这是最常用的编辑格式之一。它从 LLM 的回复中解析出 <<<<<<< SEARCH 和 >>>>>>> REPLACE 标记的代码块,并进行精确替换。
# aider/coders/editblock_coder.py
from .base_coder import Coder
from .editblock_prompts import EditBlockPrompts
import re
class EditBlockCoder(Coder):
edit_format = "diff"
gpt_prompts = EditBlockPrompts()
def get_edits(self):
"""从 LLM 回复中解析搜索/替换块"""
content = self.partial_response_content
edits = []
# 使用正则表达式查找所有的 SEARCH/REPLACE 块
# 格式: path/to/file\n```\n<<<<<<< SEARCH\n...\n=======\n...\n>>>>>>> REPLACE\n```
pattern = r'(.+?)\n```\n<<<<<<< SEARCH\n(.*?)=======\n(.*?)>>>>>>> REPLACE\n```'
matches = re.findall(pattern, content, re.DOTALL | re.MULTILINE)
for match in matches:
path, original, updated = match
edits.append((path.strip(), original, updated))
return edits
def apply_edits(self, edits):
"""将解析出的编辑应用到文件中"""
for path, original, updated in edits:
full_path = self.abs_root_path(path)
if not self.io.path_exists(full_path):
# 如果文件不存在,可能是创建新文件
self.io.write_text(full_path, updated)
continue
content = self.io.read_text(full_path)
# 在文件中查找精确匹配的 original 代码块
if original in content:
new_content = content.replace(original, updated, 1) # 只替换第一个匹配
self.io.write_text(full_path, new_content)
else:
# 如果找不到完全匹配,尝试使用更模糊的匹配(如忽略空白)
# 这里简化处理,实际代码会更复杂
self.io.tool_error(f"警告:在 {path} 中找不到要替换的代码块。")
3. 实时 Diff 生成器 (aider/diffs.py)
这个模块负责生成实时的、正在进行的代码修改的 diff 视图,让用户能边看边确认。
# aider/diffs.py
import difflib
def diff_partial_update(lines_orig, lines_updated, final=False, fname=None):
"""
生成一个智能的 diff,只显示到目前为止的修改,并忽略尚未完成的部分。
这对于流式输出非常有用。
"""
# ... (前面的代码用于计算进度条和找到最后一个未删除的行) ...
# 创建一个定制的 diff,显示修改
diff = difflib.unified_diff(lines_orig, lines_updated, n=3)
diff = list(diff)[2:] # 去掉文件头信息
diff = "".join(diff)
# 用安全的 fence 包裹 diff 以防与 markdown 冲突
show = f"```diff\n"
if fname:
show += f"--- {fname} (original)\n+++ {fname} (updated)\n"
show += diff
show += f"\n```\n\n"
return show
4. Git 仓库集成 (aider/repo.py)
Aider 与 Git 深度集成,自动为更改创建提交,并支持撤销。
# aider/repo.py
class GitRepo:
def __init__(self, io, fnames, ...):
self.repo = git.Repo(Path.cwd())
self.io = io
def commit(self, message=None):
"""自动提交所有更改"""
if not self.repo.is_dirty():
return False
# 自动生成提交信息或使用提供的
if not message:
message = self.generate_commit_message() # 调用模型生成提交信息
self.repo.git.add(A=True) # 添加所有更改
self.repo.index.commit(message)
self.io.tool_output(f"已提交更改:{message[:50]}...")
return True
def undo(self):
"""撤销上一次 AI 提交的更改"""
if not self.repo:
self.io.tool_error("不在 git 仓库中,无法撤销。")
return
# 执行 git reset --hard HEAD~1 来撤销上一次提交
self.repo.git.reset('--hard', 'HEAD~1')
self.io.tool_output("已撤销上一次提交。")
oUjNIuxTucK0Qkc3YJBJUIGq0DFPdQoo/tO6vkN5+dM=