传统数字人为什么难落地,魔珐星云以具身智能让屏幕变身AI导办员

3 阅读16分钟

数字人这几年比较火,但真正进入业务现场后,很多方案并没有想象中好用。问题不在于形象够不够逼真,而在于交互链路是否足够轻、足够快,能不能真正承接服务流程。也正是在这一点上,传统数字人方案和星云的差别非常明显。

我认为,如果要把这个差别讲清楚,不能只谈“形象”和“会不会说话”,而要回到产品本身:传统方案为什么难落地,魔珐星云到底解决了什么问题,又能做成什么样的产品。

image.png

一、现有方案:传统数字人为什么停留在展示层

传统数字人(云端渲染方案)的核心流程,是由云端 GPU 完成集中渲染,生成完整画面后再下发给终端呈现。这种方式不仅强依赖高带宽稳定网络,延迟高且无法实时打断,因此仅能满足演示、宣传片、固定讲解这类低交互场景,无法支撑需要连续对话的真实业务场景,但一旦进入高频交互和真实业务场景,问题就会集中暴露。

首先是延迟高。一次完整回答通常要经过识别、理解、生成、语音合成、动作匹配、内容下发等多个环节,链路越长,用户等待感越明显。对于线下咨询、导办、接待这类场景,用户最在意的不是“说得多华丽”,而是“能不能马上回应”。

其次是不能自然打断。传统方案里,一段回答开始输出后,系统往往很难在中途立刻切换状态。用户追问、改口、补充信息时,数字人不能像真人那样立即停下并进入新的交互轮次,这会让服务过程显得迟钝。

第三是成本高。传统数字人如果要追求更好的表现力,通常需要更重的云端算力、更高的带宽,或者更强的本地硬件支持。Demo 可以做,但一旦要规模化铺到大厅、前台、终端设备上,部署和运维成本就会迅速放大。

第四是弱网环境下容易卡顿。因为链路本身重,传输压力大,只要网络有波动,就容易出现卡顿、掉帧、音画不同步,甚至中断交互。对于真实业务场景来说,这种不稳定会直接影响用户信任。

如果把传统数字人和魔珐星云放在一起看,差别会清楚些。

image.png

这说明传统数字人的核心问题,不是不会表达,而是比较难在真实场景里以高质量,低延时,高并发,低成本、可持续的方式承接服务。

二、单点技术局限:只有 LLM、TTS 和渲染,还不等于一个产品

很多人以为,只要把大模型、语音合成和数字人渲染接起来,产品就做出来了。实际上,这只是把几个能力串起来,并没有真正形成一套可运行的终端产品。

LLM 解决的是“说什么”,TTS 解决的是“怎么发声”,渲染解决的是“怎么把形象呈现出来”。但真实业务里更关键的问题是:什么时候开始听、什么时候回答、用户打断后怎么切换、什么时候展示卡片、什么时候调接口、什么时候转人工、什么时候结束当前轮次并进入下一轮。

也就是说,单点能力可以让数字人“开口”,却不能保证数字人“工作”。如果没有统一的状态管理、轻量化的表达机制、终端侧实时运行能力,以及和业务系统联动的执行能力,数字人就仍然停留在展示层,而不是服务层。

这也是为什么很多项目看起来技术栈很先进,实际体验却不够自然。问题不在某个模型不够强,而在于理解、表达和执行之间缺少真正打通的一层。

而魔珐星云的优势有以下:

image.png

三、魔珐星云解法:把云端思考和终端表达真正拆开

星云的关键价值,在于它没有沿着“云端生成更多内容”的方向继续加重链路,而是换了一种思路:云端负责理解和驱动,终端负责实时渲染和表达。

这个变化看起来像架构调整,实际上直接决定了体验和成本。

云端只发指令,意味着传输的不是整段重内容,而是更轻量的驱动结果;终端自己渲染,意味着语音、表情、动作和界面联动都在本地实时完成。这样一来,系统就同时拿到了几个非常关键的优势。

