Rust Actor Runtime 作为 Agent Harness 基座:Kameo vs Ractor
综合自: kameo, ractor
结论先行: 如果目 标是给
dive-agent选一个更稳的 agent harness 实现基座,我更推荐ractor。
kameo更适合做 async-first、Tokio-native、带内建 tracing/metrics 的快速原型;ractor更适合做需要明确生命周期、监督、优先级、worker/factory 路由和可控停机语义的长期运行时内核。
问题定义
Agent harness 不是普通业务服务。它通常同时承担这几类职责:
- 会话隔离:每个 session / agent run 都需要自己的状态边界
- 请求-响应:主控 agent 要能同步等待 model/tool/subagent 的结果
- 事件流:token、tool-progress、trace、UI status 需要持续扇出
- 监督与取消:子 agent 卡死、tool 超时、run 被用户终止时,需要明确收尾语义
- 并发治理:tool worker 池、session 粘性路由、背压、限流不能全靠业务层手写
所以这次选型的重点不是“谁的 actor API 更顺手”,而是“谁更像一个能承载 harness 的运行时骨架”。
方案 A:Kameo
它更像什么
kameo 是一个 Tokio-first、async 友好、类型 化 request/reply 体验很顺手 的 actor 框架。
它有这些很吸引 harness 的点:
ask/tellAPI 直接,且支持mailbox_timeout、reply_timeout- actor 可以
attach_stream,把外部 stream 挂进 actor 生命周期 - 内建
tracing、metrics、otelfeature - 自带 supervision 模块,支持
OneForOne / OneForAll / RestForOne - 内建 remote 模式,底层直接走
libp2p
映射到 agent harness 的数据流
如果用 kameo 搭 harness,一个比较自然的链路是:
UserTurn
-> SessionActor.ask(TurnInput)
-> PlannerActor.ask(PlanStep)
-> ToolPool.ask/Tell(ToolCall)
-> attach_stream(TokenDelta / ToolProgress / TraceEvent)
-> EventSink.tell(EventEnvelope)
-> SessionActor.reply(TurnResult)
它的优点是:
- 把流式 token / tool progress 接进 actor 很自然
- 请求超时是现成能力,不用业务层重复包一层
- 如果以后真想做 P2P agent swarm,
libp2p集成路径比多数 actor 库更直接 - 观测接入成本低,适合快速把 tracing/metrics 打通
它不够适合作为基座的地方
问题不在“不能做”,而在“做成 runtime kernel 之后,很多关键语义不如 ractor 明确”:
- 运行时优先级语义不够突出
harness 很在意Kill、Stop、普通消息、监督事件谁先处理;kameo有生命周期和 supervision,但对“优先级调度语义”没有ractor那么明确的运行时文档和建模。 - worker/factory 级别编排能力偏轻
它有
ActorPool,但更偏“负载均衡池”;如果你要做 key-based routing、priority queue、discard policy、dead-man's switch、动态 worker 数调整,ractor的现成能力更完整。 - 更偏框架易用性,而不是 runtime 语义完整性 对 prototype 是优点;对 harness 内核,这反而意味着很多治理策略要自己补。
- 编译器门槛更高
当前
kameo需要 Rust1.88和edition = 2024,这会提高落地门槛。
方案 B:Ractor
它更像什么
ractor 明确沿着 Erlang/OTP 风格运行时语义 往前走。
它的核心价值不是“actor 很容易写”,而是“actor 系统在出故障、停机、扩缩容时语义更清楚”。
几个对 harness 很关键的点:
- 明确区分
Signal(Kill)、Stop、SupervisionEvent、普通Message的优先级 - supervision tree、monitor、registry、process group 都是第一层能力
RpcReplyPort把 call/reply 语义做成框架原语Factory提供 worker 池、路由、队列、限流、discard、动态配置更新OutputPort提供事件扇出能力,适合 token/status/trace 广播- 默认带
message_span_propogation
映射到 agent harness 的数据流
如果用 ractor 搭 harness,一个更像“运行时内核”的链路会是:
UserTurn
-> SessionSupervisor.call(TurnMessage, timeout)
-> PlannerActor.call(PlanMessage)
-> ToolFactory.Dispatch(Job<SessionKey, ToolCall>)
-> Worker.handle(Job)
-> OutputPort<TokenEvent / StatusEvent / TraceEvent>
-> UIActor / TraceCollector / PersistenceActor
-> SupervisionEvent / Stop / Kill
-> SessionSupervisor decides restart / stop / cleanup
这条链路和 agent harness 的几个核心诉求更贴:
- session 粘性路由:同一 session 的任务可以稳定落到同一 worker
- 事件旁路扇出:token 流不必强耦合在 call 返回值里
- 停机语义更清楚:正常 stop 和强制 kill 是分开的
- 监督决策更显式:子 actor 异常退出后由 supervisor 统一 收口
- 并发治理更像“平台能力”:不是每个 tool actor 各自发明限流和队列
它的代价
ractor 的问题也很明确:
- 开发体验没
kameo那么轻 想把一个业务 actor 写出来,模板代码和概念负担更重。 - cluster 仍需谨慎
ractor_cluster已经很完整,但仓库 README 仍明确说不该把它视为 production ready。 - 观测能力更偏“可插拔”而不是“内建套餐” 你会拿到 message span propagation、output port、supervision event 这些接点,但要自己把 tracing/metrics 体系拼完整。
关键维度对比
| 维度 | Kameo | Ractor | 对 harness 的含义 |
|---|---|---|---|
| actor 易用性 | 更顺手,Tokio-first | 更偏 OTP 风格 | 原型期 kameo 占优 |
| request/reply | ask/tell 直观,超时现成 | call/cast + RpcReplyPort,更底层 | 两者都够用 |
| 流式事件接入 | attach_stream 很自然 | OutputPort 更适合广播扇出 | 单流接入偏 kameo,多订阅扇出偏 ractor |
| 监督语义 | 有 supervision tree | supervision + monitor + priority channels 更完整 | ractor 更适合 runtime 内核 |
| 并发治理 | ActorPool 偏基础 | Factory 有 routing/queue/discard/rate-limit | ractor 明显更强 |
| 运行时可预测性 | 足够,但更偏框架层 | 显式文档化 stop/kill/supervision 优先级 | ractor 更稳 |
| 可观测性 | tracing/metrics/otel feature 很友好 | 需要自己组装,但接点明确 | 原型接观测偏 kameo |
| 分布式方向 | libp2p 内建 remote | ractor_cluster 仍需谨慎 | 如果要 P2P swarm,kameo 更有吸引力 |
| 落地门槛 | Rust 1.88 / edition 2024 | Rust 1.64+,默认 Tokio | ractor 更稳妥 |
维护活跃度补充
按 2026-03-10 的 GitHub 官方仓库数据看:
kameo:约 1.2k stars,最近 release 是v0.19.2(2025-11-17)ractor:约 2.0k stars,最近 release 是v0.15.12(2026-03-09)
两边都还在维护,但 ractor 在公开活跃度、发布连续性和生态可见度上更占优,这会降低它作为底层基座的选型风险。