把 Agent 的运行状态当成"会流动的张量":读懂 OpenRath

论文链接:
https://arxiv.org/pdf/2606.19409
项目主页:
https://docs.openrath.com/
代码地址:
https://github.com/Rath-Team/OpenRath
它到底要修什么 Bug?
设想一次很长的 Agent 任务:先做规划,分叉出一条支线试方案,调工具改文件,翻一下记忆,压缩上下文,最后给出答案。
任务跑完,答案也对,但你想复盘时会发现没法回答这几个最朴素的问题:哪条分支产出了最终结果?哪个工具改了哪个文件?哪条记忆被调用过?压缩时又丢掉了什么证据?
原因在于:大多数系统里,这些信息被拆散塞进了"旁路通道",对话记录在一处,工具日志在另一处,记忆在数据库,沙箱改动在工作区,分支来源藏在控制器代码里。
论文把这叫做“隐藏运行时状态”(hidden runtime state)问题:消息列表保住了对话的"表面",却暴露不出角色来源、被放弃的分支、工具落点、记忆读写、被压缩丢弃的证据。

核心点子:Session = 运行时的"Tensor"
OpenRath 借了 PyTorch 的架构思路(注意:只借接口哲学,不碰张量数学)。
å在 PyTorch 里,一个中心值(Tensor)流过一层层可复用模块,模块å暴露 forward,放置用 tensor.to(device) 表达。OpenRath 把这套搬到 Agent 运行时:


关键在于:所有组件都守同一个契约 forward(session) -> session。因为状态由"程序本身传来传去的那个值"携带,所以 fork(分叉)、merge(合并)、replay(回放)就成了显式的运行时操作,而不是事后从日志里拼出来。
还有一个常被忽略的设计:每个对象"不拥有"什么,Agent 不拥有整张对话图(血缘归 Session),Tool 不拥有放置(它走当前沙箱),Memory 不能变成藏在 prompt 里的暗文(读写要当成可见事件)。
为什么非得是 Session,而不是图状态或追踪?
论文用"三种记录、三类读者"来定位:

它的论点是:trace 写给旁观者、checkpoint 写给调度器,都不是 Agent 程序自己拿来传递、分叉、回放的那个"活值",而 Session 就长在程序流动的地方,证据贴在值上,不靠侧通道重建。
它怎么跑起来:一条生命周期 + 工具边界
OpenRath 不给每个阶段都造一个新对象,而是让同一个 Session 走完一条生命周期。

其中分叉是"对话变成图"的关键:fork 复制状态并保留父子关系,detach 另起一条血缘根,merge 合并兼容会话并记下两个父亲,而且"兼容"还包含沙箱兼容(必须共享同一个沙箱句柄或指向同一未绑定后端),于是放置也成了运行时图的一部分。
工具这边则是:模型只看到工具的 schema,真正的副作用通过 Session 的沙箱后端去跑,无论是参数报错、未知工具、异常还是成功结果,统统作为工具结果块回流进 Session,不消失在控制器里。
最该被表扬的:审计优先 + 主动认怂
这篇报告最难得的不是炫技,而是克制。它没有声称跑分超过谁,而是把每条声明映射到一个"声明账本(claim ledger)"和可重跑的"证据包(evidence packet)":

它明确把一堆东西划到"暂不主张":没有广泛基准优越性、没有验证过的本地记忆实现、OpenSandbox 在当前环境不可用、活体模型质量不保证、没有任何安全性主张(还专门点了间接提示注入这个攻击面)。
配套开源已发布 v1.0.0(pip install openrath,BSD-3 许可),仓库附带交易、工程、研究流水线等示例。
结语
如果说过去十年深度学习把"张量"做成了网络围绕的中心值,OpenRath 想说:下一代 Agent 系统也需要这一步,一个所有组件都去读取、变换、解释的统一运行时值,而它的答卷是 Session。
它不替代图运行时、追踪 SDK、工具协议或沙箱,而是做那个"穿过各层、把效果收拢到一处"的连接对象。能不能成为事实标准还要看后续评测,但"先把状态显式化,再谈跑分"这个工程姿态,本身就值得借鉴。
