尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

AI Agent自主开发闭环:构建-测试-修复循环实践

发布时间:2026/9/26 20:58:09

资讯中心
01
ARTICLE

AI Agent自主开发闭环:构建-测试-修复循环实践

AI Agent自主开发闭环:构建-测试-修复循环实践
最近我在折腾一个任务让 AI Agent 像实习生一样接到一个开发任务后自己完成“构建→测试→修复→循环”直到把代码交付到一个基本可用的状态。听上去挺科幻其实拆开之后就是一堆工程细节环境怎么初始化、命令怎么跑、报错怎么喂给模型、改完代码怎么验证。真正动手做之后我最大的感受是——写提示词让模型生成代码太简单了难的是让整个流程在无人干预的情况下自己往前走。很多人分不清 Agent 和 LLM 的区别。常说的 DeepSeek、GPT、Claude 这些属于大语言模型是“大脑”你问它问题它给你答案而 Agent 是“大脑手脚”它不仅能回答问题还能调用工具、执行命令、读取文件、根据结果决定下一步。构建、测试、修复这个闭环恰恰需要的就是这一套行为循环。而且这里的“构建”指的是软件开发里的 build不是训练 AI 模型那个“构建模型”别搞混了。1. 先理清一个概念Agent 到底比大模型多干了什么1.1 模型只负责“说话”Agent 负责“动手”你直接问一个大语言模型“这段代码哪里有问题”它能给你一份漂亮的答案但它不会自己打开终端更不会顺手帮你把问题改了。Agent 不一样它有完整的“感知—决策—行动”链路。感知读取文件、执行命令、捕获输出、解析状态。决策把感知到的结果交给 LLM 分析LLM 给出“接下来该做什么”的判断。行动修改文件、运行构建命令、触发测试、发起新的命令。这三步拼在一起就是一个循环。每一次循环的结束又变成下一次循环的开始。这也是标题里“循环”二字的本质不是简单地把同一条命令跑几遍而是让 Agent 在每次执行后根据结果调整策略直到满足退出条件。我习惯把 Agent 想象成一个刚入职的实习生。你只给他一个 KPI“把这个项目的构建跑通、测试跑通。”他不会一次成功但他会自己看报错、改代码、再跑一遍。LLM 是他的脑子手和脚则由代码里的函数和工具提供。1.2 开发闭环里 Agent 的三项核心能力要支撑“构建→测试→修复→循环”Agent 至少要具备三项能力能力说明失败表现工具调用执行 shell 命令、读写文件、处理路径卡在环境准备连依赖都装不好错误理解从日志和堆栈里提取根因判断问题类型乱改代码把环境问题当代码问题自主决策决定继续修复还是停止提交陷入死循环烧掉大量 token这三个能力不是平行的而是递进的。工具调用是基础错误理解是智力自主决策是判断力。没有第二项第三项就是瞎判断没有第一项后两项只能在纸面上高谈阔论。网上很多“AI Agent 练手小项目”都在演示“生成代码”但那离真正的“开发闭环”还很远。生成代码只是一个瞬间动作而开发是连续过程。你要的是 Agent 能在失败之后自我修正而不是撞上南墙还继续写同一句修复。2. 构建环节的自动化让 Agent 自己准备环境、编译、收集产物2.1 环境准备是最容易被低估的一步我见过太多 Agent demo 都假设环境已经就绪Python 装好了、依赖都在、路径也对。现实项目里根本不是这样缺少依赖、版本冲突、系统库不对、环境变量没设置任何一个都能让构建倒在第一关。所以构建环节的第一步不是跑编译命令而是“环境自检”。我常用的检查清单是这样的检查运行时版本python --version、node -v、java -version检查依赖是否安装pip list、npm ls --depth0安装或更新依赖pip install -r requirements.txt、npm ci设置环境变量密钥路径、编译缓存目录这些动作最好由 Agent 自动完成但你必须在脚本里给一个“重试逻辑”。比如第一次pip install因为网络失败Agent 要能重试如果重试三次还失败就上报“环境构建失败”而不是尝试修改项目代码。把环境问题和代码问题分开是让 Agent 高效工作的前提。我自己的习惯是在把 Agent 放进去之前先手动把环境调通一次。这不是多此一举而是为了给 Agent 建立一条可预期的基线。当环境本身已经可用时Agent 遇到构建失败就能大概率推断是代码或配置的问题而不是在环境泥潭里打转。2.2 构建输出要“可喂给模型”而不是一堆乱日志构建失败时终端里输出的内容少则几十行多则上千行。直接把这堆原始日志丢给 LLM结果就是上下文窗口被塞爆模型开始“失忆”甚至把无关的警告当成根因。我第一次这么做就吃了大亏——模型盯着一条 warning 分析了大半天真正的 error 被淹没在几百行输出里。更有效的做法是先把构建输出预处理成一个标准化的“反馈模板”。这个模板要至少包含几个字段[BUILD_STATUS]: FAILED [EXIT_CODE]: 1 [ERRORS]: - 文件 src/foo.py 第42行: TypeError: unsupported operand type syntax - 文件 src/bar.py 第17行: ModuleNotFoundError: No module named xxx [CONTEXT]: - 最近的命令: python -m build - 构建目录: /workspace/project你不需要把完整的build.log全部塞给 LLM可以把日志写入文件然后在反馈模板里提炼出关键错误。如果 Agent 需要更多细节它可以通过工具读取build.log的相应行。这种“摘要按需查阅”的方式能大幅降低 token 消耗也能让模型更专注于问题本身。2.3 清理旧构建别让 Agent 被旧产物骗了这是另一个高频坑尤其是涉及编译型项目时。上次构建成功留下的.class、.jar、.o文件还在Agent 这次改了代码但构建步骤因为“没有问题”而没重新生成新产物结果测试跑的是旧的东西整个循环都在假象里打转。我在每个构建动作之前都会强制清理rm -rf dist build .pytest_cache *.egg-info mvn clean即使你不用 Agent在 Jenkins 这类 CI 环境里也记得清理 workspace。热词里提到“jenkins构建清理”其实就是同一件事旧产物不删新测试就没有意义。对 Agent 来说清理动作尤其重要因为它没有人类那种“看到旧文件时的警惕心”。你必须在循环脚本里写明构建前先清理日志按时间戳命名只读取最新一份日志。我还会把旧日志一起清掉避免 Agent 在读取文件时翻到上一个循环的失败信息产生误判。典型案例是第一次失败是因为缺依赖第二次已经修好了但 Agent 从旧日志里看到了同样的错误误以为还在断点于是重复执行相同的修复动作。3. 测试环节的智能化核心不是跑用例而是“翻译失败”3.1 失败信息的分层设计测试输出是所有环节里信息量最大的。pytest、JUnit、Go test 都会给出大量细节包括用例名、断言、堆栈、截图。但对 Agent 来说原始文本并不是越详细越好关键是“结论先行证据靠后”。我把测试反馈设计成两层第一层摘要。例如3 passed, 2 failed in 12.33s。第二层失败用例详情。包括用例 ID、失败原因、触及的代码位置。比如[TEST_STATUS]: FAILED [SUMMARY]: 15 passed, 2 failed in 1.42s [FAILED_CASES]: - tests/test_auth.py::test_login_returns_200 REASON: assert 500 200 FILE: app/auth.py:45 in login - tests/test_cart.py::test_add_item_when_cart_full REASON: ValueError: Cart capacity exceeded FILE: app/cart.py:112 in add_item这比把整个pytest --tblong的输出丢给模型要清晰得多。模型只需要读到前几行就能知道“哪里炸了”如果它还需要看详细的堆栈再通过工具打开测试报告文件也不迟。3.2 什么样的失败信息 Agent 最容易理解我自己揣摩出一点模型最容易理解的失败信息是“现象—期望—实际”三要素齐全的信息。现象是“哪个用例挂了”期望是“本应该是什么结果”实际是“程序到底给了什么结果”。举两个例子差的信息assert False好的信息test_login_returns_200 failed: expected status 200, got 500差的信息只告诉模型断言失败但没告诉它为什么失败。好的信息则直接指向问题类型状态码从预期值变成了非预期值大概率是接口处理出错而不是路由不存在。要让 Agent 能自动修复测试用例本身也要写得足够“会说话”。这算是一个额外收益为了喂给 Agent你可能要把项目里的断言写得比平时更明确。3.3 从“测试通过”到“测试有价值”之间还差一个覆盖率如果项目本身的测试很薄弱Agent 跑完整个循环也只是“假绿”。构建过了、测试过了但业务逻辑可能完全没被验证。所以我在闭环里加了一步自动统计代码覆盖率低于阈值不让循环退出。这个阈值可以按项目调整个人建议先定一个保守的 60%70%。低于这个值Agent 就必须停下来补充新的测试用例再继续循环。这一步会把 Agent 的定位从“修 bug 的工具”变成“真正维护代码质量的程序员”。但请注意让 Agent 补充测试用例比让它修复源码更难。因为它需要先理解原有模块的行为再设计出合理的断言。如果你的项目太过复杂我建议第一阶段只做“构建跑测试修复”覆盖率提升放到第二阶段。一口吃不成胖子循环也是一样。4. 修复环节要求 Agent 先讲根因再动手改代码4.1 如何告诉 Agent“现在出了什么问题”修复环节的 prompt 不能是“请修复这个错误”这种空泛指令。我给 Agent 的指令模板是结构化的至少包含你是这个项目的维护者。 当前构建/测试失败信息如下 [FEEDBACK] 请完成以下步骤 1. 分析失败根因用不超过5句话说明问题出在哪里。 2. 提出修改方案明确修改哪些文件、怎么改。 3. 执行修改但严禁修改测试文件和配置文件。 4. 修改后重新运行构建和测试。为什么非要让它先“说明根因”因为模型在决策时如果跳过推理直接产生补丁很容易输出一种“看着合理但没解决根本问题”的垃圾修复。让它先写根因等于强制它的评论逻辑参与到生成过程中。实际跑下来只要根因分析靠谱修复动作大概率也靠谱。4.2 限制修复范围与回归风险Agent 最容易犯的一个错误是“打地鼠式修复”为了通过眼前这个测试偷偷改了另一个模块的常量或者加了全局异常捕获把所有异常都吞掉。这种修复表面上让测试变绿实际上把问题埋得更深。对付这个问题我在循环脚本里加了两个约束修改文件的名称必须出现在 Agent 自己的修复方案里。如果 diff 里出现了“声明外的文件”直接报错终止。遍历测试套件时如果任何一个原来通过的用例在修复后失败了立即回滚这次修改并把回归信息反馈给 Agent。听起来很简单但实际执行很有效。Agent 学会了一个教训不能为了一个失败用例去破坏其他用例。最终它给出的修复往往更保守也会更小心地触碰共享函数。4.3 环境问题与代码问题要分开处理我见过最浪费时间的场景是 Agent 花了好几轮去“修复”环境问题。比如 Windows 环境里常见的api-ms-win-crt-runtime-l1-1-0.dll报错或者kernel32.dll相关异常这根本不是你项目代码的问题而是系统运行库缺失或缺 VC 运行环境。Agent 如果在代码层面找征兆无论怎么改都是白费劲。所以我在循环脚本里加了一步“错误分类”代码类错误语法错误、类型错误、断言失败、模块缺失对当前项目而言环境类错误系统库缺失、运行时版本不对、依赖冲突、权限不足如果判断是环境类错误Agent 应当执行“环境修复”动作比如安装运行库、切换 Node 版本、更新依赖。只有识别为代码类错误才走正常的“源码修复”路径。这一步细化之后循环的无效轮次减少了至少一半。5. 循环控制让 Agent 知道什么时候收手而不是无限试错5.1 终止条件不是“全部通过”而是“连续失败 N 次就停”理论上循环可以一直跑到所有测试都通过。但实际中有些问题就是修不好的——根因可能是需求矛盾也可能是 Agent 已经把代码改得面目全非。如果一直让它试它会在同一个死胡同里反复。我在代码里设置了两类终止条件成功条件构建成功测试全部通过且覆盖率达标。失败条件连续两次失败反馈里的“错误位置”完全相同并且 Agent 给出的修复方案没有产生任何有意义的变化或者总迭代次数超过 5 次。我倾向于用“连续相同错误”来判断死循环而不是只盯次数。因为如果错误每次都不一样说明 Agent 还在探索可能再试一次就会见效。如果错误完全一样那就说明当前策略失效继续下去只是烧钱。5.2 给整个循环加一个“时间预算”很多 Agent 项目只考虑次数忽略了时间成本。一次构建可能要几分钟一套完整测试可能要十几分钟模型推理也要时间。你的等待时间会呈指数级膨胀。我会在循环入口加上两个预算总执行时间预算比如整个任务最多 20 分钟超时立即中断把当前状态写成报告。LLM 调用次数预算比如最多调用 10 次模型因为每次调用都会产生 token 费用。这两个预算不是等循环真正超时才生效而是每次进入循环前先检查剩余配额如果配额不足就提前终止“修复尝试”把部分通过的状态交给人工处理。这能有效防止一次实验烧掉几百块 token 费用。5.3 成本控制压缩反馈、限制修改次数、合并测试报告LLM 的 token 费用在 Agent 循环里是主要开销之一。我在跑了几十轮后总结出三个省钱要点压缩反馈把原始日志和测试输出全部重定向到文件只把结构化的“错误摘要”给 LLM通常控制在 200500 字符。限制修改动作每次修复前只允许 Agent 针对相关文件生成 diff不要让它全仓库搜索、打印无关文件内容。把工具调用限定在白名单里。合并测试报告如果一次跑了多个模块的测试只把失败模块的摘要合并传输不要把所有模块的通过统计都塞进提示词。这三个要点直接决定了闭环的经济性。没有它们循环就是吞金兽有了它们一次完整闭环的 token 消耗可以控制在一次普通对话的几倍以内。6. 一个最小可复现的“构建-测试-修复”循环骨架6.1 主循环逻辑如果你也想搭一个最小闭环我建议不要一上来上重量级框架先用一个 Python 脚本把循环撑起来。下面是我落地过的一个骨架# minimal_agent_loop.py import subprocess from datetime import datetime MAX_ROUNDS 5 TIMEOUT_MINUTES 20 def run_cmd(cmd, timeout120): return subprocess.run( cmd, shellTrue, capture_outputTrue, textTrue, timeouttimeout ) def build(): # 清理旧产物确保这次构建是干净的 run_cmd(rm -rf dist build .pytest_cache) result run_cmd(python -m build, timeout300) return result.returncode 0 def test(): result run_cmd(pytest --tbshort -q, timeout300) return result, result.returncode 0 def fix(feedback): # 调用 LLM 接口得到 diff 或直接修改文件 # 这里省略具体实现核心是让模型根据 feedback 生成补丁 prompt build_feedback_prompt(feedback) return generate_and_apply_patch(prompt) def main(): start_time datetime.now() for round_idx in range(MAX_ROUNDS): # 时间预算检查 elapsed (datetime.now() - start_time).total_seconds() if elapsed TIMEOUT_MINUTES * 60: return TIMEOUT if not build(): feedback parse_build_error(build.log) else: result, ok test() if ok: return SUCCESS feedback parse_test_summary(result.stdout) print(f[ROUND {round_idx}] {feedback}) # 修复动作把反馈转换成补丁 fix(feedback) # 判断是否卡死对比最近两轮的错误位置 if round_idx 0 and same_position(feedback, prev_feedback): return STUCK prev_feedback feedback return FAILURE这个骨架没有依赖任何 Agent 框架只要你自己接一个 LLM 调用函数就能跑。它最大的价值是把“循环”这个抽象概念变成了看得见的代码构建失败就解析构建日志测试失败就解析测试摘要然后丢给模型生成补丁再回到下一次循环。6.2 反馈模板示例为了让这个骨架工作反馈模板必须稳定。我建议统一成下面这种格式方便写parse_*函数[ROUND 2/5] [STATUS]: TEST_FAILED [SUMMARY]: 3 passed, 1 failed in 1.42s [FAILED_CASE]: tests/test_auth.py::test_login_returns_200 [REASON]: assert 500 200 [PINPOINTED_FILE]: app/auth.py [PINPOINTED_LINE]: 45只要这个模板生成稳定LLM 的修复准确率会明显提升。你不会希望 Agent 为了理解“到底哪里出问题”还要自己去字符串里大海捞针。6.3 跑通后的运行效果以我的一个真实小项目为例初始跑构建失败反馈指向缺失依赖Agent 调用了pip install第二轮构建通过但测试失败一条用例 500 vs 200Agent 定位到auth.py的返回值处理逻辑修复后测试通过第三轮覆盖率检查发现低于阈值Agent 补了一个测试用例第四轮全部通过循环结束。整个过程大约花了 12 分钟调用 LLM 三次。这就是一个典型的“构建→测试→修复→循环”闭环。它并不酷炫但很实在——它证明了 Agent 可以在少量人工干预下自主完成一段开发任务。7. 我实际跑下来的几个坑和调整思路7.1 坑一把完整日志丢给 AgentToken 爆掉导致“失忆”第一次跑我图省事直接把 pytest 输出和构建日志全部塞给 LLM。结果上下文窗口很快就被几千行日志占满模型开始“失忆”连自己上一轮修了什么都不知道。更离谱的是它开始从日志的警告部分找问题忽略真正的错误行。解决方案就是前面说的写一层解析器把日志压缩成结构化反馈。这一步不是可选的而是必须的。如果你要做真正的 Agent 闭环请把 80% 的工程量放在反馈解析上而不是放在写 prompt 上。解析做得好后面所有环节都顺。7.2 坑二修复后忘了重新构建测试跑在旧产物上写 Java 或 C 项目时遇到过这个问题。Agent 改了源码我没有强制“先重建再测试”结果测试直接跑旧的.class或.jar。更误导的是旧产物里碰巧也有那条测试用例但测的完全是上一版代码。我现在的做法是在主循环里把“构建”和“测试”合并成一个执行单元。无论当前步骤是否只改了一行注释只要脚本走到测试环节就强制先跑一次清理重建。虽然有时会多花一点时间但能保证测试结果的可靠性。7.3 坑三Agent“为了过测试”而绕过了原有的断言这个坑非常隐蔽。有一轮测试要求接口返回200Agent 修改了业务逻辑后还是500于是它直接在视图函数里写死了status200测试通过了但它没有检查数据是怎么生成的。这种“作弊式修复”会掩盖真实的业务故障。我加了两个预防措施第一修复方案里禁止修改测试用例也不允许跳过断言第二循环结束后额外检查 diff如果看到像return Response(, status200)这类硬编码直接被人工问责。更重要的是我会同时检查测试通过之外的数据正确性指标但这属于更高阶的玩法了。7.4 我的最终建议如果你也想动手复现这条闭环别急着把公司里复杂的微服务搬进来。先找一个只有几十个文件的小项目最好是你自己熟悉的然后写一个最小循环跑通它。第一次运行大概率会失败但每一个失败都是学习——你会知道哪里解析不合理哪里反馈不够清晰哪里循环条件太宽松。等这个小闭环跑顺了再逐步提高复杂度最终把它接到真实的 CI/CD 流程里。我现在已经习惯把“构建、测试、修复”三个动作封装成独立的函数任何项目来了都能套用同一套循环骨架。这种工程化的 Agent 应用方式比在一行 prompt 里赌模型发挥要可靠得多。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。