编者按: 为什么你的 AI 智能体总是在生产环境中悄无声息地出错,甚至在你睡觉时做出不可预测的行为?
我们今天为大家带来的文章,作者的观点是:构建可靠 AI 智能体系统的关键,不在于精巧的提示词,而在于通过强制执行少量核心不变量(Invariants)来管理并发和状态,将自主性约束在可控范围内。
文章重点介绍了 OpenClaw 架构如何通过队列模型实现会话串行化与全局限流,确立了“单写入者”等核心不变量以防止状态竞争;详细阐释了包括“steer 模式”在内的多种队列策略,以解决任务执行中途新消息介入的并发难题;同时强调了去重、防抖及会话隔离等底层传输语义对于保障系统稳定性与隐私安全的重要性。
作者 | Vinoth Govindarajan
编译 | 岳扬
在第一部分,有一个令人背脊发凉的“凌晨 3 点的电话”之问:
为什么我的 AI 助手会在我睡觉时做某些事?
第二部分则是更可怕的后续问题:
是什么阻止了它“同时执行两项任务并破坏其自身状态”?
因为一旦你拥有了:
……无论你是否能够意识到,你都已经构建了一个并发系统。
当我看到 session-lane(会话通道)设计的那一刻,我就不再去想什么“智能体魔法”,而是开始基于状态机的确定性保证(state machine guarantees)来思考问题了。
我喜欢 OpenClaw 的其中一个原因是,它没有试图用巧妙的提示词来“解决自主性问题”。
它通过强制执行少量的 invariants(译者注:指的是在整个系统运行过程中,必须始终成立、永远不能被打破的规则或条件。可以把它理解成系统的“底线”或“宪法”。),并围绕这些不变量(invariants)构建队列模型(queueing model),让其自主性变得清晰可控。
其核心理念很简单: 序列化每个会话(session)的写入操作,对全局工作(global work)进行限流,并明确规定当任务正在执行的过程中,如果突然收到了新的输入,系统具体该如何应对。
如果我在审查一个智能体运行时(agent runtime),这部分永远是我最先关注的:
invariants 有哪些?以及它们又是在哪里被强制执行的?
因为如果没有不变量,智能体不会“大张旗鼓地报错”。
它们会悄无声息地出错。
比如:文件只写入了一半。Webhook 在网络重连后重复触发。对用户的一个请求,生成并发送了两条回复。
突然间,整个系统感觉就像闹鬼了一样。
不是因为它看起来有多么智能。
而是因为你违反了某个 invariant。
下面这个 invariant,能解释系统的很多稳定性问题:
在同一时间,只应该有一个 Agent 运行实例(agent run)去操作某个特定会话。
OpenClaw 通过一个感知通道(lane-aware)的 FIFO 队列来强制执行这一点:
正是这部分机制,阻止了那些经典的“同时产生两个想法”类的故障模式:
一个不那么光鲜但真实的事实是: 一旦涉及工具和状态,协调机制比巧妙的提示词更重要。
如果你在文档/代码库中略读某个章节,请不要略读这一节。
OpenClaw 这个系统在设计时,追求的不是那种让人惊叹的“智能体魔法感”,而是踏踏实实地解决那些“无聊但重要”的基础架构问题:
OpenClaw 的队列做两件事:
1)将每个会话(session)的任务执行强制变为串行(Per-session serialization)
运行时(runtime)将工作按 session key 排入通道(lane) session:<key>,这样保证每个 session 同时只有一个任务活跃运行。
2)全局限流
然后这些 session 范围的工作会经过一个全局 lane(默认是 main),所以整体并行度被 agents.defaults.maxConcurrent 限制。
两个容易被忽略但比看起来更重要的细节:
如果你要从本篇文章中记住一张图,就是这张:

现在真正的并发问题是:
当 Agent 正在执行一个任务(还没跑完)的时候,如果突然来了一个新消息,系统该怎么办?
OpenClaw 没有把这个复杂问题,藏在模糊的“让 Agent 自己决定”背后。
而是把它做成明确的、可配置的策略选项(队列模式),让开发者主动选择。
队列模式(queue modes)包括以下几种:
如果你见过 Agent “疯狂刷屏回复”,或者在执行中途“无视用户的纠正”,那么上文提到的队列模式(queue modes)就是控制这些行为的“调节旋钮”。
这就是一种契约:
一个我无法忽视的简单故障案例:
当智能体正在执行一个耗时的多步骤任务时,用户在 Slack 上发来了一条修正指令。
如果没有明确的策略(policy),系统只有两个糟糕的选择。要么忽略用户的纠正(糟糕的用户体验),要么立刻停止当前任务,处理新消息(不安全)。
steer 模式选择了第三种方案: 不中断正在运行的工具(保证安全),但一旦当前工具执行完毕,立刻停止后续计划,转而处理用户的纠正消息(保证响应性)。
这是我阅读 steering 行为时使用的思维模型:

(有一个值得记住的细微差别:根据流式输出/聊天界面的行为差异,steer 模式在某些界面上的实际表现,可能会更接近 followup 模式)
这一节属于那种“考验工程师直觉/经验”的内容 —— 有经验的开发者会本能地重视它,而新手可能会忽略,然后踩坑。
如果你不处理好入站消息治理(去重、防抖等),最后你会把"自己在底层基础设施(plumbing)里引入的 bug",错误地归咎于"模型不聪明"。
真实的通信渠道会重复投递消息。重连(Reconnects)会发生。重试(Retries)会发生。
OpenClaw 通过一个短生命周期的去重缓存来应对这些情况,缓存的键由渠道/账号/发送方/会话/消息 ID 等字段组合而成 —— 这样重复投递的消息就不会触发新的任务执行。
人类打字是一阵一阵的。
OpenClaw 能够通过配置项 messages.inbound.debounceMs,将用户快速连续发送的多条文本消息合并为一个 agent 执行轮次(同时支持按不同渠道单独覆盖配置)。
有两个让系统行为符合人类直觉的运营细节:
队列(queue)防止“同时多个写入者”。
隔离(Isolation)防止“错误的上下文”。
OpenClaw 中会话的划分规则是明确定义的,不是靠运行时动态猜测或隐式推断:
这个问题很快就会涉及安全层面。如果你的 Agent 能接收来自多个人的私信(DM),默认的私信行为可能会导致私有上下文泄露。解决方案是通过 dmScope 配置启用“安全私信模式”。
// ~/.openclaw/openclaw.json{session:{dmScope:"per-channel-peer"}
}
而且重要的是:Gateway(网关)才是会话状态的唯一权威数据源。
客户端不应该通过自行解析聊天记录来“重建”会话状态 —— 而应该直接向 Gateway 查询会话列表和用量统计。这是一种控制平面(control-plane)层面的架构选择,也是这些 invariants(译者注:指的是在整个系统运行过程中,必须始终成立、永远不能被打破的规则或条件。可以把它理解成系统的“底线”或“宪法”。)能在多个界面和设备上保持一致的原因之一。
序列化是必要条件,但不是充分条件。
序列化(串行执行)能保证你的会话历史记录不乱。
但它不会自动让你调用的外部操作(副作用)变得安全。
即使你完美实现了“每个会话只有一个写入者”(即会话内部完全串行),系统仍然可能存在以下三种安全隐患:
这就是为什么 OpenClaw 不止步于“每个会话一个队列(one queue.)”。它还:
而且在协议层,Gateway 故意让控制平面保持“简单、明确、可预测”:
这正是整个架构的核心主题:把限制条件作为设计的第一原则。
不是靠玄学,不是靠魔法。只是一些约束机制,让“始终在线”的行为变得可读、可理解、可预测、可解释。
如果你想要“感觉有生命”的效果,但又不想上线后一团糟,这是我会直接抄的作业:
1)将所有输入标准化为统一的事件格式
2)解析出一个 session key(你的隔离边界)
3)强制执行每个 session 只有单个写入者
4)添加一个全局并发限流(concurrency throttle)
5)决定 Agent 正在执行任务的中途,新到达的消息该如何与当前任务交互(collect / followup / steer)
6)添加入向消息去重 + 防抖(真实的通信渠道会重投消息,人类打字是一阵一阵的)
7)持久化一个仅允许追加(不能修改或删除)的执行日志,以便你能够事后调试和审计系统到底发生了什么。
这就是“invariants 优先的智能体运行时”设计模式:

一个不那么光鲜但真实的事实:决定你的 Agent 是“玩具”还是“能真正上线运行的系统”的,是这一层(基础设施/运行时层),而不是 prompt。
如果你想验证本文这些内容的可靠性,请查阅以下文档:
第三部分预告:实践中的内存/状态所有权问题 —— 以及为什么“更好的上下文管理”本质上是个工程架构问题,而不是提示词层面的取巧。
END
本期互动内容 🍻
❓OpenClaw提供了collect/followup/steer/interrupt四种队列模式。假如你的智能体正在执行一个“浏览器自动化+写文件”的长任务,用户中途发来一条新指令 —— 你会选哪种模式?为什么?
本文经原作者授权,由 Baihai IDP 编译。如需转载译文,请联系获取授权。
原文链接:
https://theagentstack.substack.com/p/openclaw-architecture-part-2-concurrency
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70018536/viewspace-3113985/ ,如需转载,请注明出处,否则将追究法律责任。