设想一个做电商客服自动化的团队,碰到一件很难向老板解释的事。他们的 agent 跑到第七步,去调退款接口,网络抖了一下,连接断了。容器被重新拉起,队列把消息重新投递,agent 从第一步开始:读工单、判断意图、查订单、生成回复、调退款。退款接口第二次被调用。客户收到两笔钱,财务在对账的时候才发现。
他们最初的判断是模型不稳。换更大的模型,把 prompt 写得更细,加了一层重试,问题照旧。真正的毛病不在推理,而在执行状态。第七步之前发生过什么,没有任何地方记着。进程一死,记忆就没了。
持久化执行要解决的就是这件事。把每一步的输入、输出和状态写进存储,进程崩溃、机器重启、部署滚动,下一次从断点继续,而不是从第一行代码重来。这个能力听起来像基础设施细节,但对 AI agent 来说它是分水岭。一个 agent 跑三步,重来就重来;跑三十步,中间夹着付款、发邮件、改数据库,重来的代价就是事故。
这里有个常见的误解,值得先拆开。持久化执行保证的是进度不丢,幂等保证的是副作用不重复。两件事,缺一不可。第七步的退款请求发出去,对方超时没返回,你不知道钱到底扣没扣;这时候引擎能做的只是把这一步重试,真正防止重复扣款的,是你传给支付网关的那个幂等键。四家引擎都在文档里不同程度地提到重试和恢复,但没有一家能替你想出这个键。
现在市面上有四条不同的实现路线,分别对应 Conductor、Temporal、Inngest、Restate。它们都能让流程在崩溃后继续,但对“流程是什么”的理解完全不同。有人把流程当成一份可以被审阅、被版本化的数据,有人把流程当成一段必须被重放的代码,有人让你在现有函数上包一层,有人干脆把整个 runtime 塞进你的调用路径。选型的分歧,基本都从这个问题开始。
把流程做成一张可以版本化的图
Conductor 的路子是四家里最反代码的。工作流是一份 JSON,任务、分支、循环、并行、子流程都写在里面,业务逻辑放在 worker 里,worker 可以用 Java、Python、Go、JavaScript、C# 等语言来写。引擎负责调度和持久化,worker 只管执行和回报。
拿跨境支付团队的合规审批来举例。审批链路几乎每个月都要动,法务加一个节点,风控改一个条件,如果流程写在代码里,每次改都要重新发版,重新跑一遍回归。换成 Conductor 的写法,审批链路是 JSON,改完把新版本推上去,worker 不动。这一点值得多说两句。很多团队第一次听到“JSON 工作流”会皱眉,觉得这是低代码,觉得表达力不够。Conductor 的文档专门回应过这个质疑:它不是低代码平台,worker 仍然是普通代码,可以用任何库、任何 I/O,JSON 只负责编排。SWITCH、DO_WHILE、FORK_JOIN、SUB_WORKFLOW、DYNAMIC 这几种任务可以互相嵌套,循环里套分支,分支里套并行,复杂流程是能写出来的。代价是表达式会变长,${...} 一层套一层,读起来不如代码顺手,调试要靠 UI 里那棵树。
Conductor 的 worker 是拉取模型:worker 向服务器轮询任务,执行完把结果报回去。这个设计的好处是 worker 可以部署在任何地方,服务器和 worker 各自扩容,中间不需要彼此发现。坏处是空轮询会浪费一点资源,任务量小的时候需要调长轮询间隔。官方文档里还提到 task domain、限流和并发上限,这些是给多团队共用一套引擎时做隔离用的。
它的另一个特点是授权干净。Apache 2.0,完全开源自托管,官方说支持 5 种持久化后端和 6 种消息队列,Docker 能跑的地方就能跑。项目出身 Netflix,现在由 Orkes 主力维护,Orkes 自己卖企业版云服务。这句话反过来读也成立:开源版是完整的,商业版卖的是托管和周边。对不想被厂商锁住的团队,这是四家里最省心的一张许可证。
代码即流程,代价是你得对确定性负责
Temporal 的假设跟 Conductor 相反。流程就是代码,用 Go、Java、Python、TypeScript、.NET、PHP、Ruby、Rust 写,写成 Workflow,副作用放进 Activity,Worker 负责执行。服务端是 MIT 许可,可以自己跑,也可以用 Temporal Cloud。
这条路线的能力上限很高。订单履约那种要跑几十天、中途可能改地址、可能要人工审批的流程,用 Signal 往里发消息,用 Query 读中间状态,用 durable timer 睡到下周,都是原生操作。失败处理也是内建的:自动重试加退避、四类超时、心跳、saga 补偿。Cloud 的定价页写得很直白,按 action 计费,起步 50 美元一百万次,量大能谈到 25 美元,存储另算,活跃存储 0.042 美元每 GB 每小时,归档 0.00105 美元,新用户送 150 美元额度。
代价在学习曲线。Workflow 代码必须确定性,同样的输入要产生同样的决策,因为服务端靠重放事件历史来恢复状态。这意味着你不能在 Workflow 里直接发 HTTP 请求、读随机数、取当前时间,这些都得挪到 Activity 里。写过的人都知道,这条约束会在第一次 code review 的时候咬你一口。上线之后还有版本兼容的问题:改了 Workflow 逻辑,旧的历史还能不能重放。Temporal 给的答案是 Worker Versioning 和重放测试,工具是有的,但要养成习惯。
还有一个运维细节:每个 Workflow 的事件历史是有体积的,跑得越久、信号越多,历史越长,重放越慢。Temporal 的办法是 Continue-As-New,在一个流程跑到一定规模时开一个新的执行,把状态摘要带过去。这个机制不难用,但它会改变你对“一个流程”的直觉,设计的时候就要想好切分点。
所以 Temporal 适合那种工程能力已经成型、愿意为长期正确性付前期成本的团队。它的抽象更接近分布式系统原语,而不是业务流程工具。你要是把它当画布用,会觉得处处别扭;你要是把它当运行时用,会觉得该有的都有。
把现有函数包一层,先跑起来
Inngest 的起点是另一群人:写 Next.js 的全栈工程师,部署在 Vercel,没有队列,没有 SRE,也不想为了一个后台任务去学一套新的编程模型。
它的做法是给现有函数加一层包装。你用 inngest.createFunction 定义函数,用 step.run 把要做的事一段段包起来,每一段自动重试、自动存状态。函数由事件、cron 或 webhook 触发,Inngest 通过 HTTPS 回调你的应用,不需要你常驻 worker。并发、节流、防抖、限流、优先级这些流控写在函数配置里,按 event.data.userId 这种键做隔离。本地开发跑 npx inngest-cli@latest dev,8288 端口上有完整的 dashboard,能看每次运行的每一步。
这条路线的上手成本是四家里最低的。一个三人团队,下午接进去,晚上就能看到第一个 durable function 跑通。SDK 覆盖 TypeScript/JavaScript、Python、Go 等语言。定价也友好,免费档每月 5 万次执行,99 美元档 100 万次,499 美元档 1000 万次,单次运行最长 30 天、90 天、366 天,按档位递增。
客服场景里还有两个好用的原语。waitForEvent 让函数停在这里等一个外部事件,比如等客户回消息,等到之后继续,等不到就超时走另一条路;cancelOn 允许一个匹配的事件把正在跑的流程取消,比如客户撤单。这两个原语配上 step,很多以前要自己写状态机的地方就变成了几行配置。
有两个地方容易被忽略。一个是许可:Inngest 的服务端用的是 SSPL,附 Apache 2.0 未来授权。自托管在技术上是可行的,官方有文档,但 SSPL 和 Apache 2.0 不是一回事,法务较真的公司要提前看清楚。另一个是 step 的边界:恢复点是以 step 为单位的,一个 step 中途失败会整段重试。把一大段逻辑塞进一个 step,等于把恢复点扔了。
一个二进制,把状态和调用都收进 runtime
Restate 是四家里最年轻、也最系统的一个。它把自己描述成 low-latency runtime,一个自包含的 Rust 二进制,不需要外部数据库,也不需要消息队列。流程还是代码,用 TypeScript、Python、Java、Kotlin、Go、Rust、Ruby 写,但调用要经过 runtime,runtime 在中间记 journal,崩溃之后从最后一条完成的调用继续。
它的架构是复制命令日志加物化状态,再加一个推送式调度器,官方的说法是把协调从分布式读路径上挪开。翻译成人话:调用链路上少一次跨服务查询,延迟就稳一点。
它比另外三家多出来的东西是状态。Virtual Objects 按身份分片,每个对象有独立的 K/V 状态和单写者语义,等于把“每个用户一个持久化会话”做成了原语。做 coding agent 平台的团队会喜欢这个:一个 session 一个对象,模型调用、工具调用、人工确认都挂在同一个对象上,状态和进度一起持久化,延迟还压在请求路径里。官方首页提到 Replit 用它做 coding agent 的持久化底座,这类场景对延迟和状态的要求都很硬。
部署有三种形态:开源自托管、Restate Cloud 全托管、BYOC 把托管部署跑进你自己的 AWS 或 GCP 账号。许可是 BSL 1.1,四年后转 Apache 2.0。附加使用授权里有一条要划重点:不能拿它做对外的 Public Restate Platform Service,也就是不能让第三方开发者注册自己的服务并通过你的托管平台调用。自己内部用、给自己的客户跑业务流程,都是允许的。但如果你要做的是一个对外售卖的工作流 PaaS,这条会挡住你。
四个产品放在一张表里
把四个产品塞进一张表,很容易变成参数堆砌,因为它们的抽象层级根本不一样。Conductor 管的是图,Temporal 管的是代码的重放,Inngest 管的是函数之间的边界,Restate 管的是调用和状态。所以下面这张表只比四件真正影响决策的事:授权、部署、编程模型、适合场景。定价和生态放在正文里说,放进去反而失真。
| Conductor | Temporal | Inngest | Restate | |
|---|---|---|---|---|
| 授权 | Apache 2.0 | 服务端 MIT | SSPL,附 Apache 2.0 未来授权 | BSL 1.1,四年后转 Apache 2.0 |
| 部署 | 自托管,Orkes 另售商业云 | 自托管加 Temporal Cloud | 自托管加 Inngest Cloud | 自托管、Cloud、BYOC |
| 编程模型 | JSON 工作流定义,worker 用多语言写 | 代码即工作流,依赖确定性重放 | 代码加 step 包装,HTTPS 回调 | 代码加 runtime 拦截,durable handler |
| 适合场景 | 流程要被审阅、被频繁改图 | 长周期、复杂补偿、强工程团队 | 全栈小团队、Serverless 部署 | 低延迟、按身份存状态的平台 |
看完这张表,还是不知道怎么选,是正常的。表能排除掉明显不合适的,剩下的要靠场景。
按场景选,而不是按功能选
如果流程本身是业务资产,需要法务、风控、运营都能看懂,还要频繁调整,Conductor 是最顺手的。JSON 图可以被人审阅,可以被版本化,可以被 LLM 在运行时生成,这几点加起来,适合流程经常变、变的人不写代码的组织。代价是你要接受 JSON 的表达方式,以及自托管的运维。Conductor 的 GitHub 仓库在 https://github.com/conductor-oss/conductor ,Apache 2.0 的授权和 5 种持久化后端的清单都在 README 里,动手前值得读一遍。
如果流程要跑很久,中间有补偿、有信号、有人工审批,团队又有 Go 或 Java 的底子,Temporal 是稳妥的选择。它的能力边界最清楚,出问题时的排查路径也最成熟。要接受的是确定性约束、重放测试和按 action 计费带来的成本不可预测性。一个 agent 循环如果每一步都算 action,账单会比你想象的快。
如果团队小,产品部署在 serverless 上,目标是这周上线而不是这季度架构评审,Inngest 的性价比最高。改动最小,心智负担最轻。要留意的是 SSPL 和 step 边界,以及免费档 30 天的运行上限,长跑任务迟早要升级。
如果产品本身就是 agent 平台,每个用户、每个会话都要独立状态,延迟又不能让步,Restate 的模型最贴合。单二进制省掉了数据库和消息队列的运维,Virtual Objects 省掉了自己拼会话状态。要先过的是 BSL 那条附加授权,尤其是你打算对外提供托管能力的时候。
还有一个常被低估的成本:自托管不等于免费。Conductor 要 JVM、要数据库、要消息队列,Temporal 要一套有状态的服务和持久化存储,Inngest 自托管要维护它的 server 和队列,Restate 最轻,但也要人盯着磁盘和快照。三个人以下的团队,把这些折算成工时,往往比一年的托管费贵。反过来,数据不能出内网的团队,这笔钱花得值。
还有一种情况,四个都不该选:你只有几个定时任务,失败了大不了手动重跑。这种时候引入任何一套持久化执行引擎,都是在给未来的自己加运维。工具的价值来自失败的成本,失败不痛,工具就是负担。
回到第七步
文章开头那个客服 agent,要做的事情其实很简单:把退款调用挪到一个带幂等键的步骤里,把整条链路接进一个能记住进度的引擎。改完之后,再碰上同样的网络抖动,退款只会发生一次。
选型的时候,功能列表会骗人。四家都能持久化,都能重试,都有 UI,都支持好几种语言。真正区分它们的是三个问题:崩溃之后,你的系统是从头再来,还是从第七步之后继续;流程的所有权在工程师手里,还是在业务方手里;你愿意为许可证和运维付多少隐形成本。
这三个问题答完,答案基本就只剩一个了。



