「微醺主厨(The Culinary Studio)」——全双工语音驱动的具身交互智能先锋料理与调酒灵感共创工作台
「微醺主厨(The Culinary Studio)」——全双工语音驱动的具身交互智能先锋料理与调酒灵感共创工作台
7-6微熏主厨数字人-视频演示
一、项目背景与痛点
传统的菜谱 App 或调酒教程大多采用"图文/视频单向输出"模式——用户必须反复放下手中的食材去触控屏幕翻页、暂停、回看。在真实的烹饪场景中,双手沾满面粉或油脂时,这种交互方式几乎不可用。
为了打破"机械操作屏幕"的壁垒,本文分享一个沉浸式"数字主厨工作台"的开发实践。具身交互智能数字人化身为先锋料理主厨兼调酒师 Marc(马克),用户通过自然语音与其即兴共创料理配方、定制鸡尾酒,并在烹饪过程中获得实时、免手控的步骤指导与风味微调建议。系统支持全双工实时交互——当 Marc 正在讲解一道菜的收汁技巧时,用户可以随时喊道:"等一下,我这里没有迷迭香了,可以用什么代替?"系统立即切断播报,无缝切入新一轮对话。
作为一名代码基础较弱的开发者,本次开发全程通过 AI Coding 工具辅助,结合魔珐星云数字人 LiteSDK 的 API,几乎由 AI 辅助完成了全部核心链路。本文将从技术架构、全双工状态机、回声消除以及主题化 UI 设计四个维度,分享整个开发流程与踩坑经验。
二、核心技术亮点与架构
本系统在前端和交互控流层主要实现了以下几个技术要点:
-
四态状态机管理:系统维护 idle(待命)、listening(聆听)、processing(萃取)、speaking(呈现)四种核心交互状态,配合"风味平衡度"进度条与"五味指示器"(酸/甜/苦/咸/鲜)实现状态可视化。
-
低延迟全双工打断机制:Web Speech API 持续监听 + 1.2s 静音 VAD 判定,一旦在 speaking 状态下检测到用户有效语音,立即调用 SDK 的
interactiveidle()打断播报,状态机无缝切入新一轮倾听-推理循环。 -
LCS 回声消除:数字人播报的文本会被麦克风二次捕获。系统通过最长公共子序列(LCS)相似度算法,阈值 >0.55 的文本自动判定为回声并过滤,避免"自己打断自己"。
-
火山方舟 Response API 多轮对话:采用
stream: false+thinking: {type: 'disabled'}关闭流式与深度思考,通过previous_response_id实现原生多轮上下文衔接,确保响应效率。 -
零配置感知加载:页面通过
fetch('config.json')异步读取密钥,前端无任何配置输入框,缺失时以烹饪术语温柔提示。
三、核心功能与交互效果展示
1. 米其林后厨沉浸式视觉
-
蒸汽粒子系统:Canvas 绘制 35 颗微粒从底部缓缓上升、左右摇摆、渐隐消散,模拟分子料理干冰或锅气蒸腾。
-
火焰麦克风指示:底部状态指示为一簇 CSS 火焰造型,监听时点亮摇曳,静默时熄灭为灰色轮廓。
-
五味指示器:酸/甜/苦/咸/鲜五个色点随数字人播报随机点亮 2-3 味,呈现当前"风味轮廓"。
-
灵感便签轮播:视窗左下角每 9 秒淡入一条主厨手记(“盐不是调味,是放大镜”),斜体衬线字体,像粉笔写在黑板上。
-
服务时钟:左上角
SERVICE 21:37样式,致敬真实后厨墙上的服务计时器。 -
出菜单序号:每条对话带
TICKET #001编号,致敬后厨出菜口的 ticket 系统。