第一,轻量不卡。因为传输压力变小,系统不再那么依赖持续的大带宽,终端运行也更稳定,弱网场景下更不容易卡顿。

第二,低延迟。根据官方公开信息,星云的驱动响应可以做到小于 500ms,并支持随时打断。这意味着用户提问后,数字人不是等一大段内容准备完成再回应,而是能快速进入下一轮交互。

第三,部署成本更低。由于表达层更多放在终端侧完成,星云不必强依赖昂贵 GPU,百元级芯片即可运行。这让数字人不再只是少量高配设备上的展示项目,而真正有机会进入大量业务终端。

如果从产品层面来理解,星云更像一套 AI 屏幕操作系统。它不是单纯做一个数字人形象,而是在屏幕和 AI 之间,搭建了一层稳定的表达与交互运行时。

如果从能力层面来理解,星云又是一层具身智能表达层基础设施。上层可以接大模型、RAG、工作流和业务系统,下层可以接 Web、App、Pad、PC、电视和大屏,而中间这一层,负责把 AI 的理解和决策变成用户真正能看到、能听到、能互动的表达结果。

也正因为有了这一层,产品才真正完成了完整链路:

  • 感知:接收语音、文本、触控、接近事件等输入。
  • 理解:识别用户意图、上下文和业务问题。
  • 决策:由大模型、知识库和规则系统生成下一步动作。
  • 表达:由星云实时完成语音、表情、动作、字幕和卡片联动。
  • 执行:调用业务接口、展示结果、跳转流程或转人工。

这条“感知 → 理解 → 决策 → 表达 → 执行”的链路打通之后,数字人才不是一个会说话的角色,而是一个真正可工作的终端智能体。

image.png

四、落地场景:AI 业务导办屏

如果只停留在技术分析,还不够有说服。真正有价值的是,这套能力到底能做成什么产品。

这里我以AI 业务导办屏为例子。 首先我们要去魔珐星云注册账号,注册有免费额度。

然后我们去应用管理创建驱动应用

image.png

然后我们可以设置虚拟人的形象、场景、角色、表演动作,并谨慎保存好我们右上角的App ID和App Secret。

image.png

然后我们需要导入依赖

<!DOCTYPE html>
<html lang="en">
<body>
  <div style="width: 540px;height: 960px">
    <div id="sdk"></div>
  </div>
  <script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar@latest.js"></script>
</body>
</html>

然后创建实例我们就可以在自己的网页上看到虚拟人了

const LiteSDK = new XmovAvatar({
  containerId: '#sdk',
  appId: 'your_appid',
        // 您在魔珐星云平台建立的实时驱动应用的appid
  appSecret: 'your_appsecret',
  // 您在魔珐星云平台建立的实时驱动应用的appsecret
  gatewayServer: 'https://nebula-agent.xingyun3d.com/user/v1/ttsa/session',
  // 自定义渲染器,传递该方法,所有事件sdk均返回,由该方法定义所以类型事件的实现逻辑
  headers: {
    'Authorization': '888jn',
  },
  //自定义请求头
  hardwareAcceleration: "prefer-hardware", // 开启硬件加速
  // 自定义渲染器,传递该方法,所有事件sdk均返回,由该方法定义所以类型事件的实现逻辑
  onWidgetEvent(data) {
    // 处理widget事件
    console.log('Widget事件:', data)
  },
  // 代理渲染器,sdk默认支持subtitle_on、subtitle_off和widget_pic事件。通过代理,
  // 可以修改默认事件,业务侧也可实现各种其他事件。

  proxyWidget: {
    "widget_slideshow": (data: any) => {
      console.log("widget_slideshow", data);
    },
    "widget_video": (data: any) => {
      console.log("widget_video", data);
    },
  },
  onNetworkInfo(networkInfo) {
    console.log('networkInfo:', networkInfo)
  },
  onMessage(message) {
    console.log('SDK message:', message);
  },
  onStateChange(state: string) {
    console.log('SDK State Change:', state);
  },
  onStatusChange(status) {
    console.log('SDK Status Change:', status);
  },
  onStateRenderChange(state: string, duration: number) {
    console.log('SDK State Change Render:', state, duration);
  },
  onVoiceStateChange(status:string) {
      console.log("sdk voice status", status);
  },
  enableLogger: false, // 不展示sdk log,默认为false
})

