aider `--watch-files` 实战指南:在 IDE 中直接编写 “AI“ 注释来驱动编码与提问
2026/9/9 12:59:00 网站建设 项目流程

aider--watch-files实战指南:在 IDE 中直接编写 "AI" 注释来驱动编码与提问

【免费下载链接】aideraider is AI pair programming in your terminal项目地址: https://gitcode.com/GitHub_Trending/ai/aider

导读

aider 是一款运行在终端里的 AI 结对编程工具,而--watch-files模式让你不必离开自己熟悉的 IDE 或编辑器:只需在任意代码文件的注释里写下以AIAI!AI?开头/结尾的单行指令并保存,aider 就会自动感知文件变化、收集这些"AI 注释",把修改请求或疑问直接交给大模型执行。本文将完整拆解 AI 注释的语法规则、六种典型用法、极简写法,并结合 watch.py 的源码与 test_watch.py 测试用例,讲透其背后的识别正则、触发机制与提示词组装原理,读完即可在 VSCode 等编辑器中流畅落地这套工作流。

什么是 AI 注释:把 IDE 变成 aider 的输入面板

aider 的常规交互方式是终端里的聊天框。而--watch-files模式则换了一种更贴合"在你正在编辑的代码旁边下指令"的协作方式:aider 会持续监听仓库中的所有文件,只要检测到你在文件中写下的 AI 指令注释,就会自动拾取并执行。

启动方式很简单,在终端运行:

aider --watch-files

从源码看,--watch-files定义在 args.py,是一个布尔开关(BooleanOptionalAction),默认关闭,因此也可以用--no-watch-files显式关闭。它的配置入口共有三处,便于不同使用习惯:

