大多数 AI Agent 的演示都是「一个脚本、一个进程、一条顺风路径」:调用模型、调用工具、打印一段漂亮的结果、退出。然后真实用户来了——支付服务商超时、进程在任务中途重启、两个请求同时打到同一个购物车,而 Agent 兴高采烈地又扣了一次已经扣过的款。难的从来不是模型,而是运行时。
一个有用的思维切换是:别再把手里的 Agent 当成一次函数调用,把它当成一个小型分布式系统。这正是 Actor 模型提供的视角:彼此隔离的单元各自持有状态,只通过消息通信,并由明确的上层负责在它们失败时做决策。这份手册把这个视角拆成可执行的工程步骤,适用于任何 Agent 工作流——订单分流、商品信息补全、退款处理、本地化客服——而且不需要推翻现有技术栈。
为什么 Agent 演示一上生产就崩

图示:来源页预览图(仅作编辑上下文;版权归属原发布方) · 来源引用:www.infoq.com
真实流量有四个属性,会直接击穿天真的 Agent 代码:
- 时间。 一个任务可能横跨几分钟到几小时,中间夹着模型调用、人工审批和第三方 API。在这段窗口里,你的进程一定会被重新部署。
- 部分失败。 工具调用失败一半:仓库预留成功、支付扣款失败,工作流就卡在了一个没人设计过的状态里。
- 并发。 两个操作员,或者同一个操作员的两个重试,在同一时刻操作同一个实体。
- 可变。 计划本身会变。执行图不是在请求到达时固定的,它会生长、会重新连线。
内存态、隐式重试、共享可变对象,在演示里没问题,在触碰资金和库存的工作流里是致命的。Actor 模型不会自动解决问题,但它给每一个问题安排了一个明确的归属地。
七步打造 Actor 形态的 Agent 运行时
第一步:给每个工作流一个身份和地址
先选定天然的并发单元。对跨境店铺来说,通常是「每个订单」「每个 SKU」或「每个客户会话」,而不是「每个请求」。这个单元就是一个 Actor,地址由业务键稳定派生(例如 order/9f2c...)。请求不直接执行工作流,而是向该地址发送消息:Actor 已存在,消息进它的信箱;不存在,按需创建。
这一个决定就消灭了经典的双重处理 bug:同一个订单的两条并发 webhook,变成同一个 Actor 信箱里排队的两条消息,串行处理,而不是两条线程相互竞争。
第二步:让 Actor 成为它状态的唯一所有者
Actor 一旦存在,任何其他组件都不得直接写它的状态。工作流的中间变量——哪些步骤完成了、每次工具调用返回了什么、Agent 下一步打算做什么——都放在这个 Actor 里。其他组件通过查询消息读取,绝不能伸手去写一张所有人都能写的数据库表。
这里的关键是写穿透持久化。不要把状态放在内存里「稍后再刷」。在每一次有意义的跃迁上,先持久化,再确认该步骤。做到这点,重启就可承受:新进程从最近的检查点重建 Actor 并继续。代价是每次跃迁多一次小写入,回报是退款流程进行到一半时的一次发布从事故变成无事发生。
第三步:给每一个副作用一个身份
把 Actor 的内部记账和外部世界分开。每一个对外效果——扣款、预留库存、发邮件、创建面单——都应该是一条消息,携带由「业务键 + 步骤」确定性派生的幂等键,并且接收方必须按该键去重。
这让「至少一次投递」从一句吓人的话变成默认的运营常态。重试的安全性来自结构设计,而不是祈祷。
第四步:定义协议,而不只是提示词
把 Actor 接受的消息类型写下来:命令类(「执行扣款」「批准退款」)和事件类(「支付已捕获」「库存已预留」)。给 schema 打版本号。收到消息时校验,遇到未知字段要大声报错,而不是默默忽略。
团队经常跳过这一步,然后发现生产事故里有一半其实是协议漂移——某个服务加了一个新字段,旧的消费者视而不见,而 Agent 基于过时理解自信地做出了动作。
第五步:在你需要之前就画好监督边界
监督是这个模型里被低估的另一半。对每个 Actor 明确三件事:谁监督它;子级失败应该怎么办(重启、升级到人工队列,或终止工作流);以及在时间窗口内允许多少次重启,超过后就冻结。
要明确写下哪些是不可重试的。格式错误的模型响应可以重试,合规拒绝不可以。把这种区分编码进监督者,而不是散落在各处的 try/except 里,决定了系统是能自愈,还是会安静地空转。
第六步:把执行图当成数据
Agent 工作流不是线性的。Agent 会决定回退、分支或派生子任务。如果这张图只活在提示词里,你就无法恢复它、审计它、解释它。
把图持久化:节点是步骤,边是跃迁,每个节点带有自己的状态和结果。「续跑」于是变成「加载图、找出待处理节点、继续」。这也正是你可以在中间插入一个人工审批节点、让工作流等上几天而不必占住一个线程的原因。
第七步:给一切加上边界
信箱要有容量上限。工具调用要有超时。工作流要有截止时间。模型调用要有按 Actor 按小时的 token 与成本预算。任何没有边界的东西,都会变成一场「多绕了几步的宕机」——一个失控的重试循环,可以在人类察觉之前烧掉一个月的推理预算。
为重试耗尽的消息保留死信通道,并且附上足够上下文,让运营人员不读日志也能处置。