四、全双工打断的底层控制流实现
全双工交互的核心难点在于状态流转的时序控制与回声消除。以下是系统在检测到用户插话时的完整控流逻辑:
// 核心逻辑:全双工打断 + 回声过滤
function handleUserSpeech(text) {
if (!text || isProcessing) return;
// 1. LCS 回声过滤:数字人播报被麦克风二次捕获时自动丢弃
if (isLikelyEcho(text)) return; // lcsSimilarity > 0.55 判定为回声
// 2. 全双工打断:数字人正在说话时用户插话
if (appState === 'speaking' && avatarInstance) {
avatarInstance.interactiveidle(); // SDK 打断,返回待机
lastSpokenText = ''; // 清空回声参照
}
// 3. 状态切换至推理,投递大模型
setState('processing');
appendMsg('user', text);
processUserInput(text); // 火山方舟 Response API
}
VAD 静音判定(Web Speech API):
// continuous 模式下,interim 结果触发静音计时器
recognition.onresult = (event) => {
// ...提取 interim / final 文本
if (interim) {
interimBuffer = interim;
clearTimeout(silenceTimer);
silenceTimer = setTimeout(() => {
// 1.2s 无新语音 → 视为用户说完
handleUserSpeech(interimBuffer.trim());
}, 1200);
}
};
完整交互生命周期:
-
用户开口 -> Web Speech API 捕获 interim 结果,VAD 计时器启动。
-
静音 1.2s -> 判定说完,触发
handleUserSpeech。 -
回声过滤 -> LCS 相似度 >0.55 则丢弃(防止播报被误识别为用户输入)。
-
打断判定 -> 若当前为 speaking 状态,调用
interactiveidle()中止播报。 -
大模型推理 -> 火山方舟 Response API(stream:false),
previous_response_id衔接多轮。 -
数字人播报 ->
speak(text, true, true)非流式完整句,驱动唇形同步。 -
播报结束 ->
onVoiceStateChange('end')回调,自动恢复监听,进入循环。
五、开发踩坑记录与解决方案
1. SDK 初始化是两步式,没有 onReady 回调
-
现象:点击"点燃炉火"后永远卡在"点燃中",无任何响应。
-
原因:魔珐星云 LiteSDK 的初始化是
new XmovAvatar({containerId, appId, ...})+await instance.init({initModel:'normal'})两步,不存在onReady回调。且容器参数是 CSS 选择器字符串'#sdk',不是 DOM 元素。 -
解决:构造后必须
await init(),在 Promise resolve 后再执行后续逻辑(启动 ASR、切换 UI 状态)。
2. speak 方法签名与打断方法命名
-
现象:调用
speak(text)无声音输出;interactiveIdle()报 undefined。 -
原因:非流式播报必须传
speak(text, true, true)标记 is_start 和 is_end;打断方法全小写interactiveidle()。 -
解决:严格对照 SDK 文档的方法签名,注意大小写。
3. 回声自激:数字人打断自己
-
现象:Marc 播报时突然自我打断,进入新一轮"倾听"。
-
原因:扬声器播出的 TTS 音频被麦克风捕获,ASR 转写后与原文高度相似。
-
解决:记录每次
lastSpokenText,用 LCS 相似度 >0.55 阈值过滤回声文本。
4. 编程小白如何利用 AI 工具攻克复杂 SDK?
- 技巧:不要把整个 SDK 文档直接丢给 AI。应该将 SDK 提供的官方 Demo 代码和核心 API 说明(如
speak入参、interactiveidle签名、onVoiceStateChange回调)提取成 Context 喂给 AI,让其定向生成状态切换逻辑。
六、总结与后续演进方向
通过本次技术原型的搭建,可以看出"AI Coding 辅助 + 魔珐星云 LiteSDK + 火山方舟 Response API"已经可以让非资深研发快速搭建出具备全双工语音交互能力的沉浸式数字人应用。四态状态机设计简洁灵活,极易扩展到其他垂直领域(健身教练、外语陪练、心理咨询等)。
下一步的优化迭代方向:
-
RAG 食谱知识库挂载:接入私有菜谱与调酒配方库,提升 Marc 回答的专业度与配方准确性。
-
多语种风味词汇:结合用户语言偏好,支持中/英/法/日料理术语的自然切换。
-
情感语气识别:通过 Web Audio API 分析用户语速与音调,判断烹饪紧迫度,动态调整 Marc 的回复节奏与详略。
-
食材视觉识别:接入摄像头 + 多模态模型,用户举起食材即可识别并纳入配方推荐。
数字人SDK部分参考官方文档——https://xingyun3d.com/?utm_campaign=daily&utm_source=juzhen
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)