每一句台词都是 AI 现编的:我用一个 WebSocket 接住了 Vidu S1 实时数字人

体验台

资源 地址 说明
官方文档 https://platform\\.vidu\\.cn/docs/vidu\\-s1 ViduS1官方文档,更详细的接入教程
Agent Skills https://github\\.com/shengshu\\-ai/vidu\\-s1\\-api/tree/main/skills/vidu\\-s1\\-api 开发者可快速体验
邀请码【8O2QQNQE1O】 platform.vidu.cn/account-ove... 赠送积分立刻体验20分钟与S1数字人的互动

3 秒决策区

  • 这是什么:Vidu S1 实时交互式数字人,单张图直出形象,实时对话,官方称支持 1 分钟到 2 小时的连续互动无质量损失。

  • 和别的数字人有什么不同 :它不是"播放预录视频",而是双向流式------你说话它能听见并打断自己的输出,它说话你能随时插嘴。

  • 接起来难不难 :3 步。创建会话 → 建 WebSocket 发 conn_init → 接入 AliRTC 拉流。核心代码不超过 100 行。

  • 坑在哪NOT_READY、token 1 小时过期、video 模式"创建成功 ≠ 能说话"、13 种 hangup_reason 要分开处理。下面都有解。

  • 读完你能拿走:一条可跑通的最小链路、一份参数调优对照表、一份错误码速查表。


一、先看结果:这段视频没有剧本

一场密钥失窃案,侦探挨个盘问嫌疑人。

角色说的每一句话、每一个表情,都是模型实时生成 的------没有台词本,没有预录素材,没有"下一句该接什么"的状态机。我第一遍看完又倒回去看了一遍,不是因为画质有多惊艳,而是因为我不知道它下一句要说什么

这一点很关键。

过去我们说的"数字人",绝大多数是"播放器":提前写好话术库,用 TTS 驱动口型,靠关键词命中来分支。用户问到话术库外的问题,就只能"我没听懂,换个话题问问吧"。

Vidu S1 想做的是另一件事:让数字人从播放 变成在场


二、为什么开发者该关心:架构变了,接入方式就必须变

这是很多人第一次接实时数字人会卡住的地方------它不是一个 HTTP 接口

传统 AI 服务的调用模型是这样的:

Plaintext 复制代码
请求 → 等待 → 返回完整结果

而实时数字人是全双工长连接。你和它同时在说话、同时在听,媒体流和控制信令走两条完全独立的通道:

通道 承载内容 技术选型
控制信令 建连、开始、发文字、打断、挂断 WebSocket(文本 JSON)
媒体流 你的麦克风/摄像头、数字人的音视频 AliRTC

这两条通道必须同时存在,缺一不可。 很多"数字人接不进去"的问题,本质上都是只打通了一条。

这个架构多出来的复杂度,换来的东西也很实在:

  1. 真双向感知------它能"看见"你(video 模式下摄像头画面)、"听见"你,并在你开口时中断自己

  2. 可打断------这是体验分水岭。不能打断的对话,本质上还是广播

  3. 长时程------连续互动不降质,这是"陪伴"类场景的硬门槛


三、整条链路,一张图说完

Plaintext 复制代码
sequenceDiagram
    participant App as 你的 App
    participant API as Vidu HTTP API
    participant WS as Vidu WebSocket
    participant RTC as AliRTC

    App->>API: ① POST /live/v1/lives
    API-->>App: live.id + rtc.token + rtc.user_id

    App->>WS: ② 连接 /live/ws/live/connect?live_id=xxx
    App->>WS: 发送 conn_init
    WS-->>App: conn_init_ack.success = true
    Note over App,WS: 控制链路就绪

    App->>RTC: ③ joinChannel(rtc.token, rtc.user_id)
    App->>RTC: publishLocalAudioStream(true)
    App->>RTC: subscribe(数字人流)
    RTC-->>App: 数字人音视频 / 音频

    Note over App,RTC: 开始实时对话
    App->>WS: text_msg / audio_interrupted / call_hangup

记住这三步的顺序,以及一个反直觉的点:第 ① 步成功 ≠ 可以开始说话。 原因见第五节坑位 2。


四、三步跑通:可直接复制的最小链路

所有 HTTP 接口都需要 Header:Authorization: Token vda_xxx

4.0 接口总览(先看这里找入口)

方法 路径 用途
POST /live/v1/lives 创建会话(核心入口)
GET /live/v1/lives/{live_id} 查询会话状态与账单
GET /live/v1/lives 列表查询
WebSocket /live/ws/live/connect App 控制信令
--- AliRTC joinChannel 实时媒体流
POST /live/v1/voices/clone 音色克隆
GET /live/v1/voices 查询自定义音色
POST/PUT /tools/v2/files/uploads 图片上传(三步式)

