助手
扣子 AI 帮助与支持
你好,我是 扣子 文档问答助手 🎉 你在阅读当前文档的过程中,无论对文档概念的解释,还是文档内容方面的疑问,都可以随时向我提问,我会全力为你解答
推荐问题
如何快速了解这个空间的核心内容?
有哪些近期更新的重点文档?
我应该从哪些文档开始阅读?
文档反馈
低代码项目
快速开始
智能体
工作流
应用
资源
发布
模型
多人协作
推广与变现

集成 WebSocket 实时语音 Web SDK

更新于: 2026-06-25 19:29:14

WebSocket 实时语音 Web SDK (简称 WsChat SDK) 基于双向流式语音对话 WebSocket OpenAPI 封装 ,为开发者提供开箱即用的语音交互解决方案,详细的接口信息请参见双向流式语音对话

体验 Demo

扣子提供实时语音 Demo 和 TypeScript 格式的 实时语音 WebSocket 示例源码,帮助你快速体验实时语音的功能,并根据示例源码快速实现实时语音。

Demo 功能简介

Demo 的主要功能包括:

  • 实时语音识别:将用户语音即时转换为文本。
  • 配置管理:支持设置降噪模式、音频配置。
  • 设备管理:支持设置不同的音频输入设备。
  • 交互控制:支持打断对话、静音、发送文本、发送事件等。
  • 会话管理:支持建立和断开语音连接、设置静音等。

Image

使用 Demo

  1. 配置参数。
    单击右上角的 Settings,配置个人访问令牌和智能体 ID 等参数,具体如下表所示。

    配置

    说明

    Base WS URL

    保持默认值 wss://ws.coze.cn

    个人访问令牌

    扣子 API & SDK 通过访问令牌进行 API & SDK 请求的鉴权。
    个人访问令牌的获取方式可参考添加个人访问令牌

    说明

    • 应为令牌授予 chat、createVoice 和 listVoice 的权限。
    • 令牌授予的访问工作空间中包含了待与其通话的智能体,否则会提示鉴权失败。

    智能体 ID

    配置希望与其实时语音聊天的智能体 ID。
    进入智能体的开发页面,开发页面 URL 中 bot 参数后的数字就是智能体ID。例如https://www.coze.cn/space/341****/bot/73428668*****,智能体ID 为73428668*****

    说明

    • 确保个人访问令牌开通了此智能体所在空间的权限。
    • 确保该智能体已发布为 API 服务。

    音色 ID

    设置智能体使用的音色。扣子提供一系列系统音色,你可以在系统音色列表查看音色 ID。

    工作流 ID

    如果你需要自定义传参,你可以在对话流的开始节点设置自定义参数,然后在本参数中指定相应的对话流 ID。
    获取对话流 ID 的方法:通过进入 Workflow 编排页面,在页面 URL 中,workflow 参数后的数字就是对话流 ID。例如 https://www.coze.com/work_flow?space_id=42463***&workflow_id=73505836754923***,对话流 ID 为 73505836754923***

  2. 单击开始对话,向指定智能体发起实时语音通话。

    说明

    实时语音通话需要获取设备的麦克风权限,如果页面提示 [DEVICE_ACCESS_ERROR] Failed to get audio devices,表示浏览器禁用了麦克风设备。

实现流程

步骤一: 安装依赖

运行以下命令安装 WsChat SDK 及其依赖项。

npm install @coze/api

步骤二:检查设备权限

在使用语音功能前,先检查并获取麦克风访问权限。调用WsToolsUtils.checkDevicePermission() 方法,检查浏览器是否已授予麦克风权限。
在 HTTPS 或 localhost 中执行该方法。首次调用时,浏览器会向用户显示权限请求对话框,如果用户拒绝麦克风权限,在应用中提供明确指引,告知用户如何在浏览器设置中启用权限。在 iOS Safari 浏览器中,必须由用户交互操作(如点击按钮)触发权限请求。

import { WsToolsUtils } from "@coze/api/ws-tools";

const result = await WsToolsUtils.checkDevicePermission();
if (!result.audio) {
   throw new Error("需要麦克风访问权限");
}

步骤三:初始化客户端

调用 new WsChatClient 方法创建 WsChatClient 实例,配置 token 和 botId。