这里给出我创建出来的可以直接输入App ID和App Secret就可以看到自己创建的虚拟人并且进行业务询问的完整代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>星云导办屏</title>
    <script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar@latest.js"></script>
    <style>
        :root { --brand-color:#0f766e; --bg-color:#f8fafc; --panel-bg:#ffffff; }
        body { font-family:-apple-system, BlinkMacSystemFont, "Microsoft YaHei", sans-serif; background:var(--bg-color); margin:0; padding:20px; display:flex; flex-direction:column; align-items:center; color:#0f172a; }
        .header { width:100%; max-width:1100px; margin-bottom:20px; display:flex; justify-content:space-between; align-items:flex-end; }
        .header h1 { margin:0; font-size:24px; letter-spacing:1px; }
        .header span { color:#64748b; font-size:14px; }
        .config-bar { background:var(--panel-bg); padding:15px 20px; border-radius:12px; box-shadow:0 4px 10px rgba(0,0,0,.05); display:flex; gap:15px; width:100%; max-width:1100px; margin-bottom:20px; box-sizing:border-box; }
        .config-bar input { flex:1; padding:10px; border:1px solid #e2e8f0; border-radius:6px; outline:none; }
        .btn-init { padding:10px 24px; background:#0f172a; color:#fff; border:none; border-radius:6px; cursor:pointer; font-weight:700; }
        .retail-workspace { display:flex; gap:20px; width:100%; max-width:1100px; align-items:stretch; }
        .stage-panel { flex:0 0 420px; height:747px; background:#000; border-radius:16px; overflow:hidden; box-shadow:0 15px 30px rgba(0,0,0,.1); position:relative; }
        .avatar-layer { position:absolute; inset:0; z-index:1; }
        #sdk { position:absolute; inset:0; width:100%; height:100%; }
        .status-badge { position:absolute; top:15px; left:15px; background:rgba(0,0,0,.6); color:#fff; padding:6px 12px; border-radius:20px; font-size:12px; backdrop-filter:blur(4px); z-index:30; display:flex; align-items:center; gap:6px; }
        .dot { width:8px; height:8px; border-radius:50%; background:#94a3b8; }
        .dot.active { background:#10b981; box-shadow:0 0 8px #10b981; }
        .stage-subtitle { position:absolute; left:0; right:0; bottom:26px; z-index:20; display:flex; justify-content:center; padding:0 24px; pointer-events:none; opacity:0; transform:translateY(10px); transition:.2s; }
        .stage-subtitle.show { opacity:1; transform:none; }
        .stage-subtitle span { display:block; min-width:240px; max-width:min(88%,360px); padding:12px 18px; border-radius:14px; background:rgba(24,22,29,.88); color:#fff; line-height:1.8; text-align:center; backdrop-filter:blur(6px); box-shadow:0 10px 28px rgba(0,0,0,.28); }
        .product-panel { flex:1; background:var(--panel-bg); border-radius:16px; box-shadow:0 15px 30px rgba(0,0,0,.05); padding:20px; display:flex; flex-direction:column; gap:16px; border:1px solid #e2e8f0; }
        .card { border:1px solid #e2e8f0; border-radius:12px; padding:16px; background:#fff; }
        .card h3 { margin:0 0 12px; font-size:15px; }
        .card p, .card li { margin:0; line-height:1.7; color:#334155; }
        .card ul { margin:0; padding-left:20px; display:grid; gap:8px; }
        .empty-state { color:#94a3b8; font-size:14px; line-height:1.8; text-align:center; padding:20px 8px; }
        .product-img { width:100%; max-height:260px; object-fit:cover; border-radius:10px; display:block; margin-bottom:12px; }
        .speech-box { min-height:88px; padding:14px; border-radius:12px; background:#f8fafc; color:#1e293b; line-height:1.8; }
        .log-list { max-height:220px; overflow:auto; display:grid; gap:8px; }
        .log-item { padding:10px 12px; border-radius:10px; background:#f8fafc; color:#475569; font-size:12px; line-height:1.6; }
        .customer-interaction { margin-top:25px; width:100%; max-width:1100px; display:flex; gap:15px; }
        .chat-input { flex:1; padding:15px 20px; border:1px solid #e2e8f0; border-radius:50px; box-shadow:0 10px 20px rgba(0,0,0,.05); font-size:15px; outline:none; }
        .btn-speak { padding:0 30px; background:var(--brand-color); color:#fff; border:none; border-radius:50px; cursor:pointer; font-weight:700; box-shadow:0 10px 20px rgba(15,118,110,.25); }
        .btn-speak:disabled { background:#cbd5e1; box-shadow:none; cursor:not-allowed; }
        .btn-stop { padding:0 26px; background:#fff; color:#475569; border:1px solid #e2e8f0; border-radius:50px; cursor:pointer; font-weight:700; }
        .mock-actions { margin-top:15px; display:flex; flex-wrap:wrap; gap:10px; width:100%; max-width:1100px; }
        .mock-btn { padding:8px 16px; font-size:12px; background:#e2e8f0; border:none; border-radius:6px; cursor:pointer; color:#475569; }
        @media (max-width:980px) {
            .config-bar, .retail-workspace, .customer-interaction { display:grid; }
            .stage-panel { width:min(100%,420px); height:auto; aspect-ratio:9 / 16; margin:0 auto; }
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>AI 业务导办屏</h1>
        <span>星云虚拟人演示</span>
    </div>

    <div class="config-bar">
        <input type="text" id="inp-appid" placeholder="输入平台分配的 App ID">
        <input type="password" id="inp-secret" placeholder="输入对应的 App Secret">
        <input type="text" id="inp-gateway" value="https://nebula-agent.xingyun3d.com/user/v1/ttsa/session" placeholder="输入网关地址">
        <button class="btn-init" id="btn-init" onclick="startSystem()">连接虚拟人</button>
    </div>

    <div class="retail-workspace">
        <div class="stage-panel">
            <div class="status-badge">
                <div class="dot" id="sys-dot"></div>
                <span id="sys-status">系统未连接</span>
            </div>
            <div class="avatar-layer">
                <div id="sdk"></div>
            </div>
            <div class="stage-subtitle">
                <span id="stage-subtitle"></span>
            </div>
        </div>

        <div class="product-panel">
            <div class="card" id="business-card">
                <div class="empty-state">连接成功后,这里会显示窗口、路线、材料清单或业务图片。</div>
            </div>
            <div class="card">
                <h3>当前话术</h3>
                <div id="speech-box" class="speech-box">数字人当前没有播报内容。</div>
            </div>
            <div class="card">
                <h3>连接日志</h3>
                <div id="log-list" class="log-list"></div>
            </div>
        </div>
    </div>

    <div class="customer-interaction">
        <input type="text" id="tts-input" class="chat-input" placeholder="请输入导办问题,例如:医保报销需要什么材料?" value="欢迎来到星云导办屏演示。">
        <button class="btn-speak" id="btn-speak" onclick="handleGuideAsk()" disabled>发送导办问题</button>
        <button class="btn-stop" onclick="interruptSpeech()">打断播报</button>
    </div>

    <div class="mock-actions">
        <button class="mock-btn" onclick="fillQuestion('居住证去哪个窗口办理?')">居住证窗口</button>
        <button class="mock-btn" onclick="fillQuestion('医保报销需要什么材料?')">医保材料</button>
        <button class="mock-btn" onclick="fillQuestion('门诊挂号在哪里?')">门诊挂号</button>
        <button class="mock-btn" onclick="fillQuestion('洗手间怎么走?')">洗手间路线</button>
        <button class="mock-btn" onclick="fillQuestion('我要转人工服务')">转人工</button>
        <button class="mock-btn" onclick="clearBusinessCard()">清空业务卡片</button>
    </div>

    <script>
        const knowledgeBase = {
            services: [
                { name:'居住证办理', aliases:['居住证','居住证办理'], window:'二楼3号窗口', route:'从大厅右侧电梯上二楼,出电梯左转直行约20米即可到达。', materials:['身份证原件','居住证明','近期一寸照片2张'], time:'工作日09:00-17:00', link:'https://example.com/guide/residence-permit' },
                { name:'医保报销', aliases:['医保报销','报销'], window:'二楼5号窗口', route:'从大厅中央电梯上二楼,出电梯右转,第一个服务区即为5号窗口。', materials:['身份证','医保卡','发票原件','费用清单','出院小结或门诊病历'], time:'工作日08:30-16:30', link:'https://example.com/guide/medical-reimbursement' },
                { name:'门诊挂号', aliases:['挂号','门诊挂号','看病挂号'], window:'一楼自助机和人工挂号台', route:'进入门诊大厅后直走10米,自助机在右侧,人工挂号窗口在左侧。', materials:['身份证或医保卡'], time:'每日07:30-17:30', link:'https://example.com/guide/outpatient-registration' }
            ],
            facilities: [{ name:'洗手间', aliases:['洗手间','卫生间','厕所'], location:'一楼东侧走廊尽头', route:'沿右侧走廊直行约30米,看到饮水区后继续前行即可到达。' }],
            handoff: { location:'大厅中央咨询区', route:'请从导办屏正前方直行12米,到中央咨询区找工作人员。', time:'工作日08:30-17:30', link:'https://example.com/service/handoff' }
        };

        let avatar = null;
        let isSpeaking = false;
        let pendingAnswer = '';
        const $ = (id) => document.getElementById(id);
        localStorage.removeItem('inp-appid');
        localStorage.removeItem('inp-secret');
        if (localStorage.getItem('inp-gateway')) $('inp-gateway').value = localStorage.getItem('inp-gateway');

        function escapeHtml(value) { return String(value).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", '''); }
        function stringify(value) { return typeof value === 'string' ? value : JSON.stringify(value); }
        function appendLog(type, message) { const item = document.createElement('div'); item.className = 'log-item'; item.innerHTML = <strong>${escapeHtml(type)}</strong> ${escapeHtml(stringify(message))}; $('log-list').prepend(item); while ($('log-list').children.length > 10) $('log-list').lastElementChild.remove(); }
        function updateStatus(state, text) {
            $('sys-status').innerText = text;
            if (state === 'loading') { $('sys-dot').style.background = '#f59e0b'; $('sys-dot').classList.remove('active'); }
            else if (state === 'ready') { $('sys-dot').style.background = '#10b981'; $('sys-dot').classList.add('active'); }
            else { $('sys-dot').style.background = '#ef4444'; $('sys-dot').classList.remove('active'); }
        }
        function showStageSubtitle(text) {
            $('stage-subtitle').textContent = text;
            $('stage-subtitle').parentElement.classList.add('show');
        }
        function hideStageSubtitle() {
            $('stage-subtitle').textContent = '';
            $('stage-subtitle').parentElement.classList.remove('show');
        }
        function setSpeechText(text) {
            $('speech-box').textContent = text || '数字人当前没有播报内容。';
        }
        function clearBusinessCard() { $('business-card').innerHTML = '<div class="empty-state">业务卡片已清空。</div>'; }
        function fillQuestion(text) { $('tts-input').value = text; handleGuideAsk(); }
        function renderBusinessCard(title, lines, list, image) {
            const imageHtml = image ? `<img src="${escapeHtml(image)}" class="product-img" alt="业务图片">: '';             const linesHtml = (lines || []).map((line) =><p>${escapeHtml(line)}</p>`).join('');
            const listHtml = list && list.length ? `<ul>${list.map((item) => <li>${escapeHtml(item)}</li>).join('')}</ul>: '';             $('business-card').innerHTML =<div class="card"><h3>${escapeHtml(title)}</h3>${imageHtml}${linesHtml}${listHtml}</div>;         }         function parseGuideQuestion(question) {             if (['人工','工作人员','客服','不会操作','投诉'].some((item) => question.includes(item))) return { title:'人工服务', answer:好的,我已为您切换人工服务。总服务台位于${knowledgeBase.handoff.location},${knowledgeBase.handoff.route}, lines:[knowledgeBase.handoff.location, knowledgeBase.handoff.time, knowledgeBase.handoff.route, knowledgeBase.handoff.link] };             const facility = knowledgeBase.facilities.find((item) => item.aliases.some((alias) => question.includes(alias)));             if (facility) return { title:facility.name, answer:${facility.name}在${facility.location}。${facility.route}`, lines:[facility.location, facility.route] };
            const service = knowledgeBase.services.find((item) => item.aliases.some((alias) => question.includes(alias)));
            if (!service) return { title:'可参考提问', answer:'我暂时没有找到完全匹配的业务。你可以换一种问法,或者直接说转人工服务。', lines:['居住证去哪个窗口办理?','医保报销需要什么材料?','门诊挂号在哪里?'] };
            if (['材料','证件','带什么','需要什么','清单'].some((item) => question.includes(item))) return { title:`${service.name}材料清单, answer:${service.name}需要准备${service.materials.join('、')}。办理地点在${service.window}。`, lines:[service.window, service.time, service.link], list:service.materials };
            if (['几点','工作时间','营业时间','什么时候','下班','开门'].some((item) => question.includes(item))) return { title:`${service.name}办理时间, answer:${service.name}的办理时间是${service.time},办理地点在${service.window}。`, lines:[service.time, service.window, service.link] };
            return { title:service.name, answer:`${service.name}在${service.window}办理。${service.route}`, lines:[service.window, service.route, service.link] };
        }

        async function startSystem() {
            const appId = $('inp-appid').value.trim();
            const appSecret = $('inp-secret').value.trim();
            const gateway = $('inp-gateway').value.trim();
            if (!appId || !appSecret || !gateway) return alert('请完整填写授权凭证');
            localStorage.setItem('inp-gateway', $('inp-gateway').value.trim());
            if (avatar) try { avatar.destroy(); } catch {}
            updateStatus('loading', '请求资源分配...');
            $('btn-init').disabled = true;
            appendLog('初始化', '开始创建虚拟人');

            avatar = new XmovAvatar({
                containerId:'#sdk',
                appId:appId,
                appSecret:appSecret,
                gatewayServer:gateway,
                hardwareAcceleration:'prefer-hardware',
                proxyWidget:{
                    subtitle_on:(data) => {
                        const text = data && data.text ? data.text : '';
                        setSpeechText(text);
                        if (text) showStageSubtitle(text);
                    },
                    subtitle_off:() => hideStageSubtitle(),
                    widget_pic:(data) => data && data.image && renderBusinessCard('图片卡片', ['来自数字人下发的图片内容'], null, data.image),
                    widget_slideshow:(data) => data && data.url && renderBusinessCard('轮播卡片', [当前页码:${data.page || '?'}], null, data.url)
                },
                onStatusChange:(status) => appendLog('SDK状态', status),
                onMessage:(message) => appendLog('消息', message),
                onVoiceStateChange:(status) => {
                    const state = typeof status === 'string' ? status : (status && (status.state || status.status || status.data)) || '';
                    isSpeaking = state === 'start' || state === 'voice_start';
                    if (state === 'end' || state === 'idle' || state === 'voice_end') {
                        isSpeaking = false;
                        hideStageSubtitle();
                        if (pendingAnswer) {
                            const next = pendingAnswer;
                            pendingAnswer = '';
                            avatar.speak(next, true, true);
                        }
                    }
                },
                enableLogger:false
            });

            try {
                await avatar.init({ onDownloadProgress:(p) => updateStatus('loading', 加载具身模型: ${p}%) });
                updateStatus('ready', '导办员已上线');
                $('btn-speak').disabled = false;
                appendLog('初始化', '连接成功');
                avatar.changeAvatarVisible && avatar.changeAvatarVisible(true);
                avatar.setVolume && avatar.setVolume(1);
                avatar.speak(' ', true, true);
                setTimeout(() => { try { avatar.interactiveidle(); } catch {} }, 400);
            } catch (err) {
                console.error(err);
                updateStatus('error', 启动失败:${err.message || err.code || '未知错误'});
                appendLog('错误', err.message || err.code || err);
            } finally {
                $('btn-init').disabled = false;
            }
        }

        async function handleGuideAsk() {
            const question = $('tts-input').value.trim();
            if (!avatar || !question) return;
            const result = parseGuideQuestion(question);
            renderBusinessCard(result.title, result.lines, result.list, result.image);
            setSpeechText(result.answer);
            hideStageSubtitle();
            if (isSpeaking) {
                pendingAnswer = result.answer;
                avatar.interactiveidle();
                return;
            }
            avatar.listen();
            setTimeout(() => {
                avatar.think();
                avatar.speak(result.answer, true, true);
            }, 180);
        }

        function interruptSpeech() {
            if (!avatar) return;
            pendingAnswer = '';
            avatar.interactiveidle();
            appendLog('手动', '已打断当前播报');
        }

        window.addEventListener('beforeunload', () => { if (avatar) avatar.destroy(); });
    </script>
</body>
</html>

最终展示效果:

image.png

五、开发方式:它不是一个展示页面,而是一套完整业务系统

从开发角度看,AI 业务导办屏并不是“接个数字人 SDK”这么简单,而是一套完整的业务系统。

前端终端负责接入星云 SDK,完成角色加载、状态切换和界面联动。像 Idle、Listen、Speak 这样的状态,本质上就是在为连续交互场景服务。再配合图片、字幕、路线卡片等 Widget 能力,数字人的表达就能和业务信息同步出现。

中间层负责语音识别、大模型理解、RAG 检索和规则决策。这里的重点不是让大模型自由发挥,而是让它在明确业务边界内组织答案。大模型负责把话说清楚,知识库和规则系统负责保证答案可信、流程正确。

业务层则连接真实系统,比如窗口信息、预约接口、路线服务、叫号系统和工单系统。最终,用户看到的不是几个技术模块的堆叠,而是一套连贯的服务流程。

也就是说,开发路径其实很清晰:前端接表达层,中间层接理解与决策,业务层接真实系统,最终再由星云把结果稳定地表达出来并推动执行闭环。

这也是为什么我更愿意把星云理解成产品化方案,而不只是一个数字人能力组件。它补上的不是“更像真人”的那一层,而是 AI 从思考走向表达、从表达走向执行的那一层关键基础设施。

结语

今天再看数字人,真正值得讨论的问题已经不是“像不像真人”,而是“能不能像一个真正的服务者那样工作”。传统数字人的短板,集中在延迟高、不能打断、高成本、弱网卡顿,这些问题决定了它很难大规模进入真实业务现场。

星云给出的解法,则是通过“自研的文生3D多模态大模型,进行AI端渲。云端下发轻量指令,终端本地实时渲染”的方式,把交互链路做轻,把响应速度做快,把部署成本做低,并进一步补齐表达层和执行层能力。它不仅是在做数字人,更是在做 AI 屏幕操作系统,在做具身智能表达层基础设施。

当“感知 → 理解 → 决策 → 表达 → 执行”真正连成闭环,屏幕里的 AI 才不再只是展示,而开始真正工作。这也是我理解的,星云最值得被重新认识的地方。

魔珐星云体验链接xingyun3d.com?utm_campaign=daily&utm_source=jixinghuiKoc45