AI 具身互動:實現一個會說話的 3D 虛擬伴侶

大家好,我是石小石~

引言

市面上絕大多數 3D 虛擬形象仍停留在循環播放預製內容的階段,互動方式單一,缺乏真正的理解與回饋能力;而單純接入大模型,也只能解決文字問答,無法實現語音、神態、動作與畫面的同步回應。若建構一套完整的具身互動體系,既能對接主流大模型完成對話理解與推理,又能依託原生 3D 動作生成和端側即時多模態畫面生成能力,就可以讓虛擬形象從「呆板的數位外殼」,進化為真正具備感知、表達與陪伴能力的「AI 伴侶」。

設想一下,如果在網頁、手機、大螢幕等任意終端螢幕上,我們可以隨時召喚一個具備大模型能力的 3D 虛擬互動夥伴,它能聽懂你的問題,即時給出回應,並透過語音、表情和動作完成自然表達,是不是一件非常有趣的事情?

本篇文章將結合 Trae魔珐星雲 SDK,帶大家快速實現一個會說話、可打斷、能即時互動交流的智慧 AI 伴侶。

AI 伴侶效果展示

參考下面的圖片和影片,執行前端服務後,只需在頁面中輸入 App IDApp Secret,點擊「連線」按鈕,即可載入並建立一個 3D 虛擬人。連線成功後,我們就可以在右側對話面板中輸入問題與其交流了。

Demo 效果影片地址:www.bilibili.com/video/BV1rt…

從最終影片效果來看,這套 3D 虛擬智慧體已經具備完整的即時互動能力。系統聯動大模型完成語義理解與內容生成後,依託自研參數流架構,以及 AI 端渲染與解算核心技術,由雲端下發輕量化的動作與語音參數,終端本地完成完整 3D 形象生成。由此,虛擬人不僅能夠理解使用者提問並給出自然、連貫的回答,還能同步透過語音、表情和動作完成具身化表達,讓互動從單純的文字問答升級為更真實的多模態陪伴體驗。

更重要的是,這套 3D 虛擬人的回應速度足夠快,基本可實現約 500ms 的低延遲回饋,整體互動體驗流暢自然。而實現這樣一個能聽懂問題、即時回應、並完成自然表達的網頁 AI 伴侶,落地成本極低,一般網頁設備即可流暢執行。

下文將介紹如何借助 Trae 與魔珐星雲具身驅動 SDK,快速搭建一個最小可執行 Demo。

核心技術:魔珐星雲具身驅動 SDK

從零實現一個 3D 虛擬人互動並不容易,背後需要打通一整套複雜鏈路:

  • 3D 形象載入和端側渲染;
  • 文字轉語音 TTS;
  • 口型、表情、肢體動作同步;
  • AI 回覆串流輸出後的播報拼接;
  • 使用者打斷、思考、傾聽、待機狀態切換;
  • 低延遲和多終端相容

好在,這些複雜能力已經有了成熟方案: 魔珐星雲具身驅動 SDK

魔珐星雲是魔珐科技打造的「AI 具身互動智慧體開放平台」,提供 AI 形象生成、多模態感知、大模型 Agent 認知、即時 3D 具象表達、機器人運控等端到端能力。並且支援一套 SDK 全域覆蓋螢幕終端、人形服務機器人、AR/VR 三大終端,區別傳統高頻寬影片流方案。

借助其具身驅動 SDK,我們可以把 AI 的表達方式從「文字回覆」升級為「3D 多模態互動」:基於文字輸入,即時生成語音、表情與動作,驅動 3D 數位人完成自然表達。

其核心功能包括:

  • 即時 3D 數位人渲染與驅動:網頁、大螢幕、車載等各類瀏覽器終端均可載入、即時渲染 3D 數位人;
  • 語音合成與口型同步:支援文字/SSML 播報,並自動完成語音、口型、表情同步;
  • 多狀態行為控制:支援待機、互動待機、播報等狀態切換;
  • Widget 元件展示:支援字幕、圖片、影片等內容展示;
  • 事件回調與日誌除錯:支援自訂事件回調,方便接入業務邏輯和排查問題。

具身驅動 SDK 對瀏覽器的要求

目前,具身驅動 SDK 已提供 JS 版本。也就是說,只要終端支援瀏覽器核心,就可以接入具備 AI 互動能力的 3D 虛擬人,適用於網頁、PC 用戶端、車機、大螢幕等多種場景。其 SDK 支援的瀏覽器版本要求如下:

實戰教學:用 Trae 快速搭建 3D 虛擬人專案

取得 App ID、App Secret

要使用具身驅動 SDK 快速建立一個可互動的 AI 虛擬形象,首先需要登入魔珐星雲控制台,在應用中心建立一個驅動應用,並完成角色、音色、場景和表演風格配置,同時取得後續接入 SDK 所需的 App IDApp Secret

參考下面的動圖,登入控制台後,進入「應用管理」中的「驅動應用」Tab,點擊「開始建立」,填寫應用名稱並確認。隨後會進入形象選擇頁面,可以根據業務場景選擇合適的 3D 數位人形象。

選擇形象後,還可以繼續配置場景、音色和表演風格。確認配置無誤後,點擊「儲存」,系統就會自動完成驅動應用建立。

現在,點擊「接入 SDK」按鈕即可查看並複製 App IDApp Secret,用於後續網頁 Demo 接入。

核心程式碼實作

具身驅動 SDK 的接入方式非常簡單,整體流程可以分為三步:引入 SDK、初始化實例、呼叫播報方法

首先,在頁面中引入 SDK:

js 代碼解讀複製代碼<script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/[email protected]"></script>

然後建立 SDK 實例,並完成初始化。這裡需要將 appIdappSecret 替換為剛才在魔珐星雲控制台中複製的內容:

js 代碼解讀複製代碼const sdk = new XmovAvatar({
  containerId: "#sdk", // 必填:數位人掛載容器
  appId: "your_appid", // 必填:應用 AppID
  appSecret: "your_appsecret", // 必填:應用 AppSecret
  gatewayServer: "https://nebula-agent.xingyun3d.com/user/v1/ttsa/session", // 必填:服務介面位址

  // SDK 事件回調,方便除錯
  onMessage(message) {
    console.log("SDK message:", message);
  },
});

// 初始化 SDK,載入數位人資源
await sdk.init({
  onDownloadProgress(progress) {
    console.log(`資源載入進度:${progress}%`);
  },
});

初始化完成後,呼叫 speak 方法即可讓數位人開口說話:

js 代碼解讀複製代碼sdk.speak("你好,石小石,我是你的 AI 伴侶~", true, true);

如果只是播報一句完整的話,後兩個參數通常都傳 true

接下來,我們可以把以上接入邏輯貼到 Trae 的 AI 對話框中,讓它幫我們快速生成一個基於 Vue 3 的最小 Demo。

下面是 Trae 生成的一個最小使用 Demo:

js 代碼解讀複製代碼<template>
  <!-- 數位人掛載容器 -->
  <div id="sdk"></div>
</template>
<script setup>
import { onMounted, onBeforeUnmount } from "vue";

// 保存 SDK 實例
let sdk = null;

onMounted(async () => {
  // 建立 SDK 實例
  sdk = new window.XmovAvatar({
    containerId: "#sdk", // 數位人掛載容器
    appId: "你的 AppID", // 替換為控制台中的 AppID
    appSecret: "你的 AppSecret", // 替換為控制台中的 AppSecret
    gatewayServer: "https://nebula-agent.xingyun3d.com/user/v1/ttsa/session",

    // SDK 事件回調,方便查看執行狀態
    onMessage(message) {
      console.log("SDK message:", message);
    },
  });

  // 初始化 SDK,載入數位人資源
  await sdk.init({
    onDownloadProgress(progress) {
      console.log(`資源載入進度:${progress}%`);
    },
  });

  // 初始化完成後,讓數位人播報一句話
  sdk.speak("你好,我是你的網頁 AI 伴侶,很高興見到你。", true, true);
});

onBeforeUnmount(() => {
  // 頁面卸載時銷毀 SDK,釋放資源
  if (sdk) {
    sdk.destroy();
  }
});
</script>
<style scoped>
#sdk {
  width: 800px;
  height: 450px;
  background: #000;
  border-radius: 12px;
  overflow: hidden;
}
</style>

啟動專案後,頁面會渲染出 3D 數位人,並在初始化完成後自動播報一句歡迎語。

對接 DeepSeek,讓 AI 伴侶具備智慧

接入 DeepSeek:取得 AI 回覆