import { WsChatClient } from "@coze/api/ws-tools";

const client = new WsChatClient({
    token: 'pat_Qm47PKJR5dvMOP53v6DyzwCbTtvEZHQc2TVINEveg9v1T3iSYlTdScJ8***',
    botId: 'your bot id',
    allowPersonalAccessTokenInBrowser: true,  // 可选:允许在浏览器中使用个人访问令牌
});

参数说明:

  • token:访问密钥,用于身份认证与鉴权。体验或调试场景可以生成短期的个人访问令牌(PAT),以快速完成 WsChat SDK 的整体流程。个人访问令牌的获取方法请参见添加个人访问令牌。在线上环境中,应使用服务访问令牌(SAT)或 OAuth 鉴权方案,详细说明请参见鉴权方式概述

    说明

    扣子 SDK 封装了多种鉴权方式,能够有效简化鉴权流程,你可以参考鉴权示例代码实现不同方式的 OAuth 认证,以获取和管理访问扣子 API 所需的令牌

  • botId:配置希望与其实时语音聊天的智能体 ID。进入智能体的开发页面,开发页面 URL 中 bot 参数后的数字就是智能体ID。例如https://www.coze.cn/space/341****/bot/73428668*****,智能体ID 为73428668*****

步骤四:监听事件

在初始化客户端后,通过 client.on 方法注册各种事件监听器。详细的事件说明请参见双向流式对话上行事件

import { WsChatEventNames } from "@coze/api/ws-tools";

// 监听所有事件
client.on(WsChatEventNames.ALL, (eventName, data) => {
    console.log(eventName, data);
});

支持的事件类型如下,若想了解所有事件的详细情况,可以直接查看示例项目源码中的 types.ts

// 事件监听示例
client.on(WsChatEventNames.ALL, (event) => {
  console.log(`收到事件:`, event);
});

// 支持的事件类型
enum WsChatEventNames {
  // 客户端基础事件
  ALL = 'realtime.event',                    // 所有事件
  CONNECTED = 'client.connected',            // 客户端已连接
  CONNECTING = 'client.connecting',          // 客户端连接中
  INTERRUPTED = 'client.interrupted',        // 客户端已中断
  DISCONNECTED = 'client.disconnected',      // 客户端已断开
  ERROR = 'client.error',                    // 客户端发生错误

  // 音频控制事件
  AUDIO_UNMUTED = 'client.audio.unmuted',    // 音频已取消静音
  AUDIO_MUTED = 'client.audio.muted',        // 音频已静音
  AUDIO_INPUT_DUMP = 'client.audio.input.dump', // 音频输入数据导出
  
  // 设备变更事件
  AUDIO_INPUT_DEVICE_CHANGED = 'client.input.device.changed',   // 音频输入设备已改变
  AUDIO_OUTPUT_DEVICE_CHANGED = 'client.output.device.changed', // 音频输出设备已改变

  // 降噪控制事件
  DENOISER_ENABLED = 'client.denoiser.enabled',   // 降噪已启用
  DENOISER_DISABLED = 'client.denoiser.disabled', // 降噪已禁用

  // 服务端对话事件
  CHAT_CREATED = 'server.chat.created',      // 对话已创建
  CHAT_UPDATED = 'server.chat.updated',      // 对话已更新
  
  // 会话状态事件
  CONVERSATION_CHAT_CREATED = 'server.conversation.chat.created',           // 会话对话已创建
  CONVERSATION_CHAT_IN_PROGRESS = 'server.conversation.chat.in.progress',   // 对话进行中
  CONVERSATION_CHAT_COMPLETED = 'server.conversation.chat.completed',       // 对话已完成
  CONVERSATION_CHAT_FAILED = 'server.conversation.chat.failed',            // 对话失败
  CONVERSATION_CHAT_CANCELLED = 'server.conversation.chat.cancelled',      // 对话已取消
  CONVERSATION_CHAT_REQUIRES_ACTION = 'server.conversation.chat.requires_action', // 对话需要端插件响应
  
  // 消息事件
  CONVERSATION_MESSAGE_DELTA = 'server.conversation.message.delta',         // 文本消息增量返回
  CONVERSATION_MESSAGE_COMPLETED = 'server.conversation.message.completed', // 文本消息完成
  
