循环工程是一个与使用AI代理相关术语,它有点像提示工程的更新、更酷的版本。但在提示工程中,重点在于编写一个完美无缺的终极提示词,然后将其发送给大型语言模型。接着模型会返回响应,你需要编写下一个完美的提示词,以此类推。现在,循环工程是指设计一个系统来为你完成所有这些提示工作。

那么,循环工程是如何运作的呢?它接收一个提示词并发送给AI代理。随后,循环工程会检查代理的工作成果,并再次对其进行提示。我们这样来回往复、不断循环,直到任务完成。但我们不需要手动为每一步设计提示词,这正是循环工程的工作职责。尽管这里提到的人类介入极少,不过我们稍后会再回到“极少”这个词上。

总之,让我们给代理分配一项任务。假设有一个结账服务,其中包含大量失败的单元测试。这项任务是让那些失败的单元测试不再失败。为此我们将使用一个循环。现在,这个循环始于一个目标:让结账服务的单元测试通过。接下来是AI代理采取行动的阶段。

对于编码代理而言,这通常涉及打开文件或编辑代码等操作。循环的下一个阶段是代理观察输出结果。而循环的最后一步则是根据这些反馈进行调整。如果测试变绿(通过),那就太好了,该项任务完成,代理将继续处理下一个失败的用例。

如果测试仍然显示红色(失败),它会尝试不同的修复方案,然后再次回到目标阶段:我们完成了吗?还没有。好的,再来一次。如此周而复始地循环下去。因此,设定一个良好的目标非常重要,因为每次代理完成一轮循环时都会评估该目标。

这决定了代理是继续执行还是停止。例如,“让结账服务更快”是一个相当糟糕的目标,就像“更快乐”作为新年决心一样缺乏意义。它们都没有可衡量的测试标准,因此代理可能永远循环下去,或者仅仅经过一次迭代就宣布胜利。

相比之下,“当结账流程中的所有单元测试都通过时停止”是一个可验证的目标,这样代理就能确切知道何时达成目标。一个好的目标是具体的,包含结束条件和停止条件。这就是循环的基本原理:基本上就是这四个阶段。

听起来没什么大不了的,对吧?似乎并不需要一门以其命名的整个工程学科。那么为什么需要呢?因为循环工程实际上是围绕这个循环构建起来的体系。让我们来看看具体细节。首先,必须有某种机制来启动这个循环。

这种触发器可能是一个计划任务(schedule),或者被称为钩子(hook)的东西。例如,每晚运行结账循环就是一个简单的计划任务。许多团队会直接使用传统的cron作业来实现这一点。而钩子则是事件驱动的,意味着当发生特定情况(如文件更改或拉取请求打开)时触发。

开发人员主要使用钩子来确保安全性和质量,例如强制执行策略。现在,代理循环的每一次往返都会生成一些内容,也就是上下文(context)。例如测试输出或文件内容都属于上下文。这些上下文可能会迅速堆积,使得代理难以将注意力集中在重要信息上。

因此,循环工程的一部分在于选择让代理在每一轮中实际看到哪些内容。这可能意味着我们需要对上下文进行操作,比如进行压缩(compaction)。或者我们可以使用渐进式披露的代理技能,其中包含执行特定重复任务的指令。

在循环内部有一个我称之为“脊柱”(spine)的东西,这是持久状态的一部分。例如,代理可能会写入一些Markdown文件,记录它做了什么以及是否成功。存储在脊柱中的信息可以指导循环未来的迭代,告诉代理之前哪些方法有效、哪些无效。

在行动阶段,代理可能需要调用外部资源。它通过工具访问来实现这一点。这可能涉及使用模型上下文协议(MCP)等标准,或者直接通过API进行工具调用。代理利用工具来执行代码、访问文件系统、在终端中运行命令以及查询数据库等。

而在观察阶段,与其让编写代码的同一个代理去检查代码,良好的循环工程会引入第二个代理。我们可以将第二个代理视为一个子代理(sub-agent)。它充当检查员和协作者的角色,用于分发任务。

这个子代理拥有自己的指令和自己的上下文,并且可能由不同于主AI代理的另一个AI模型驱动。在将结果发回之前,它会进行独立评估。这就是整个循环:有一个触发器启动循环;有上下文和技能为其提供信息;有脊柱记住发生的情况;有工具让它执行任务;还有子代理来验证结果。

这就留下了一个问题:在这一切循环运行时,人类究竟在做什么?好吧,回到“最少的人类参与”这个话题。我之前说过,与提示工程相比,循环工程需要极少的人类介入,因为代理会自行编写提示词,而不是由人手动提交。

然而,即使是一个构建良好的循环——包含检查器、子代理、脊柱以及其他组件——仍然需要人类的参与。人机协作(Human-in-the-loop)的方法有助于避免自动化代码生成中可能出现的最大危险陷阱。那么我指的是哪些陷阱呢?我有四个要点,首先就是未经验证的代码。

检查器子代理仍然只是一个代理。人类开发人员最终要对所有发布的代码负责,这意味着必须有真人阅读并验证这些代码。系统中代码总量与人类对其理解程度之间的差距被称为“认知债务”(comprehension debt)。

随着代理编写越来越多的代码,而人类检查的代码越来越少,我们的认知债务将持续上升。这种债务积累得非常快,因为代理确实编写了大量代码。如果不加以缓解,认知债务将成为一个大问题。

当人类开发人员需要解决紧急的生产故障时,或者需要进行架构迁移时……此外,在陷阱类别下还有另一种债务,那就是“意图债务”(intent debt)。

智能体可以读取系统做了什么,但要弄清楚它为什么这么做则有些困难,除非这些信息被记录在某处,比如在一个 agent.md 文件中。如果没有这些记录,智能体可能会做出技术上合理但违背项目目标更改。在我们的结账循环示例中,也许智能体通过放宽折扣码的验证规则来修复失败的测试。就测试而言这是一个完全正确的修复,但就企业的底线来说这却是一个糟糕的修复方案。因此,人类的工作是写下意图,保持更新并让 AI 智能体可见这些内容。

我想提到的第四个陷阱是听起来相当严重的“认知投降”。我们肯定不想看到这种情况,但它非常容易发生。当一个人盲目接受循环产生的任何结果时,外包工作就会导致认知投降。“既然 AI 做的,我确信它是正确的。”当这种情况发生时,理解债务也会增加,因为现在没有人试图去理解生成的 AI 输出。

事实证明,“最小化人类干预”实际上意味着特定程度的人类干预。因此,人类需要写下目标和停止条件;人类需要将意图写入智能体可以找到的地方;并且人类需要阅读来自智能体的输出。当有人在循环中时,循环工程效果最佳。你在工作工程中构建自主 AI 代理的循环吗?请在评论中告诉我!