4.1 创建会话

HTTP 复制代码
POST https://{host}/live/v1/lives
Authorization: Token vda_xxx
Content-Type: application/json

最小请求体(只需要 3 个字段就能跑起来):

JSON 复制代码
{
  "call_mode": "video",
  "avatar": {
    "persona": "你是一个友好的客服,请自然地与用户实时互动",
    "image_uri": "https://你的数字人图片地址.png",
    "voice": ""
  }
}

完整参数版(生产环境建议至少配这些):

JSON 复制代码
{
  "call_mode": "video",
  "character_id": "1",
  "avatar": {
    "persona": "你是甜甜 Tina,我的声音像温热的奶茶,甜甜的、暖暖的,但解决问题可一点都不含糊哦!",
    "image_uri": "https://scene.cf.vidu.studio/media-asset/070302-ZFkgvJxBTM0ZQJoO.png",
    "voice": "Tina",
    "greeting_instruction": "直播刚刚开始。请用中文主动向观众说一句简短、温暖、自然、符合人设的开场白。直接说出来,不要用旁白叙述。",
    "farewell_enabled": true,
    "idle_action": true,
    "persona_enhance": true
  },
  "audio": { "enable_transcription": true },
  "vad": {
    "type": "semantic",
    "threshold": 0.5,
    "silence_duration_ms": 200,
    "idle_timeout_ms": 500
  },
  "llm": {
    "temperature": 0.7,
    "top_p": 0.8,
    "top_k": 20,
    "frequency_penalty": 1,
    "presence_penalty": 0.3,
    "seed": -1,
    "max_tokens": 50
  },
  "idle_timeout_seconds": 7200,
  "memory_retrieval": {
    "enabled": true,
    "endpoint": "https://api.example.com/memory/search",
    "authorization": "Bearer memory-api-token",
    "timeout_ms": 3000
  },
  "knowledge_retrieval": {
    "enabled": true,
    "endpoint": "https://api.example.com/knowledge/search",
    "authorization": "Bearer knowledge-api-token",
    "timeout_ms": 3000
  }
}

响应:

JSON 复制代码
{
  "live": {
    "id": "123456789",
    "status": "waiting",
    "live_duration": 600,
    "call_mode": "video"
  },
  "rtc": {
    "app_id": "xxxx",
    "channel_id": "live-user-123456789",
    "user_id": "live-user-1001-123456789",
    "token": "base64-token...",
    "token_expire_at": "1750003600"
  }
}

务必保存这三个值,后面每一步都要用:

字段 用途
live.id 房间 ID,WebSocket 建连、查询账单、发文本全靠它
rtc.token 加入 RTC 频道的凭证,默认 1 小时有效
rtc.user_id 你在 RTC 频道里的用户名

⚠️ 注意 live.status 此时是 waiting------数字人还没准备好


4.2 建立 WebSocket 并发起信号

Bash 复制代码
wss://{host}/live/ws/live/connect?live_id={live_id}
Authorization: Token vda_xxx

连接建立后立刻 发送 conn_init

JSON 复制代码
{
  "type": 1,
  "live_id": "123456789",
  "seq_id": 1,
  "payload": {
    "conn_init": { "version": 1 }
  }
}

收到 conn_init_ack.success = true,才说明控制链路初始化完成。

JavaScript 复制代码
// 建连 + 指数退避重试(video 模式强烈建议加)
async function initControlChannel(liveId, token) {
  const ws = new WebSocket(
    `wss://${HOST}/live/ws/live/connect?live_id=${liveId}`
  );

  ws.onopen = () => {
    ws.send(JSON.stringify({
      type: 1,
      live_id: liveId,
      seq_id: 1,
      payload: { conn_init: { version: 1 } }
    }));
  };

  ws.onmessage = (e) => {
    const msg = JSON.parse(e.data);
    if (msg.payload?.conn_init_ack?.success) {
      console.log('[WS] 控制链路就绪');
    } else if (msg.payload?.conn_init_ack?.reason === 'NOT_READY') {
      // 数字人渲染侧还没回连,等 2~3 秒重试
      setTimeout(() => ws.send(buildConnInit()), 2500);
    }
  };

  // 兜底:必须监听 close / error
  ws.onclose = (e) => console.warn('[WS] closed', e.code, e.reason);
  ws.onerror = (e) => console.error('[WS] error', e);
}

4.3 接入 AliRTC,把画面和声音跑起来

SDK 下载地址

JavaScript 复制代码
await aliRtc.joinChannel(rtc.token, rtc.user_id);
await aliRtc.publishLocalAudioStream(true);

if (callMode === 'video') {
  await aliRtc.publishLocalVideoStream(true);
}

两种模式的推/订阅关系不一样,别搞混:

模式 加入频道 推流 订阅
audio live-audio-{liveID} 麦克风音频 数字人音频 live-bot-...
video live-user-{liveID} 麦克风 + 摄像头 数字人音视频 live-video-push-...

实际渲染数字人,还需要订阅远端音视频,并在订阅状态变为 subscribed 后绑定视频容器。


五、参数怎么调:这才是拉开体验差距的地方

文档会告诉你每个字段的取值范围,但不会告诉你该怎么选。这一段是我自己调下来的经验。

5.1 vad:决定"打断手感",优先级最高

字段 默认 怎么调
vad.type server server 会过滤附和词和背景音;semantic用户开口即打断 。要做"自然对话"选 semantic,要防止误打断选 server
vad.threshold 0.5 拟声词/嘈杂声屏蔽力度,值越低屏蔽越少。嘈杂环境往上调
vad.silence_duration_ms 400 语音结束后静音多久触发响应。调小→响应快但容易抢话;调大→稳但显迟钝
vad.idle_timeout_ms 0 静默多久后模型主动开口。做陪伴类场景建议设 3000~5000,让它会主动找话题

💡 我的建议 :先用 semantic + silence_duration_ms: 200 跑起来,这个组合最接近真人对话节奏。觉得太敏感再切 server 慢慢调 threshold。

5.2 llm:控制"嘴瓢"和"话痨"

字段 默认 直觉理解
temperature 0.7 创意度。客服/导购压到 0.4~0.6;陪伴/角色扮演拉到 0.9+
top_p 0.8 质量下限,和 temperature 二选一调即可
top_k 20 候选词范围
frequency_penalty 1.0 防嘴瓢。<1 反向鼓励重复;>1 惩罚重复。数字人反复说同一句口头禅就往上加
presence_penalty 0.3 话题广度,值大更容易换话题
max_tokens 50 实时场景别调大。50 token 大概对应一句话,回复太长会严重拖慢节奏
seed -1 固定值可复现,-1 为随机

⚠️ 实时对话里,max_tokens 是最容易被忽略的性能杀手。它直接决定"你说完到它开口"的等待时长。

5.3 avatar:像不像人,看这几个字段

字段 说明
persona 人设提示词,5 万字以内,空间远超你的想象,值得认真写
persona_enhance true 会让平台帮你扩写优化提示词。自己写不好就打开
greeting_instruction 开场白提示词,≤200 字符。默认就在打招呼,想要别的开场一定要覆盖
idle_action 不说话时是否做自然动作。强烈建议开,静止不动的数字人很出戏
farewell_enabled 结束时自动生成几秒"礼貌离开"视频,体验完整度提升明显

图片要求:仅支持 1 张单人图 ,PNG/JPG/JPEG/WEBP,≤50MB;base64 需带 data:image/png;base64, 前缀。

5.4 idle_timeout_seconds:别让僵尸会话烧钱

默认 7200 秒(2 小时),范围 10~7200。用户关掉页面但没挂断时,会话会一直挂着计费。实际业务里建议按场景收紧,比如客服场景设 600。

5.5 外调记忆与知识库(内测)

memory_retrievalknowledge_retrieval 可以把你自己的记忆/知识系统挂进来,让数字人有长期记忆、能回答业务问题。

JSON 复制代码
{
  "enabled": true,
  "endpoint": "https://api.example.com/memory/search",
  "authorization": "Bearer memory-api-token",
  "timeout_ms": 3000
}

四个字段都要注意:endpoint 必须是平台可访问的 http(s) 绝对 URL;authorization 会作为 Authorization header 转发且校验非空timeout_ms 最大 30000。

这个能力是内测版。它决定了你的数字人能不能"记住上周聊过什么"------做长期陪伴产品的话,这是核心。


六、避坑清单:这 6 个坑我建议先读

坑 1:NOT_READY 不是报错,别慌

video 模式下,数字人渲染侧需要时间回连。这时候发 conn_init 会收到 NOT_READY

正确做法 :等待 2~3 秒重试,用指数退避。不要立刻重建页面或重新创建会话------那只会让等待更久。

坑 2:video 模式"创建成功 ≠ 能说话"

这是最反直觉的一点。POST /live/v1/lives 返回 200,只代表房间和外部 stream 已创建,不代表渲染侧就绪。

判断是否真的 ready,唯一标准是收到 conn_init_ack.success = true

坑 3:token 只有 1 小时

rtc.token 默认 1 小时有效,过期时间看 rtc.token_expire_at长会话必须自己实现续期逻辑,否则用户聊到第 61 分钟直接断线。

坑 4:403 是因为跨 Key / 跨账号

403 的典型原因是拿 A 的 API Key 去访问 B 创建的 live_id不要跨账号复用 ****live_id

