让 Agent 等待时只剩一页笔记:AWS 开源运行时 Infinity
AWS 开源 Agent 运行时 Infinity:Agent 等模型回复时,每个空闲 Agent 只占约 100KB 内存;按官方的换算,约 7.5 万个空闲 Agent 才装满树莓派 5 的 8GB 内存。
一、书签和书桌
读一本厚书,中途要出门,你会怎么做?
一种做法是,书桌原样不动。书摊开着,台灯亮着,笔记本翻在那一页,回来坐下就能接着读。
另一种做法是,夹一张书签,把书放回书架,台灯关掉,书桌让给别人。
回来的时候,从书架取出书,翻到书签那一页,照样能接着读。
前一种做法很省心,但是占着一张书桌。如果有成千上万个读者,每人都这样,图书馆就没有空桌子了。
后一种做法麻烦一点,好处是等待的时候,你只占一张书签。
今天的大多数 AI Agent,用的是第一种做法。
AWS 最近开源的 Infinity,想让 Agent 改用第二种做法。
二、Agent 在等什么
先说背景。
一个 Agent 的大部分时间,其实不在思考,而在等工具。
编程 Agent 等编译跑完;分诊 Agent 等别人提交 PR;个人助手等用户第二天点一下审批。
这些等待,短的几秒,长的几天。
问题在于,多数 Agent 框架(harness)的写法是"阻塞等待":发出工具调用,然后原地等结果回来。
等待期间,进程一直活着,内存一直占着。
这就像那张摊开的书桌,人不在,桌子还是你的。
Infinity 的思路是,工具调用一发出,Agent 就挂起,对话存起来;结果回来了,再恢复。
挂起期间,它占用的资源几乎只剩对话历史本身。
三、什么是"无栈协程"
AWS 官方博客把这个思路,比作"无栈协程"(stackless coroutine)。
这个词听上去很吓人,其实不难理解。
协程就是一种可以"暂停"和"继续"的函数。普通函数一旦开始运行,就要一口气跑完;协程跑到一半可以停下,把控制权交出去,过一会再从停下的地方接着跑。
暂停的时候,要保存"跑到哪里了"。保存方法有两种。
1、有栈协程:把整个调用栈原样保存。函数里有哪些局部变量、调用到了第几层,统统留着。这就是那张摊开的书桌。
2、无栈协程:不保存调用栈,只保存继续运行真正需要的那几个状态。这就是那张书签。
对 Agent 来说,继续运行真正需要的状态是什么?
答案很简单:对话历史。
模型下一步要做什么,完全取决于它看到的历史。只要历史还在,Agent 就还在,跟哪个进程、哪台机器无关。
Infinity 就是把这个事实,做成了运行时的基本结构。
四、一个 slice 里发生了什么
具体来说,Infinity 把每个 Agent 的执行,切成一个个有界的片段,叫做 slice。
据官方博客,一个 slice 的步骤是这样的。
1、加载这个 Agent 的对话历史。
2、调用一次模型补全。
3、把结果写入存储(落盘)。
4、至多派发一个工具调用。
5、slice 结束。
注意第 4 步。工具的 execute 会立刻返回 Ok,并不等工具真正跑完。
真正的结果,由工具在完成以后,通过 send_to_input_queue 异步送回来。
工具结果和用户消息,都进入一个共享的输入队列(input queue)。队列里来了新消息,运行时再为对应的 Agent 开一个新的 slice。
同一个对话线程(thread)里的 slice 串行执行,不同线程之间可以并行。
这样一来,"等待"这件事,就从程序里消失了。
程序里没有任何一行代码在等,只有一条条消息在队列里排队。
五、模型不会"等事件",那就造一次工具调用
这里有一个有趣的细节。
Agent 有时候要等的不是工具结果,而是外部事件,比如"有人在这个仓库开了新 PR"。
但是,现在的模型 API 里,没有"异步事件"这种东西。模型只认识几种消息:用户说的话、它自己的回复、工具调用和工具结果。
怎么办呢?
Infinity 的办法是"合成工具调用":当事件到达时,运行时在对话里注入一次名为 receive_event__injected 的工具调用,再附上一个工具结果,用来表示"你订阅的事件来了"。
这个名字是保留的,模型不能主动调用它。
于是在模型眼里,事件就像一次普通的工具返回,不需要新的消息类型。
同样的队列,还承载了 spawn_thread(开一个子线程)和 report_to_parent(子线程向父线程汇报)。
官方博客还提到,事件默认可以交给临时的子线程处理,处理完再汇报,避免大量事件淹没父线程的上下文。
六、进程可以立刻退出
既然状态全在存储里,进程本身就不重要了。
Infinity 提供一种 step 模式:平台每收到一批消息,就调用一次 step,处理完,进程可以马上退出。
这天然适合 serverless。
官方给的参考部署是这样搭的。
1、消息队列用 SQS FIFO,按线程设置 MessageGroupId,保证同一线程的消息按顺序处理。
2、计算用 Lambda。
3、对话历史存在 Aurora DSQL。
4、去重用 DynamoDB。
5、Agent 想"睡一会",就用 SQS 的延迟消息,或者 EventBridge Scheduler 定时唤醒。
官方博客的说法,大意是:一个要等三天 CI 的 Agent,不会占着一个正在运行的 invocation。
回到开头的比喻,书签夹好了,书桌已经让出去了。
七、那组数字怎么看
官方博客给了一个基准测试,下面的数字都是 AWS 自报。
测试条件是:模拟模型(不是真的大模型)、单线程的 AMD EPYC 9R14、内存存储。
规模是 8 万个 Agent,每个大约跑 20 轮(turn),一共 320 万次补全。
常驻内存方面,每个空闲 Agent 大约 100 KB。官方据此换了一个说法:大约 7.5 万个空闲 Agent,对应 Raspberry Pi 5 的 8 GB 内存。
这句话要读仔细。它只是拿内存总量做对比,并不是真的在树莓派上跑了这么多 Agent。
另外,据 TSN 的转述,这个测试没有计入真实模型调用的费用和时间。
这一点很关键。真实的 Agent 系统里,最贵、最慢的通常是模型调用本身。Infinity 解决的是"等待期间别浪费资源",不是"让模型变便宜"。
所以,这组数字说明的是运行时自己的开销很小,而不是整套系统能便宜地跑起来。
八、几点看法
我觉得,Infinity 最值得看的,不是那组数字,而是它对 Agent 的理解。
一个 Agent,本质上就是一份不断变长的对话历史,加上一个读历史、写历史的循环。
想通了这一点,很多事情就顺了。挂起就是停止读写,恢复就是重新读,迁移就是换一台机器读,并发就是同时读很多份。
当然,它还是早期研究版本。
Infinity 属于 Hydro 项目(AWS 和 UC Berkeley 合作),用 Rust 编写,Apache 2.0 许可证,博客作者是 Shadaj Laddad,发表于 10 月 23 日。
官方博客自己也列了一些开放问题。
1、事件的真实性:注入进对话的事件,怎么保证不是伪造的?
2、交错事件的推理:多个事件交替到达,模型能不能理清先后?
3、树状 compaction:父子线程组成一棵树,历史怎么压缩?
4、调度优先级:队列里消息很多时,先处理谁?
这些问题都没有现成答案。
如果你在写自己的 Agent 框架,正在为"等待"发愁,可以读一读 Infinity 的官方介绍,哪怕不用它,它的 slice 和合成工具调用的设计也值得借鉴。
(完)
来源:AWS 开源博客(2026-10-23);TSN Media。每个空闲 Agent 约 100KB、约 7.5 万个空闲 Agent 对应 8GB 内存(只是内存总量换算,并非实测在树莓派上运行)、单线程跑 8 万个 Agent 等数字均为 AWS 自报的测试结果,未见第三方复测;测试用的是内存存储,生产环境换成持久化存储后表现可能不同;许可证为 Apache 2.0;文中比方为作者概括。