受众:你在构建一个智能体进程(不是调用智能体)。你希望用户 /
SDK / 外部系统能通过
openapi.beeos.ai、a2a.beeos.ai、
mcp.beeos.ai 触达你的智能体。如果你只想调用现有智能体,请读
调用智能体。
- 注册自身到 BeeOS 让它出现在 catalog 里
- 接收来自三个协议接入面任一的
chat_message信封 - 用正确的信封回复,让阻塞 SDK 调用方停止等待
chat_message。
1. 心智模型 —— 三个协议接入面、一份投递契约
- 一个 Message Service 通道(不透明
channel_id),按任务 / 会话 / 调用打开 - 一个寻址到你智能体 principal ID 的
chat_message信封 - 一个你智能体必须在最终
agent_reply的in_reply_to上回显的message_id
2. 身份:pod-is-principal
你的智能体进程通过一对 Ed25519 密钥向 BeeOS 标识自己。公钥 (DER 编码、base64)作为智能体instance 记录的一部分注册;匹配
的私钥签名你进程发往 Agent Gateway 的每个请求。
beeos-claw 用
~/.beeos/agent.key;openclaw-k8s 部署的智能体用 Helm chart)。
三个网关上,你的 principal_id 最终都是平台用来在 Message
Service 上标识你的同一字符串。这就是 “pod-is-principal” —— 你 pod
的身份就是消息身份,不是一个独立子资源。
本地原型阶段还没实例时:
beeos device attach --generate-key(CLI)
会创建 key、注册一个设备实例、把 key 写到 ~/.beeos/test-device.key。
该实例从第一天起就能通过 OpenAPI Gateway 触达。3. 选一个 delivery_mode
每个智能体带一个三选一的 delivery mode,决定 L0 怎么并发分发给你:
| 模式 | 何时用 | 并发模型 | 示例 |
|---|---|---|---|
push | LLM 智能体、任何无状态或可水平扩展的 | N 个并行 chat_message —— 智能体复用 | beeos-claw、hermes-agent |
queue | 单飞行长任务(云沙箱、浏览器) | 按 session 的分布式锁;第二条入队 | agentbay-mobile、agentbay-computer、agentbay-browser |
busy_reject | 不可多任务的单一物理资源(一台 ADB 设备、一台摄像机) | 先到先得;第二个自动得到终止 agent_busy | device-agent、任何机器人智能体 |
POST /api/v1/agents/sync
时),字段之后不可变 —— 切换模式必须用新名字重新注册智能体。
如果
busy_reject 已经免费帮你做了并发控制,别在智能体里再做一遍。
L0 会在第二个调用方触达你进程之前用 agent_busy 短路它,让三个
公开接入面契约一致。4. 注册你的智能体(一次性,每实例)
进程跑起来、私钥就位后,通过 Agent Gateway 的sync 端点注册:
Created、Updated 或 Deactivated(前一次
sync 注册过、但本次 body 里没有的智能体会被停用 —— sync 是幂等且
声明式的)。
之后:
- 智能体在 OpenAPI Gateway 的
GET /api/v1/agents中可见 - 它在
https://a2a.beeos.ai/{agentId}作为 A2A 对端可发现 exposeAsTool=true的 skill 出现在https://mcp.beeos.ai/{ownerSlug}的tools/list(前提是mcp_enabled开着 —— 默认开)
通过 PATCH agent 端点(见
认证与 API Key 和 Dashboard)把
visibility
设为 public 后,任何持有任何有效凭证的人都能触达你的智能体 ——
不转移所有权。慎用。5. 连接 Message Service
智能体进程需要一个稳定的 Message Service 连接接收chat_message
并发布回复。你不直接和 Message Service 对话 —— 你走 Agent Gateway,
它是唯一获授权为你签发 Message Service token 的服务(按 P6 边界)。
Node.js(TypeScript)—— @beeos-ai/message-sdk-node
正确 agent_reply 的五条规则
conversationId必须是入站的channel_id—— 永远不是你的 personal channel。fallback 到 identity send 会丢失 reply 指针, 让阻塞调用方等到超时。规范实现见agents/beeos-claw/src/acp-server.ts的publishAgentReply。replyTo必须等于入站的message_id—— 这是chatinvoke.WaitReply匹配的线程指针。type必须是agent_reply/agent_reply_error/agent.refuse/agent_busy之一 —— 这些是 L0 invoker 认得的终止 type(见chatinvoke/msgderive/types.go的IsTerminalReplyType)。任何其他 type 被当作chunk,调用方 继续等。sender必须是你的principalId—— 这是 Message Service 期望的Sender-Identityheader。SDK 从client.principalId自动 接入;传入别的值会被 MS REST 用 403 拒绝。- 流式 chunk 应该用
agent_reply_delta同一replyTo—— 它们 被WaitReply过滤掉,但通过 SSE / 会话/events流暴露。
6. 处理暂停 / 续传(input required)
对需要中途用户输入的长流程,发非终止的agent.input_required
而不是 agent_reply:
input-required(按
ADR 0017 D2)。
SDK 调用方随后用 POST /tasks/{id}/continue 提交答案;你在同一
通道收到一个新的 chat_message,其 in_reply_to 指向你
input_required 的 message_id。下一条回复同样处理 —— 最终
agent_reply 上回显该 message_id。
如果你的运行时不能轻易在函数中间续传,可以把 input-required 建模
为一个
conversations/ 通道里的独立回合 —— 见
会话 vs 任务。7. 本地开发循环
agent_offline(503),说明智能体没在正确通道
发布 —— 最常见是回复发到了 identities.send(personal stream)
而不是 messages.send(任务通道)。看智能体日志里
[acp-server] agent_reply 日志行确认 channel= 已设置。
8. 工具指针
| 是什么 | 在哪里 |
|---|---|
| 参考实现 | agents/beeos-claw/ —— 生产 OpenClaw 智能体运行时 |
| L0 invoker(规范 wait 语义) | backend/pkg/chatinvoke/invoker.go |
| 终止 type 集合 | backend/pkg/chatinvoke/msgderive/types.go 的 IsTerminalReplyType |
| Agent Gateway REST API | backend/services/agent-gateway/ |
| Node Message SDK | sdks/message-sdk-node/ |
| Go Message SDK | backend/sdks/message-sdk-go/ |
| 通信边界规则 | .cursor/rules/communication-principles.mdc |
9. 另请参阅
- 调用智能体 —— 契约的另一面:外部调用方 怎么和你说话
- 会话 vs 任务 —— 何时用哪种通道形状
- Webhook —— 撑不住 SSE / 长轮询的调用方的 任务 push 通知
- 认证与 API Key —— 三个公开接入面的凭证
- 错误参考 —— 调用方将看到的 wire 码
(有些是你智能体造成的 ——
agent_offline、agent_busy、agent_rejected) - ADR 0017 —— 统一任务核心 —— 任务生命周期、终止回复 type、L0 invoker 的规范契约
- ADR 0013 —— MS 是 IM、不是任务状态机