原生JS+SSML实战:低门槛构建带情绪动作的AI陪伴智能体
针对AI应用缺乏情绪价值的痛点,本文提供一份原生JS接入魔珐星云SDK的实战指南,详解如何利用SSML与动作指令控制数字人,低门槛构建陪伴型智能体。
解析传统视频流架构瓶颈、魔珐星云四路参数流协议,以及 GPT/Claude/DeepSeek 流式输出与 Action Function Calling、存量终端落地要点。
在当前的大模型(LLM)与智能体生态中,后端的推理引擎与工具链(如 MCP 协议)已日趋完善,但在前端的「具身表达层」,行业内广泛使用的开源或传统数字人方案(如 Wav2Lip、MuseTalk 等)暴露出了显著的架构瓶颈。
传统方案普遍采用「云端视频流架构」(包含 ASR 识别 -> LLM 生成文本 -> TTS 合成语音 -> THG 生成唇形视频 -> FFmpeg 合成 MP4 -> WebRTC 推流)。这种架构将视频作为传输单元,天生不适配 Agent 实时流式对话的需求:
为了打破视频流架构的固有限制,魔珐星云 SDK 采用了一套专为具身智能设计的「端侧参数流协议」。
在星云的底层架构中,服务端不再下发沉重的视频画面,而是通过 WebSocket/SSE 实时下发四路并行的结构化参数:
这四路参数流到达终端后,由 XmovAvatar SDK 调用本地硬件加速(WebGL/Canvas)进行实时 3D 渲染。
星云 SDK 的原生方法 speak(ssml, is_start, is_end) 在设计上完美对齐了大模型的流式(Streaming)输出生命周期。以下为接入不同主流大模型时,解析流式数据并实现「边生成、边渲染」的核心代码实战。
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
async function talkWithClaude(userInput) {
const stream = await client.messages.stream({
model: "claude-3-5-sonnet",
max_tokens: 1024,
messages: [{ role: "user", content: userInput }],
});
let isFirst = true;
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta?.type === "text_delta") {
// 首包传入 is_start=true,后续为 false
sdk.speak(event.delta.text, isFirst, false);
isFirst = false;
}
}
sdk.speak("", false, true); // 流式输出结束闭合
}import OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
async function talkWithGPT(userInput) {
const stream = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: userInput }],
stream: true,
});
let isFirst = true;
for await (const chunk of stream) {
const textDelta = chunk.choices[0]?.delta?.content;
if (textDelta) {
sdk.speak(textDelta, isFirst, false);
isFirst = false;
}
}
sdk.speak("", false, true);
}async function talkWithDeepSeek(userInput) {
const response = await fetch("https://api.deepseek.com/v1/chat/completions", {
method: "POST",
headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ model: "deepseek-chat", stream: true, messages: [...] }),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let isFirst = true;
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunkStrings = decoder.decode(value).split("\n").filter(line => line.trim() !== "");
for (const line of chunkStrings) {
if (line.includes("[DONE]")) break;
if (line.startsWith("data: ")) {
const textDelta = JSON.parse(line.slice(6)).choices[0]?.delta?.content;
if (textDelta) {
sdk.speak(textDelta, isFirst, false);
isFirst = false;
}
}
}
}
sdk.speak("", false, true);
}工程建议:为消除 TTS(文本转语音)发音时的短时顿挫,建议在前端构建一个「标点符号缓冲区」,将文本按完整句读切片后再喂给 speak 接口。
要让 Agent 具备真正的具身感知能力,它必须学会在对话中驱动肢体。魔珐星云提供了标准化的 KA(Knowledge Action,具身动作语义库)接口。在工程上,可将其转化为大模型的 Function Calling 工具目录。
1. 提取可用动作清单:调用星云的 /user/v1/external/lite_ka_summary API 接口获取当前数字人的可用动作(如:PointingSelf, PointingRight)。
2. 构建 LLM 工具集定义 (Tool Use):在向 LLM 提交 System Prompt 时,将上述动作封装为供模型调用的函数工具。
const tools = [{
name: "avatar_action_with_speech",
description: "选择合适的肢体动作并附带讲话内容",
input_schema: {
type: "object",
properties: {
action: { type: "string", enum: ["PointingSelf", "PointingRight", "Explain"] },
dialogue: { type: "string", description: "数字人需要说的内容" }
}
}
}];3. 下发 SSML 渲染:当大模型推理决定在介绍商品时使用 PointingRight 动作后,将结果拼接为标准 SSML 协议发给星云引擎执行同步渲染:
// LLM 返回决策后,前端组合发送给 SDK
const ssmlPayload = `<speak><action name="${llmResponse.action}" />${llmResponse.dialogue}</speak>`;
sdk.speak(ssmlPayload, true, true);在将具身智能部署到线下的商业场景(如教培一体机、政务接待屏、门店导购系统)时,设备算力与运维成本是两大核心考量。
魔珐星云,不止是数字人,让 AI 从会思考,走向能表达、会交流。