
1. 从写提示词到搭循环Loop Engineering 到底在解决什么问题大多数人接触 AI 编程工具的第一反应是我该怎么把提示词写得更精准。这个思路在单次问答场景里没问题但一旦你开始用 Claude Code、Codex、Cursor 这类工具做真实项目就会发现一个尴尬的事实单次提示词的质量上限远低于你反复迭代的效率下限。你花十分钟打磨一句提示词不如花三分钟搭一个能自动跑三轮的循环。Loop Engineering循环工程这个词最近在开发者圈子里被频繁提起但它并不是某个官方框架的名字而是一种工作范式的总结。核心思想很朴素把 AI 编程工具从你问我答的对话模式改造成定义目标 → 自动执行 → 检查结果 → 修正偏差 → 再执行的闭环系统。你不再是那个每次都要手动敲指令的人而是设计循环规则的人。我最初接触这个概念是在一个重构项目里。当时用 Claude Code 处理一个遗留的 Python 服务代码有三千多行函数之间耦合严重。如果按传统方式我得一个函数一个函数地让 AI 改改完还要自己检查有没有破坏调用关系。后来我换了个思路写一个循环脚本让 Claude Code 每次只处理一个函数处理完自动跑测试测试不过就把错误信息喂回去让它重试最多重试三次。结果原本预计两天的工作量一个下午就跑完了。这个经历让我意识到Loop Engineering 的价值不在于让 AI 变得更聪明而在于让 AI 的犯错成本变得可控。单次对话里 AI 犯错你得重新组织语言再问一遍循环系统里 AI 犯错错误信息会自动成为下一轮的输入你只需要设定好什么算成功和最多试几次。适合读这篇内容的人有三类一是已经在用 Claude Code 或 Codex 但觉得效率没达到预期的开发者二是想从 Cursor 的图形界面转向更自动化工作流的人三是团队里需要把 AI 编程工具标准化、流程化的技术负责人。如果你还没装过这些工具也没关系我会在讲循环设计的时候顺带把环境配置的关键点带出来。2. 循环工程的四个核心组件目标、执行器、检查器、反馈通道2.1 目标定义为什么把代码改好不是一个合格的目标循环工程的第一步不是写代码而是把目标拆成机器能判断的格式。很多人在这里就卡住了因为他们给 AI 的目标是优化这段代码或者修复这个 bug。这种目标对人来说很清晰但对循环系统来说完全不可执行——系统怎么知道优化到什么程度算完成bug 修没修好谁来判定我在实际项目里总结出一个目标定义的模板包含三个要素输入状态、期望状态、判定条件。举个例子不要说修复登录接口的报错而要说输入是一个返回 500 的登录接口调用期望状态是返回 200 且响应体包含 token 字段判定条件是连续三次调用都满足期望。这个模板看起来啰嗦但它直接决定了循环能不能自动跑下去。判定条件尤其关键它必须是机器可验证的。常见的判定条件包括测试用例通过率、编译是否成功、lint 检查是否零报错、接口返回码是否符合预期、代码覆盖率是否达到阈值。如果你给不出机器可验证的判定条件那这个任务就不适合放进循环老老实实手动做。还有一个容易被忽略的点目标要可拆分。一个循环只解决一个原子问题。我见过有人写一个循环让 AI把整个项目从 Python 2 迁移到 Python 3结果跑了两个小时AI 在第五个文件就迷失了方向后面的修改全是胡编。正确的做法是拆成逐个文件迁移 → 每个文件迁移后跑单元测试 → 测试不过就回滚并记录这样的子循环。2.2 执行器选型Claude Code、Codex、Cursor 在循环里各自适合什么位置执行器就是实际干活的那个 AI 工具。Claude Code、Codex、Cursor 都能当执行器但它们在循环里的表现差异很大选错了会让整个循环的效率打对折。Claude Code 的优势在于终端原生。它可以直接执行 shell 命令、读写文件、跑测试这意味着你的循环脚本可以用最少的胶水代码把它串起来。我通常用 Claude Code 处理需要跑命令验证的任务比如重构后跑测试、修改配置后重启服务检查日志。它的输出是流式的你可以实时看到它在干什么出问题容易定位。Codex 的优势在于代码补全和单文件级别的精准修改。如果你循环的任务是给每个函数补文档字符串或者把每个 var 改成 letCodex 的响应速度和准确率通常比 Claude Code 高。但 Codex 在跨文件操作和命令执行上偏弱所以它更适合作为循环里的精细加工环节而不是全流程执行环节。Cursor 的优势在于图形界面和上下文管理。它能看到你当前打开的文件、光标位置、最近的编辑历史这些信息在循环里可以作为额外的上下文输入。但 Cursor 的自动化接口不如前两者开放如果你要搭一个完全无人值守的循环Cursor 通常需要配合它的 CLI 工具或者外部脚本触发。我的实际搭配方案是Claude Code 做主力执行器Codex 做代码生成环节的补充Cursor 做人工介入时的调试界面。循环脚本用 Python 写通过子进程调用 Claude Code 的 CLI把任务描述和上下文传进去捕获输出后判断是否需要重试。2.3 检查器设计自动判定比自动执行更难检查器是循环工程里最容易被低估的部分。很多人把精力全花在怎么让 AI 执行上结果循环跑起来了但检查器太弱AI 改错了也判定为成功最后交付的代码一堆隐藏问题。检查器的设计原则是能用确定性工具判定的绝不用 AI 判定。编译是否通过用编译器判定测试是否通过用测试框架判定代码风格是否合规用 linter 判定。只有在这些确定性工具覆盖不到的地方才考虑用 AI 做检查而且 AI 检查的结果只能作为参考不能作为最终判定。我常用的检查器组合是这样的第一层是语法和编译检查用对应语言的编译器或解释器第二层是单元测试用项目原有的测试框架第三层是静态分析用 ESLint、Pylint、Clippy 这类工具第四层才是 AI 检查让另一个 AI 实例或者同一个 AI 的新会话审查代码逻辑是否合理。前三层任何一层不过直接触发重试第四层不过记录警告但不阻塞流程。这里有个实操细节检查器的输出格式要统一。编译器报错、测试失败、lint 警告这些信息的格式各不相同如果直接喂回给 AI它可能抓不住重点。我通常会写一个格式化函数把各种检查结果统一成文件路径 行号 问题描述 严重程度的结构化文本再传给执行器。这个格式化函数大概三十行代码但能让重试的成功率提升不少。2.4 反馈通道错误信息怎么喂回去才有效反馈通道决定了循环的学习能力。同样一个错误喂回去的方式不同AI 修正的成功率能差一倍以上。最差的反馈方式是直接把原始错误日志贴回去。比如编译器报了一百行错你全贴给 AI它大概率会挑几个显眼的改剩下的继续错。好的反馈方式是提取关键错误 附加上下文 明确修正要求。关键错误通常只有前三条最重要后面的往往是连锁反应上下文包括出错的文件、相关的函数、最近的修改记录修正要求要具体比如只修改第 45 行的类型声明不要动其他逻辑。我还会在反馈里加一个历史尝试记录。如果这是第三次重试我会告诉 AI前两次你分别尝试了方案 A 和方案 B都失败了错误信息分别是……这次请换一个思路。这个信息能有效避免 AI 在同一个坑里反复摔。另一个技巧是限制单次修改的范围。循环里最怕 AI 一次改太多改出连锁问题。我会在反馈里明确说本次只允许修改一个文件或者本次只允许修改函数签名不允许改函数体。范围越小检查器越容易判定循环收敛越快。3. 从零搭一个可跑的循环以批量重构为例的完整实操3.1 环境准备Claude Code 和 Codex 的安装与配置要点在搭循环之前得先把执行器装好。Claude Code 的安装方式取决于你的系统macOS 和 Linux 下通常通过包管理器或者官方提供的安装脚本Windows 下建议用 WSL 环境因为 Claude Code 的很多能力依赖 Unix 风格的 shell。安装完成后第一件事是验证 CLI 能不能正常调用在终端里跑一个简单的命令看它有没有响应。Codex 的安装相对简单它通常作为编辑器插件或者独立 CLI 存在。如果你用的是 VS Code可以在扩展市场里搜到相关插件如果要用 CLI 模式需要单独配置。Codex 的配置文件一般在用户目录下的隐藏文件夹里里面可以设置默认模型、超时时间、重试次数这些参数。我建议把超时时间设长一点因为循环里经常要处理大文件超时太短会导致任务被误判为失败。Cursor 的配置重点在语言设置上。很多人第一次用 Cursor 会发现它默认用英文回复想改成中文需要在设置里找到语言选项或者在对话开头明确说请用中文回复。Cursor 的注册流程对国内用户来说有个坑手机号填写环节需要选择国家代码如果直接填手机号会提示格式错误。正确的做法是先在下拉菜单里选对应的国家代码再填号码。还有一个跨工具的配置问题如果你同时用 Claude Code 和 Codex要注意它们的默认工作目录可能不同。Claude Code 通常以当前终端所在目录为工作目录Codex 可能以项目根目录为工作目录。在循环脚本里我建议显式指定工作目录避免 AI 改错文件。3.2 循环脚本的骨架用 Python 串起执行器和检查器下面是我实际在用的循环脚本骨架用 Python 写的核心逻辑大概一百行。你可以直接拿去改。import subprocess import json import os from pathlib import Path MAX_RETRIES 3 WORK_DIR Path(/path/to/your/project) def run_executor(task_description, context, attempt): 调用 Claude Code 执行任务 prompt f 任务{task_description} 上下文{context} 这是第 {attempt} 次尝试。 要求只修改必要的文件修改后不要执行测试我会单独跑。 result subprocess.run( [claude, -p, prompt], cwdWORK_DIR, capture_outputTrue, textTrue, timeout300 ) return result.stdout, result.stderr def run_checker(): 跑测试和 lint返回结构化结果 test_result subprocess.run( [pytest, -x, --tbshort], cwdWORK_DIR, capture_outputTrue, textTrue ) lint_result subprocess.run( [pylint, src/, --output-formatjson], cwdWORK_DIR, capture_outputTrue, textTrue ) return { test_passed: test_result.returncode 0, test_output: test_result.stdout[-2000:], lint_output: lint_result.stdout[-1000:] } def format_feedback(check_result, attempt): 把检查结果格式化成 AI 能理解的反馈 if check_result[test_passed]: return None feedback f第 {attempt} 次尝试失败。\n feedback f测试输出\n{check_result[test_output]}\n feedback 请只修复导致测试失败的问题不要做额外改动。 return feedback def main(): task 把 src/utils.py 里的所有函数改成类型注解完整的版本 context 项目使用 Python 3.10类型检查用 mypy for attempt in range(1, MAX_RETRIES 1): print(f 第 {attempt} 次尝试 ) stdout, stderr run_executor(task, context, attempt) print(f执行器输出{stdout[:500]}) check_result run_checker() if check_result[test_passed]: print(检查通过循环结束) break feedback format_feedback(check_result, attempt) context feedback # 把反馈作为下一轮的上下文 else: print(达到最大重试次数需要人工介入) if __name__ __main__: main()这个骨架的关键设计点有三个。第一执行器和检查器分离。执行器只负责改代码检查器只负责判定两者通过文件系统交互。这样你可以随时替换其中任何一个比如把 Claude Code 换成 Codex检查器不用动。第二上下文是累积的。每一轮的反馈会覆盖上一轮的上下文但反馈里包含了历史尝试的信息。这样 AI 既知道当前错在哪也知道之前试过什么。第三最大重试次数是硬限制。我设的是 3 次超过就停下来人工介入。这个数字可以根据任务复杂度调整但不要设太大因为 AI 在同一个问题上连续失败三次以上通常意味着任务定义有问题继续重试只是浪费资源。3.3 第一次跑循环最容易翻车的三个地方我第一次跑这个循环的时候连续翻车了三次每次都是不同的问题。现在回头看这三个坑几乎是所有人都会踩的。第一个坑是工作目录不对。Claude Code 默认以终端当前目录为工作目录但我的脚本是从项目根目录启动的而实际要改的文件在子目录里。结果 AI 在根目录找文件找不到开始自己创建新文件把项目结构搞乱了。修复方法是在脚本里显式指定cwd参数并且在任务描述里写清楚文件的相对路径。第二个坑是测试跑太久。我的项目测试套件跑一遍要三分钟循环里每轮都跑全量测试三轮下来光测试就花了九分钟。后来我改成只跑受影响的测试文件用 pytest 的-k参数指定测试范围单轮测试时间降到二十秒。这个优化的前提是你要知道每次修改影响哪些测试如果不知道可以在任务描述里让 AI 顺便输出它改了哪些文件然后根据文件路径推断测试范围。第三个坑是AI 改完不保存。Claude Code 在某些模式下修改文件后需要显式确认才写入磁盘如果脚本里没有处理这个确认步骤AI 的输出看起来改了但文件实际没变检查器跑的还是旧代码。修复方法是在调用 CLI 时加上自动确认的参数或者在 prompt 里明确说直接写入文件不要询问。3.4 让循环收敛更快限制修改范围和增加中间检查点循环跑起来之后下一个要解决的问题是收敛速度。我遇到过最慢的一次一个简单的重构任务跑了五轮才通过每轮都在改不同的地方改完 A 破坏了 B改完 B 又破坏了 C。后来我加了两个约束收敛速度明显提升。第一个约束是单轮单文件。在任务描述里明确说本次只允许修改一个文件如果你认为需要改多个文件请先只改最重要的那个并在输出里说明其他文件需要后续处理。这个约束把每轮的修改范围缩小了检查器更容易判定AI 也不容易改出连锁问题。第二个约束是中间检查点。对于复杂的重构任务我会在循环里插入多个检查点每个检查点跑一次轻量级检查。比如第一轮只检查语法能不能通过编译第二轮检查单元测试第三轮检查集成测试。这样问题能在早期被发现不会等到最后一轮才暴露。还有一个技巧是给 AI 一个参考实现。如果项目里已经有类似功能的代码我会在上下文里附上那段代码让 AI 照着改。这比让它从零生成要快得多也更符合项目原有的风格。4. 循环工程的边界什么任务不该放进循环4.1 需要人类审美判断的任务循环工程再强大也有它处理不了的任务。最典型的是需要审美判断的任务比如 UI 设计、交互流程优化、文案撰写。这些任务的好没有机器可验证的标准你没法写一个检查器来判断这个按钮放这里好不好看。我试过让循环处理前端样式调整目标是让页面看起来更现代。结果 AI 改了三轮每轮都改了一堆 CSS但检查器只能判断页面能不能正常渲染判断不了看起来现不现代。最后交付的版本技术上没问题但视觉上还不如我手动调十分钟。这类任务的正确做法是AI 做执行人做判定。让 AI 生成多个方案你挑一个然后让 AI 按你挑的方向细化。循环的检查器由你来当但循环的执行器还是 AI。4.2 涉及外部依赖和网络状态的任务循环里的检查器通常假设环境是稳定的但现实里很多任务依赖外部状态。比如修复调用第三方 API 的报错这个报错可能是第三方服务临时挂了也可能是你的代码写错了。如果循环里不区分这两种情况AI 会一直改代码但问题根本不在代码上。我的处理方式是在检查器里加一个环境预检步骤。跑任务之前先调一次外部依赖确认它是可用的。如果不可用直接终止循环并报警不要浪费 AI 的算力。这个预检逻辑因项目而异但核心思路是把环境问题和代码问题分开处理。4.3 安全敏感和不可逆的操作有一类任务绝对不能放进自动循环涉及数据删除、权限变更、生产环境部署的操作。这些操作一旦出错后果不可逆而循环的重试机制在不可逆操作面前毫无意义——删掉的数据重试一百次也回不来。我的原则是循环只处理可回滚的操作。代码修改可以回滚因为你有版本控制配置文件修改可以回滚因为你有备份但数据库迁移、生产环境发布、密钥轮换这些操作必须人工确认每一步。如果非要用 AI 辅助也只能让它生成操作方案由人来执行。4.4 任务定义本身模糊的情况最后一个边界是任务定义模糊。如果你自己都说不清楚做成什么样算完成那这个任务就不适合放进循环。循环工程的前提是目标可判定目标不可判定循环就变成了随机游走。我判断任务是否适合循环的标准很简单能不能用一句话写出判定条件且这句话里不包含合理适当优雅这类主观词汇。能写出来就适合写不出来就先回去把需求想清楚。5. 多工具协同的进阶玩法Claude Code 和 Codex 怎么配合5.1 分工策略谁做规划谁做执行当你同时有 Claude Code 和 Codex 的时候一个自然的想法是让它们分工。我的分工策略是Claude Code 做规划和验证Codex 做代码生成。具体来说循环的第一阶段让 Claude Code 分析任务输出一个修改计划包括要改哪些文件、每个文件改什么、改完怎么验证。第二阶段把计划拆成子任务每个子任务交给 Codex 执行代码生成。第三阶段让 Claude Code 跑检查器验证 Codex 的产出。这个分工的依据是两者的能力差异。Claude Code 在理解项目结构、执行命令、分析错误方面更强适合做大脑Codex 在单文件代码生成方面更快更准适合做手。让它们各司其职比让一个工具从头做到尾效率高。5.2 上下文传递两个工具之间怎么共享状态多工具协同最大的难点是上下文传递。Claude Code 分析出来的计划怎么传给 CodexCodex 改完的代码怎么让 Claude Code 知道我的做法是用一个中间文件做状态存储。Claude Code 输出的计划写到plan.json里Codex 从里面读任务改完代码后把修改记录写到changes.json里Claude Code 再从里面读修改记录做验证。这个中间文件是纯文本的 JSON两个工具都能读写不依赖任何特定工具的私有格式。这个设计的另一个好处是可追溯。循环跑完之后你可以翻看plan.json和changes.json清楚地知道每一轮 AI 做了什么决策、改了什么代码。出问题的时候这个记录比看终端日志有用得多。5.3 冲突处理两个工具改同一个文件怎么办多工具协同最容易出的问题是冲突。Claude Code 和 Codex 同时改一个文件后改的会覆盖先改的。我的处理方式是在循环里加一个文件锁机制每个文件同时只能被一个工具修改修改期间其他工具要排队。实现上很简单在中间文件里维护一个当前被锁定的文件列表工具开始修改前先检查文件是否被锁被锁就等待或者跳过。这个机制在单机环境下用文件锁就能实现不需要复杂的分布式协调。还有一个更简单的策略按文件类型分工。让 Claude Code 只改配置文件和测试文件Codex 只改源代码文件。这样两者永远不会碰同一个文件冲突自然就没了。这个策略的代价是灵活性降低但对于大多数项目来说够用了。6. 实测数据与调优经验循环跑了一百次之后我学到了什么6.1 成功率与重试次数的关系我在一个中型项目上跑了大概一百次循环记录了每次的成功率和重试次数。数据很有意思第一次尝试就成功的比例大约是 45%第二次成功的比例是 30%第三次成功的比例是 15%三次都失败的比例是 10%。这个分布说明两件事。第一大部分任务其实不需要循环单次执行就能搞定循环的价值主要体现在那 55% 需要重试的任务上。第二三次是一个合理的上限因为第三次之后成功率急剧下降继续重试的边际收益很低。我还发现任务粒度越细首次成功率越高。把一个大任务拆成五个小任务每个小任务的首次成功率能到 70% 以上。所以与其优化重试机制不如优化任务拆分。6.2 哪些参数最影响循环效率影响循环效率的参数有好几个但实测下来最关键的是三个超时时间、上下文长度、检查器粒度。超时时间设太短大文件处理到一半就被掐断任务失败设太长真失败的任务要等很久才判定。我的经验值是单文件任务设 120 秒多文件任务设 300 秒超过这个时间大概率是 AI 卡住了不如重试。上下文长度直接影响 AI 的理解质量。上下文太短AI 不知道项目背景改出来的代码风格不一致上下文太长AI 抓不住重点容易跑偏。我的做法是只传相关文件的内容不传整个项目。相关文件的判断可以基于 import 关系也可以让 AI 自己说它需要看哪些文件。检查器粒度是很多人忽略的参数。检查太粗问题发现不了检查太细每轮跑检查的时间比 AI 执行的时间还长。我的平衡点是语法检查每轮都跑单元测试每两轮跑一次集成测试只在最后一轮跑。6.3 循环跑崩了怎么排查循环跑崩是常事关键是要能快速定位问题。我总结了一个排查顺序从外到内逐层检查。先看执行器有没有正常启动。有时候 CLI 路径配错了或者环境变量没设执行器根本没跑起来但脚本没报错因为子进程的失败被吞掉了。检查方法是看执行器的输出是不是空的空的基本就是没启动。再看检查器的判定逻辑对不对。我遇到过一次检查器把测试通过判定为失败因为测试框架的返回码和预期不一致。这种问题看检查器的原始输出就能发现。然后看反馈通道有没有把信息传对。有时候检查器判定对了但反馈格式化的时候把关键信息截断了AI 收到的反馈不完整自然改不对。检查方法是把每轮传给 AI 的 prompt 打印出来人工看一眼。最后看任务定义本身有没有问题。如果前面三层都没问题循环还是跑不通那大概率是任务定义太模糊或者太复杂。这时候不要继续调参数回去重新拆任务。6.4 长期维护循环脚本本身也需要版本管理最后一个经验是关于循环脚本本身的。很多人把循环脚本当成一次性工具写完就不管了。但实际上循环脚本会随着项目演进而变化任务类型变了、检查器升级了、执行器换版本了脚本都得跟着改。我的做法是把循环脚本纳入版本管理和项目代码放在一起。每次修改脚本都写清楚改了什么、为什么改。这样过几个月回头看能快速回忆起当时的决策背景。另外脚本里的关键参数超时时间、重试次数、检查器配置我建议抽出来放到配置文件里不要硬编码在代码里这样调参不用改代码。还有一个小技巧给循环脚本加日志。每轮的执行器输出、检查器结果、反馈内容都写到日志文件里按日期分文件。出问题的时候翻日志比翻终端历史快得多。日志文件不用保留太久我一般保留最近七天的再久的就归档或者删掉。这套循环工程的方法我在三个项目上跑过最长的跑了两个月累计执行了上千次循环。最大的体会是循环工程不是让 AI 替代你而是让你从重复劳动里解放出来把精力放在设计循环规则和处理边界情况上。规则设计得好AI 的产出质量能稳定在一个可接受的水平规则设计得不好循环跑得越快错得越多。所以每次搭新循环之前我都会花十分钟想清楚这个任务的判定条件是什么、失败了怎么反馈、最多试几次、什么情况下必须人工介入。这十分钟的投入能省下后面几个小时的调试时间。