量子位
微信公众号
行业动态
别再只堆Agent了:清华团队把Session重新做成了多智能体系统的核心
发布:2026-06-18 07:26:43
· 事件:2026-06-18 07:26:43
Rath Team 投稿 量子位 | 公众号 QbitAI Agent越来越多,Session却越来越乱。 这是几乎所有人把多智能体系统真正跑大之后,都会撞上的一堵墙。 demo跑得挺好,可当系统扩到几十上百个Agent,调试、复现、编排全部开始失控。 来自 清华大学、中山大学和 香港中文大学 的Rath Team把他们的解法开源了,叫 OpenRath :一个像PyTorch的多智能体、多会话运行时。它的主张是: 别再围着Agent转了。真正该被当成 一等公民 的,是Session。
检测数据施工设计质量
Rath Team 投稿
量子位 | 公众号 QbitAI
Agent越来越多,Session却越来越乱。
这是几乎所有人把多智能体系统真正跑大之后,都会撞上的一堵墙。
demo跑得挺好,可当系统扩到几十上百个Agent,调试、复现、编排全部开始失控。
来自
清华大学、中山大学和
香港中文大学
的Rath Team把他们的解法开源了,叫
OpenRath
:一个像PyTorch的多智能体、多会话运行时。它的主张是:
别再围着Agent转了。真正该被当成
一等公民
的,是Session。
目前OpenRath已在PyPI发布到v1.2.1,
pip install openrath
即可安装,BSD-3-Clause协议,官网、文档、博客、GitHub一应俱全。
Agent动了手,证据该存在哪
第一代大模型应用,可以概括成「提示词进、回答出」。Agent系统改变了这条边界。
一个有用的Agent不只产出文本。它会检索、规划、调用工具、读文件、写代码、查API、跑测试、操作浏览器,有时还会改动外部状态。从ReAct让推理和行动在一个循环里交替,到Toolformer让模型学会何时调用工具,再到Model Context Protocol把工具变成协议级的边界——这条线一直在往前走。
可一旦Agent真的对世界动了手,一个运行时层面的问题就冒出来了:
这些动作的证据,到底存在哪?
如果一次工具调用读了文件,我们需要它的参数和结果;如果它改了仓库,我们需要diff;如果它跑在某个沙箱里,我们需要沙箱的身份;如果它失败重试了,我们需要那条失败路径;如果有人批准或否决了某个动作,我们需要那个校验信号。一份聊天记录顶多
叙述
这些事,却不足以
还原
这些事。
举个具体例子。一个软件任务:研究Agent读了issue、检索了笔记;编码Agent改了仓库;沙箱跑了测试;校验Agent否决了第一版补丁,于是工作流分叉;记忆后端记下这次失败,免得以后重犯。如果这些事件散落在各自的日志里,那么
最终答案几乎是最不重要的产物
,真正有价值的,是那条「工作如何一步步推进」的证据链。
这就是OpenRath的出发点:把Session当成
证据的载体
,而不只是聊天历史。
为什么是Agent Cluster
早期一个Agent基本够用:接收输入、理解任务、调用工具、返回结果,像个增强版聊天机器人。但真实任务很快超出单个Agent的边界。
一个像样的软件工程任务,往往要拆成需求理解、资料检索、架构设计、代码实现、测试验证、结果审查。不同环节要的能力并不一样——有的擅长规划,有的擅长写码,有的擅长挑错。继续让一个Agent全包,它就会膨胀成一个巨大的prompt和一个越来越混乱的上下文窗口。
于是有了
Agent Cluster
:让Planner、Researcher、Coder、Reviewer、Executor、Memory Agent各司其职,围绕一个复杂目标协作。多个专业Agent围绕共享的Session协作:各自读取当前状态、完成局部任务、把结果写回,供下一个Agent接力。
可一旦真把它跑起来,难题就冒出来了:这些Agent怎么共享上下文?某个结论到底来自哪个Agent、哪条分支、哪次工具调用?一个Agent出了错,能不能回滚到对应分支重来?
说白了,Agent Cluster真正的挑战,从来都不在「造更多Agent」——难的是
管住这些Agent之间的状态怎么流动
。
△
Agent Cluster状态流动示意图
和AutoGen、LangGraph比,OpenRath多问了一句
多智能体这个词,常让人想到一个群聊:一个Agent提议,一个批评,一个执行,一个主管决定什么时候收尾。这个模式有用,但不够。
这条路上已经有不少工作:
AutoGen
把多Agent对话做成了一个实用的编程模型;
CrewAI
把Agent团队和更结构化的流程分开;
LangGraph
用图状态和supervisor节点来表达路由与控制。它们都解决了
Agent之间怎么说话
。
OpenRath接着往下问了一句:
Agent们说完话之后,谁来拥有这份工作的状态?
一个生产级的Agent Cluster,需要决定:当前这个Session该交给哪个Agent、它该看到什么上下文、读了哪些记忆、下一条命令在哪个沙箱跑、继续之前需要什么校验信号。这些都是
控制平面
的问题,靠往群聊里再加一个角色是解决不了的。
OpenRath的答案是:让Session成为路由的单位,让Session Graph成为那张控制平面——Agent、工具、工作流、记忆、沙箱位置,都在这张图上交汇。
一句话:
Agent集群不是群聊,而是建立在持久Session状态之上的运行时控制平面。
从
Agent数量×Session数量
两个维度看,多智能体系统会分成四象限:单Agent单Session是ChatGPT式聊天;多Agent单Session是子代理协作;单Agent多Session是OpenClaw式分支扇出;而
多Agent多Session(MAMS)
,正是OpenRath面向的方向。
它的判断很干脆:真正需要被fork(分叉)、merge(合并)、复用、追踪的,是整条Session数据流——而非某个Agent内部那份各自维护的消息列表。
换个说法:
大多数框架攒的是一屋子聪明的工人,OpenRath先把工位、工单和流水线建好。
用官方那句话说就是——Agent是工人,Session才是工作本身。
△
MAMS四象限示意图
像PyTorch一样搭Agent集群:从深度学习借来的三招
OpenRath最聪明的一步,是把深度学习开发者最熟的那套抽象,整套搬到了Agent系统上。
PyTorch为什么好用?因为它把复杂计算拆成了清晰的积木:Tensor是流动的数据,Module/Layer是变换这份数据的可组合单元,device决定算在哪,而整张计算图是
跑起来才长出来的
。OpenRath给Agent系统做了几乎一一对应的映射:
核心映射:
Tensor→Session
、
Module/Linear→Workflow/Agent
、
Device→Sandbox/Backend
、
Parameter→Memory
、
Function→Tool
、
控制流→Selector
。
△
PyTorch与OpenRath映射对照图
支柱一:Agent是变换层,不是全能助手
PyTorch里,
nn.Linear
不是一个应用,它只是一层变换:吃进一个Tensor,吐出一个Tensor。
OpenRath把Agent设计成了同一种东西。Agent就是Session上的一层变换,核心就是一条
forward(session) -> session
的路径:进来一个Session,出去一个Session。
变换层不止一种。同样是
forward(session) -> session
这个形状,可以装下完全不同的活儿:
一个Agent调工具、改workspace里的文件,把执行结果写回Session
一个
Compressor
把跑了几十轮的长会话压缩成一条精简消息
一个Agent在跑之前
recall
记忆、跑之后
commit
记忆,相当于给这次会话做了一次「索引与归档」
你也可以写一个只做摘要、只做校验、只做改写的Agent
它们对外都是同一个接口,于是能像神经网络的层一样
任意堆叠、任意嵌套
。这正是
Workflow
(对应
nn.Module
)的意义:子类只要实现一个
forward(session) -> session
,里面就能串联多个Agent、fork Session、压缩上下文、调用工具、分发到子工作流。
管上百个Agent,于是从拼提示词变成了搭模块。
Layer不持有数据,数据是Tensor;Agent也不持有状态,状态是Session。
至于工具本身,OpenRath抽象成了
FlowToolCall
:一手攥着给模型看的name/description/JSON schema,一手攥着真正在Python里执行的行为,让
工具长什么样
和
工具干什么
始终待在一起。内置了文件、shell、代码执行工具,stdio的MCP工具也能直接适配进同一个循环。
支柱二:Sandbox与Memory是可插拔后端
PyTorch第二个聪明的地方,是把「算在哪」从「算什么」里剥了出来。同一份模型代码,
.to("cuda")
就上GPU,换个后端就换块卡,计算逻辑一行不用动。
OpenRath把这个思想用在了两个最容易被写死的地方:
执行环境
和
长期记忆
。
Sandbox(对应Device)——工具到底在哪运行。
很多框架把「对话历史」和「工具实际执行的位置」分开管,模型以为自己还在某个工作区,shell或容器其实早就切走了。OpenRath把Sandbox绑在Session上:工具跑在Session当前的backend上,返回的Session会记住自己的执行位置,不会悄悄漂移。
它真正的巧思,是
把Sandbox做成了可插拔的backend
:本地进程始终可用(
session.to("local", spec="./")
),容器化的OpenSandbox是可选项(
pip install "openrath[opensandbox]"
),未来任何第三方执行后端,只要接到同一套Session placement模型后面就能用。
Memory(对应Parameter)——跨运行保留的记忆。
它是独立的一层持久状态,能绑定到Agent、运行前recall、运行后commit;既不像工具结果那样用完即弃,也不只是塞进prompt的几行文本。基础安装自带零依赖的本地后端,把数据存在
.openrath/memory/
,不用LLM也能做BM25词法检索;配了embedding就能用向量排序;想要更强的,可以接OpenViking这类外部记忆服务。
这一招对
自带本地状态
的团队尤其友好:你已经有自己的容器调度、有自己的向量库或知识库,不必推倒重来,只要把它包成一个backend接进去,就能复用OpenRath的整套Session/Workflow抽象。
支柱三:Session Graph是动态图,完全为Agent Cluster而生
PyTorch还有第三个让人上瘾的设计:
动态图(define-by-run)
。它不要求你先把整张计算图画死再喂数据,而是代码跑到哪、图就长到哪。控制流就是普通的Python
if
/
for
,灵活到可以在运行时根据中间结果改变走向。
OpenRath的Session Graph,是同一个性格的东西。先看
Session
长什么样——它远不止一串聊天记录,而是一张结构化的
chunk表
:
它能fork出分支,能detach切断父链,能merge合并,还能序列化成JSONL直接交给下一个Workflow。而这张由fork/merge织出来的图,是Agent们跑起来、一步步演化出来的,并非事先画死的剧本——这正是「动态图」的含义。
为什么这件事对Agent Cluster是决定性的?因为集群规模一大,你迟早要回答:这个结论到底是哪个Agent、走哪条分支、调哪次工具、在哪个workspace产出的?散落的日志答不了,一张带血缘的动态图能答。Session Graph于是从
实现细节
升格成了集群的
可观测层与控制层
:路由、复现、回滚、审计,全在同一张图上做。
△
Session Graph动态分叉/合并示意图
几十行,把这套东西跑通
抽象讲再多,不如看一段能跑的代码。下面这个最小例子(取自官方README),把Session、Sandbox、Tool、Agent、Memory、Workflow、Compressor一次性串了起来:
读这段代码,三根支柱全在里面:数据是Session,执行位置由
.to()
决定(支柱二),
agent
和
compressor
是两层不同的变换叠起来(支柱一),而它们怎么串、串几层,是
forward
里用普通Python写出来的(支柱三)。每一步进出,都是同一个Session。
真正动态的地方:Selector
上一节的
forward
是写死的顺序。但真实任务往往要等跑起来才知道该往哪拐——这时候就轮到动态图的「运行时路由」登场。
很多框架的做法是把流程提前编排死:if走A,else走B。OpenRath的答案是
Selector
:一个由大模型驱动的路由器。它在若干个「会自我描述」的Workflow之间做选择,返回下一个该跑的Workflow,任务结束就返回一个空操作。妙处在于——它让Agent之间的
if
/
while
,依然是普通的Python:
selector = flow.Selector(provider)
while not isinstance(
nxt := selector.forward(session, triage, tech, wrapup), flow.EmptyWorkflow
):
session = nxt(session)
把流程写进提示词,是把不确定性焊死;交给Selector,才是让系统学会拐弯。
这也正是官方把OpenRath称为「dynamic multi-agent workflow」的底气:流程从写死的剧本,变成了运行时才定下来的路由——和PyTorch动态图里「代码跑到哪、图就长到哪」是同一种自由。
它现在到底能不能用
最能说明问题的是它的
example/
目录——一条编号递进的学习阶梯,每个脚本只讲一个概念,前一个的产出正好是后一个的输入:
01_hello_agent
最小程序,构造Agent、在Session上调用、流式输出
02_session_lineage
用fork分叉、detach切断血缘、查看session graph、导出JSONL
03_sandbox_backend
把同一个Session放到local或opensandbox,看工具在哪执行
04_tools_builtin
/
05_custom_tool
/
06_mcp_tool
:内置工具、自定义工具、借用MCP工具
07_streaming
/
08_compress
/
09_memory
/
10_provider_variation
流式、上下文压缩、记忆、换模型厂商
11_dynamic_selector
用Selector做if分支和while循环
从「先让一个Agent跑起来」到「让一群Agent动态协作」,11步走完,OpenRath的核心也就理解透了。安装分层:
基础
pip install openrath
要容器沙箱加
[opensandbox]
要外部记忆加
[openviking]
模型则走OpenAI兼容的环境变量或
~/.openrath/config.json
更值得说的是这套example的设计取向:官方强调,例子的目标是产出一份「证据档案」,而不是一张截图。一个软件任务跑完,理想的产物不该只停在一句「成功了」,而该是一整份可回溯的卷宗——
issue原文→Session Graph→调了哪些工具→副作用落在哪个sandbox→被否决的那条分支→最终采纳的补丁→测试结果→这次往Memory里写了什么。
这份卷宗,正是「一个demo」和「一个能拿来做技术报告的运行时」之间的区别。按团队自己的说法,他们在内部已经用OpenRath组织起接近Transformer结构的Agent Workflow——不过这更偏系统能力验证,还不是公开benchmark,这点他们说得很坦白。
从持久Session,到Agent Cluster
把视野拉远一点:OpenRath的版本演进本身就是一条干净的线。
v1.1解决「持久」——如果一个Agent的工作是跨时间展开的,凭什么唯一被保存的只有最终答案?于是有了持久Session,把干活的证据完整留下。
v1.2再抬高一层:让Session从「单个Agent事后可查的记录」,升级成「
能在多个Agent和工作流之间被路由的对象
」。一行代码就概括了这个转变:
session = workflow.forward(session)
它意味着,工作的单位从一个prompt、一个答案或一个Agent角色,挪到了一份
持久、可路由的Session状态
上。
从Prompt工程,走向系统工程
OpenRath的意义,不只是「又一个Agent框架」。
它真正想解决的是:当Agent Cluster成为主流形态,开发者能不能像写深度学习那样,获得一套可组合、可追踪的工程体验。这正是它借PyTorch之名的底气——同一套直觉迁移了过来:
层是变换(Agent),device可插拔(Sandbox/Memory backend),图是动态的(Session Graph)
。
在PyTorch里,你定义Module,让Tensor在网络中流动;在OpenRath里,你定义Agent和Workflow,让Session在系统中流动。剩下的——血缘记录、工具调度、沙箱绑定、长期记忆、动态路由——交给框架。
如果说过去的Agent框架面向的是「一个智能助手」,那么OpenRath面向的是「一个智能体系统」。
而这件事的起点,朴素得有点反直觉——
不是再多造一个Agent,而是先把Session当回事。
官网:https://www.openrath.com/
文档:https://docs.openrath.com/
博客:https://blog.openrath.com/
GitHub:https://github.com/Rath-Team/OpenRath
一键三连
「点赞」「转发」「小心心」
欢迎在评论区留下你的想法!
—
完
—
我们正在招聘一名眼疾手快、关注AI的
学术编辑实习生
🎓
感兴趣的小伙伴欢迎关注 👉
了解详情
🌟 点亮星标 🌟
科技前沿进展每日见