论集群的本质:从上下文压缩到智能体网状协作
On the Nature of the Swarm
Prime Intellect 博客文章讨论智能体如何突破上下文窗口限制,指出压缩只是把上下文容量从单窗口扩展到多窗口,且每次压缩都是对未来需求的猜测。作者提出用磁盘卸载、子智能体、持久化智能体三种方式提升总上下文容量,并认为多智能体并非新的扩展维度,而是推理算力的结构化使用。
从压缩、子智能体到持久化智能体逐层拆解上下文容量问题,并借科斯与哈耶克解释为何树形结构会失效。
论集群的本质
最初于10月6日发表在我的个人博客上。
让我们从一个人人都应认同的观点开始:推理扩展是有效的。事实上,它有效到LLMs现在能够实现令人印象深刻的壮举,比如可信地声称解决了千禧年大奖难题——在我们发现推理遵循扩展定律之前,这似乎是荒谬的。在测试时为模型提供更多计算资源(让它思考更久、调用更多工具、检查自己的工作),它就能在任务上表现更好。只有一个问题:最终,你会耗尽上下文。
我是说字面意思:你填满了预定义的上下文窗口。1 上下文窗口也没有变得更大:当前的前沿模型都最多在1M tokens左右。例如,你看不到任何严肃的模型有100M-token的上下文窗口。然而,如今的智能体经常执行那些仅凭1M tokens上下文应该不可能解决的任务。这怎么可能?
如果你在过去一年里使用过编码智能体,你已经知道解释这种差异的魔术了…… 压缩!
压缩
压缩的工作原理是这样的:一旦你接近上下文窗口的末端,你就让智能体写一个摘要,并将其工作交接给一个全新的上下文,在那里这项工作被继续,直到上下文窗口再次填满,你又得再次压缩。你这样做直到(智能体认为)任务解决。
压缩很神奇。它让你可以让同一个智能体会话持续数天(或数周)而不耗尽上下文。问题解决了,无限上下文,无限推理扩展,一切皆有可能。那我为什么要写这篇博客文章呢?
嗯……压缩实际上并没有给你无限上下文。它做了别的事情。更微妙的事情。它提升了模型的总上下文容量2,粗略地定义为模型能承担的最大任务,其中任务的大小是你一次性完成它所需的窗口大小。压缩超出模型预定义上下文窗口的程度取决于智能体所做的工作在每次交接中必须存活多少。
这种限制背后的基本原则是,每次压缩都是一次赌注。进行总结的智能体必须现在决定什么在以后重要。通常它猜得足够好,3 但有些任务比其他任务更不容忍错误。4 大多数真实任务也是部分可观察的,所以你所看到的东西是否重要往往取决于你尚未看到的东西。正如俗话所说,“做出预测很难,尤其是关于未来的预测”。5
使摘要损失更小(或者用我们的术语来说,提升总上下文容量)的一种方法是让智能体使用文件系统或REPL来卸载记忆。例如,智能体可以将某个复杂工作流的细节写入磁盘,并在摘要中放置指向相关文件的指针。
这其实帮了大忙!没有任何东西会因压缩而丢失。摘要只需说明东西在哪里。所以我们的赌注变得没那么可怕了:问题曾经是“我需要记住什么?”而现在变成了“我需要知道什么东西存在?”这让人想起那句名言:“绅士不必懂拉丁语,但他至少应该已经把它忘了。”6
但这仍然是一场赌注,而且它带来了新的成本。磁盘上的文件本身什么都不做;它们只是静静地待在那里。7 要让这些文件发挥作用,下一个 agent 必须 (a) 意识到它相关,(b) 去找到它,以及 (c) 把它读回自己的上下文中。最后一步相当烦人,因为读取会消耗上下文,而这正是我们一开始就快用完的东西。8
换句话说,卸载到磁盘让我们能持久保存信息,但前一个上下文窗口中的 agent 通过阅读所有这些内容所理解到的东西已经消失了,每当有人需要时都必须重新构建。
那么我们完蛋了吗?也许吧。但我们还有几个锦囊妙计。
多 agent 系统
首先,注意我们可以把压缩看作一个(退化的)多 agent 系统:9 每次压缩都会启动一个新的 agent,其初始上下文是上一个 agent 摘要的函数。
第二种多 agent 系统是主 agent 协调子 agent。思路很简单:主 agent 启动一个带有任务的新 agent(“找到重试逻辑在哪里”、“弄清楚为什么这个测试不稳定”),然后拿回一个答案。子 agent 可能会消耗 20 万 token 来阅读文件并运行东西。主 agent 的上下文只增加任务和答案,可能也就几千 token。
现在有趣的部分来了。在我们的框架中,子 agent 的答案就是……它上下文的摘要。所以子 agent 实际上也是一种做压缩的方式!但有一个关键区别:摘要是在问题已知之后才写出来的。压缩必须猜测以后什么会重要。卸载到子 agent 则不需要猜测,因为你是在需要时才启动子 agent。10
额外的好处是,如果你有几个独立的问题,你可以同时启动几个子 agent。并行性是个不错的额外优势,但即使它们必须一个接一个地运行,基于上述原因,子 agent 在这些任务上仍然会胜过压缩。(这一点以后会很重要。)
子 agent 特别适合那些适合进行子任务分解、并且在交接和交付时有清晰边界的工作负载。对于这类任务,它们提升总上下文容量的程度远超压缩,因为主 agent 永远不必持有混乱的中间部分。
但子 agent 也并非没有缺点。它们有与磁盘相反的问题:它们会忘记一切。一旦子 agent 给出答案,它就消失了,连同它那 20 万 token 的阅读代码、运行测试和排除可能性的过程一起消失。下次你有相关问题时,你会启动一个新的子 agent,而它会再次完成所有这些阅读。你也不能在十轮对话之后追问它,比如“等等,你刚才那是什么意思?”
所以现在我们有两个半吊子解决方案。卸载到磁盘能记住,但不能思考。子 agent 能思考,但不能记住。嗯。
雇用子 agent
你大概能看出这要往哪儿走了。第四个角是显而易见的那一个:干脆……别杀掉子代理。把它留着。实在不行就雇着它。总之别把它拆了。
一个持久化子代理会保留它的上下文(以及它的文件,还有它留下的任何还在运行的东西)。当你对它参与过的事情有新的问题时,直接问它就行。它已经读过所有内容,所以不必从头开始,而你的上下文只增加问题和答案。
现在我们两全其美了。像磁盘那样,什么都不丢。像子代理那样,等你知道需要什么时再写摘要。又不同于两者,你明天还能带着不同的问题再问一次。这意味着压缩不再是一次性的赌注。你永远不必事先决定要保留什么,因为你随时可以回来再问。
现在回到我们那个退化的多代理系统。压缩是一串代理串联工作,每一个都依赖前一个,而且在任何时刻只有一个“活着”。凡是没进摘要的东西都消失了,因为知道它的那个代理已经没了。
有了持久化代理,好几个可以同时活着。当然,它们也可以同时运行:把问题拆成子问题,并行解决,更快完成。11这是多代理显而易见的论据,12而且确实成立。从基础设施的角度看,有很多很好的理由说明这为什么重要。但即便它们必须轮流来、一个接一个,它们的上下文仍然会并排存在。它们也是上下文层面的并行,而这正是如今讨论不足的地方:总上下文容量增长到(大致)每个代理一个窗口。13
当然,这些代理每一个仍然可以压缩!一个已经干了一阵子的子代理可以总结一下然后继续,和之前一样。所以两者能很好地叠加:压缩让每个代理沿时间方向延展,更多代理则让整个系统向侧面延展。你最终得到几条并排的链,它们可以互相提问。
没有免费的午餐
让我们先拉远一点看。这些技巧到底在做什么?压缩、卸载到磁盘、子代理、持久化代理:它们都是构建上下文的方式。在理想世界里,你早就该在一个窗口里拥有恰好正确的上下文,然后让模型直接吐出答案(或采取正确的行动序列)。14而在实践中,模型必须自己去构建它。推理通过思考来构建,代理通过行动(读文件、跑测试)来构建,而上面这一切都是关于构建出比一个窗口能容纳的更多的上下文。
一旦代理在真实世界中行动,构建上下文就基本是推理扩展的主要形态。这也是为什么我强烈反对像很多人那样把多代理称为“新的扩展轴”。我们仍然在扩展推理算力,只是以一种更有结构的方式在做。
当然,没有免费的午餐。代价是通信。每当一段上下文需要从一个代理传到另一个代理,它就必须被塞进一条消息里,这要消耗 token,而且本身是有损的。15如果一项任务最难的部分需要所有东西同时集中在一处,那么把它拆开根本帮不上忙。
需要说明的是,这一切都没有让我变得不那么乐观。OpenAI 刚刚让 10,000 个智能体解决了 Navier-Stokes 方程。16 两年前,你很难找到一个理智的人会认为这会发生。但集群并非万能灵药。你不能只是把一百万个智能体扔向一个难题,然后指望答案自己掉出来。首先,智能体本身必须足够好——而且要足够好到能够自我组织、有效协调,而不是仅仅重复彼此的工作。诚然,很多开销可能可以通过训练消除(那些擅长与成千上万个自身副本协作的智能体),但有些通信成本是结构性的。
从树到集群
到目前为止,一切都是树状的:一个根智能体生成子智能体,子智能体再生成自己的子智能体,结果向上回流。但一旦智能体之间可以互相发消息,树就会把每一次对话都路由经过根节点。根节点的上下文被填满,于是它必须压缩,然后……我们又回到了起点,只是上升了一个层级。树把上下文问题转移到了根节点。
显而易见的解决办法是让兄弟节点之间直接对话。但一旦兄弟节点可以跟任何需要的节点对话,你就得问:根节点到底还有什么用?没有人需要为了完成工作而听命于上方的某个人。不如让它们全都成为对等节点。
所以:没有根节点。你把若干个智能体放进一个共享世界,让它们作为网状结构中的对等节点彼此协调。就像每个智能体仍然可以压缩一样,每个智能体也仍然可以生成自己的子智能体。所以你可以在网状结构中拥有树。
这没问题。去掉根节点并不意味着层级结构毫无用处——毕竟公司仍然有 CEO。科斯在近 90 年前就问过这个问题:如果市场如此擅长协调,为什么公司还会存在?17 他的答案是:因为利用市场并非免费。每一次,你都必须找到合适的人,解释你想要什么,并就条款达成一致。而在公司内部,某个人可以直接决定。所以,公司恰恰存在于那种协调方式比作为对等方协调更便宜的地方。智能体也是如此:从没有层级结构开始,然后在任何能带来回报的地方加上一点层级。
这种方法之所以有效,原因之一是专业化。在集群中,没有人需要分配角色;角色会自然产生。假设某个智能体碰巧先看了前端。现在它在那里有了上下文,也许还构建了一个小工具。于是下一个前端问题就会去找它,因为这比让其他任何人从头开始都更便宜,而它回答的每一个问题都会让它在前端工作上变得更好一点。一个随机的早期差异会随着时间推移固化为一个角色。
这正是树结构真正有害的地方。下两级的子智能体受制于其父节点:它只为生成它的那个节点工作。所以,如果我们的前端专家位于某个分支,而另一个分支中的智能体有一个前端问题,它不能直接去问。问题必须向上传到它们共同的祖先,再向下传回来,途中经过那些根本不关心前端的上下文。
所以树只有两个选择,都很糟糕。要么每个分支都培养自己的前端专家,于是我们又回到了一遍又一遍重新发现同样东西的老路(而这正是持久化本该解决的问题)。要么其他分支没有这个专家,于是专家学到的一切只能帮助一个分支。而在网状结构中,任何人都可以直接问它。它的上下文会被任何需要它的人复用。
代理越多,这个问题就越严重。有 10 个代理时,树状结构大概还行。但如果有 10,000 个,让它们彼此发现并自行分工的同伴式结构就合理得多。18
经济学家在大约 80 年前就有过这场争论。哈耶克的观点19是,中央计划之所以失败,是因为运行一个经济体所需的知识分散在数百万人手中,无法全部汇聚到中心。根代理就是一个中央计划者。要想规划得好,它需要全部上下文,而全部上下文恰恰装不进一个窗口。(要让这个类比成立,群体并不需要价格或市场。关键在于知识存在于哪里,以及谁有权据此行动。)
群体应该是什么样子?
现在,我还不知道正确的结构是什么。纯粹的网状结构大概也不是答案。我的猜测是,我们先照搬人类组织的方式。给代理们我们使用的工具(共享的 git 仓库、问题跟踪器、Slack),让它们对共享状态拥有结构化访问权限,而共享状态可以作为唯一事实来源。正确的结构可能还取决于规模:一家五个人的初创公司靠几个 Slack 频道就能运转,而一家 10,000 人的公司则不行。布鲁克斯定律之类的东西。20
但关键在于:我们甚至不必锁定结构。我们可以让代理自己改变结构,这样我们就能把苦涩教训重新引入进来。21 所以我们可以用人类结构来播种这个群体,然后让代理在解决手头问题的过程中改进它。
关于如何构建一个代理群体,还有很多可说的,但我留到以后再谈。
感谢 Sebastian Müller 和 Sami Jaghouar 的校对和宝贵反馈!
脚注
-
不要与上下文腐化混淆:后者指的是代理随着上下文填满而表现变差,因此“有效”上下文窗口(代理表现达到峰值的窗口)比宣传的要小。↩
-
这是我编的。如果你有更好的名字,或者已经以别的名字发明了这个概念,请告诉我。↩
-
根据我的经验,对大多数任务来说,100 万 token 的工作上下文可以相当好地压缩到 16k token。↩
-
想想一次漫长的调试过程:第一天,一次不稳定的测试运行打印出一行奇怪的内容,你把它当作噪声忽略了,于是摘要把它丢掉了。这个不稳定问题再也没出现过。到了第三天,那行内容本会是整个 bug 的关键,但没人记得它存在过。注意,更聪明的摘要器在这里也救不了你:在第一天,根据当时任何人所知,丢掉那行内容都是合理的判断。↩
-
通常归功于尼尔斯·玻尔或约吉·贝拉,但它似乎是一句古老的丹麦谚语。最早见于印刷品的版本出现在 Karl Kristian Steincke 1948 年的回忆录中。↩
-
通常归于 Brander Matthews。塞缪尔·约翰逊在 1775 年更字面地表达了同样的观点,据詹姆斯·博斯韦尔记载:“知识有两种。我们要么自己了解一个主题,要么知道去哪里找到关于它的信息。”↩
-
而当它们坐在那里时,世界仍在前进:文件被覆盖,状态发生变化,所以你保存的东西可能会悄悄过时。这个问题有自己的解决办法,而且并不是真正的多代理问题,所以我就说到这里。↩
-
还记得那次不稳定运行中出现的那行奇怪输出吗?它现在就在磁盘上的某个地方。但第三天的 agent 并不知道它存在,更不知道它重要,所以它不知道要去找它,也不知道该 grep 什么。它又回到了阅读。↩
-
它仍然可能误读问题或带回错误的东西。但朝着一个已知目标进行压缩,比朝着一个未知目标压缩要容易得多。↩
-
当然,是在不违反 Amdahl 定律的前提下。↩
-
Noam Brown 在 Dwarkesh Podcast 上称之为“一种并行而非纯串行地扩展测试时计算的方式”。↩
-
只要任务能拆分成各部分之间靠短消息就能应付的片段。如果每个部分都需要其他所有部分的完整上下文,那么再怎么拆分也无济于事,你又回到了需要更大窗口的境地。↩
-
这假设模型能完美利用其上下文。在实践中,一个小而聚焦的上下文往往胜过庞大而杂乱的上下文,但那就是我说过要忽略的上下文腐化问题。↩
-
这有个花哨的名字叫通信复杂度:当各方各自掌握问题的一部分时,他们必须交换多少信息才能解决问题。↩
-
OpenAI 的说法,数学家们仍在验证。↩
-
Ronald Coase,The Nature of the Firm(1937)。↩
-
人类组织也弄明白了这一点:大公司里的数据库专家会收到来自各个团队的问题。如果他们只能为自己的经理工作,那每个团队都得配一个。↩
-
F. A. Hayek,The Use of Knowledge in Society(1945)。↩
-
出自 Fred Brooks 的The Mythical Man-Month:给一个已经延期的软件项目增加人手只会让它更延期,部分原因是沟通路径的数量大致随团队规模的平方增长。↩
-
Rich Sutton,The Bitter Lesson(2019):随计算规模扩展的通用方法最终会击败建立在人类知识之上的方法。↩
来源:Prime Intellect Blog · primeintellect.ai