API 参考
示例使用本地运行时,其中 productId 是设备智能体 ID,deviceId 是真实设备 ID,HTTP 路径里的 products 按设备智能体理解。
HTTP: http://127.0.0.1:3000
Voice WebSocket: ws://127.0.0.1:3001/ws/voice
Voice HTTP: http://127.0.0.1:3001/api/chat, /api/vision/frames启用直接 HTTPS 后,主 HTTP 地址改用 https://。主 HTTP TLS 不会同时为 MQTT Broker 或语音服务启用 TLS;请分别配置这些端点,浏览器连接时使用 wss://。使用私有 CA 时,应向客户端提供 CA 文件,不要关闭证书校验。
Gateway 不提供用户认证、租户隔离、会话归属或资源级授权。HTTP、SSE 和语音 WebSocket 只应由可信系统或受控客户端访问;多用户或公网接入时,应放在带认证与授权的网关后。HTTPS/WSS 只保护传输,不等于访问控制。
选择协议
| 使用场景 | 推荐协议 | 说明 |
|---|---|---|
| 真实设备长期在线、上报状态、接收命令 | MQTT | 适合设备端连接、状态同步和命令响应。 |
| 其他智能体发现并调用已启用 A2A 的设备智能体 | A2A over MQTT | 使用 MQTT v5 的发现和请求/回复主题。 |
| 业务系统创建或执行多智能体场景与一次性任务 | HTTP + SSE | 使用 HTTP 提交请求,通过 SSE 持续接收规划、步骤和最终结果。 |
| 业务系统、控制台扩展或自动化脚本调用 Device Agent | HTTP | 适合一次性请求、查询和命令下发。 |
| 实时语音交互 | WebSocket | 适合连续音频输入、实时识别结果和语音合成输出。 |
| 浏览器或设备端通过 WebSocket 连接 MQTT Broker | MQTT over WebSocket | 这是 MQTT 的传输方式,不是 Device Agent 的语音 WebSocket。 |
MQTT
MQTT 用于设备侧接入。设备通过 MQTT 上线、上报状态、接收命令、返回命令结果和上报事件。MQTT 服务地址、用户名、密码和主题模板以控制台配置为准。
| 方向 | 主题 | 用途 |
|---|---|---|
| MQTT 客户端 -> Device Agent | device-agent/{productId}/in | 向某个设备智能体发送文本请求。 |
| Device Agent -> MQTT 客户端 | device-agent/{productId}/out | 返回设备智能体回复。 |
| MQTT 客户端 -> Device Agent | device-agent/{productId}/device/{deviceId}/in | 向某台设备上下文发送文本请求。 |
| Device Agent -> MQTT 客户端 | device-agent/{productId}/device/{deviceId}/out | 返回带设备上下文的回复。 |
| Device Agent -> 设备 | device-agent/{productId}/device/{deviceId}/commands | 下发设备命令。 |
| 设备 -> Device Agent | device-agent/{productId}/device/{deviceId}/responses | 返回命令结果。 |
| 设备 -> Device Agent | v1/{productId}/{deviceId}/telemetry | 上报在线状态和当前数据。 |
| 设备 -> Device Agent | v1/{productId}/{deviceId}/event | 上报设备事件。 |
| 设备 -> Device Agent | device-agent/{productId}/device/{deviceId}/ntp/request | 发起时间同步。 |
| Device Agent -> 设备 | device-agent/{productId}/device/{deviceId}/ntp/response | 返回时间同步结果。 |
文本请求消息体:
{
"id": "req-001",
"prompt": "查看当前温度",
"sessionId": "session-default:thermostat:thermostat-001",
"metadata": {
"source": "mqtt-client"
}
}设备智能体回复消息体:
{
"sessionId": "session-default:thermostat:thermostat-001",
"text": "当前温度是 28 度。",
"metadata": {
"timestamp": "2026-05-11T10:00:00.000Z"
},
"timestamp": "2026-05-11T10:00:00.000Z"
}一次对话会返回多条消息。过程消息的顶层 text 为空,进度位于 metadata.status:
metadata.status.type | 关键字段 |
|---|---|
start、thinking | 当前执行阶段。 |
text_block | 增量文本位于 metadata.status.text。 |
tool_start、tool_end | 工具名、输入、输出或错误。 |
complete、error | 当前执行结果。最终完整回复仍以普通消息的顶层 text 返回。 |
中断或清空会话时,向原输入主题发送空 prompt,并分别设置 metadata.interrupt: true 或 metadata.clearSession: true。响应是 metadata.status.type: complete,metadata.replyTo 对应请求 id。
消息体规则、校验方式和 MQTTX 示例见 MQTT 接入。
A2A over MQTT
A2A 客户端通过 MQTT v5 发现并调用实时网络中已启用 A2A 的设备智能体:
| 用途 | 主题 |
|---|---|
| 发现智能体卡片 | $a2a/v1/discovery/{org_id}/{unit_id}/{agent_id} |
| 发现当前组织 | $a2a/v1/discovery/{org_id}/+/+ |
| 发现全部组织 | $a2a/v1/discovery/+/+/+ |
| 发送请求 | $a2a/v1/request/{org_id}/{unit_id}/{agent_id} |
| 接收回复 | 通过 MQTT v5 responseTopic 指定,通常位于 $a2a/v1/reply/... 下 |
智能体卡片使用 QoS 1 的 retained 消息;空 retained 消息表示移除卡片。Device Agent 处理 JSON-RPC SendMessage 请求。请求使用 QoS 1,并且必须携带 responseTopic;可选的 correlationData 会原样返回。需要延续同一上下文时使用 params.message.contextId;需要指定设备时使用 params.metadata.deviceId。
请求示例:
{
"jsonrpc": "2.0",
"id": "task-001",
"method": "SendMessage",
"params": {
"message": {
"role": "user",
"parts": [
{
"type": "text",
"text": "检查当前温度。如果温度过高,把空调切换到制冷模式。"
}
],
"taskId": "task-001",
"contextId": "server-room-session"
},
"metadata": {
"sender": "my-a2a-client",
"deviceId": "air-conditioner-01"
}
}
}回复使用 QoS 1,并发送到 responseTopic:
| JSON-RPC 结果 | 内容 |
|---|---|
result.statusUpdate | taskId、可选 contextId,以及 status.state、status.timestamp、可选 status.message。 |
result.artifactUpdate | taskId、可选 contextId,以及 artifact.artifactId、artifact.parts、append、lastChunk。 |
完整文本先通过 artifactUpdate.artifact.parts[].text 返回,再以 TASK_STATE_COMPLETED 结束;失败以 TASK_STATE_FAILED 结束。客户端应校验相同的 JSON-RPC id 和 correlationData,并为等待回复设置超时。
启用智能体、使用任务与场景以及排错方式见 A2A 多智能体协作。
HTTP
HTTP API 路径都以 /api 开头,目前没有版本号。/api/chat 和多智能体编排执行接口返回 Server-Sent Events,其他对外接口使用 JSON。升级前请查看发布历史。
GET /api/health 只表示 HTTP 进程可响应,不检查大模型、MQTT 或设备是否可用。
对话和视觉
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /api/health | 检查 HTTP API 是否可用。 |
POST | /api/chat | 发起文本对话,必须设置 stream: true。 |
GET | /api/sessions/:sessionId/history | 查询会话历史。 |
POST | /api/sessions/:sessionId/interrupt | 中断当前会话。 |
DELETE | /api/sessions/:sessionId | 清空会话。 |
POST | /api/sessions/:sessionId/tool-approvals | 授权或撤销高风险工具。仅限可信管理客户端。 |
POST | /api/vision/frames | 上传视觉帧,供后续对话使用。 |
| 请求字段 | 要求 |
|---|---|
message | 必填,非空文本。 |
stream | 必须为 true。 |
sessionId | 终端接入建议自行生成并保存;历史、中断、清空和工具授权使用同一 ID。 |
metadata.productId、metadata.deviceId | 需要设备上下文时传入。 |
visionRefs | 可选,引用同一会话上传的视觉帧。 |
对话示例:
$ curl -N http://127.0.0.1:3000/api/chat \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
-d '{
"message": "查看当前温度,并把目标温度设置为 24 度",
"stream": true,
"sessionId": "demo-session",
"metadata": {
"productId": "thermostat",
"deviceId": "thermostat-001"
}
}'SSE 事件:
| 事件 | 数据 | 是否结束 |
|---|---|---|
status | type 为 start、thinking、text_block、tool_start、tool_end、complete 或 error。 | 否 |
message | { "text", "sessionId", "timestamp" } | 是 |
error | { "error", "sessionId", "timestamp?" } | 是 |
同一 sessionId 同时只能有一个对话请求,否则返回 429。请求最长等待 5 分钟;超时会返回 error 并中断会话。客户端断开 SSE 也会中断本轮执行;主动中断使用 POST /api/sessions/:sessionId/interrupt。
工具授权
当 status 事件包含 data.approvalRequired: true 时,原 SSE 会等待授权。可信管理客户端确认 toolName 和 toolInput 后,在 5 分钟内提交:
{
"action": "approve",
"toolName": "write_file",
"scope": "once",
"target": {
"type": "write_file",
"path": "<toolInput.path>"
}
}toolName 支持 write_file、execute_command;scope 支持 once、session,默认 once。execute_command 的 target 使用 { "type": "execute_command", "command": "...", "cwd": "..." }。服务器未启用对应工具时返回 403。优先使用带精确 target 的单次授权。
视觉帧先通过 /api/vision/frames 上传,再把返回的 frameId 和 capturedAt 作为 visionRefs 传给 /api/chat。mimeType 支持 image/jpeg、image/png 和 image/webp。
$ curl http://127.0.0.1:3000/api/vision/frames \
-H 'Content-Type: application/json' \
-d '{
"sessionId": "demo-session",
"deviceId": "thermostat-001",
"mimeType": "image/png",
"imageBase64": "<base64>",
"source": "camera"
}'上传成功返回 201,包含 frameId、capturedAt、source 和 mimeType;请求无效返回 400,视觉帧存储不可用返回 503。imageBase64 字符串最大 6 MiB;每个会话最多保留 20 帧,5 分钟后过期。清空会话时也会删除对应视觉帧。
带视觉帧发起对话:
{
"message": "根据这张图判断设备屏幕是否异常",
"stream": true,
"sessionId": "demo-session",
"visionRefs": [
{
"frameId": "frame-001",
"capturedAt": "2026-05-11T10:00:00.000Z",
"source": "camera"
}
]
}设备、命令和事件
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /api/products | 查询设备智能体列表。 |
GET | /api/products/:productId | 查询设备智能体定义,包括属性、命令、参数和事件。 |
GET | /api/products/:productId/devices | 查询设备列表;支持 status 和 tags 筛选。 |
GET | /api/products/:productId/devices/:deviceId | 查询设备详情。 |
POST | /api/products/:productId/devices/:deviceId/commands | 向在线设备下发命令。 |
GET | /api/products/:productId/devices/:deviceId/events | 查询设备事件。 |
先查询真实 ID 和产品定义,不要自行拼接命令名或参数:
$ export BASE=http://127.0.0.1:3000
$ curl "$BASE/api/products"
$ export PRODUCT_ID=your_product_id
$ curl "$BASE/api/products/$PRODUCT_ID"
$ curl "$BASE/api/products/$PRODUCT_ID/devices?status=online&tags=site:lab"
$ export DEVICE_ID=your_device_id设备列表返回 status、state、tags、modelStatus 和 lastSeenAt。status 支持 online、offline、error、all;多个 tags=key:value,key:value 条件需同时匹配。
命令名和参数必须来自产品定义:
$ curl "$BASE/api/products/$PRODUCT_ID/devices/$DEVICE_ID/commands" \
-H 'Content-Type: application/json' \
-d '{
"command": "set_drive_mode",
"params": {
"mode": "eco"
},
"timeoutMs": 30000
}'timeoutMs 默认 30,000,最大 120,000。命令响应:
| HTTP | 结果 |
|---|---|
200 | { "result": <设备响应> } |
400 | COMMAND_VALIDATION_FAILED |
404 | DEVICE_NOT_FOUND |
409 | DEVICE_NOT_ONLINE 或 DEVICE_COMMAND_FAILED |
504 | COMMAND_TIMEOUT |
收到 504 时,设备仍可能稍后执行命令;确认设备状态后再决定是否重试。
设备事件按新到旧返回,limit 默认 50、最大 200。下一页把本页最后一条事件的 id 作为 beforeId。
多智能体编排
HTTP 编排 API 只挂载在主 HTTP 端口,用于创建和执行 A2A 场景或一次性任务。调用前请配置可用的大模型,并从 /api/a2a/agents 返回的 cards 中选择 status: online 的真实 agentId;不要手动拼接。visibility 支持 public、private 和 all,默认 all。需要本地设备时,再用卡片顶层的 productId 查询真实 deviceId。
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /api/a2a/agents?visibility=all | 查询当前 A2A 组织和单元中的智能体卡片及在线状态。 |
GET | /api/a2a/scenes | 查询已保存场景。 |
POST | /api/a2a/scenes | 创建场景并异步生成协作流程。 |
GET | /api/a2a/scenes/:sceneId | 查询场景详情和生成状态。 |
POST | /api/a2a/scenes/:sceneId/input | 为处于 needs_input 的场景补充信息。 |
POST | /api/a2a/scenes/:sceneId/recreate | 完整替换场景名称、目标和智能体,并重新生成。 |
DELETE | /api/a2a/scenes/:sceneId | 删除场景。 |
POST | /api/a2a/chat | 在已就绪场景中选择一个进行对话或执行,返回 SSE。 |
POST | /api/a2a/scenes/:sceneId/chat | 将对话限制在指定场景,返回 SSE。 |
POST | /api/a2a/tasks | 发起一次性多智能体任务,返回 SSE。 |
创建并等待场景就绪
$ curl "$BASE/api/a2a/scenes" \
-H 'Content-Type: application/json' \
-d '{
"name": "机房响应",
"instructions": "检查机房温湿度,超过阈值时调节空调并返回处理报告",
"agentIds": ["<sensor-agent-id>", "<air-conditioner-agent-id>"]
}'接口返回 202 { "sceneId": "<scene-id>", "status": "creating" }。保存 sceneId,通过 GET /api/a2a/scenes/:sceneId 轮询状态:
status | 处理方式 |
|---|---|
creating | 继续等待并查询。创建和重新生成都使用此状态。 |
needs_input | 读取 pendingInput,提交补充信息后继续查询。 |
ready | 场景可以执行。 |
failed | 读取 failureReason;根据原因处理后调用 recreate。 |
需要补充信息时,向 /api/a2a/scenes/:sceneId/input 提交 { "answers": "..." }。recreate 使用与创建场景相同的 name、instructions 和 agentIds,保留 sceneId 并重新生成。
执行场景
共享场景对话使用 /api/a2a/chat。请求中写明场景名称和执行意图,规划器会从已就绪场景中选择至多一个:
$ curl -N "$BASE/api/a2a/chat" \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
-d '{
"prompt": "现在执行机房响应场景,并返回最终处理报告",
"contextId": "terminal-demo-001"
}'如果调用方持有准确的 sceneId,可向 /api/a2a/scenes/:sceneId/chat 提交相同的 prompt,把候选范围限制在该场景。
这两个接口都是对话式执行接口。请求不够明确时,系统可能直接回答或要求补充信息,不会无条件下发设备动作。多轮场景对话的 history 由调用方保存并随请求传回;contextId 用于下游 A2A 上下文,不会保存 HTTP 对话历史。
发起一次性任务
一次性任务不保存场景。devices 可选;需要提前指定设备时,每个 productId 只能出现一次。
$ curl -N "$BASE/api/a2a/tasks" \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
-d '{
"text": "检查所有房间的温度,把高于 28°C 的房间空调设置为 24°C,并返回汇总",
"devices": [
{
"productId": "<sensor-product-id>",
"deviceId": "<sensor-device-id>"
},
{
"productId": "<air-conditioner-product-id>",
"deviceId": "<air-conditioner-device-id>"
}
]
}'首次请求必须提供 text。任务也可能直接回答或要求补充信息,不保证每次都会执行设备动作。可选的 history 最多包含 12 条 { "role": "user|assistant", "text": "..." } 消息,每条 text 最多 4000 个字符;对话历史由调用方保存,并在后续新的任务请求中传回。
处理设备选择
执行需要具体设备但请求中没有可用选择时,当前 SSE 会先返回 status: input-required,再以 binding_required 事件结束。appId 是场景 ID:
event: binding_required
data: {"kind":"scene","appId":"<scene-id>","continuationId":"<id>","prompt":"<prompt>","tasks":[{"taskId":"<task-id>","productId":"<product-id>"}]}续接请求必须发回原端点,三种请求体不能混用:
| 原端点 | 续接请求体 |
|---|---|
/api/a2a/chat | prompt、continuationId、devices: [{ productId, deviceId }]。 |
/api/a2a/scenes/:sceneId/chat | prompt、continuationId、deviceBindings: { taskId: deviceId }。 |
/api/a2a/tasks | 只能包含 continuationId 和非空 devices;不能再次携带 text 或 history。 |
continuationId 有效期为 5 分钟且只能使用一次,Gateway 重启后失效。场景的 continuationId 还会在该场景被删除或重新生成时失效。收到事件后应立即完成设备选择。
读取 SSE
使用 curl -N 关闭输出缓冲。执行接口可能返回以下事件:
| SSE 事件 | 内容 |
|---|---|
status | working、input-required、completed 或 failed。metadata.type 为 plan 时,规划文本位于 data.text;为 task_step 时,步骤详情位于 data.metadata。 |
artifact | 最终文本位于 data.parts[].text。 |
binding_required | 返回需要绑定设备的步骤和一次性 continuationId,并结束当前流。 |
HTTP 200 只表示 SSE 已建立;运行失败会通过 status 事件的 data.state: failed 返回。正常执行以 status 事件的 data.state: completed 结束。客户端应持续读取到终止事件。
多智能体执行不是持久化任务:接口不返回运行 ID,也不提供运行历史或断线后的状态查询。断开 SSE 会停止尚未下发的步骤,但不会撤销已经发送给智能体或设备的动作。执行接口没有幂等键,不要在结果未知时直接重复请求。
控制台操作见 A2A 多智能体协作。
工作流
工作流可以通过 HTTP 查询、启停和删除。创建和完整更新由设备智能体的工作流工具完成,通常在对话中说明触发条件和处理动作。使用方式见 工作流。
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /api/workflows | 查询已保存工作流。 |
PATCH | /api/workflows/:workflowId | 启用或停用工作流。请求体为 { "enabled": true } 或 { "enabled": false }。 |
DELETE | /api/workflows/:workflowId | 删除工作流。 |
GET | /api/workflow-runs | 查询工作流运行记录,支持 limit、offset 和 q。 |
GET | /api/workflows/:workflowId/runs | 查询指定工作流的运行记录。 |
GET | /api/workflow-runs/:runId | 查询一次运行及各步骤结果。 |
列表返回 { "workflows": [...] };修改返回 { "workflow": {...} };删除成功返回 204。运行列表返回 runs、total、limit 和 offset;传入 q 时还会返回 query。limit 默认 50、最大 100。
定时任务
定时任务通过设备智能体对话创建。HTTP 可以查询、暂停、恢复、修改、取消任务,并读取运行历史。
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /api/timers?status=active&limit=50 | 按 active、paused、running、completed 或 deleted 查询任务。 |
PATCH | /api/timers/:timerId | 设置 enabled,或替换 instruction,也可以同时修改。 |
DELETE | /api/timers/:timerId | 取消任务。 |
GET | /api/timers/:timerId/runs?limit=25&offset=0 | 分页查询该任务的运行历史。 |
0.4.0 不提供 HTTP 创建接口。需要修改调度规则时,也要先取消任务,再通过对话重新创建。
任务列表返回 { "timers": [...] },默认只查询 active,limit 最大 100;修改返回 { "timer": {...} },取消成功返回 204。运行历史返回 { "runs", "total", "limit", "offset" }。
控制台中的创建和管理流程见 定时任务。
Webhook
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /api/webhooks | 查询已保存连接,不返回 URL、Header 或签名密钥。 |
POST | /api/webhooks | 创建连接。 |
PATCH | /api/webhooks/:webhookId | 修改名称、启用状态、凭据、消息体模板或响应条件。 |
DELETE | /api/webhooks/:webhookId | 删除未被使用的连接;仍被工作流引用时返回 409。 |
POST | /api/webhooks/:webhookId/test | 发送测试消息并等待投递结果。 |
创建一个基础自定义连接:
$ curl "$BASE/api/webhooks" \
-H 'Content-Type: application/json' \
-d '{
"name": "operations-alerts",
"enabled": true,
"credential": {
"url": "https://hooks.example.com/device-agent"
},
"preset": "custom",
"bodyTemplate": {
"message": "{{message}}"
}
}'通过 POST /api/webhooks/:webhookId/test 和 { "message": "Device Agent test" } 测试连接。
JSON 请求体最大 64 KiB。创建成功返回 201 { "webhook": {...} },修改返回 200 { "webhook": {...} },删除返回 204,测试成功返回 200 { "ok": true, "httpStatus": <状态码> }。
预设、签名、模板、投递限制和工作流用法见 Webhook。
WebSocket
语音通道使用 /ws/voice。连接时可带 Header:
| Header | 说明 |
|---|---|
Protocol-Version | 协议版本,当前为 3。 |
Device-Id | 当前设备 ID。 |
Client-Id | 客户端 ID,不传时默认使用设备 ID。 |
语音连接建立后,先发送 hello:
{
"type": "hello",
"version": 3,
"audio_params": {
"format": "pcm",
"sample_rate": 16000,
"channels": 1
},
"sessionId": "demo-session",
"productId": "thermostat",
"deviceId": "thermostat-001",
"provider": "aliyun"
}JSON 控制消息可使用 WebSocket 文本帧,也可放入类型 1 的二进制帧。音频使用类型 0 的二进制帧,格式由 audio_params 约定。二进制帧头固定为 4 字节:
| 字节 | 内容 |
|---|---|
0 | 类型:0 音频,1 UTF-8 JSON。 |
1 | 保留位,设为 0。 |
2..3 | payload 长度,big-endian uint16。 |
16 位 PCM payload 应保持偶数字节,单帧不超过 65,534 字节。客户端应为每轮生成 taskId,并在 listen、stop 和 abort 中使用同一值。
一次语音交互的消息顺序通常是:
| 方向 | 消息 | 说明 |
|---|---|---|
| 客户端 -> Device Agent | hello | 建立语音会话,提交音频参数、设备上下文和语音服务商。 |
| Device Agent -> 客户端 | hello | 返回会话 ID 和服务端语音输出参数。 |
| 客户端 -> Device Agent | listen | 发送 `mode: auto |
| 客户端 -> Device Agent | 音频二进制帧 | 发送语音数据。 |
| Device Agent -> 客户端 | asr | 返回 text、definite、utterances 和 taskId。 |
| 客户端 -> Device Agent | stop | 发送同一 taskId,可携带 visionRefs。 |
| Device Agent -> 客户端 | agent_reply | 返回 text 和 taskId;streaming: true 表示增量文本。 |
| Device Agent -> 客户端 | 语音合成音频二进制帧 | 播放语音回复。 |
| Device Agent -> 客户端 | tts_complete | 表示本轮完成或已中断,可带 taskId。 |
| 客户端 -> Device Agent | abort | 使用当前 taskId 中断本轮。 |
| 客户端 -> Device Agent | goodbye | 携带服务端 hello 返回的 session_id。 |
服务端 hello.audio_params 是下行 TTS 音频格式,客户端应按其中的 sample_rate 播放 PCM;即使 listen.mode 为 auto,每轮录音结束时也必须发送 stop。连接以 1000 正常关闭;1011 表示语音服务不可用,1012 表示语音配置已重载,客户端可重新连接。