  // 音频事件
  CONVERSATION_AUDIO_DELTA = 'server.conversation.audio.delta',           // 语音消息增量返回
  CONVERSATION_AUDIO_COMPLETED = 'server.conversation.audio.completed',   // 语音回复完成
  
  // 语音识别事件
  CONVERSATION_AUDIO_TRANSCRIPT_UPDATE = 'server.conversation.audio_transcript.update',     // 用户语音识别实时字幕更新
  CONVERSATION_AUDIO_TRANSCRIPT_COMPLETED = 'server.conversation.audio_transcript.completed', // 用户语音识别完成
  
  // 语音检测事件
  INPUT_AUDIO_BUFFER_SPEECH_STARTED = 'server.input_audio_buffer.speech_started', // 检测到用户开始说话
  INPUT_AUDIO_BUFFER_SPEECH_STOPPED = 'server.input_audio_buffer.speech_stopped', // 检测到用户停止说话
  
  // 缓冲区事件
  INPUT_AUDIO_BUFFER_COMPLETED = 'server.input_audio_buffer.completed',   // 语音输入缓冲区提交完成
  INPUT_AUDIO_BUFFER_CLEARED = 'server.input_audio_buffer.cleared',      // 语音输入缓冲区已清除
  
  // 其他事件
  SERVER_ERROR = 'server.error',              // 服务端错误
  CONVERSATION_CLEARED = 'server.conversation.cleared', // 对话上下文已清除
  DUMP_AUDIO = 'server.dump.audio'            // 音频导出
}

步骤五:建立连接

在开始对话前,调用 client.connect 方法建立客户端和服务端之间的连接。


try {
  await client.connect();
} catch (error) {
  console.log('连接失败', error);
}

说明

  • 连接过程可能因网络问题、权限问题或配置错误而失败,确保妥善处理异常。
  • 连接成功后,麦克风会自动开始录音。若 audioMutedDefault 设置为 true,则会静音。

步骤六:对话控制

在对话过程中支持静音或取消静音、打断对话、发送文本消息。

  • 静音/取消静音
    调用setAudioEnable() 方法静音或取消静音。该方法是一个异步方法,使用await 等待操作完成。在静音状态下,麦克风仍在工作,但不会发送音频数据。

    // 静音与取消静音
    await client.setAudioEnable(false); // 静音
    await client.setAudioEnable(true);  // 取消静音
    
  • 打断对话
    调用 interrupt() 方法打断当前对话,使智能体停止回复。

    // 打断对话
    client.interrupt();
    
  • 发送文本消息
    使用 sendTextMessage() 可以发送文本消息,而不是语音输入。

    // 发送文本消息
    client.sendTextMessage("你好,我想了解一下天气情况");
    

步骤七:断开连接

调用 disconnect() 方法关闭连接并释放资源。如果需要重新开始对话,重新调用 connect() 方法建立连接。

// 断开连接
await client.disconnect();

完整示例代码

完整的示例代码如下。你也可以参考实时语音 WebSocket 示例源码获取更多示例代码。

import {
  WsChatEventNames,
  WsChatClient,
  WsToolsUtils,
} from '@coze/api/ws-tools';

// 初始化 client & 注册事件
const initClient = async () => {
  // 检查语音设备权限
  const result = await WsToolsUtils.checkDevicePermission();
  if (!result.audio) {
    throw new Error("需要麦克风访问权限");
  }
  // 初始化 client
  const client = new WsChatClient({
    token: "pat_Qm47PKJR5dvMOP53v6DyzwCbTtvEZHQc2TVINEveg9v1T3iSYlTdScJ8***",
    botId: "your bot id",
    allowPersonalAccessTokenInBrowser: true, // 可选:允许在浏览器中使用个人访问令牌
  });
  
  // 注册事件,一般在初始化 client 后设置
  client.on(WsChatEventNames.ALL, (eventName, data) => {
    console.log(eventName, data);
  });

  return client;
};

const handleConnect = async () => {
  try {
    const client = await initClient();
    // 连接
    await client.connect();
  } catch (error) {
    console.log("连接失败", error);
  }
};

进阶功能

客户端配置

在初始化客户端时,你还可以进行高级配置,以满足不同的开发需求,包括:开启调试模式、指定智能体的音色、指定音频输入设备、音频处理及录制、AI 降噪、音频录制等。完整的配置项请查看示例项目源码中的 types.ts

