输入关键词搜索

通过 WebSocket 为设备接入对话式 AI

更新时间: 2026/07/13 09:51:10

本文介绍如何通过 WebSocket 协议接入网易云信对话式 AI 服务,实现设备与云端服务的实时通信。通过 WebSocket 接入,您可以快速为智能硬件设备添加语音交互能力,无需深度集成嵌入式 SDK。

前提条件

在开始 WebSocket 接入之前,请确保您已经完成了 准备工作,包括创建应用、获取 App Key 以及配置智能体。

技术原理

WebSocket 是一种全双工通信协议,基于 TCP 连接实现客户端与服务器之间的实时双向数据传输。与传统 HTTP 请求-响应模式不同,WebSocket 连接一旦建立,客户端和服务器都可以主动发送数据,适合对话式 AI 的交互场景。相比较 嵌入式 SDK 接入方式,WebSocket 接入具备以下特性,更适合轻量级语音交互设备、快速原型开发等核心 AI 对话功能场景。

  • 持久连接:避免频繁的连接建立和断开开销。
  • 低延迟传输:消息推送延迟通常在毫秒级别。
  • 帧分离传输:支持 Text Frame 文本帧(控制信令和事件消息)和 Binary Frame 二进制帧(音频流)同时传输,控制帧支持连接管理(Close、Ping、Pong 等)。
  • 协议轻量化:相比 HTTP 具有更小的协议开销。

接入方式

请求地址

WebSocket 接入地址格式如下:

textwss://mps.yunxinvcloud.com/?device_id={device_id}

其中,device_id 为在 网易云信智能体管理平台 中绑定的设备标识符,用于唯一标识您的硬件设备。

请求头

WebSocket 建连请求头字段说明如下:

httpapp-key: {app_key}
token: {token}
yunxin-license: {license}
请求头 是否必填 说明
app-key 网易云信应用的 App Key。device_id 归属于对应的 App Key 下,服务端通过 App Key 确定应用归属。
token 基于 App Secret 生成的动态 Token。传入时,需与 app-key 配合使用。
yunxin-license 授权码请求头。用于兼容既有授权码传入方式;传入时,服务端会结合授权码信息进行校验。

设备授权

设备授权通过为设备绑定授权码(license)实现。设备完成绑定与授权配置后,device_id 会作为设备授权校验和智能体配置查询的依据;设备端建连时传入 device_id 后,服务端会校验对应的绑定关系和授权状态。

授权步骤如下:

  1. 生成全局唯一的 device_id
  2. 在智能体管理平台绑定 device_id、用户身份和智能体。
  3. 在智能体管理平台完成设备激活和授权配置,使 device_id 与授权信息建立关联。
  4. 设备端接入 WebSocket 请求地址 时,在 URI 中传入 device_id。如需兼容既有授权码传入方式,也可以在请求头中传入 yunxin-license
  5. 服务端根据 device_id 校验设备绑定关系和授权状态,并获取对应的智能体配置;如请求头中传入 yunxin-license,服务端会结合授权码信息进行校验。

身份鉴权

WebSocket 接入以 device_id 作为设备授权和智能体配置查询的主要依据,app-key 为必填项,token 为可选项。

出于安全考虑,您可以在请求头中传入 token,开启应用级身份校验。传入后,云信服务会校验 Token 的时效性和签名合法性;校验失败时,本次连接将被拒绝。

token 由服务端根据 App Secret 生成。App Secret 不应下发到设备端,也不应写入设备固件或客户端代码。设备端应从可信服务端获取短期有效的动态 Token。

应用级身份校验流程如下:

  1. 网易云信控制台 申请 appkey,获取鉴权密钥 appsecret
  2. 服务端安全保存 App Secret,并按 Token 生成算法生成动态 Token。
  3. 设备端向服务端获取动态 Token。
  4. 设备端建立 WebSocket 连接,并在请求头中传入 app-keytoken
  5. 云信服务校验 Token 的时效性和签名合法性。

协议规范

本章节介绍 WebSocket 连接的通信协议规范,包括会话初始化、音频流传输、交互控制等。

会话初始化

