这一版按纯技术口径重写去掉茶空间品牌名和产品叙事“我们做的一盏”“开分店/规模化”数字人只称老师删掉平台宣传语、utm 官网链接和评论区钩子四段代码全部保留注释里的品牌字样也一并中性化。刷了十几个泡茶视频、记了两页笔记真上手还是抓瞎——问题不在视频不够多而在视频不会看你不知道你此刻水温是 98 度还是 82 度没看见你出汤早了三秒也不会因为你插一句这泡为什么苦就停下来看着你讲。可行的做法是把教学做成一个持续交互循环持续感知看注水、读水温→ 理解这泡该到多少度、是不是急了→ 决策该夸、该拦还是该演示→ 表达与行动提醒、示范、记下口味且感知与表达并行、每约 100ms 转一圈、随时可被打断。下面分四块拆实现交互循环、冲泡知识图谱、个性化开场、口播驱动示范。① 持续交互循环——感知与行动并行常驻// 茶道老师的持续交互循环泡一壶茶能转几十圈 const loop { state: 落座待机, tick() { const seen 席面.感知(); // 摄像头看动作 数显杯读水温 麦克风听说话 const plan 智脑.决策(seen, 茶档); // 结合怕苦/第几冲决定下一步 switch (plan.意图) { case 纠正: 席面.开口(plan.话术); break; // 边说边继续 tick随时能打断 case 示范: 席面.演示(plan.手法); break; // SDK 驱动手势眼神 case 记录: 茶档.写入(seen.口味反馈); break; // 记住皱眉还是点头 default: /* 等待沉默时也在看不催不重开 */; } // 任一 tick 里只要 Barge-in 检测到插话立刻中断当前表达转入新一轮 }, }; setInterval(() loop.tick(), 100); // 每 100ms 转一圈直到够了不喝了② 把茶类→怎么泡做成知识图谱实时提醒就是拿它跟眼前读数做对照# 茶类冲泡知识图谱节选水温/投茶量/出汤秒数按茶类锚定 BREW_KG { 龙井: {水温: 82, 投茶量g: 3, 首泡出汤s: 20, 禁忌: 沸水直冲、闷泡}, 铁观音:{水温: 92, 投茶量g: 8, 首泡出汤s: 15, 禁忌: 水温不足则香不出}, 白毫银针:{水温:85, 投茶量g: 5, 首泡出汤s: 30, 禁忌: 搅动、坐杯过久}, 岩茶: {水温: 98, 投茶量g: 8, 首泡出汤s: 8, 禁忌: 出水要快闷则苦涩}, } def 纠正(tea, now_temp, steep_seconds): kg BREW_KG[tea] if now_temp kg[水温] 3: return (water_hot, f{tea}别用沸水直冲{kg[水温]}度上下最稳再等半口气。) if now_temp kg[水温] - 5: return (water_cold, f水温掉到{now_temp}度了{tea}香出不来续点热。) if steep_seconds kg[首泡出汤s] 5: return (over_steep, f这泡坐杯{steep_seconds}秒了该放了再闷就苦。) return (ok, None)③ 个性化开场——记的不只是这一泡还有你这个人的口味档案def 开场(tea, profile): tips [] if profile.get(怕苦): tips.append(知道你怕苦今儿出汤我帮你盯着秒。) if profile.get(口味) 清香: tips.append(f你爱清香型这泡{tea}水温我帮你压半度别把香气烫散了。) return 落座啦。 .join(t for t in tips) 我看着你泡。 # profile {怕苦: True, 口味: 清香}④ 括号里的动作不念出来而是由 SDK 依据语义 角色状态把口播和手势一起长出来function 示范高冲(tea, temp) { const ssml speak看好了${tea}讲究水线细。break time300ms/ 提壶压低手腕细水高冲就这样水温${temp}度正好。/speak; // is_start 只在整段第一句传 trueis_end 只在最后一句传 true avatar.speak(ssml, /*is_start*/ true, /*is_end*/ true, { action: PourHigh }); }几个踩过的实现要点麦克风常开 VAD 收口 本体声音抑制避免老师自己的口播被录回去当成用户输入、开始自己跟自己讲茶分段演示要区分段间空隙和真正收尾只在最后一句才传结束标记否则每个动作之间会莫名收势、手势全乱3D 形象走端侧渲染画面在本地设备画、网络只传轻量参数弱网也能稳稳接话。—