interface WsChatClientOptions {
  // 必填项
  token: GetToken; // Personal Access Token (PAT) 或 OAuth2.0 token,或获取 token 的函数
  botId: string; // 智能体 ID
  
  // 选填项
  debug?: boolean; // 是否启用调试模式
  headers?: Headers | Record<string, unknown>; // 自定义请求头
  allowPersonalAccessTokenInBrowser?: boolean; // 是否允许在浏览器环境中使用个人访问令牌
  baseWsURL?: string; // WebSocket 基础 URL,默认为 wss://ws.coze.cn
  websocketOptions?: WebsocketOptions; // WebSocket 配置选项
  
  workflowId?: string; // 工作流 ID
  voiceId?: string; // 音色 ID
  deviceId?: string; // 音频输入设备 ID
  
  // 音频相关配置
  audioCaptureConfig?: {
    noiseSuppression?: boolean; // 是否启用降噪
    echoCancellation?: boolean; // 是否启用回声消除
    autoGainControl?: boolean; // 是否启用自动增益控制
  };
  audioMutedDefault?: boolean; // 是否默认静音

  // AI 降噪配置
  aiDenoisingConfig?: {
    mode?: AIDenoiserProcessorMode; // AI 降噪模式:NSNG(非平稳噪声抑制) 或 STATIONARY_NS(平稳噪声抑制)
    level?: AIDenoiserProcessorLevel; // 降噪级别
    assetsPath?: string; // AI 降噪 wasm 文件路径,默认为 '/external'
  };

  // 自定义音频流
  mediaStreamTrack?: MediaStreamTrack;

  // 音频录制配置(仅在 debug = true 时生效)
  wavRecordConfig?: {
    enableSourceRecord: boolean; // 是否启用源音频录制
    enableDenoiseRecord: boolean; // 是否启用降噪后音频录制
  };
}

音视频控制

在通话过程中,支持开启或关闭麦克风、设置输入音频设备。

  • 开启或关闭麦克风

    // 开启/关闭麦克风
    await client.setAudioEnable(true);  // 开启麦克风
    await client.setAudioEnable(false); // 关闭麦克风
    
  • 设置输入音频设备
    你可以通过 WsToolsUtils.getAudioDevices 方法获取系统的音频输入和输出设备列表,返回的设备列表包含每个设备的 deviceId 和 label 信息。

    import { WsToolsUtils } from "@coze/realtime-api";
    
    const devices = await WsToolsUtils.getAudioDevices();  // 获取输入、输出设备列表
    client.setAudioInputDevice(devices.audioInputs[0].deviceId); // 设置音频输入设备
    

    说明

    • 获取设备列表需要用户已授予麦克风权限。
    • 在用户插入或移除设备后,应重新获取设备列表。
    • 切换设备是异步操作,需要使用 await 等待完成。
    • 如果指定的设备不可用,用户操作时将抛出异常。

开启或关闭调试模式

在调试模式下可以使用音频 dump 功能,以验证降噪效果。

  1. 在创建 WsChatClient 时,将 debug 设置为 true,开启调试模式,并配置音频录制。

    const client = new WsChatClient({
      // ... 其他配置
      debug: true, // 必须设置为 true,否则录制配置不生效
      wavRecordConfig: {
        enableSourceRecord: true,    // 启用原始音频录制
        enableDenoiseRecord: true,   // 启用降噪后的音频录制
      }
    });
    
  2. 监听音频 dump 事件来获取录制的音频数据。

    // 监听音频输入 dump 事件
    client.on(WsChatEventNames.AUDIO_INPUT_DUMP, (eventName, event) => {
      // event.data 包含:
      // - name: string 文件名
      // - wav: Blob 音频数据(WAV格式)
      const { name, wav } = event.data;
      console.log(`收到音频dump,文件名: ${name}`);
      
      // 可以将 wav 数据保存为文件
      const url = URL.createObjectURL(wav);
      const a = document.createElement('a');
      a.href = url;
      a.download = name;
      a.click();
    });
    

    说明

    dump 功能会产生两种音频文件:

    • 原始音频文件:包含用户的原始输入音频。只有当 enableSourceRecord = true 时才会生成原始音频文件。
    • 降噪后音频文件:包含经过降噪处理后的音频。只有当 enableDenoiseRecord = true 时才会生成降噪后音频文件。