客户端建立 WebSocket 连接后,需要先发送 start 信令初始化会话。服务端完成鉴权、设备配置查询和任务创建后,返回 server_ready

发送开始信令

客户端向服务端发送:

JSON{
  "action": "start",
  "data": {
    "input_audio": {
      "format": "pcm",
      "sample_rate": 16000,
      "channels": 1,
      "encoding": "raw"
    },
    "output_audio": {
      "format": "pcm",
      "sample_rate": 24000,
      "channels": 1,
      "frame_duration": 20,
      "redundant_duration": 800,
      "encoding": "raw"
    },
    "manual_mode": false,
    "alive_timeout": 0,
    "pre_context": [
      {
        "role": "user",
        "content": "你好"
      },
      {
        "role": "assistant",
        "content": "你好,我在。"
      }
    ],
    "cunstom_params": {
      "prompt_keywords": {
        "scene": "indoor"
      },
      "tts_config": {
        "vendor": 0,
        "voice": "default",
        "speed": 1,
        "volume": 1,
        "pitch": 0,
        "ignore_bracket_text_set": [1, 2]
      }
    },
    "features": {
      "mcp": true
    }
  }
}

data 参数说明

参数 类型 是否必需 示例值 说明
- input_audio Object {"format":"pcm","sample_rate":16000} 上行音频格式。未传时使用默认配置。
format String "pcm" 音频格式,支持 pcmopusg711
sample_rate Integer 16000 采样率(Hz)。g711 仅支持 8000 Hz。
channels Integer 1 声道数。g711 仅支持单声道。
encoding String "raw" 编码方式。当前支持 raw
- output_audio Object {"format":"pcm","sample_rate":24000} 下行音频格式。未传时使用默认配置。
format String "pcm" 音频格式,支持 pcmopusg711
sample_rate Integer 24000 采样率(Hz)。g711 仅支持 8000 Hz。
channels Integer 1 声道数。g711 仅支持单声道。
frame_duration Integer 20 下行音频帧长(毫秒)。决定服务端下行音频编码帧长。
redundant_duration Integer 800 每轮开始预发送音频时长(毫秒)。
encoding String "raw" 编码方式。当前支持 raw
manual_mode Boolean false 是否启用按键输入音频模式。启用后仅处理 listen_startlisten_stop 之间上传的音频。
alive_timeout Integer 60 连接业务保活超时时长(秒)。0 表示不启用。
- pre_context Array [{"role":"user","content":"你好"}] 会话级预置上下文,按顺序传入,最多 40 项。每项需包含 rolecontent
role String "user" 角色,支持 userassistant
content String "你好" 对话内容。
- cunstom_params Object {"prompt_keywords":"科技","tts_config":{...}} 自定义参数。
prompt_keywords String "科技" 会话级环境变量。仅对智能体后台已配置的变量生效。
- tts_config Object {"vendor":1,"voice":"xiaoyan"} 会话级 TTS 覆盖配置。
vendor Integer 1 平台配置,TTS 供应商。传入非 0 值时覆盖平台配置。
voice String "xiaoyan" 平台配置,TTS 音色。
speed Number 1.0 语速。
volume Number 50 音量。
pitch Integer 0 语调。
ignore_bracket_text_set Array [1, 2] 过滤模型回复中指定括号内的文本后再进行 TTS。取值(可组合):1(中文括号 ())、2(英文括号 ())、3(中文方括号 【】)、4(英文方括号 [])、5(英文花括号 {})。未列出的扩展取值以平台配置为准。
- features Object {"mcp": false} 功能开关。
mcp Boolean false 是否启用端侧 MCP 能力。

服务端准备完成

服务端向客户端返回:

JSON{
  "action": "server_ready",
  "data": {
    "code": 0,
    "msg": "ok",
    "connection_id": "c70cde776a074170bb5d270cfd8691f"
  }
}
参数 类型 说明
code Integer 状态码,0 表示成功,非 0 表示失败。
msg String 状态描述。
connection_id String 当前 WebSocket 会话的连接标识。

如初始化失败,服务端返回 error 信令,详见 错误响应

音频流传输

WebSocket 连接的音频流传输遵循以下规范:

上传音频流

客户端在会话初始化成功后,通过 Binary Frame 持续发送音频数据。音频格式必须与 start.data.input_audio 中声明的格式一致。

接收音频流

服务端通过 Binary Frame 下发合成后的语音数据。音频格式与 start.data.output_audio 中声明的格式一致。

下行音频说明

服务端按照 start 信令中协商的 output_audio 参数进行下行音频编码,并通过 WebSocket Binary Frame 下发音频数据。每个 Binary Frame 对应一帧编码后的音频数据,客户端应以 WebSocket 消息边界作为音频包边界进行处理。

output_audio.frame_duration 用于指定下行音频帧长,单位为毫秒。若未指定,服务端默认按照 20 ms 帧长进行下行音频编码,即每个 Binary Frame 对应约 20 ms 的音频数据。

当下行音频格式为 Opus 时,服务端下发的是裸 Opus packet,不包含额外容器封装。

交互控制

WebSocket 连接的交互控制遵循以下规范。

收音模式

WebSocket 接入支持自动收音和按键收音两种模式,由 start.data.manual_mode 控制。

模式 manual_mode 说明
自动收音 false 默认模式。客户端可持续上传音频,服务端根据语音活动检测自动判断用户开始和结束说话。
按键收音 true 客户端通过 listen_startlisten_stop 明确标记本轮用户输入的开始和结束。服务端只处理开始与结束信令之间上传的音频。

按键收音模式下,一个完整轮次的推荐时序如下:

  1. 用户按下按键或开始录音时,客户端发送 listen_start
  2. 客户端通过 Binary Frame 上传本轮音频数据。
  3. 用户松开按键或结束录音时,客户端先发送完本轮剩余音频数据,再发送 listen_stop
  4. 服务端根据已收到的音频生成识别结果,并继续后续模型回复流程。

listen_stop 只表示本轮用户输入结束,不会关闭 WebSocket 连接。如需结束整个会话,请发送 stop 信令或关闭 WebSocket 连接。

按键输入音频开始

manual_modetrue 时,客户端应在本轮音频上传前发送:

JSON{
  "action": "listen_start",
  "data": {
    "id": "event_001"
  }
}

按键输入音频结束

manual_modetrue 时,客户端应在本轮音频上传完成后发送:

JSON{
  "action": "listen_stop",
  "data": {
    "id": "event_002"
  }
}

手动打断

客户端可通过 manual_interrupt 打断当前交互:

JSON{
  "action": "manual_interrupt",
  "data": {
    "id": "event_003"
  }
}

手动提交对话内容

客户端可通过 manual_message 提交文本、图片或需要播报的助手消息:

JSON{
  "action": "manual_message",
  "data": {
    "id": "event_004",
    "role": "user",
    "text": "请描述这张图片",
    "img_url": "{image_url}",
    "img_fragment": 1,
    "img_fragment_seq": 1,
    "add_context": true,
    "interrupt_mode": 1
  }
}
参数 类型 是否必填 说明
id String 客户端生成的事件 ID,用于问题定位。
role String 消息角色,支持 user(作为用户输入进入对话,可触发模型回复) 和 assistant(将文本作为助手消息进行语音播报,并可按 add_context 控制是否加入上下文),默认 user
text String 文本内容。role=user 时,文本和图片至少传入一项。

img_url

String

图片地址,支持 HTTPS URL 或 Base64 Data URL。

  • 网络图片https://yunxin.com/nos/test.jpeg
  • 本地图片data:image/{format};base64,{base64_image},例如 data:image/jpeg;base64,{base64_image}
img_fragment Integer 图片分片总数,默认 1
img_fragment_seq Integer 当前图片分片序号,从 1 开始,默认 1。当本地图片数据较大时,可通过 img_fragmentimg_fragment_seq 分片上传。
add_context Boolean role=assistant 时,是否将文本加入对话上下文,默认 true

interrupt_mode

Integer

外部输入处理优先级。

  • 1:高优先级,立即打断当前交互进行处理。
  • 2:中优先级,等待当前交互结束后处理。
  • 3:低优先级,如正在交互则直接丢弃。

