开发者必读:qwen-audio-agent Gateway 客户端协议与自定义客户端开发完全参考
【免费下载链接】qwen-audio-agentA realtime voice runtime that keeps Agents talking, working, and present. Real-time Voice Runtime for AI Agents项目地址: https://gitcode.com/gh_mirrors/qw/qwen-audio-agent
qwen-audio-agent 是一个实时语音运行时,让 AI Agent 能持续说话、工作并保持在场。本文面向新手,用最少的代码带你快速理解它的Gateway 客户端协议,并手把手教你从零开发一个自定义客户端——连接、握手、收发消息、断线重连一次讲透。
为什么需要理解 Gateway 客户端协议
在开发任何客户端之前,先分清两个角色,能帮你少走弯路:
- Gateway(网关):框架的服务宿主,负责认证、连接管理、会话、任务与协议入口。
- Client Environment(客户端):你正在开发的东西,负责 I/O、显示、播放、本地 UX 与环境事件。
它们之间只走一条 WebSocket(可选 WebRTC 媒体传输),不额外建立第二连接。这就是理解整个协议的核心:单连接、类型化事件、能力协商。
💡 关键原则:客户端按协商到的能力位分支,而不是比较产品版本号。旧版 Gateway 会自动降级而非报错。
Gateway 客户端协议核心概念一览
当前线协议版本为7.0,核心概念可归纳为四类,记住它们就能看懂所有文档:
| 概念 | 作用 | 一句话理解 |
|---|---|---|
| 信封 Envelope | 每条消息的公共字段 | type+event_id,命令结果用request_event_id关联 |
| 能力 capabilities | 声明你能做什么 | 握手时请求,Gateway 返回交集 |
| Event / Action | 描述发生了什么 / 要求执行 | Event 只上报,Action 才执行 |
| 回放 replay | 断线恢复 | 用sequence有界回放未消费事件 |
单条 WebSocket 与 session.hello 握手
客户端连接ws://<gateway>/api/realtime,第一条消息必须是session.hello,声明协议版本、客户端身份与能力:
{ "type": "session.hello", "event_id": "evt_client_1", "protocol": { "min": "7.0.0", "max": "7.0.0" }, "client": { "type": "desktop", "version": "1.0.0", "instance_id": "my_client" }, "capabilities": ["input.audio", "input.text", "playback.receipts", "client.events"], "locale": "zh-CN", "connection": { "voice_enabled": true, "text_only": false } }Gateway 返回协商后的session.ready,携带协议版本与能力交集。收到它之后,客户端才算“就绪”。
⚠️ 每个已认证用户同一时刻只有一个活动 Client。要抢占需显式声明
session.takeover能力并设置connection.takeover: true。
能力协商 capabilities
你只需用session.hello声明支持的能力,常见能力位包括:input.audio、input.text、input.image、playback.receipts、tasks.commands、permissions.respond、conversation.history、client.events、session.replay。完整清单与实现见 shared/protocol/gateway-client-protocol.mjs,第一方参考 profile 在 shared/gateway/client-profiles.mjs。
从零开始:自定义客户端开发最快路径
好消息:你不需要从零手写协议。仓库已提供一个共享的参考客户端 SDK——GatewayClient,统一处理握手、命令关联、Client Action、断线重连和有限回放。第一方的 WebUI、Desktop、TUI 都用它,并通过了同一套一致性测试。
第一步 安装并启动 Gateway
在仓库根目录安装一次(推荐 Node.js 22.22.2):
npm install npm run start --workspace serverGateway 默认只监听127.0.0.1,本机访问零配置;远程访问才需要配置访问密钥或设备令牌。
第二步 建立连接并完成握手
用GatewayClient只需几行。createSocket让你注入自己的 WebSocket 实现(浏览器或 Node 均可):
import { GatewayClient } from 'qwen-audio-agent/gateway-client-sdk' const client = new GatewayClient({ url: 'ws://127.0.0.1:3101/api/realtime', createSocket: url => new WebSocket(url), clientType: 'web', clientInstanceId: 'my_custom_client', capabilities: ['input.text', 'playback.receipts', 'client.events'], onEvent: event => console.log('收到事件', event.type), onStatus: status => console.log('状态', status.state), }) client.start()onStatus会依次给出connecting → connected → ready;ready后即可发业务消息。SDK 源码见 shared/gateway/client-sdk.mjs。
第三步 发送与接收事件
- 提交文本输入:发
conversation.item.create,按顺序提交text/file类型的 parts。 - 追加音频:发
input_audio_buffer.append,base64 PCM16 单声道。 - 打断回复:发
response.cancel。 - 上报环境事件:发
client.event.publish(如“用户触摸了水杯”)。 - 查询任务 / 权限 / 历史:用
task.create、permission.respond、conversation.history等运行时命令,即时结果通过request_event_id关联。
事件名与消息 Schema 都由 shared/protocol/gateway-client-protocol.mjs 固化,客户端应使用这些包入口,而非依赖内部路径。
四种路由模式 AgentDelivery
这是协议最精妙的部分,决定了“一条事件如何被 Gateway 处理”。Gateway 会把它路由成四种模式之一:
handle:Gateway 确定性处理,不产生模型回复。context:只更新模型上下文,不创建回复。respond:更新上下文,并在安全边界安排回复。interrupt:打断当前回复、更新上下文并请求回复。
client.event.publish可用delivery_hint指定context/respond/interrupt。理解这四点,你就明白为什么“上报摄像头关闭”只会静默更新上下文,而“用户请求休息”才会触发回复。
Client Event 与 Client Action 的区别
新手最容易混淆的一对,请务必分清:
| Client Event | Client Action | |
|---|---|---|
| 语义 | 描述发生了什么 | 要求环境执行操作并返回结果 |
| 关联 | event_id | client.action.request/client.action.result |
| 例子 | “用户按下了物理按钮” | 让客户端进入休眠enter_sleep |
| 能否执行操作 | 否 | 是 |
客户端工具通过握手时的tools声明(最多 32 个),模型调用后由ClientActionPort转发为client.action.request。注意:这是GCP 的工具发现和传输,不是 MCP Server,配置的 MCP 工具仍走标准 MCP 通道。
断线重连与有限回放
GatewayClient内置了重连(指数退避,默认 500ms–5000ms)与有限回放:
- 服务端推送携带 Session 内递增的
sequence; - 断线重连后,
session.replay按sequence游标回放断线前未消费的事件(默认 50、最大 200); - 之后通过
task.list与conversation.history恢复最终快照。
媒体增量、临时转写与即时命令结果不回放。SDK 的recover()方法会自动完成这套恢复流程,你通常无需手写。
可选的 WebRTC 传输
如果你的场景对语音延迟更敏感,可选用实验性的 WebRTC 媒体传输——它只扩展“客户端到 Gateway”的传输,不改变语义事件路由。最小浏览器示例位于 examples/webrtc/client.mjs,共享连接逻辑在shared/gateway/webrtc-browser.mjs。音频走原生 Track,控制事件走 DataChannel,供应商密钥始终留在网关、不下发给客户端。完整说明见 docs/gateway-webrtc-client.zh.md。
关键模块路径速查
| 你想知道 | 去哪里看 |
|---|---|
| 完整协议契约 | docs/gateway-protocol.zh.md |
| 唯一对外契约索引 | docs/contract.zh.md |
| 参考 Client SDK | shared/gateway/client-sdk.mjs |
| 能力 profile | shared/gateway/client-profiles.mjs |
| 协议 Schema 与解析器 | shared/protocol/gateway-client-protocol.mjs |
| WebRTC 最小客户端 | examples/webrtc/client.mjs |
| 架构总览 | docs/architecture/overview.zh.md |
常见问题 FAQ
- 为什么我的能力没生效?客户端必须按
session.ready返回的协商后能力判断,不能只比较产品版本,也不要在连接中改协议/身份——需要重连。 - accepted: true 表示模型收到了吗?不。
client.event.publish.result的accepted: true只表示网关已接收,不表示模型已收到或播报。它不是持久化消息队列。 - 能伪造内部事件吗?不能。Client Event 不能发布
task.*、permission.*、gateway.*、response.*,也不能伪装成用户输入。 - 旧版 5.x 客户端还能连吗?可以。
connect与部分 REST 路由作为兼容别名保留,但新客户端请使用 7.0session.hello。
下一步:先跑通GatewayClient最小示例,再逐步启用client.events、tasks.commands、session.replay等能力。遵循 docs/contract.zh.md 里的能力位表,你的自定义客户端就能稳定地接入 qwen-audio-agent 的实时语音运行时。
【免费下载链接】qwen-audio-agentA realtime voice runtime that keeps Agents talking, working, and present. Real-time Voice Runtime for AI Agents项目地址: https://gitcode.com/gh_mirrors/qw/qwen-audio-agent
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考