即将到来的循环

Armin Ronacher 新闻

摘要

讨论了使用外部控制循环将AI编码代理会话扩展到正常边界之外的新兴模式,并批评了当前的代码质量问题。

<blockquote> <p>我不再向Claude发提示了。我有一些循环在运行,它们自己会提示Claude并决定该做什么。我的工作就是写循环。</p> <p>—— Boris Cherny</p> </blockquote> <p>过去几个月,我看到越来越多的人在编码代理之上构建一些东西,感觉与仅仅使用编码代理有本质上的不同。其中一些是在Pi之上完成的,这当然很酷!不过模式到处都是一样的:工作被放入某种队列,机器接收、尝试、停止,然后某个外部控制循环决定那是否真的是终点。</p> <p>如果不是,该外部控制循环会继续同一个会话,注入另一条消息,启动一个具有修改后上下文的新会话,或者将任务发送给另一台机器。任务的生命周期会持续超过模型自身正常情况下会说“我完成了”的那个点。</p> <p>我思考这种类型循环的次数比我愿意承认的要多。</p> <p>每个编码代理内部已经有一个代理循环。模型调用工具,整合结果,调用另一个工具,读取文件,编辑文件,运行测试,最终产生某个答案。这个循环我们已经非常熟悉很长时间了。另一个循环是外部控制层次的循环:即代理循环外层的循环。那个循环也不是新东西。从早期Claude Code时代开始,我们就在做各种版本的这种循环,但那个循环在代理工程中变得越来越普遍,最近几周它已经开始主导Twitter上的讨论。</p> <h2>我还不擅长这个</h2> <p>我目前的状态是,对于我深为关心的代码(其实相当多)采用这种工作方式,我还没有取得多少成功。</p> <p>部分原因是品味,部分原因是控制。我试图为我期望的代码样貌设定高标准,并且我想要理解我所发布的代码。在压力之下,或在与他人讨论时,我希望能够解释系统做了什么,而不必先问一个AI助手来向我解释。显然,存在一个问题:几年后我是否还会有这种理解代码的愿望?目前,我还没有跨越理解对我来说依然重要的那个点。</p> <p>鉴于这种愿望,对于我没有亲自关注的代码(尤其是来自循环的代码)的经验中,我缺乏某些东西。当前的模型倾向于生成过于防御性、过于复杂、推理过于局部的代码。它们避免强不变量。它们添加后备方案,而不是让错误状态变得不可能。它们重复代码,发明糟糕的抽象,并用更多的机制来掩盖不清晰的设计。更糟的是:到目前为止,我几乎没有看到这方面有所改善。相反,在我看来,我们在这方面可能甚至还在朝错误的方向前进。至少以我的品味,当前像搭配ultracode的Claude Code这样的放手式外部控制循环产生的代码比去年秋天我们生产的更差。这是因为Claude Code(例如使用Fable时)会不间断地工作三十分钟或更久,而以前的过程中会有更多人类参与。</p> <p>此外,众所周知,模型倾向于观察到局部失败并添加局部防御。Karpathy提到它们“对异常恐惧得要命”。在存在重要不变量的系统中,尤其是持久化数据格式或核心基础设施,正确的修复不是“处理每个错误格式的情况”。正确的修复是让错误格式的情况从一开始就不可表示或不可能写入。然而,即使有大量的人工引导,那种代码也不会自然地来自LLM,即使代码自然生成,它们仍然会试图处理现在已经不可能的错误。</p> <p>当你把这种行为放到循环后面,你往往会放大它。如果每次迭代都添加一个小防御,系统会慢慢变得不那么可理解,同时看起来更健壮。你越是放手,这种情况就越多。当这类工具在缺乏明确指导的情况下交给初级开发者时,还会教会他们非常糟糕的实践。因为如果你问他们为什么这样做,他们会有说服力地为自己辩护。</p> <h2>循环在哪里有效</h2> <p>同时,假装循环模式不奏效是不诚实的,因为它在某些领域已经表现出惊人的效果。</p> <p>代码移植就是其中之一。已经有一些令人印象深刻的大型自动移植工作,包括报道中将Bun的部分代码从Zig移植到Rust。我自己也成功使用循环将MiniJinja移植到Go。性能探索是另一个效果极佳的场景。机器可以尝试实验、进行基准测试、丢弃失败、继续搜索。安全扫描也很自然适用,几乎任何类型的研究也是如此:让系统探索一个复杂的问题空间并报告结果,而不一定生成长期保留的代码。这些场景的许多共同点是:要么它们不生成新代码,而是转换现有代码;要么它们产生的代码有意不具长期寿命。它们要么产生概念验证或想法,要么揭示发现,或者更像是机械转换。</p> <p>我认为,产生无需长期保留的产物或创建某种可清晰验证的机械转换的循环,比外部控制循环机械地衡量一个目标的通用能力更重要。许多成功的循环应用使用另一个LLM作为评判者或编排者。机械转换的情况可以通过二元测试用例验证,但也可以由LLM来评判!</p> <p>例如,Claude Code越来越擅长创建完整的实验性工作流,然后执行它们。当然,它生成的代码是垃圾,但这更多是模型的错,而不是外部控制循环不能很好判断工作流中的某一步是否带来了净改进或完成。</p> <p>外部控制循环只需要一些信号来让其继续。它不必是客观的或二元的,它只需要足够有用以驱动下一次迭代。</p> <p>我绝对已经喜欢那些能从我日常工作中去除无聊部分的循环——用来实验、测量并给我带来灵感。</p> <h2>软件作为有机体</h2> <p>另一方面,使用同样的循环方法论来编写持久性代码,目前我还不太适应。我喜欢用的比喻是从软件作为确定性机器转向软件作为有机体。</p> <p>我在一个鼓励理解机器的环境中成为一名软件工程师。总是有一层你可以剥开来加深理解。那些不表现出确定性可观察行为的机器也许能被接受,但通常被视为不够理想。从软件架构的角度看,我认为朝着更多确定性而不是更少推进是可取的。同样,理解代码的能力一直是一个不容否认的目标。虽然实际上并非总能实现,但我们仍然为编写代码感到自豪,使得即使是新工程师也能通过巧妙的架构导航复杂的代码库。在精心设计的系统上,总有工程师知道不变量在哪里,哪些部分是承重的,哪些修改是安全的。理想情况下,所有这些都有良好的文档记录。在缺乏理解的地方,通常被视为需要改进之处。</p> <p>显然,那个理想一直</p>
查看原文
查看缓存全文