图示:HEXOPS 原创配图(受选题启发,非复制原文图片) · 来源引用:www.infoq.com
跨境团队最该在意的几点
如果你面向多区域发货,Actor 这个形状会自然带出一些额外约束:
- 把 Actor 固定到某个区域。 状态归属让数据驻留变得容易推理:Actor 持久化的状态就在 Actor 所在的地方。不要让一条消息把欧洲订单的状态绕经美国托管的写入方。
- 币种与税务逻辑只留一个所有者。 多币种舍入和含税定价,是重试场景下重复扣款的高发区。让每个订单只有一个 Actor 持有计算后的总额,远比在三个服务里各自重算安全。
- 对第三方延迟的长尾要有预期。 跨境支付和物流服务商的延迟分布很宽。超时和死信队列不是锦上添花,而是常态运行方式。
- 在边缘做本地化,在 Actor 里做决策。 语言和格式属于展示层。不要让某个语种的提示词变体悄悄变成一条不同的业务规则。
上线前检查清单
- 每个工作流都有基于业务键的稳定地址,入站请求是消息而不是直接调用。
- 状态在每次跃迁时写穿透,不存在「只存在于内存」的进度。
- 每个外部副作用都带确定性幂等键,接收方做去重。
- 消息 schema 有版本号,并在接收时校验。
- 每个 Actor 有具名监督者、明确的失败策略和重启预算。
- 执行图已持久化,可在不占用线程的情况下恢复。
- 信箱、工具调用、工作流、模型开销都有显式上限。
- 死信队列由人值守,而不只是挂一块看板。
- 每条消息都带 trace ID,单个工作流可以端到端回放。
- 你已在预发环境演练过「工作流进行中杀掉进程」,并亲眼看到它恢复。
关键要点
- 可靠性问题不在模型,而在运行时。把两者拆开看。
- 每个业务实体一个 Actor,把并发 bug 变回一个队列问题。
- 写穿透状态,是发布、崩溃和长时间人工等待都能承受的前提。
- 每个副作用都加幂等键,让重试从风险变成默认行为。
- 监督边界把「可重试失败」和「终止性失败」区分开来。
- 持久化执行图,是把聪明的提示词变成可审计流程的关键。
下一步
从影响面最大的工作流开始——退款、支付扣款或库存预留——这个迭代先跑完第一步到第三步。你不一定需要引入 Actor 框架:一个队列、一条持久化记录、一个幂等键,就能拿到大部分收益。然后在扩大并发工作流数量之前(不是之后)补上监督机制与执行图持久化。最后,把故障演练排进日程。一个你从未故意杀死过的工作流,是一个你还没真正理解的工作流。
来源
- InfoQ 演讲,Manju Rajashekhar,Actors for Agents: Patterns for Production AI:https://www.infoq.com/presentations/actors-for-production-ai-agents/