AI 降噪

说明

  • 降噪处理可能增加 CPU 使用率,在低性能设备上可能影响体验。
  • 不同的降噪等级会影响音频质量和降噪效果。
  1. 检查浏览器是否支持 AI 降噪。
    某些浏览器或设备可能不支持全部降噪功能,当不确定设备支持情况时,可以使用 WsToolsUtils.checkDenoiserSupport() 方法检查。

    const denoiserSupport = await WsToolsUtils.checkDenoiserSupport();
    if (!denoiserSupport) {
      console.warn("当前浏览器不支持 AI 降噪");
    }
    
  2. 在初始化时配置 AI 降噪。

    const client = new WsChatClient({
      // 其它配置
      aiDenoisingConfig: {
        mode: 'NSNG',           // AI 降噪模式,包括NSNG(非平稳噪声抑制) 或 STATIONARY_NS(平稳噪声抑制)
        level: 'SOFT',        //  降噪等级,包括SOFT(舒缓降噪), AGGRESSIVE(激进降噪。将降噪强度提高到激进降噪会增大损伤人声的概率。)
      }
    });
    
  3. 开启或关闭 AI 降噪,设置 AI 降噪的等级和模式。

    // 设置降噪开关
    client.setDenoiserEnabled(true);
    
    // 设置降噪等级
    client.setDenoiserLevel("SOFT"); // 可选值: SOFT(舒缓降噪), AGGRESSIVE(激进降噪。将降噪强度提高到激进降噪会增大损伤人声的概率。)
    
    // 设置降噪模式
    client.setDenoiserMode("NSNG"); // NSNG(非平稳噪声抑制) 或 STATIONARY_NS(平稳噪声抑制)
    

配置音色

在初始化 WsChat SDK 时,你可以通过指定 voiceId 来自定义智能体在对话中使用的音色。以下是使用说明:

  1. 获取可用的音色 ID。
    你可以通过查看音色列表 获取可用的音色列表。

    import { CozeAPI, COZE_CN_BASE_URL } from '@coze/api';
    const api = new CozeAPI({
        token: 'your-access-token',
        baseURL: COZE_CN_BASE_URL,
    });
    // 获取可用的音色列表
    const voices = await api.audio.voices.list();
    
  2. 在初始化 WsChat 客户端时,指定智能体使用的音色。
    每个音色都有不同的特征,如性别、语言、风格等,如果不指定 voiceId 或值为空,将使用默认的柔美女友音色,音色 ID 为 7426720361733046281。

    import { WsChatClient } from "@coze/api/ws-tools";
     
    const client = new WsChatClient({
      // 其它配置
      voiceId: "7426720361733046281",
    });
    

WebSocket 事件

基本概念

  • 上行事件:设备端向服务端发送的请求,如提交插件执行结果、更新对话配置等。
  • 下行事件:服务端向设备端发送的通知,如端插件请求、对话状态变化等。
  • 会话与对话:会话是用户与智能体的一次完整交互,对话是会话中的一次具体调用。
  • 事件 ID:每个事件应有唯一 ID,便于问题定位。

事件的使用流程

信令事件的使用流程如下:

  1. 初始化。通过监听 chat.created 事件,确认对话初始化完成。
  2. 发送请求。使用上行事件(如 conversation.message.create)向智能体发送消息。
  3. 处理响应。监听下行事件(如 conversation.message.delta)获取智能体的增量回复。
  4. 插件交互。在收到事件 conversation.chat.requires_action 后,执行插件操作并通过事件 conversation.chat.submit_tool_outputs 提交结果。根据需求选择 blocking 或 nonblocking 模式,控制插件执行是否阻塞对话。
  5. 错误处理。通过监听 error 事件捕获和处理异常情况。

使用示例如下:

import { WebsocketsEventType, RoleType } from '@coze/api';
// 使用示例
client.sendMessage({
  "id": "1",
  "event_type": WebsocketsEventType.CONVERSATION_MESSAGE_CREATE,
  "data": {
    "role": RoleType.User,
    "content_type": "text",
    "content": "你好"
  }
});