前面的 Demo 已經可以讓數位人播報固定文字。接下來我們單獨接入 DeepSeek,讓頁面具備 AI 回覆能力。這裡先不考慮複雜的串流輸出,只用最簡單的非串流介面:使用者輸入一句話,前端請求 DeepSeek,拿到完整回覆後再交給數位人播報。

首先準備一個 DeepSeek API Key,然後在程式碼中定義:

js 代碼解讀複製代碼// DeepSeek API Key,Demo 為了方便直接寫在前端
const DEEPSEEK_API_KEY = "你的 DeepSeek API Key";

然後封裝一個最簡單的請求方法:

js 代碼解讀複製代碼async function askDeepSeek(question) {
  const response = await fetch("https://api.deepseek.com/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${DEEPSEEK_API_KEY}`,
    },
    body: JSON.stringify({
      model: "deepseek-chat",
      messages: [
        {
          role: "system",
          content:
            "你是一個網頁 AI 伴侶,請用簡潔、自然、口語化的中文回答使用者問題。",
        },
        {
          role: "user",
          content: question,
        },
      ],
      stream: false,
    }),
  });

  const data = await response.json();

  // 取出 DeepSeek 回傳的回答內容
  return data.choices?.[0]?.message?.content || "抱歉,我暫時沒有想好怎麼回答。";
}

這個方法只做一件事:把使用者的問題送給 DeepSeek,並回傳 AI 的文字回覆。

可以先用一段簡單程式碼驗證介面是否正常:

js 代碼解讀複製代碼async function testDeepSeek() {
  const answer = await askDeepSeek("請用一句話介紹你自己");
  console.log("DeepSeek 回覆:", answer);
}

如果控制台能正常列印回覆,說明 DeepSeek 已經接通了。

將 DeepSeek 回覆交給數位人播報

DeepSeek 接通後,我們只需要把它回傳的 answer 傳給 sdk.speak(),數位人就可以把 AI 回覆說出來。

核心邏輯如下:

js 代碼解讀複製代碼async function askAndSpeak() {
  if (!sdk) {
    alert("請先初始化數位人");
    return;
  }
  const question = inputText.value.trim();
  if (!question) {
    alert("請先輸入問題");
    return;
  }

  try {
    // 使用者提問後,讓數位人進入思考狀態
    sdk.think();
    // 請求 DeepSeek 取得回答
    const answer = await askDeepSeek(question);
    // 將 AI 回覆交給數位人播報
    sdk.speak(answer, true, true);
  } catch (error) {
    console.error("DeepSeek 請求失敗:", error);
    // 出錯時也可以讓數位人播報錯誤提示
    sdk.speak("抱歉,AI 服務暫時不可用,請稍後再試。", true, true);
  }
}

這裡為了讓 Demo 更容易理解,直接把 DeepSeek API Key 寫在了前端。實際開發中不建議這樣做,正式專案應透過後端介面轉發請求,避免密鑰外洩。

進階 API:狀態控制、串流播報與事件監聽

完成最小 Demo 後,如果要把它升級成一個真正可互動的 AI 伴侶,就需要用到一些進階 API。這裡重點介紹幾個最常用的能力:狀態切換、串流播報、打斷、音量控制和事件監聽。

數位人狀態切換

在真實互動中,數位人不應該一直處於同一個狀態,而是要根據使用者行為和 AI 回應過程切換狀態。例如:使用者沒說話時待機,使用者提問時進入思考,AI 回覆時開始播報,使用者打斷時回到互動待機。

常用狀態 API 如下:

js 代碼解讀複製代碼// 一般待機狀態
sdk.idle();

// 互動待機狀態,常用於打斷目前播報
sdk.interactiveidle();

// 進入離線模式,此狀態下不消耗點數
sdk.offlineMode();

// 從離線模式切回線上模式
sdk.onlineMode();

在 Demo 中,最常用的是 idle()interactiveidle()

js 代碼解讀複製代碼// 初始化完成後,讓數位人進入待機狀態
await sdk.init();
sdk.idle();

// 使用者點擊「打斷」按鈕時,打斷目前播報
function interrupt() {
  sdk.interactiveidle();
}

其中,interactiveidle() 很適合用來處理「打斷」場景。比如數位人正在播報一段長文字,使用者想重新提問,就可以先呼叫它讓數位人回到互動待機狀態,再開始下一輪對話。

對接大模型串流輸出

