2026/10/9 21:30:05

Loop Engineering 实战:用 Claude Code 构建自动化反馈循环

Loop Engineering 实战:用 Claude Code 构建自动化反馈循环 1. 先搞清楚 Loop Engineering 到底在解决什么问题第一次听到“Loop Engineering”这个词很多人会以为是某种新的编程语言或者框架。其实不是。它描述的是一类工程实践让 AI 编程工具比如 Claude Code、Codex、Cursor 这类在一个可控的循环里反复执行“生成—验证—修正”的过程直到产出满足预期为止。核心不在于工具本身而在于你怎么设计这个循环的边界、退出条件和反馈机制。我最初接触这个概念是在用 Claude Code 处理一个批量重构任务的时候。当时我让它改一个模块的接口签名它改完第一遍编译报错我手动把报错贴回去它改第二遍又引入了新的类型不匹配第三遍才通过。整个过程我像个传话筒一样在终端和编辑器之间来回切换。后来我意识到这个“贴报错—等修改—再验证”的动作完全可以自动化而 Loop Engineering 要解决的正是这个问题把人的重复劳动从循环里抽出来只保留关键的判断节点。所以这篇内容适合三类人看一是已经在用 Claude Code、Codex、Cursor 但还在手动复制粘贴报错的开发者二是想把这些工具接入自己工作流、做批量任务处理的工程师三是单纯好奇“循环工程”到底怎么落地、值不值得投入时间学习的人。我会从最基础的概念拆起然后给出一套可以直接复现的实战方案包括环境准备、循环设计、退出条件、常见故障排查。全程用我自己踩过的坑来说明不堆砌术语。需要先说明一点Loop Engineering 不是某个官方产品名称它更像是一个实践模式的统称。不同团队对它的定义有差异但共同点都是围绕“自动化反馈循环”做文章。你不需要安装一个叫 Loop Engineering 的软件而是要用现有的工具组合出一套循环机制。2. 循环工程的核心构件反馈信号、退出条件与状态保持2.1 反馈信号从哪来决定了循环能不能跑起来一个循环要能自动运转最关键的不是 AI 有多聪明而是“它怎么知道自己做错了”。这就是反馈信号的来源问题。在编程场景里反馈信号通常有三类第一类是静态检查结果比如编译器的报错、类型检查器的输出、linter 的警告。这类信号最结构化最容易解析也最适合作为循环的驱动。比如 TypeScript 的tsc --noEmit输出就是标准的错误列表你可以直接提取文件路径、行号、错误码。第二类是测试结果比如单元测试的通过/失败、集成测试的断言输出。这类信号比编译错误更接近业务正确性但解析成本更高因为测试框架的输出格式各不相同。第三类是运行时行为比如程序崩溃的堆栈、接口返回的异常状态码、日志里的错误关键字。这类信号最贴近真实问题但也最不稳定容易受环境影响。我自己的做法是优先用第一类信号驱动循环因为它的确定性最高。第二类作为补充第三类只在必要时引入。原因很简单循环每多跑一轮消耗的是 token 和时间如果反馈信号本身有噪声循环就会在无效方向上反复横跳。2.2 退出条件设计不好循环就会变成死循环退出条件是 Loop Engineering 里最容易被忽视、但最容易出事的部分。我见过有人写了个循环让 AI 修 bug结果 AI 每轮都改一点点改了二十轮还在改最后 token 烧完了问题还在。这就是退出条件没设计好。退出条件至少要包含三层成功退出反馈信号显示目标达成比如编译零错误、测试全绿。这是理想情况。失败退出达到最大轮次仍未成功或者连续 N 轮反馈信号没有改善。这时候要停下来把当前状态交回给人。异常退出工具本身报错、网络中断、文件被外部修改等。这类情况要有兜底处理不能让它卡死。我一般会把最大轮次设在 5 到 8 之间。超过这个数还没收敛说明要么任务拆得不够细要么反馈信号有问题继续跑下去大概率是浪费。连续无改善的判定也很重要如果第 3 轮和第 2 轮的报错数量一样、错误内容也基本一样那就该停了。2.3 状态保持循环之间要传递什么循环不是每一轮都从零开始。你需要决定哪些信息在轮次之间传递。最基础的传递内容是上一轮的反馈信号和 AI 的修改记录。更进阶的做法是维护一个“已尝试方案”列表避免 AI 反复走同一条死路。我在实际项目里会用两个文件来做状态保持一个是loop-state.json记录当前轮次、累计错误数、上次修改的文件列表另一个是attempts.log追加每一轮的反馈摘要和 AI 的关键改动。这两个文件不需要多复杂但能让循环在中断后恢复也方便事后复盘。提示状态文件不要放在会被 AI 修改的目录里否则可能出现循环自己改自己状态的情况。我一般放在项目根目录下的.loop/文件夹并在提示词里明确告诉 AI 不要动这个目录。3. 用 Claude Code 搭一套最小可用的循环从环境到跑通3.1 环境准备里最容易忽略的两个细节Claude Code 的安装本身不复杂官方文档写得很清楚。但有两个细节是我踩过坑之后才注意到的。第一个是工作目录的隔离。如果你直接在主项目目录里跑循环AI 的修改会和你自己的未提交改动混在一起一旦循环跑飞回滚很麻烦。我的做法是每次循环前先创建一个独立的工作副本比如用git worktree或者直接复制一份到临时目录。这样即使循环把代码改乱了删掉副本就行主项目不受影响。第二个是权限配置。Claude Code 默认会询问是否允许执行某些操作这在交互模式下没问题但在自动化循环里会卡住。你需要提前配置好允许的操作范围比如允许读写特定目录、允许执行测试命令。配置的时候要遵循最小权限原则不要一股脑全放开。# 创建独立工作副本的示例 git worktree add ../loop-workspace-$(date %s) HEAD cd ../loop-workspace-*3.2 循环脚本的骨架一个可复用的 bash 结构下面这个脚本是我用了几个项目之后沉淀下来的骨架你可以直接改成自己的版本。它的逻辑很简单跑检查、如果有错就把错误喂给 Claude Code、等它改完、再跑检查直到通过或达到轮次上限。#!/bin/bash MAX_ROUNDS6 ROUND0 STATE_DIR.loop mkdir -p $STATE_DIR while [ $ROUND -lt $MAX_ROUNDS ]; do ROUND$((ROUND 1)) echo Round $ROUND # 跑静态检查把输出存下来 npx tsc --noEmit $STATE_DIR/check-output.txt 21 ERROR_COUNT$(grep -c error TS $STATE_DIR/check-output.txt || true) if [ $ERROR_COUNT -eq 0 ]; then echo Check passed at round $ROUND break fi echo Found $ERROR_COUNT errors, feeding to Claude Code # 把错误和上下文喂给 Claude Code claude --print 以下是 TypeScript 编译错误请修复。只修改必要的文件不要重构无关代码。错误输出$(cat $STATE_DIR/check-output.txt) \ $STATE_DIR/claude-response-$ROUND.txt 21 # 记录本轮状态 echo {\round\: $ROUND, \errors\: $ERROR_COUNT} $STATE_DIR/attempts.log done if [ $ROUND -ge $MAX_ROUNDS ]; then echo Max rounds reached, manual intervention needed exit 1 fi这个骨架有几个设计取舍值得说明。第一我用--print模式而不是交互模式因为循环里不需要人工确认。第二提示词里明确说了“只修改必要的文件”这是为了防止 AI 顺手重构导致改动范围失控。第三每轮的响应都单独存文件方便出问题时回溯。3.3 提示词怎么写才能让循环收敛循环能不能收敛很大程度上取决于你喂给 AI 的提示词。我总结下来有三个要点第一把反馈信号原样给它不要自己总结。很多人喜欢把报错“翻译”一遍再给 AI比如“有个类型不匹配的问题”。这样做反而丢失了关键信息。编译器报错里的文件路径、行号、错误码都是 AI 定位问题的重要线索原样给它效果更好。第二明确约束修改范围。如果不加约束AI 可能会顺手改一堆无关文件导致下一轮出现新的错误。我通常会在提示词里写清楚“只修改报错涉及的文件”或者“不要改动 public API”。第三告诉它上一轮试过什么。如果这是第 3 轮以上我会把前几轮的修改摘要附上并说明“以下方案已经尝试过但没有解决请换一个思路”。这能有效避免 AI 在原地打转。注意提示词长度要控制。把整个项目的代码都塞进去既浪费 token 又干扰判断。只给报错相关的文件和必要的上下文就够了。4. Codex 与 Cursor 在循环里的角色差异4.1 Codex 更适合做批量生成不适合做精细修正Codex 的强项是根据上下文生成代码片段它在“从零写一个函数”这类任务上表现很好。但在循环修正场景里它的表现不如 Claude Code。原因是 Codex 对错误反馈的响应粒度比较粗你给它一段报错它倾向于重写整个函数而不是做最小修改。这在循环里是个问题因为每轮改动越大引入新错误的风险越高。我的做法是把 Codex 用在循环的“生成阶段”而不是“修正阶段”。比如循环的第一轮让 Codex 根据接口定义生成初始实现后续轮次交给 Claude Code 做修正。这样分工之后整体收敛速度明显提升。4.2 Cursor 的编辑器集成在循环里的独特价值Cursor 和前面两个工具的区别在于它是编辑器原生的。这意味着它能直接利用编辑器里的诊断信息比如波浪线报错不需要你手动跑命令再解析输出。在 Loop Engineering 的语境下这带来一个便利你可以用 Cursor 的 diagnostic API 直接拿到结构化的错误列表省掉解析文本的步骤。但 Cursor 的自动化能力相对弱一些它更偏向交互式使用。如果你想做全自动循环Cursor 不是首选。我的用法是循环跑完之后用 Cursor 打开结果做人工审查利用它的 diff 视图快速确认改动是否合理。它在这个环节的体验是最好的。4.3 三个工具在循环不同阶段的配合方式把这三个工具串起来我目前的工作流是这样的阶段主力工具原因初始生成Codex生成速度快适合从零起草循环修正Claude Code对错误反馈响应精细改动范围可控结果审查Cursordiff 视图清晰便于人工确认批量任务Claude Code脚本化能力强适合无人值守这个分工不是固定的你可以根据自己手头的工具和任务类型调整。关键是要理解每个工具在循环里的定位不要指望一个工具包打天下。5. 循环跑不起来时的排查链路5.1 从“AI 没反应”到“AI 改错文件”的逐层定位循环出问题的时候症状往往很模糊比如“跑了几轮没效果”。这时候需要一套系统的排查方法。我一般按下面的顺序逐层检查第一层反馈信号是否正常。先手动跑一遍检查命令确认它确实能输出错误。有时候是检查命令本身配置错了导致循环以为没有错误直接退出了。第二层AI 是否收到了正确的输入。查看claude-response-*.txt文件确认 AI 的响应里有没有针对报错内容做修改。如果响应是空的或者答非所问说明提示词有问题。第三层AI 的修改是否落到了文件上。有时候 AI 在响应里说了要改什么但实际没有执行写文件操作。这通常是权限配置的问题检查一下工作目录是否在允许范围内。第四层修改是否引入了新错误。对比每轮的check-output.txt如果错误数量在增加说明 AI 的修改方向有问题需要调整提示词里的约束条件。这个排查链路看起来简单但实际用的时候能省很多时间。我见过有人循环跑不通就直接怀疑工具不行其实大部分问题都出在反馈信号或提示词上。5.2 几个高频故障的具体表现和修法故障一循环第一轮就退出提示“check passed”。这通常是因为检查命令的退出码被错误处理了。比如grep -c在没匹配到内容时返回 1如果脚本里用了set -e就会直接退出。修法是在 grep 后面加|| true。故障二AI 每轮都改同一个文件但错误不变。这是典型的“原地打转”。原因是提示词里没有告诉它上一轮试过什么。修法是在提示词里附上历史尝试记录并明确要求换思路。故障三循环跑到一半卡住不动。可能是 AI 在等待人工确认。检查一下是否用了交互模式或者权限配置里有没有需要确认的操作。改成--print模式并提前配好权限。故障四修改后的代码能编译但测试挂了。说明循环的反馈信号只覆盖了编译检查没有覆盖测试。修法是把测试命令也加入检查环节让反馈信号更完整。5.3 怎么判断该继续循环还是该人工介入这个问题没有绝对标准但有几个信号可以参考如果连续两轮的错误数量没有下降继续跑大概率是浪费。如果错误类型从“类型不匹配”变成了“找不到模块”说明修改引入了新问题需要人工看一下。如果 AI 的响应开始变得很短、很敷衍可能是上下文太长了需要清理状态重新开始。我自己的习惯是设一个“三轮无改善就停”的规则。停下来之后不急着改代码先看attempts.log搞清楚卡在哪再决定是调整提示词还是手动改。6. 把循环工程用在实际项目里的几点经验6.1 任务拆解粒度比循环本身更重要我一开始做循环工程的时候总想着让一个循环解决一个大任务比如“把这个模块从 JavaScript 迁移到 TypeScript”。结果循环跑了十几轮都没收敛。后来我把任务拆成更小的单元先迁移类型定义再迁移工具函数最后迁移业务逻辑。每个单元单独跑循环基本都在三轮内完成。这个经验的核心是循环适合解决边界清晰的小问题不适合解决模糊的大问题。你在设计循环之前先问自己“这个任务的完成标准能不能用一条命令验证”。如果不能就继续拆。6.2 日志和状态文件要当成一等公民来对待很多人做自动化的时候不重视日志觉得跑通了就行。但在循环场景里日志是你唯一的调试依据。我现在的做法是每轮都记录轮次编号、错误数量、AI 修改的文件列表、耗时。这些信息在事后复盘时非常有用能帮你判断循环的效率瓶颈在哪。状态文件还有一个作用是支持断点续跑。如果循环跑到第 4 轮因为网络问题中断了你可以从状态文件里恢复不用从头再来。这在处理大项目的时候能省不少时间。6.3 不要追求全自动保留人工检查点Loop Engineering 的目标是减少重复劳动不是完全取代人。我见过有人追求“一键全自动”结果循环把代码改得面目全非回滚都困难。我的做法是在循环的关键节点保留人工检查比如第一轮修改之后看一眼 diff确认方向对了再让它继续跑。这个检查点不需要很频繁但要有。它能在循环跑偏的早期就发现问题避免浪费更多轮次。从投入产出比来看花三十秒看一眼 diff比跑五轮无效循环再回滚要划算得多。6.4 循环工程的边界哪些任务不适合不是所有任务都适合用循环来做。根据我的经验以下几类任务不适合需要外部环境交互的任务比如调试一个只在特定网络环境下出现的 bug。循环里的反馈信号不稳定容易误判。涉及主观判断的任务比如 UI 设计调整。什么叫“好看”没法用命令验证循环没有明确的退出条件。改动范围不可控的任务比如“优化整个项目的性能”。这类任务没有清晰的完成标准循环容易失控。适合循环的任务通常有这些特征完成标准可自动化验证、改动范围可约束、反馈信号稳定。你在决定用循环之前先对照这几条检查一下。7. 关于循环工程的一些个人体会用了几个月 Loop Engineering 之后我最大的感受是它的价值不在于让 AI 多干活而在于逼你把任务定义清楚。一个循环能跑起来前提是你能说清楚“什么叫做完了”和“怎么知道做错了”。这两个问题想明白了即使不用 AI你的工作流也会变得更清晰。另一个体会是工具的选择没有想象中那么重要。Claude Code、Codex、Cursor 各有各的强项但循环的骨架是通用的。你把反馈信号、退出条件、状态保持这三件事设计好换哪个工具都能跑。反过来如果这三件事没设计好用再贵的工具也是白搭。最后分享一个我最近在用的技巧在循环的提示词里加一句“如果你认为当前错误无法通过修改代码解决请直接说明原因并停止”。这句话能有效避免 AI 在死路上硬撑把问题交回给人来判断。实测下来它让循环的无效轮次减少了大概三分之一。