循环工程指的是设计驱动智能体工作的系统,而非单纯编写提示词。本文展示这一理念在真实生产问题中的应用:让我们的MCP服务器与不断变化的API保持同步。
本文最初发表于Rapidflare官方网站,经Rapidflare授权转载于此。
“我现在已经不直接向Claude下达提示了。我运行的是一些循环程序,由它们去提示Claude并决定下一步做什么。我的工作就是编写这些循环。”
——Boris Cherny,Anthropic公司Claude Code项目负责人
这句话,加上Peter Steinberger类似的表述,引发了业界对“循环工程”这一概念的关注热潮。Addy Osmani将其描述为:用系统取代你自己作为提示者的角色,由系统去完成提示工作,而你负责设计这个系统。工作的发力点从“写出好的提示词”转移到了“设计好的循环”。
这是一个颇具吸引力的想法,但也需要谨慎看待。与其再写一篇空泛的观点文章,我们更想通过一个具体而朴实的问题来展示这种实践:让我们的MCP服务器与不断变动的API保持同步。事实证明,这个问题非常适合用循环来解决,也清晰地展示了判断力、确定性流程与人工介入各自应该发挥作用的位置。
漂移问题
我们提供一个模型上下文协议(MCP)服务器,为智能体——无论是我们自己的还是客户的智能体——提供与Rapidflare平台交互的工具。这些工具本质上是对两个后端API的轻量封装。MCP服务器并不直接引入后端代码,而是通过HTTP与后端通信,并根据每个API的OpenAPI规范文件(openapi.json)自动生成客户端代码。
这种设计在API保持稳定时运行良好,但现实中API经常变动。后端新增一个接口、修改请求结构、重命名某个字段——一旦发生这些变化,三件事情就会立刻脱节:
MCP仓库中提交的规范文件变得过时。
自动生成的客户端不再匹配真实的API接口。
MCP工具完全没有暴露出新增的能力。
过去的做法是靠人工按清单逐步操作:拉取新的规范文件、重新生成客户端、查看差异、手写新增接口的封装代码、运行测试、提交PR。这个流程虽然可行,但也是那种容易悄悄腐化的重复性、易出错任务——总会有人漏掉某个步骤,或者同步进度落后API数周之久。在实际操作中,封装代码的重写和更新工作是借助AI编程工具完成的,依靠的是一种不断演变却缺乏系统记录的经验,再加上这些工具对现有代码结构的跟随能力。
这正是循环工程适用的典型场景:一项重复出现、定义清晰、在流程中包含一个或多个AI/智能体环节、且你不想一直盯着的任务。于是我们构建了这样一个循环。
规范文件为何频繁变动
值得追问的是,为什么API变动如此频繁,因为答案正是这个循环真正重要的原因所在。
与许多网络平台类似,我们API最初、也是最主要的客户端是用户界面,以及各种内部命令行工具和其他配套工具。但我们的平台正在快速向“智能体优先”的架构演进。越来越多的运营工作——那些曾经需要人工操作员点击完成的任务——现在由运行技能的智能体来完成。这场转变正同时从两个方向推进:我们自身的运营环节,以及客户与平台的交互环节。
这些智能体通过与客户智能体相同的MCP工具访问平台。这使得我们自己的智能体成为工具接口最苛刻的使用者,也改变了API变更需求的来源。
我们构建“技能”的一部分工作方式是:让智能体运行任务,然后反馈它所使用工具的易用性情况——比如某个参数令人困惑、缺少某个接口、某个响应需要三次调用才能完成本应一次调用就能完成的事、某个工具容易被误用。这些反馈会转化为对API的改进压力。工具因此被那些必须使用它们的智能体不断重塑。
这个过程还处于早期阶段,是一个尚未成形的雏形循环,而非完整闭环。但方向已经很清晰:对API的改动越来越多地源自使用它的智能体本身。这使得同步循环的角色不仅仅是“保持客户端最新”,而是一个更大循环的传播环节:
智能体使用工具
这次交互暴露出易用性方面的反馈
API和MCP封装根据反馈进行调整
记录的智能体技能文档随之更新,以反映改进后的工具接口
同步循环将这一变化传递给每一个智能体,下一个智能体就能用上更好的工具接口。使用者在塑造生产者,而同步循环确保这一过程保持真实和及时。
这就是背景——本文接下来要讨论的,是其中更偏向工程层面的内部循环:让API与MCP保持同步。
重新同步的解剖
人工操作流程有一个固定的结构。
同步——将新的openapi.json文件拉取到仓库中
预处理——为代码生成器做规范化处理
代码生成——重新生成带类型的HTTP客户端
差异比对——计算实际发生的变化
整理——按照我们的工具映射模式,将真正新增的接口转化为规范的MCP工具
验证——代码检查、类型检查、运行测试套件
提交PR——开启一个供审核的拉取请求
这七个步骤可以分为两类,而这种划分正是整个设计的核心。
六个机械步骤,一个需要判断力的步骤
七个步骤中有六个是机械性的。给定相同的规范文件,它们每次都会产生相同的输出。同步是文件复制。代码生成是确定性的转换。差异比对是集合运算。验证是运行测试。这些都不需要智能判断,只需要一段脚本。
只有一个步骤需要判断力:整理。我们的工具封装是刻意做得很薄的,但并非对API的机械式直接转发。我们制定了工具应如何映射到API的模式:命名方式、暴露内容、参数结构,以及如何保证调用的安全性。将一个新接口转化为优质的MCP工具,意味着要判断它是否应该出现在工具接口中,然后再使其符合这一模式。
这一步骤本身也由Claude完成,它运行一个高度精炼的技能,该技能编码了这一模式,将其应用到新接口上,并将任何新颁或不太匹配的情况标记出来供人工判断。这是推理性的工作,而非代码生成,这正是我们把模型能力用在这一环节的原因。
这种区分贯穿了关于循环工程的讨论。Armin Ronacher在反思循环真正奏效的场景时指出,循环在可验证的机械式转换任务上,以及不需要长期维护的产物上表现最强;而在无人监督地生成需要长期维护的代码时,风险最大。我们的代码生成正是最安全的那种情况:从规范文件到客户端的可验证转换。Andrew Ng用控制理论的语言表达了同样的原则:循环中最难的部分在于明确它控制什么、如何检测误差、用什么执行器来纠正、以及在何处停止。对我们而言,这个循环控制的是规范文件与工具之间的一致性,误差信号是规范文件的差异,执行器是重新同步操作,停止条件是开启一个PR。
我们最终确定的原则是:让确定性的步骤保持确定性,把模型能力留给真正需要思考的那一个步骤。交给大语言模型的每一个步骤,都可能变得不确定、缓慢且成本高昂;而保留为脚本的每一个步骤,都是可复现、可信赖的。我们并不想要一个能自行重新同步仓库的AI,而是想要一个确定性的流水线,其中只包含一个边界清晰的推理步骤。
将其接入一个循环
Ronacher在两种循环之间划出了一条有用的界线。一种是每个编程智能体内部的智能体循环:调用工具、读取结果、编辑文件、运行测试、重复这一过程。另一种是外部的“框架循环”,它决定智能体所谓的“完成”是否真的完成,以及接下来该做什么。循环工程主要关注的正是这种外部循环。我们的实现如下。
当某个后端将API变更合并到主分支时,一个GitHub Actions工作流会向MCP仓库发出一个repository_dispatch事件。这会触发一个工作流,无交互地运行Claude Code——与我们日常交互使用的是同一个智能体,只是此时在AWS Bedrock上的CI环境中无人值守地运行,指向一个编码了重新同步流程的技能。
该智能体运行完整的流水线并提交一个拉取请求。它从不直接推送到主分支。人工审核该PR并完成合并。框架循环包裹着Claude Code的智能体循环,而拉取请求是唯一需要人工介入的环节。
流程写在技能文档中
这个推理步骤并不是一个自由发挥、“自己想办法”的提示。它是一个“技能”:一份版本受控的文档,记录了该流程、各个API的特定约定以及防护措施,与它所操作的代码一起存放在同一个仓库中。
技能是Osmani提出的五种循环基本构件之一,与自动化、隔离工作树、连接器和子智能体并列,他的这种框架划分是恰当的。技能是写在外部的意图说明,只需写一次,智能体每次运行时都会读取它。没有它,循环就会每次从零推导出项目的上下文,并用自信的猜测来填补空白;而有了它,知识就能不断积累。
这份技能文档还有一个我们很看重的特性:它既可以由人工使用,也可以由机器使用。工程师可以在本地运行它来手动完成一次重新同步,CI也可以无交互地运行它。关于我们如何完成这项工作,只存在一个真相来源,而改进它会同时惠及两条路径。
防护措施
赋予智能体对仓库的写入权限,会提高对防护措施的要求。我们的防护措施分为多层:
仅通过PR提交。输出结果始终是一个拉取请求,它无法直接触及主分支。
基于差异的工作触发机制。如果传入的规范文件与已提交的版本完全一致(逐字节相同),循环就什么都不做。大多数上游推送改变的是实现细节,而非接口契约,所以大多数时候根本无需任何操作。
基于判断力的成本控制。推理步骤只在差异比对显示有新增接口时才会运行。单纯的模式微调仅通过机械路径处理。循环的运行成本可能迅速攀升,这也是每一位撰写相关文章的从业者都会提到的首要问题。
最小权限原则。使用范围受限的令牌,以及仅限于当前任务的工具许可列表。
这种分层防护很重要,因为一个具有自主编辑能力的循环会找到你留下的任何漏洞。保护措施必须分布在多个层面——配置、技能文档和CI流程中——这样一来,一个漏过某道检查的错误,也能被另一道检查拦截下来。
面向未发布API的第二个循环
当合并到主分支的循环投入使用后,一个显而易见的需求随之而来。一位正在功能分支上开发某项特性的后端工程师,希望在任何代码合并之前,就能通过MCP服务器驱动他尚未发布的API。
于是我们在第一个循环之上构建了第二个循环。工程师只需为其API拉取请求打上“Preview MCP”标签,从那一刻起,MCP仓库就会维护一个跟踪分支以及一个实时预览部署,二者都跟随该工程师的功能分支同步变化。预览环境的客户端会根据该分支的规范文件重新生成,并指向该分支自己的预览后端。客户端与后端同步变化,这样新的API就可以在合并之前,通过真实的MCP工具端到端地被完整测试。
按照Ronacher的判断标准,这正是最适合使用循环的场景之一,因为预览环境本身就是一个无需长期维护的临时产物。其经济性被严格把控,因为开发者推送代码的频率很高,而大多数推送并不改变接口契约:
模型只在确实出现了需要转化为工具的新接口时才会被调用。其余情况几乎是零成本的,并且同样适用那条拉取请求的门槛机制。
依然做工程师
关于循环工程的讨论背后,隐藏着一种担忧。Ronacher直言不讳地指出:在一个完全由框架驱动的循环中,“我甚至不太确定自己的角色是什么”,被简化成了一个传话人。Osmani将这种失败模式称为“认知投降”——设计循环这件事,“如果带着判断力去做,就是解药;如果只是为了逃避思考,就会变成催化剂”。
我们的答案是设置人工关卡。循环消除了繁琐的重复劳动,所以现在没有人再逐项执行清单了,但它在决策环节保留了人的角色——审核真实的差异,批准真实的变更。工程师的角色从“执行流程”转变为“批准结果”,这是一个真正的角色,而不是橡皮图章式的走流程。我们始终坚持的是Osmani的总结:构建这个循环,同时依然做那个工程师。
在实践中,有几件事让这个循环真正发挥了作用,而它们并非MCP服务器所独有:
将机械性工作与需要判断力的工作分开。把一切确定性的事情都写成脚本,把模型能力留给真正需要思考的那个步骤。
挑选适合用循环处理的问题。可验证的转换任务和无需长期维护的临时产物,是目前循环能够安全发挥作用的领域。而在无人监督的情况下交付需要长期承载业务的代码,则是另一种风险。
把流程写成技能文档。打造一份人类和CI都能运行的产物,并且它会随着每一次经验教训不断改进。
对昂贵的步骤和成本设置门槛。先做差异比对,再决定是否需要推理,只有确实存在需要判断的情况时才动用模型。
分层设置防护措施。循环会找到你留下的任何漏洞,所以要在配置、流程文档和CI这三个层面都设好保护。
在关键节点保留人工审核。拉取请求就是一个很合适的位置。
拉远视角来看,这其实是循环嵌套循环的结构。Claude Code运行着它自己的智能体循环,我们的CI则用一个框架循环将其包裹起来,以保持工具的同步状态。而这两者又都处于我们正在构建的更大产品循环之内——一个“智能体优先”的平台,在这个平台上,使用工具的智能体正是重塑工具的那一方。同步循环正是让这个外部循环能够安全闭合的关键所在,这样一个智能体所提出的改进需求,才能传递到下一个智能体手中,并且全程都有人工把关签字。
Cherny所观察到的现象,并不是说工作变得更轻松了,而是发力点发生了转移——从提示词转移到了循环本身。有意识地把握这一转移,同时手始终放在关卡上,一个持续变动的API与它的MCP服务器,就能以极少的中间环节保持彼此的真实同步。
Rapidflare为电子与半导体行业的技术销售与支持场景构建垂直领域的AI智能体。如果构建可靠的智能体基础设施正是你想解决的问题,我们很愿意与你交流。
延伸阅读
Addy Osmani,《循环工程——五大构件》——提出了五种基本构件,以及“构建循环,依然做工程师”的理念。
Armin Ronacher,《即将到来的循环》——阐述了智能体循环与框架循环的区别,以及循环适用的安全场景。
John Williams
Rapidflare首席科学家