如果只是播報一句固定文字,可以這樣呼叫:

js 代碼解讀複製代碼sdk.speak("歡迎使用魔珐星雲", true, true);

但在 AI 伴侶場景裡,大模型通常是串流回傳內容的。此時可以多次呼叫 speak(),透過 is_startis_end 標識告訴 SDK 目前文字處於哪一段。

js 代碼解讀複製代碼// 第一段:is_start 為 true,is_end 為 false
sdk.speak("你好,我是你的 AI 伴侶,", true, false);

// 中間段:is_start 和 is_end 都為 false
sdk.speak("我可以陪你聊天、講故事,", false, false);

// 最後一段:is_start 為 false,is_end 為 true
sdk.speak("也可以幫你解答問題。", false, true);

參數說明:

ini 代碼解讀複製代碼sdk.speak(ssml, is_start, is_end);
  • ssml:播報文字,也可以是 SSML;
  • is_start:是否為本輪播報的第一段;
  • is_end:是否為本輪播報的最後一段。

需要注意的是,串流播報時建議先累積一小段文字再開始呼叫 speak(),避免文字太短導致數位人頻繁等待。同時,前一輪 speak(..., true) 結束後,不建議馬上連續開啟下一輪播報,最好先透過 interactiveidle() 做一次狀態切換。

使用 SSML 觸發動作

speak() 不僅可以傳普通文字,也可以傳 SSML。透過 SSML 可以讓數位人在播報時執行指定動作,比如歡迎、揮手、跳舞等。

例如,讓數位人說歡迎語時觸發一個 Hello 動作:

js 代碼解讀複製代碼const ssml = `
<speak>
  <ue4event>
    <type>ka</type>
    <data><action_semantic>Hello</action_semantic></data>
  </ue4event>
  歡迎來到星雲具身 3D 數位人平台,很高興見到你。
</speak>
`;

sdk.speak(ssml, true, true);

如果需要根據語義觸發動作,也可以使用 ka_intent

js 代碼解讀複製代碼const ssml = `
<speak>
  熱烈
  <ue4event>
    <type>ka_intent</type>
    <data><ka_intent>Welcome</ka_intent></data>
  </ue4event>
  歡迎各位來到今天的分享。
</speak>
`;

sdk.speak(ssml, true, true);

這類能力很適合用於虛擬主持人、歡迎頁、導覽講解等場景,讓數位人不只是「說話」,而是能配合語義做動作表達。

監聽播報狀態

在真實專案中,我們經常需要知道數位人什麼時候開始說話、什麼時候說完。可以透過 onVoiceStateChange 監聽音訊播放狀態。

js 代碼解讀複製代碼const sdk = new XmovAvatar({
  containerId: "#sdk",
  appId: "your_appid",
  appSecret: "your_appsecret",
  gatewayServer: "https://nebula-agent.xingyun3d.com/user/v1/ttsa/session",

  // 監聽數位人播報狀態
  onVoiceStateChange(status) {
    console.log("數位人語音狀態:", status);

    // 開始說話
    if (status === "voice_start" || status === "start") {
      console.log("數位人開始播報");
    }

    // 播報結束
    if (status === "voice_end" || status === "end") {
      console.log("數位人播報結束");
    }
  },
});

監聽 SDK 訊息和錯誤

onMessage 是除錯時非常重要的回調。SDK 的錯誤資訊、執行訊息都可以透過它輸出。

js 代碼解讀複製代碼const sdk = new XmovAvatar({
  containerId: "#sdk",
  appId: "your_appid",
  appSecret: "your_appsecret",
  gatewayServer: "https://nebula-agent.xingyun3d.com/user/v1/ttsa/session",

  onMessage(message) {
    console.log("SDK message:", message);

    // message 中通常包含 code、message、timestamp 等欄位
    if (message.code) {
      console.warn("SDK 錯誤碼:", message.code);
      console.warn("SDK 錯誤資訊:", message.message);
    }
  },
});

常見錯誤可以簡單理解為幾類:

  • 10001:容器不存在,通常是 containerId 寫錯或 DOM 還沒渲染;
  • 10002:Socket 連線異常,可能是網路或服務連接問題;
  • 10003:會話建立失敗,優先檢查 appIdappSecret、應用配置;
  • 30001:背景圖片載入失敗;
  • 40001:音訊解碼失敗;
  • 50001 / 50002:離線/線上狀態變化;
  • 50003 / 50004:網路重試或網路中斷。

