SiMaster Stateless Agent Runtime
static page
把依赖进程内存的 Agent session、sandbox 和工具调用状态,迁移到更适合水平扩容和恢复的分布式链路中。
Agent Infra 2025 done
#agent-runtime#redis#sandbox#distributed-systems#mcp#observability
Context#
SiMaster 是一个面向科研场景的 Agent 产品。它涉及主 Agent、子 Agent、工具调用、沙箱执行、任务状态管理和长链路消息流转。
我参与的一项核心工作,是把原先更偏 demo / 单进程形态的 Agent runtime,改造成更适合生产环境的分布式执行链路。
The problem#
早期实现里,很多 session、sandbox、子 Agent 状态和工具调用状态都维护在单个进程的内存中。这样在小规模实验里能跑,但一旦进入生产环境,就会遇到一组很具体的问题:
- 服务无法水平扩容;
- K8S 动态调度困难;
- 负载均衡后请求可能找不到原来的 session;
- worker 重启后任务状态丢失;
- 多 Agent 和工具调用的嵌套顺序难以恢复;
- 异步消息容易乱序;
- retry 可能带来重复消费和状态不一致。
这类问题很容易在 demo 阶段被忽略,但线上产品一定会碰到。
What I did#
我的工作主要围绕 Agent runtime 的无状态化改造:
- 将 session / sandbox / tool-call 状态从进程内存外置到 Redis-backed 链路;
- 通过 session_id、run_id、step_id、tool_call_id 等标识建模任务过程;
- 解耦 Agent 后端、工具执行器和子 Agent 调用;
- 改造消息入站 / 出站结构,使它能表达嵌套 Agent 和工具调用关系;
- 处理分布式环境下消息乱序、重复消费、延迟返回和上下文恢复问题。
Message ordering#
Agent 执行过程不是线性的。一个主 Agent 可能调用子 Agent,子 Agent 继续调用工具,工具异步返回后还需要重新写入上下文。
我当时比较关心的是:如何让这些消息在分布式链路里仍然保持可理解的拓扑顺序。
一个可解释的抽象是把执行过程看成事件流和调用栈的组合:
- parent_id 表示父子调用关系;
- sequence_id 表示同一链路内的顺序;
- run_id 表示一次任务运行;
- tool_call_id 表示一次工具调用;
- session_id 表示用户任务上下文。
这样做以后,系统能更清楚地知道:当前消息属于哪个任务、哪个 Agent、哪个工具、哪一步,以及它应该被恢复到哪个上下文中。
What I learned#
这段经历让我意识到,Agent runtime 的难点不是“能不能调一次模型”,而是系统能不能接住 Agent 运行过程中的中间状态。
真正的 Agent 产品里,runtime 需要处理状态、顺序、失败、恢复、观测和多 worker 并发。这些东西不显眼,但会决定产品能不能真的上线。