坑 5:App WebSocket 只能发文本 JSON

不要试图通过 App WS 发送二进制音频或视频 ,媒体流只能走 AliRTC。协议里预留的 audio_startaudio_stopemotion_signal 当前接入不要求客户端发送。

另外,除了 conn_init 之外,text_msgaudio_interruptedcall_hangup 当前没有独立的业务 ack,别在代码里傻等。

坑 6:13 种 hangup_reason 必须分开处理

被强制断开时你会收到:

JSON 复制代码
{
  "type": 6,
  "payload": {
    "hangup": { "hangup_reason": "xxxx" }
  }
}

按类别给出不同的用户提示,体验差别很大:

分类 hangup_reason 该怎么做
正常结束 user_end, timeout 正常收尾,不需要报错
账户问题 credit_insufficient 必须弹出"积分不足"提示,否则用户以为产品坏了
风控 audit_violation 提示内容违规,但措辞要柔和
网络/链路 sip_closed, provider_closed, sip_reconnect_timeout, client_reconnect_timeout 提示网络异常 + 提供重连按钮
服务端调度 prepared_sip_disconnected, owner_taken_over, owner_lease_lost 一般可直接静默重连
AI 侧 ai_output_closed 输出通道异常,建议重建会话
其他 external 兜底提示

七、错误码速查

HTTP 错误

统一错误结构:

JSON 复制代码
{
  "code": 400,
  "reason": "BAD_REQUEST",
  "message": "参数非法",
  "metadata": {}
}
状态码 典型原因 处理建议
400 参数非法/字段缺失/call_mode 非法/文本超长/会话状态不允许 按字段说明修正;live 已结束就重建
401 API Key 缺失、格式错误或无效 检查 Authorization: Token vda_xxx,确认 Key 属于当前环境
403 访问了不属于当前 Key/账号的 live 用创建时的同一个 Key
404 会话不存在/已过期/live_id 写错 确认 live_id;无法恢复就重建
500 服务内部依赖异常(DB、SIP/video provider、AliRTC token 等) 可短暂重试;持续失败带上 live_id + trace_id + 请求时间反馈

WebSocket 错误

错误码 原因 处理建议
NOT_READY video 模式渲染侧未回连完成 等 2~3 秒重试 conn_init,指数退避
LIVE_CONN_INIT_FAILED 初始化失败,会话状态或服务端依赖异常 关闭当前 WS,重新创建 live;仍失败则带日志反馈

兼容性提醒

  • 除监听 conn_init_ack 外,必须 监听 close / error 做兜底

  • stream_url 当前是保留字段,实时播放请用 rtc 信息接入 AliRTC


八、写在最后

回看开头那段没有剧本的侦探视频。

Vidu S1 做的这件事其实很纯粹:让数字人从"播放"变成"在场"

从开发者角度看,WebSocket + RTC 的架构确实比普通 HTTP 接口多了几步,但换来的是真正的实时双向交互------你说话它能听见,它说话你能打断。在这之前的视频生成产品里,这件事基本做不到。

单图直出、无限时长、准实时响应,加上三步就能跑通的最小链路,接入门槛已经压得相当低了。剩下的想象空间,在各位开发者手里。

未来,Vidu API开放平台将持续分享:

AI 视频创作教程、最佳实践案例、行业解决方案及最新能力解析......

欢迎关注我们,与更多开发者和创作者共同探索 AI 视频的无限可能!

相关推荐
LingYi_041 分钟前
建筑提取—BuildFormer
人工智能·深度学习
智购无人售货机厂家43 分钟前
2026自动售货机软硬件版本管理策略:从版本号规范到兼容性矩阵的工程实践~YH
运维·服务器·人工智能·单片机·嵌入式硬件·线性代数·矩阵
知识分享小能手1 小时前
深度学习学习教程,从入门到精通,概率与信息论 — 知识点详解(3)
人工智能·深度学习·学习·数据挖掘·概率论
俊哥V1 小时前
每日 AI 研究简报 · 2026-09-01
人工智能·ai
Wendy不吃榴莲1 小时前
# AI短剧教程 - 《后西游记》开播后,AI影视为什么更考验“连续讲故事”?
人工智能·笔记·学习·ai·视频
木圭的AI时代指南1 小时前
AI江湖录①·斩杀线
人工智能·ai
Agudamu11611 小时前
B站学习视频怎么变笔记:用 Ai好记 + Obsidian 搭建个人知识库的完整教程
人工智能·笔记·学习·音视频
麦豆GEO1 小时前
GEO优化流量密码:吃透4大用户提问模型,精准拿捏AI自然流量
大数据·人工智能
dh2711987791 小时前
南京企业AI搜索“可见度之战”:GEO服务商竞合格局与选型逻辑
大数据·人工智能