在開發階段,建議始終保留 onMessage 日誌,這樣排查問題會快很多。

音量與除錯資訊

最後還有幾個開發除錯時比較實用的方法。

控制音量:

js 代碼解讀複製代碼// 靜音
sdk.setVolume(0);

// 一半音量
sdk.setVolume(0.5);

// 最大音量
sdk.setVolume(1);

顯示或隱藏除錯資訊:

js 代碼解讀複製代碼// 顯示除錯資訊
sdk.showDebugInfo();

// 隱藏除錯資訊
sdk.hideDebugInfo();

在聯調階段,可以暫時打開除錯資訊;上線前再關閉,保持頁面乾淨。

使用 Trae 完善互動體驗

到這裡,我們的 Demo 已經具備了基礎能力:頁面可以載入 3D 虛擬人,並透過 DeepSeek 取得 AI 回覆,再交給數位人進行播報。接下來,我繼續結合具身驅動 SDK 的常用 API,讓 Trae 幫我做多輪程式碼迭代,逐步完善頁面互動體驗。

這一步主要補充了幾個能力:

  • 支援在頁面中輸入 App IDApp Secret,無需手動修改程式碼;
  • 增加連線狀態顯示,方便判斷 SDK 是否初始化成功;
  • 增加對話面板,用於和 AI 虛擬伴侶對話;
  • 在請求 DeepSeek 時,讓數位人進入「思考」狀態;
  • AI 回覆後,呼叫 speak 方法驅動數位人播報;
  • 增加「打斷」能力,使用者可以中斷目前播報;

經過與 Trae 的多輪對話、除錯和修復後,最終互動效果介面如下:

實際使用時,只需要在頁面頂部輸入 App IDApp Secret,點擊「連線」完成初始化。連線成功後,在輸入框中輸入問題,虛擬助手就會呼叫 DeepSeek 取得回答,並透過 3D 數位人形象進行語音播報。

具體互動可以參考下面的影片:

Demo 效果影片地址:www.bilibili.com/video/BV1rt…

可以看到,虛擬人的回應幾乎沒有延遲,神情、動作都比較自然。如果你對目前的形象不滿意,在魔珐星雲控制台建立新的形象,更換 App IDApp Secret 即可。

增加語音對話功能

在上面的示例中,我們已經完成了基本的文字輸入、AI 回覆和數位人播報能力。但在很多真實場景中,比如車載大螢幕、商場導覽螢幕、智慧客服終端等,語音對話往往才是更自然的互動方式。

要實現語音對話能力其實並不複雜:前端可以呼叫瀏覽器麥克風權限,即時擷取使用者語音,再透過語音辨識服務將語音轉換為文字;隨後把辨識結果送給大模型取得回覆,最後再交給魔珐星雲 SDK 驅動 3D 虛擬人播報。這樣就可以形成完整的語音互動閉環:

由於篇幅原因,本文不展開語音辨識和即時音訊擷取的具體實作,後續我會單獨寫一篇文章拆解這一部分。

如果你對 3D 虛擬人、AI 伴侶、具身智慧互動、語音對話等方向感興趣,可以關注我的專欄,後續會繼續分享更多相關實作。

總結

借助本文可以看到,透過魔珐星雲具身驅動 SDK,實現一個能說話、可互動的 3D 虛擬人物成本非常低。基於瀏覽器和安卓 SDK 的支援,讓它具備很強的終端相容性,讓網頁、行動端、大螢幕、車機等多種螢幕和應用,都有機會接入 AI 具身互動智慧體。

這也意味著,AI 不再只能停留在文字對話中,而是可以透過 3D 形象、語音、表情和動作完成更自然的表達,帶來更接近真實陪伴的互動體驗。

當然,本文只是一個最小可執行 Demo,主要用於驗證從 3D 數位人載入、語音播報到大模型回覆的完整鏈路。後續還可以繼續擴充串流回覆、語音輸入、自訂字幕、動作控制等能力,讓這個 AI 伴侶更加自然、智慧和好用。

本文中的 Demo 已經開源,留言任意內容即可獲得。


原文出處:https://juejin.cn/post/7656050265523372032


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝14   💬2   ❤️2
591
🥈
我愛JS
📝2   💬2   ❤️2
97
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登