业务保活

start.data.alive_timeout 设置为非 0,客户端应周期性发送 ping 信令:

JSON{
  "action": "ping",
  "data": {}
}

服务端返回:

JSON{
  "action": "pong"
}

建议客户端发送周期小于 alive_timeout。例如 alive_timeout 为 30 秒时,可每 3 到 10 秒发送一次 ping

主动关闭

客户端可通过 stop 主动结束会话:

JSON{
  "action": "stop",
  "data": {}
}

服务端收到后会释放会话资源并关闭 WebSocket 连接。

Function Call

WebSocket 连接的 Function Call 用于同步端侧设备状态、下发工具调用以及透传端侧 MCP 消息。

工具配置

网易云信智能体管理平台 配置 tools 时,建议添加 response_success 参数用于操作反馈:

JSON{
  "parameters": {
    "type": "object",
    "properties": {
      "response_success": {
        "description": "操作成功时的友好回复,关于该设备的操作结果,设备名称尽量使用 description 中的名称",
        "type": "string"
      }
    },
    "required": ["response_success"]
  }
}

设备状态同步

客户端可通过 iot_status 同步端侧设备状态:

JSON{
  "action": "iot_status",
  "data": {
    "iot_status": [
      {
        "name": "SetVolume",
        "status": {
          "volume": 50
        }
      }
    ]
  }
}
参数 类型 说明
- iot_status Array 设备状态列表。
iot_status[].name String 对应智能体工具配置中的函数名。
iot_status[].status Object 设备状态参数。

端侧 MCP 信令上行

如会话启用了 features.mcp,客户端可通过 mcp 信令上报端侧 MCP 消息:

JSON{
  "action": "mcp",
  "data": {
    "jsonrpc": "2.0",
    "id": "mcp_001",
    "result": {}
  }
}

data 为端侧 MCP 协议的 payload。服务端会将该 payload 透传给智能体侧处理。

如工具由端侧 MCP 执行,工具执行结果也通过 mcp 信令回传。tool_calls 中的工具调用 ID 可放入 MCP payload 中,便于服务端关联当前工具调用。

工具调用

服务端通过 tool_calls 下发工具调用请求:

JSON{
  "action": "tool_calls",
  "data": {
    "request": "将音量设置为 80%",
    "tool_calls": [
      {
        "id": "call_001",
        "type": "function",
        "function": {
          "name": "SetVolume",
          "arguments": "{\"volume\": 80}"
        }
      }
    ]
  }
}
参数 类型 说明
request String 触发工具调用的用户请求文本。
- tool_calls Array 工具调用列表。
id String 工具调用 ID。
type String 工具类型,当前为 function
- function Object 函数信息。
name String 函数名。
arguments String 函数参数,JSON 字符串格式。

客户端执行工具后,如结果需要回传服务端,应通过端侧 MCP 信令上报。

事件通知

WebSocket 连接的服务端事件通知遵循以下规范。

语音转文本结果

JSON{
  "action": "asr_text",
  "data": {
    "type": 0,
    "content": "今天天气怎么样"
  }
}
参数 类型 说明
type Integer 结果类型,0 表示最终结果,1 表示中间结果。
content String 识别文本。

大模型回复文本

JSON{
  "action": "llm_text",
  "data": {
    "type": 0,
    "content": "今天适合外出,请注意查看当地天气预报。"
  }
}
参数 类型 说明
type Integer 结果类型,0 表示最终结果,1 表示中间结果。
content String 模型回复文本。

文本转语音状态

TTS 开始:

JSON{
  "action": "tts_start",
  "data": {}
}

TTS 结束:

JSON{
  "action": "tts_stop",
  "data": {}
}

情绪状态

JSON{
  "action": "llm_emotion",
  "data": {
    "emotion": "happy"
  }
}
参数 类型 说明
emotion String 情绪标识。具体取值以智能体配置和模型输出为准。

控制信令

服务端通过 on_ai_data 下发内容、MCP 或智能体事件:

JSON{
  "action": "on_ai_data",
  "data": {
    "externData": {
      "type": "content",
      "data": {
        "timestamp": 1754654765,
        "request": "展示图片",
        "content": {
          "type": "photoTag",
          "message": "happy"
        }
      }
    }
  }
}