缓存时间: 2026/06/23 13:39

# 即将到来的循环 来源:https://lucumr.pocoo.org/2026/6/23/the-coming-loop/ 写于2026年6月23日 > 我不再直接提示 Claude 了。我有循环在运行,提示 Claude 并让它自己决定该做什么。我的工作是写循环。—— Boris Cherny 过去几个月里,我看到越来越多的人基于编程代理构建出一些东西,这些东西给人的感觉与仅仅使用编程代理截然不同。其中一部分构建在 Pi (https://pi.dev/) 之上,这当然值得高兴!不过,模式在任何地方都一样:工作被放入某种队列,机器将其取走、尝试执行、然后停下,接着由某个外层框架决定这是否真的就是终点了。 如果不是终点,外层框架就会继续同一个会话,注入另一条消息,用修改过的上下文启动一个新会话,或者把任务发送给另一台机器。任务的生命周期会延续到模型自己通常会说“我完成了”那个点之后。 我思考这种循环的频率远超我愿意承认的。 在每个编程代理内部,已经有一个代理循环。模型调用一个工具,整合结果,调用另一个工具,读取文件,编辑文件,运行测试,最终得出某种答案。这个循环我们早已非常熟悉。另一个循环是框架层循环:代理循环外面的那个循环。这个循环也并非新鲜事物 (https://ghuntley.com/ralph/)。自早期 Claude Code 时代以来,我们就一直在做它的各种变体,但这个循环在代理工程中正变得愈发普遍,近几周它甚至开始主导 Twitter 上的讨论。 ## 我还没掌握好这个 我目前的状况是,在我真正在意的代码上,用这种工作方式并没有取得太大成功——而那样的代码量相当多。 这其中有品味的因素,也有控制的因素。我试图为我想要的代码设定一个高标准:我希望理解我发布的代码。在面对压力或者与他人讨论时,我需要能够在不必先请一个 clanker 向我解释的情况下,解释系统是如何工作的。当然,这里有一个问题:这种理解代码的愿望,几年后我是否还会保留?目前来说,理解对我来说仍然很重要,我还没跨越这个阶段。 出于这种愿望,我对那些我没有全程参与的代码(特别是来自循环的代码)有一种缺失感。当前的模型往往倾向于编写过于防御性、过于复杂、推理过于局部的代码。它们回避强不变性。它们添加回退机制,而不是让错误状态变得不可能。它们重复代码,发明糟糕的抽象,用更多的机器来掩盖不清晰的设计。更糟糕的是:在我看来,这方面几乎看不到什么进步。甚至在某些方面,我觉得我们可能正在朝着错误的方向迈进。至少以我的品味,当前像 Claude Code 配上 ultracode 这种放手式的框架,生成的代码比我们去年秋天产出的还要差。这是因为 Claude Code(例如配合 Fable)会连续三十分钟或更久无中断地解决问题,而以前的过程中会有更多人类参与其中。 此外,我们都知道模型倾向于观察到局部失败后就添加局部防御。Karpathy 提到 (https://x.com/karpathy/status/1976082963382272334) 他们“对异常极度恐惧”。在那些具有重要不变性的系统中——特别是持久化数据格式或核心基础设施——正确的修复方式不是“处理每一个异常情况”,而是让异常情况从一开始就无法表示或根本不可能出现。然而,即使有大量的人工引导,这种类型的代码也不会自然地从 LLM 中产生;即使代码自然出来了,模型仍然会试图去处理现在已经不可能的“错误”。 当你把这种行为放进循环里,往往会放大它。每一次迭代都增加一点小防御,系统就会在不那么易理解的同时,显得更加健壮。你越是放手,这种情况就越严重。当这种工具在没有明确指导的情况下交给初级开发者时,还会教会他们非常糟糕的实践。因为如果你问他们为什么要做所有这些防御,他们会很有说服力地为自己辩解。 ## 循环在哪些地方有效 与此同时,假装循环模式不管用也是不诚实的——它在某些领域已经表现得惊人地好。 代码移植就是其中之一。已经有了令人印象深刻的大规模自动移植案例,包括报道中提及的将Bun 的部分代码从 Zig 移植到 Rust (https://ziggit.dev/t/bun-is-being-ported-from-zig-to-rust/15330) 的工作。我自己也成功用它来将 MiniJinja 移植到 Go (https://lucumr.pocoo.org/2026/1/14/minijinja-go-port/)。性能探索是另一个效果极佳的领域。机器可以不断尝试实验、做基准测试、丢弃失败的结果并继续搜索。安全扫描也天然适合,几乎所有类型的研究也是如此:让系统探索一个复杂的问题空间并汇报结果,而不必生成长期保留的代码。这些案例的共性之一是:它们要么不生成新代码,而是转换已有代码;要么生成的代码本身就刻意不打算长存。它们要么产生概念验证或想法、呈现发现结果,要么更像是机械性的转换。 我认为,那些生成不需要长期存在的制品、或者产生某种可以清晰验证的机械翻译的循环,比框架机械地衡量目标的一般能力更为重要。许多成功的循环应用会使用另一个 LLM 来充当评判者或编排者。机械翻译的情况可以用二元测试用例来验证,但同样也可以由 LLM 来评判! 例如,Claude Code 在创建完整的实验工作流方面越来越擅长,然后它自己就会去执行这些工作流。当然,它生成的代码可能是垃圾,但这更多是模型的过错,而不是框架没有做好对工作流中某一步是否带来净改进或完成的评判。 框架只需要一些信号来让它继续下去。这个信号不必是客观的或二元的,只要能足够有用以驱动下一次迭代就够了。 我非常喜欢那些从日常工作中去掉枯燥部分的循环,让我有时间去实验、测量并获得灵感。 ## 软件即有机体 另一方面,用同样的循环方法来编写持久性代码,目前对我来说仍然不太合适。我喜欢用的比喻是:从软件作为确定性机器,转变为软件作为有机体。 我成为一名软件工程师的环境鼓励我去理解机器。总有一层你可以剥开以加深理解。那些不表现出确定性可观察行为的机器或许可以被接受,但通常被视为不是最优的。在软件架构上,我认为追求更多的确定性(而不是更少)是可取的。同样,理解代码的能力一直是一个无可否认的目标。虽然实践中并非总是可能,但我们仍然以编写出能让即使是新工程师也能通过巧妙架构驾驭复杂代码库的代码而自豪。在精心设计的系统中,总有工程师知道不变性在哪里、哪些部分承重、哪些更改是安全的。理想情况下,所有这些都有良好的文档记录。在缺乏这种理解的地方,通常被视为需要改进之处。 显然,这种理想一直面临压力。许多软件系统,尤其是非常成功的系统,都经历过团队中的工程师能够保持它们整洁的时期。大型软件系统常常过于庞大、过于动态、过于依赖外部服务,以至于无法装入任何人的头脑。即使在 LLM 出现之前,我们诊断分布式系统的方式就已经有点像医生:观察症状、形成假设、“安排更多测试”、尝试一些补救措施、再次观察。 然而,有了 LLM,我们正更快地向那个方向推进。我们用它们来编写代码,也用于诊断和补救。已经有很多工程师生活在一个世界中:生产问题发生后,第一步是让一个 clanker 读取日志、提出根因并主动打上补丁。结果补丁常常由另一台机器接手审查,有时甚至在没有人工监督的情况下直接合并到主分支。 显然这很强大,我不能否认它听起来很有吸引力。但屈服于这种想法——尤其是在人类监督越来越少的情况下——意味着接受我们可能不再以同样的方式理解整个系统。我们治疗它、监控它、稳定它,但未必真正理解它。 我毫不怀疑,对于某些软件来说,这没问题。并非每一行代码都值得人类创作,更糟糕的代码过去可能也写过。 但我希望所有软件都这样创作吗? ## 你无法完全置身事外 令人非常不安的是,完全避开这个机器驱动的未来可能不是一种选择。 安全性就是当下最明显的例子。即使你不用循环来构建你的软件,其他人也会用循环来对抗你的软件。攻击者会持续运行机器,即使不是攻击者,安全研究人员也会这么做;其中一些自动化工作会产生大量噪音,但也会发现真正的问题。而无论是信号还是噪音,都会以巨大的量流向你,让你几乎无法应对,除非你自己也扔一台机器来处理问题。 Daniel Stenberg 关于 curl 的“夏日极乐”的博文 (https://daniel.haxx.se/blog/2026/06/15/curl-summer-of-bliss/) 就是一个很好的例子,展示了维护者已经承受的压力。据我所知,AI 目前并未在 curl 的核心开发中扮演重要角色。然而尽管如此,维护者仍被大量报告淹没,其中大多数现在都是由 AI 生成的。 如果攻击者和报告者在循环,那么防御者最终也需要循环才能跟上。也许不是直接写补丁,也许只是为了分类和复现,但压力会不断增加。 同样的情况也存在于竞争中:一些团队会通过纯粹的速度超越其他团队。一些项目会突然加速,因为一个小组学会了如何有效地编排机器。一些初创公司可以用五个人的团队完成过去需要五十个人才能完成的事。有些人甚至会直接让你的产品进入一个循环,并告诉机器“把它做得像另一个一样”。而如果他们的用户满意,那真的重要吗? 并非所有软件都会受到同等影响。有些领域会惩罚粗制滥造,要求信任和责任;但很多软件存在于一个原始速度、快速实验和大范围覆盖至关重要的世界里。 ## 建立新的依赖关系 对我来说,最可怕的部分是,我们正以新的方式依赖这些新机器。软件从来都依赖工具。我还记得必须为编译器付费的年代。这些新工具让人回想起创建软件需要真实成本的时光。但现在不再是单次付款,而是持续的依赖关系。不仅仅是对充实钱包的依赖,还有认知上的依赖。 如果一个代码库是由循环产生的、由循环审查的、由循环打补丁的、并由循环维持存活的,那么当你不再能访问同一类系统时会发生什么?当某些贸易限制剥夺了访问最强大模型的权限时呢?如果使用成本变得无法承受呢?如果你和你的团队失去了最后一种不用机器就能理解代码的能力呢? 我们可能会创造出不仅人类难以维护,而且其维护模式本身就需要机器参与的代码库。这已经在发生了!并非到处都在发生,甚至可能还没有被视为问题,但我们看到越来越多这种情况。越来越多的人合并了他们无法完全解释的代码。人们失去了创建问题报告或在聊天中讨论问题而不借助 clanker 增强或改写上下文的能力。越来越多的人依赖机器来总结或提供上下文。我越来越多地遇到一些通过 LLM 作为中间媒介与我交谈的人。 再说一次,也许这甚至不会被认为是错的,但对我们做事的方式来说,这是一个巨大的变化。 ## 未来的框架 我毫不怀疑这是大势所趋,但要走到那一步,我们需要在各个方面改进我们的工具,不仅仅是在编程代理里。 仅仅编排更多的循环是不够的。更好的变更可视化、更好的编排可视化或代理可视化,并不能恢复我们的理解。要么我们需要找到巧妙的方法,把人拉回循环中,并使循环的变更长期可读;要么我们需要找到更好的方法来组合这些日益复杂的系统。 这也是我对 Pi 角色看法发生变化的地方。Pi 一直很谨慎,我认为这种谨慎是好的。我不希望未来每一次交互都变成一群不受控制的机器在做出我无法追踪的变更。我不希望 Pi 为了赢得“软件自我编写”的竞赛而变成一团不可维护的混乱,我也不希望 Pi 推广这种工程方式。与此同时,Pi 是一个框架,而框架正处在人们运行这些新型实验的中心。 用于编码任务的任务队列、代理编排、子代理、持久会话将变得越来越重要。即使是我们这些有保留意见并且没有盲目拥抱循环的人,也必须开始做这些实验。我们需要这样做,因为我们必须理解如何让这个未来变得有边界、可存活。 ## 控制循环 正如你从这篇文章中能读到的,我对这个未来感到非常不安。不是出于恐惧,而是出于谨慎——基于迄今为止对这项技术的经验。 接受框架循环的想法意味着框架来决定工作何时完成。在代理循环中,模型最终会说“完成”,然后我来审查。甚至在那之前,我通常会在过程中进行引导。我参与其中,并且我喜欢在这个过程中学习。在框架操作的循环中,我甚至不确定自己的角色是什么。连“完成”信号都失去了意义,只是传递给另一台评判的机器。我的角色被简化为一个信使。 今天,我不喜欢我看到的那种由这些方式构建的系统所产出的代码,也不喜欢与太多由 AI 辅助构建的软件进行交互。循环是很强大,但它越来越多地移除责任,至少在当下,它非常鼓励我们向机器屈服。 然而我毫不怀疑,尽管我目前对此感到厌恶,但循环式的未来将依然是我们的未来。我已经看到规模小得惊人的团队以不可思议的速度构建,我看到代码库越来越多地变成只有更多机器才能诊断的、晦涩而令人困惑的有机体。这些代码库同时既有用又混乱。 所以我想我正在接受这样一个事实:问题不在于我们是否会循环——因为显然我们会。也许真正的问题是:在一个充满循环的未来中,我们如何不放弃判断,如何保留良好工程的原则,如何确保负责任的人类能够在需要时拥有真正的理解?

相似文章

AI世界正在变得‘循环’

TechCrunch AI

本文讨论了AI智能体系统中‘循环’的兴起,即智能体持续提示其他智能体执行任务,这被视为超越简单智能体使用的重要一步。Claude Code的Boris Cherny在Meta的@Scale大会上支持这一方法。

@mvanhorn: https://x.com/mvanhorn/status/2063865685558903149

X AI KOLs Following

本文解释了AI编程中'循环'的概念,即开发者编写程序来提示编码代理,而不是手动提示,这一概念由Peter Steinberger和Boris Cherny推广开来,并讨论了这种转变如何代表了AI辅助开发中的新抽象层。