配置途径写法依据
命令行参数aider --watch-filesargs.py
环境变量AIDER_WATCH_FILES=true(默认falsesample.env、options.md
配置文件watch-files: true.aider.conf.ymlaider_conf.md、sample.aider.conf.yml

aider 究竟在找什么样的注释

aider 会扫描仓库中所有文件,查找以#//--开头的单行注释,并从中挑出那些"以AIAI!AI?开头或结尾"的行。例如 Python 风格:

# Make a snake game. AI! # What is the purpose of this method AI?

//注释语言同理:

// Write a protein folding prediction engine. AI!

两类特殊标记对应两种不同的动作:

  • AI!(带感叹号):触发 aider 对代码执行修改;
  • AI?(带问号):触发 aider 回答你的问题。

普通的不带!/?AI注释只是被"记录在案",不会被立即执行——你可以攒够一批后,用一条AI!统一触发。

源码视角:AI 注释到底是怎么被"认出来"的

识别逻辑的核心在 watch.py 中FileWatcher类编译好的这条正则:

ai_comment_pattern = re.compile( r"(?:#|//|--|;+) *(ai\b.*|ai\b.*|.*\bai[?!]?) *$", re.IGNORECASE )

几点值得注意的实现细节:

  • 该正则对大小写不敏感(re.IGNORECASE),所以文档示例中才会出现小写ai的合法写法;
  • 前缀注释符覆盖#//--,还额外支持了;+(分号),这是为 Lisp 家族注释风格预留的(get_ai_comments中注释 "Added semicolon for Lisp comments"),见 watch.py;
  • get_ai_comments()在 watch.py 中逐行扫描,返回三个结果:注释所在行号、注释原文、动作标记(None/"!"/"?")。判断动作时对注释去注释符、去空格后检查是否以ai!/ai?开头或结尾。

这些边界情况都有专门的测试夹具覆盖:test_watch.py 分别验证了 Python 夹具 tests/fixtures/watch.py、JavaScript 夹具 tests/fixtures/watch.js(内含 16 处 AI 注释)、提问夹具tests/fixtures/watch_question.js(动作标记为?)以及 Lisp 夹具tests/fixtures/watch.lisp

端到端示例:让 aider 替你实现一个函数

在代码里写下这样一行注释并保存:

function factorial(n) // Implement this. AI!

aider 检测到以AI!结尾的注释后,会把文件加入会话并让模型"就地实现",于是文件被更新为:

function factorial(n) { if (n === 0 || n === 1) { return 1; } else { return n * factorial(n - 1); } }

请求完成后,aider 还会顺手把这段 AI 注释从代码中移除(详见下文"幕后原理")。

支持的注释风格与文件过滤规则

原文档明确:aider 只监听这些类型的单行注释

# Python and bash style // Javascript style -- SQL style

它会在所有文件中查找这些注释形态,因此即使注释符与当前文件语言不匹配也没关系——例如在 Python 文件里写// ... AI!同样能被识别并触发,因为它们只是充当 aider 的"指令载体"。

在监控层面,watch.py 还内置了几道"闸门",避免无关文件打扰:

  • gitignore 过滤load_gitignores()(watch.py)会把仓库.gitignore.aiderignore与一长串内置默认忽略项(如.git.envnode_modules/.venv/.idea/.vscode/*.log*.svg*.pdf、编辑器备份文件*~*.swp*.pyc等)合并成一份PathSpec,命中即跳过,见 watch.py;
  • 文件大小上限:超过 1MB 的文件不读取内容、不参与匹配(watch.py);
  • 路径范围:只监控仓库根目录(root)内的文件,配合--subtree-only时可收窄到当前子目录(见 main.py)。

AI 注释的四种高效玩法

这套机制非常灵活,文档中展示了多种典型用法。

1. 就地(in-context)指令

把请求写在要改的那个函数里,让上下文"近在咫尺":

app.get('/sqrt/:n', (req, res) => { const n = parseFloat(req.params.n); // Add error handling for NaN and less than zero. AI! const result = math.sqrt(n); res.json({ result: result }); });

2. 多条注释 + 最终统一触发

可以先写多条不带!AI注释,最后再用一条AI!触发。这些注释还可以分散在多个文件里,用于协调跨文件的联动修改,但记得把AI!放在最后:

@app.route('/factorial/<int:n>') def factorial(n): if n < 0: return jsonify(error="Factorial is not defined for negative numbers"), 400 # AI: Refactor this code... result = 1 for i in range(1, n + 1): result *= i # ... into to a compute_factorial() function. AI! return jsonify(result=result)

3. 长文本指令块

需要较长说明时,可以用一整块注释写清楚,只要保证其中至少有一行以AIAI!开头/结尾,就能引起 aider 的注意:

# Make these changes: AI! # - Add a proper main() function # - Use Click to process cmd line args # - Accept --host and --port args # - Print a welcome message that includes the listening url if __name__ == "__main__": app.run(debug=True)

4. 用一条注释把文件"加入"会话

在终端聊天里通常用/add添加文件。而在--watch-files模式下,只需在文件中放一个#AI注释并保存,文件就会被自动加入 aider 会话。此时即使你立刻撤销/删除这条注释,文件也仍然留在会话中

这一点可以从源码中得到印证:process_changes()(watch.py)会把变更文件加入coder.abs_fnames集合并打印Added <file> to the chat;如果文件里只有普通AI注释、没有任何!/?触发标记,则只做"添加文件"动作并提示:

End your comment with AI! to request changes or AI? to ask questions

与终端聊天无缝衔接:先用注释启动,再进终端深化

用 AI 注释把改动"开个头"往往很高效,但后续想继续打磨时,切回终端聊天同样方便——因为aider 聊天上下文里保留了刚才这批 AI 注释的记录,你可以顺着它们自然延续。

终端聊天还提供了大量 AI 注释之外的进阶能力:

  • /undo回退不满意的改动(在 IDE 里也可用编辑器自身的撤销来逐步回溯文件历史);
  • 使用聊天模式提问或求助;
  • /tokens/clear/drop/reset管理聊天上下文——AI 注释会把文件加入会话,累积过多时记得用这些命令清理不再需要的上下文;
  • 修复 lint 与测试错误;
  • 运行 Shell 命令;
  • 等等。

偷懒指南:极简ai!注释也完全够用

上面所有示例都用了完整句子与规范大小写,那是为了便于讲解。实际上大多数 LLM 完全能处理歧义并推断隐含意图,因此你可以写得非常随意:既可以用小写ai/ai!,也可以把请求本身压到最简。

当上下文足以表明意图时,一句ai!或许就够了。例如在一个充满数学函数的程序里实现阶乘函数,下面任一种写法通常都能生效:

function factorial(n) // ai!

或者:

// add factorial() ai!

与其写冗长的 "Add error handling for NaN and less than zero",让 aider 自己推断需求即可,这样简单的一句往往就够:

app.get('/sqrt/:n', (req, res) => { const n = parseFloat(req.params.n); // add error handling ai! const result = math.sqrt(n); res.json({ result: result }); });

同理,前面的重构需求其实也可以浓缩成这样:

@app.route('/factorial/<int:n>') def factorial(n): if n < 0: return jsonify(error="Factorial is not defined for negative numbers"), 400 # ai refactor... result = 1 for i in range(1, n + 1): result *= i # ... to compute_factorial() ai! return jsonify(result=result)

至于到底需要写多明确,随你与所选 LLM 的磨合自然形成手感。

幕后原理:AI 注释如何被喂给大模型

aider 会把你收集到的 AI 注释连同 repo map(仓库地图) 以及会话中已加入的所有代码上下文一起发送给 LLM;同时它会从代码中把 AI 注释"抽取并高亮"出来,配以所在位置的代码上下文,让模型精确理解注释与代码的镶嵌关系。

构造给模型的指令模板定义在 watch_prompts.py:修改类动作使用watch_code_prompt,提问类动作使用watch_ask_prompt(以/ask命令形式发起)。修改类提示词的要点是:告诉模型注释(用标记)就藏在共享的代码文件中、包含了用户的指令,请按要求修改并把代码里的所有 AI 注释一并删除

The "AI" comments below marked with █ can be found in the code files I've shared with you. They contain your instructions. Make the requested changes. Be sure to remove all these "AI" comments from the code! todo_app.py: ⋮... │class TodoList: ⋮... │ def __init__(self): │ """Initialize an empty todo list""" ⋮... │ │ def list_tasks(self): │ """Display all tasks""" █ # Implement this. AI! │ │def main(): │ todo = TodoList() │ ⋮...

这段上下文拼装由process_changes()完成:它会遍历会话中已跟踪的所有文件,重新提取 AI 注释,再用grep_astTreeContext生成带定位标记(mark_lois=Trueadd_lines_of_interest())的代码上下文,注释行会按缩进树结构展示出来,见 watch.py。

一次完整的触发链路

把上面的实现串起来,一次AI!触发在仓库内走的是这条链路:

  1. io.py:aider 进入等待输入时后台启动FileWatcher(独立守护线程,见 watch.py);
  2. 文件保存引发变化后,io.py 检测到输入被中断(interrupt_input),随即调用process_changes()
  3. 该函数先"添加文件进会话",再根据动作标记!/?选择watch_code_promptwatch_ask_prompt模板;
  4. 模板 + 高亮注释上下文作为一条用户消息注入会话,交给 LLM 执行修改或回答;
  5. main.py 负责在启动时按--watch-files创建并绑定FileWatcher

这套特性最初源自对 IDE 文件监听思路的借鉴(受 Override 项目"监听文件变化、从代码内特定分隔符中提取内嵌提示"方式的启发),aider 将其简化为人人都能上手的AI/AI!/AI?约定。想进一步验证识别与过滤行为的读者,可以阅读对应的单元测试 tests/basic/test_watch.py,或直接查看各语言夹具 tests/fixtures/watch.py 与 tests/fixtures/watch.js 里的真实注释样例。

【免费下载链接】aideraider is AI pair programming in your terminal项目地址: https://gitcode.com/GitHub_Trending/ai/aider

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询