externData.type 支持以下取值:

取值 说明
content 内容下发。内容字段位于 externData.data.content
mcp MCP 信令下发。MCP payload 位于 externData.data.mcpPayload
agentEvent 智能体平台事件。事件 payload 位于 externData.data.agentEventPayload

MCP 下发示例:

JSON{
  "action": "on_ai_data",
  "data": {
    "externData": {
      "type": "mcp",
      "data": {
        "timestamp": 1754654765,
        "mcpPayload": {
          "jsonrpc": "2.0",
          "method": "tools/call",
          "params": {}
        }
      }
    }
  }
}

智能体事件示例:

JSON{
  "action": "on_ai_data",
  "data": {
    "externData": {
      "type": "agentEvent",
      "data": {
        "timestamp": 1754654765,
        "agentEventPayload": {}
      }
    }
  }
}

错误响应

JSON{
  "action": "error",
  "data": {
    "code": 400,
    "msg": "param error",
    "connection_id": "c70cde776a074170bb5d270cfd8691f"
  }
}
参数 类型 说明
code Integer 错误码。
msg String 错误描述。
connection_id String 连接标识。

生成 Token

如需启用应用级身份校验,可参考本节生成 Token,用于 WebSocket 连接 Token 验证。

算法实现

Token 内容为 Base64 编码后的 JSON 字符串,JSON 中包含:

字段 类型 说明
signature String 签名结果。
curTime Long 当前时间戳,单位毫秒。
ttl Integer Token 有效期,单位秒。

签名计算方式:

textsignature = SHA1(curTime + ttl + appSecret)

以下示例代码中,使用 Java 语言实现 Token 生成算法:

javapublic class TokenGenerator {
    private final String appSecret;

    public TokenGenerator(String appSecret) {
        this.appSecret = appSecret;
    }

    public String getToken(int ttlSec) throws Exception {
        long curTimeMs = System.currentTimeMillis();
        return getTokenWithCurrentTime(ttlSec, curTimeMs);
    }

    public String getTokenWithCurrentTime(int ttlSec, long curTimeMs) throws Exception {
        DynamicToken tokenModel = new DynamicToken();
        tokenModel.signature = sha1(String.format("%d%d%s", curTimeMs, ttlSec, appSecret));
        tokenModel.curTime = curTimeMs;
        tokenModel.ttl = ttlSec;

        ObjectMapper objectMapper = new ObjectMapper();
        String tokenJson = objectMapper.writeValueAsString(tokenModel);
        return Base64.getEncoder().encodeToString(tokenJson.getBytes(StandardCharsets.UTF_8));
    }

    private String sha1(String input) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-1");
        byte[] result = digest.digest(input.getBytes(StandardCharsets.UTF_8));
        StringBuilder builder = new StringBuilder();
        for (byte item : result) {
            builder.append(String.format("%02x", item));
        }
        return builder.toString();
    }

    public static class DynamicToken {
        public String signature;
        public long curTime;
        public int ttl;
    }
}

验证 Token

网易云信服务器接收到 Token 后会进行以下校验:

  1. 时效性校验:当前时间不得超过 curTime + ttl
  2. 签名校验:使用 curTimettl 和服务端保存的 App Secret 重新计算签名,并与 Token 中的 signature 比对。

任一校验失败,连接鉴权失败。

下一步

  • 了解如何在设备端优化音频处理以提高识别准确率。
  • 探索如何结合 Function Call 机制实现设备控制功能。
此文档是否对你有帮助?
有帮助
去反馈
  • 前提条件
  • 技术原理
  • 接入方式
  • 请求地址
  • 请求头
  • 设备授权
  • 身份鉴权
  • 协议规范
  • 会话初始化
  • 音频流传输
  • 交互控制
  • Function Call
  • 事件通知
  • 语音转文本结果
  • 大模型回复文本
  • 文本转语音状态
  • 情绪状态
  • 控制信令
  • 错误响应
  • 生成 Token
  • 算法实现
  • 验证 Token
  • 下一步