mq9:RobustMQ 为 AI Agent 设计的通信层
从一个真实的问题出发
人和人之间有飞书、钉钉、邮件。我发出去,你空了来看,不需要同时在线。这件事我们觉得理所当然,因为人类的异步通信基础设施已经非常成熟。
Agent 和 Agent 之间呢?
Agent 不是服务——它是临时的,任务完成就消亡,可能只存在几秒钟。Agent A 给 Agent B 发消息,B 不在线,消息直接丢了。没有标准机制保证"我发出去的消息,对方上线后能收到"。每个构建多 Agent 系统的团队,都在用自己的临时方案绕过这个问题——HTTP callback、Redis pub/sub、轮询数据库、自研任务队列。能用,但都是绕路。
更进一步,如果两个 Agent 运行在不同人的不同机器上,今天完全没有办法让它们直接通信。每个 Agent 系统都是孤岛。
这是 mq9 想解决的问题。
mq9 是什么
mq9 是一个为 AI Agent 设计的消息 broker。不是协议,不是 SDK,不是框架——是一个可部署的服务。docker run 一行命令,Agent 就有了异步通信的能力。
mq9 是 RobustMQ 的第五个原生协议层,与 MQTT、Kafka、NATS、AMQP 并列,生长于 RobustMQ 的底层统一存储架构之上。不是插件,不是外部集成,是原生能力。
docker run -d -p 4222:4222 robustmq/robustmq:latest这一行之后,Agent 就可以创建邮箱、发消息、订阅广播。
mq9 只解决通信问题——消息怎么可靠送达。至于消息里装什么、怎么用、业务语义是什么,mq9 不管。消息内容是 byte 数组,不解析、不校验、不限制。
核心概念:邮箱
mq9 只有一个核心抽象:邮箱(MAILBOX)。
邮箱是 Agent 的通信地址。临时的,TTL 驱动生命周期,到期自动销毁。Agent 为每个任务申请一个邮箱,拿到一个 mail_id,这就是它在这个任务里的通信地址。任务结束,邮箱自动过期清理。不需要注销,不需要手动删除。
mail_id 不可猜测即安全边界。 mail_id 是系统生成的不可猜测字符串。知道 mail_id 就能往里发消息、能订阅——就像知道邮件地址就能发邮件。不知道 mail_id 就无从操作。没有 token,没有 ACL,没有额外的权限控制。
一个 Agent 可以同时持有多个邮箱——一个接收任务分配,一个接收审批结果,完全隔离,互不干扰。
邮箱分两种:
| 私有邮箱 | 公开邮箱 | |
|---|---|---|
| mail_id | 系统生成,不可猜测 | 用户自定义,有意义的名字 |
| 可发现性 | 不公开,只有知道 mail_id 的 Agent 能找到 | 自动注册到 PUBLIC.LIST,任何 Agent 可发现 |
| 适合场景 | 点对点私信、任务结果回传 | 任务队列、公共频道、能力公告 |
公开邮箱的 mail_id 本身就是地址,起一个有意义的名字——task.queue、analytics.result——比 UUID 更容易被其他 Agent 发现和理解。
三件事,六条命令
mq9 的全部操作只有三件事:创建邮箱、发消息、订阅邮箱。
创建邮箱
# 私有邮箱
nats req '$mq9.AI.MAILBOX.CREATE' '{"ttl":3600}'
{"mail_id":"mail-d7a5072lko83gp7amga0-d7a5072lko83gp7amgag","is_new":true}
# 公开邮箱,自动注册到 PUBLIC.LIST
nats req '$mq9.AI.MAILBOX.CREATE' '{"ttl":3600, "public":true, "name":"task.queue", "desc":"任务队列"}'
{"mail_id": "task.queue"}ttl 是邮箱的生命周期,单位秒。到期自动销毁,消息随之清理。
发消息
知道 mail_id 即可发送,无需任何授权。消息按优先级发送:
nats pub '$mq9.AI.MAILBOX.MSG.mail-d7a5072lko83gp7amga0-d7a5072lko83gp7amgag' 'payload' # 常规(默认,无后缀)
nats pub '$mq9.AI.MAILBOX.MSG.mail-d7a5072lko83gp7amga0-d7a5072lko83gp7amgag.urgent' 'payload' # 紧急
nats pub '$mq9.AI.MAILBOX.MSG.mail-d7a5072lko83gp7amga0-d7a5072lko83gp7amgag.critical' 'payload' # 最高优先级,优先处理三个优先级:
| 级别 | 语义 | 典型场景 |
|---|---|---|
| critical | 最高优先级,优先处理 | 中止信号、紧急指令、安全事件 |
| urgent | 紧急,时间敏感 | 任务中断、时间敏感指令 |
| normal | 常规通信(默认,无后缀) | 任务分发、结果返回、审批请求 |
存储层保证优先级顺序。边缘设备离线 8 小时后上线,先收到紧急停机指令,再收到常规配置更新。消费方无需自行排序。
订阅邮箱
nats sub '$mq9.AI.MAILBOX.MSG.mail-d7a5072lko83gp7amga0-d7a5072lko83gp7amgag' # 仅常规(默认)优先级
nats sub '$mq9.AI.MAILBOX.MSG.mail-d7a5072lko83gp7amga0-d7a5072lko83gp7amgag.*' # 所有优先级(critical + urgent + normal)
nats sub '$mq9.AI.MAILBOX.MSG.mail-d7a5072lko83gp7amga0-d7a5072lko83gp7amgag.critical' # 仅最高优先级订阅即全量推送——所有未过期消息立即推送,后续新消息实时推送。Agent 重连后不会漏消息,不需要单独的拉取接口。
没有已读未读,没有消费位点,没有 QUERY 命令。每条消息带唯一 msg_id,客户端自行去重。
禁止的操作:
nats sub '$mq9.AI.MAILBOX.MSG.*' # 禁止,broker 拒绝
nats sub '$mq9.AI.MAILBOX.MSG.#' # 禁止,broker 拒绝订阅必须精确到 mail_id,不允许通配符订阅所有邮箱。
发现公开邮箱
$mq9.AI.PUBLIC.LIST 是系统内置地址,broker 维护,不接受用户写入。
public:true 的邮箱创建后自动注册到 PUBLIC.LIST,TTL 到期自动移除。Agent 无需手动维护注册表。
nats sub '$mq9.AI.PUBLIC.LIST'订阅即全量推送——当前所有 public 邮箱立即推送,后续新增和移除实时推送。Agent 启动后订阅一次,就能持续感知网络里有哪些公开频道。
为什么现有方案不够
HTTP:要求双方同时在线。Agent 频繁上下线,HTTP 的假设不成立。加 retry loop 是在同步协议上贴异步补丁,越贴越复杂。
Redis pub/sub:没有持久化。对方不在线,消息直接丢。加 Redis Streams 可以持久化,但引入了 consumer group、offset 管理——为发一条 Agent 消息,不值得。
Kafka:为高吞吐数据管道设计。topic 需要预创建,partition 需要规划,consumer group 需要管理。Agent 是临时的,Kafka 的资源模型假设长期存在、精心维护,根本不匹配。
NATS Core:纯内存转发,没有持久化,对方不在线消息直接丢。做不了邮箱。
JetStream:stream、consumer、offset、replay,一整套对标 Kafka 的语义。为 Agent 发个消息,概念太重。
这些方案有一个共同假设:对方在线。Agent 频繁上下线这个最本质的特征,在所有现有方案里都是需要绕过去的问题。mq9 不绕路——store-first delivery,消息到达先写存储,持久化是默认行为,不是可选项。
为什么选择 NATS 协议
mq9 兼容 NATS 协议。所有 NATS 客户端 SDK——Go、Python、Rust、JavaScript、Java、.NET——直接就是 mq9 的客户端,零生态成本。
选择 NATS 有三个原因:
第一,Agent 天然懂 NATS。 LLM 在训练过程中接触了大量 NATS 的代码和文档。pub/sub、subject 寻址、queue group——这些概念已经在模型的先验知识里。mq9 不发明新概念,站在 Agent 已经懂的东西上定义语义约定,采用成本为零。
第二,NATS 的 subject 模型天然适合邮箱寻址。 $mq9.AI.MAILBOX.MSG.mail-d7a5072lko83gp7amga0-d7a5072lko83gp7amgag.critical——一行字符串,清晰表达:协议、场景、消息类型、邮箱地址、优先级。裸地址(无后缀)承载常规优先级消息,通配符让 Agent 灵活选择订阅粒度。
第三,NATS 足够轻。 协议本身是文本协议,解析简单,连接开销小,适合大量临时 Agent 频繁上下线的场景。
八个场景
场景一:点对点,离线可达 子 Agent 完成任务,结果发回主 Agent。主 Agent 可能不在线,不需要等待。
nats pub '$mq9.AI.MAILBOX.MSG.m-orchestrator' '{"task_id":"t-001","result":"done"}'场景二:任务广播,竞争消费 Orchestrator 创建公开任务队列,多个 Worker 竞争消费,每条任务只被一个 Worker 处理。
nats req '$mq9.AI.MAILBOX.CREATE' '{"ttl":86400,"public":true,"name":"task.queue"}'
nats sub '$mq9.AI.MAILBOX.MSG.task.queue.*' --queue workers场景三:能力发现 Agent 启动,订阅 PUBLIC.LIST,发现网络里有哪些公开频道,决定订阅哪些。
nats sub '$mq9.AI.PUBLIC.LIST'场景四:优先级,离线边缘设备 云端给离线边缘设备发紧急指令和普通配置。设备上线后紧急指令先到。
nats pub '$mq9.AI.MAILBOX.MSG.m-device-001.critical' '{"cmd":"abort"}'
nats pub '$mq9.AI.MAILBOX.MSG.m-device-001' '{"cmd":"update_config"}'场景五:异步 request-reply Agent A 问离线的 Agent B,B 上线后处理并回复。
# A 发请求,payload 里带 reply_to
nats pub '$mq9.AI.MAILBOX.MSG.m-uuid-b' '{"reply_to":"m-uuid-a","payload":"..."}'
# B 上线后处理,结果发回 A 的邮箱
nats pub '$mq9.AI.MAILBOX.MSG.m-uuid-a' '{"correlation_id":"...","result":"..."}'场景六:人机混合工作流 Agent 发审批请求到审批员邮箱,审批员回复到 Agent 邮箱。人和 Agent 用同一套协议。
场景七:广播告警 Agent 发现异常,发到公开频道,所有订阅者响应。离线的 handler 上线后也能收到未过期的告警。
nats req '$mq9.AI.MAILBOX.CREATE' '{"ttl":3600,"public":true,"name":"alert.anomaly"}'
nats pub '$mq9.AI.MAILBOX.MSG.alert.anomaly.critical' '{"type":"anomaly","confidence":0.95}'场景八:Orchestrator 感知 Worker 状态 多个 Worker 定期上报状态到各自邮箱,Orchestrator 订阅感知。Worker TTL 到期,Orchestrator 感知消亡。
mq9 和 RobustMQ 的关系
mq9 不是一个独立的产品,是 RobustMQ 的一部分。
RobustMQ 是用 Rust 构建的统一消息引擎——单个二进制,零外部依赖,原生支持 MQTT、Kafka、NATS、AMQP 四种协议,底层统一存储。mq9 是从这个地基上生长出来的第五个协议层。
对用户来说,mq9 就是一个 broker。部署一个 RobustMQ,IoT 设备通过 MQTT 发数据,分析系统通过 Kafka 消费,Agent 通过 mq9 协作——同一个 broker,同一份存储,零桥接,零复制。
什么 mq9 不是
- 不是更好的 NATS。 mq9 不跟 NATS 竞争通用消息场景。兼容 NATS 协议是为了零生态成本,不是为了替代。
- 不是数据管道。 不替代 Kafka 做高吞吐流处理。
- 不是服务间 RPC。 不替代 HTTP/gRPC 做始终在线的服务通信。
- 不是编排框架。 mq9 搬运消息,不做决策。编排逻辑属于上层框架。
我们的判断
Agent 之间缺乏异步通信机制,这个问题是真实的。协议层和基础设施层分别做了努力,但"Agent 原生语义 + 原生 store-and-forward + 轻量开箱即用 + 可私有部署"这个组合,今天没有人做。这是 mq9 填的空白。
mq9 还在建设中。协议在迭代,功能在完善。这不是一个做完的产品,是一个正在生长的方向。
只要你需要跑多个 Agent,你就需要 mq9。
