一、项目简介

解决什么问题

暑假在家期间打开手机 App 给孩子用 AI,孩子很容易滑走去看动画和游戏;一台普通智能音箱又看不见、没性格。家长真正想要的是:让孩子自由地和 AI 对话,但既不接触娱乐化内容,又不需要操作复杂的界面。

AR 眼镜佩戴即用、屏幕信息由我们完全控制、交互靠语音——天然适合做成会说话的伙伴。

目标用户

  • 主力用户:3~10 岁的小朋友;

二、场景与用户意图

场景一 · 睡前闲聊

小朋友戴着眼镜说说话,然后发起语音:恐龙是怎么灭绝的呀?应用:

  1. ASR 识别文字;

  2. 交给当前角色(恐龙科普)的专属会话流式生成;

  3. 回复屏幕上显示 +朗读同时反馈给小朋友。

场景二 · 语音换人

小朋友说我要切换太空科普或者换成安全科普。应用在闲聊优先分支命中口令词 + 角色别名:

  • 重建议会为太空科普/安全科普;

  • 界面左侧高亮随之移动到对应头像;

  • 文字 + 语音双重确认已切换太空科普主题。

意图承接要点:口令(换成/选/我要/找…)+ 名字(或别名如太空或者换成安全)必须同时命中才切换,避免孩子闲聊说那个恐龙好可怜也触发换人。

场景三 · 拿起东西问

孩子举起一个玩具:帮我看看这是什么?,应用检测到相机权限后拍照,把图片送往多模态 LLM,用当前角色口吻介绍眼前物体(这是一辆红色消防车,消防车会去救火哦)。

三、方案设计

3.1 定义角色

用一张表描述所有角色(PROFILES):

字段

说明

示例

name

界面展示名

科普小助手

emoji

角色头像

🌸

voice

官方音色 ID

female-tianmei

system

角色 Prompt(人设)

科普小助手

所有角色的 system 都前置注入统一安全护栏 SAFETY_RULES:

  • 不展开暴力/危险/色情/违法内容,温和转移话题;

  • 不询问姓名、住址、电话、学校等隐私;

  • 回答简短、口语化、童趣、适合朗读。

关键决策:切换角色 = 重建会话(session.destroy() 后再创建),而不是只改界面文案。 这样每个伙伴不认识上一个伙伴说过的话,记忆不串台;新角色第一次开口即自我介绍。

3.2 页面与卡片

  • 左:角色区,一行 2 个,7 个角色占 4 行;

  • 右:聊天区,固定高度 + 单条分页:每页只显示最新 1 条消息,旧消息折叠,让眼镜屏永远只呈现一句对话;

  • 底:操作栏,说话 / 重置两个主操作常驻。

3.3 状态流转与交互模型

onLoad → refreshAvailability(检测 ASR / TTS / 相机权限)
└→ 默认聚焦「说话」→ 确定即说话
├─ 话 → 企ASR → 文本意图路由:
│── 命中换人 → doSwitchProfile(重建会话 + 双通道确认)
│── 命中拍照 → doPhotoTurn(拍照 → 多模态识物)
│ ── 闲聊 → promptStreaming → 文字 + TTS
└─── 重置 → 清空会话与消息

四、AIUI 实现

4.1 项目结构

aiui-kids-companion/
├── AGENTS.md
├── app.json
└── pages/index/
└── index.ink

4.2 语音输入输出

ASR 采用 AIUI 的识别能力;输出走官方 Web 标准 speechSynthesis:

const u = new SpeechSynthesisUtterance(text);
u.voice = this.voice; // 角色音色 ID
u.lang = ‘zh-CN’;
speechSynthesis.cancel(); 
speechSynthesis.speak(u, ‘immediate’);

4.3 语音换角色

const intents = /(换成|换|选|我要|来一个|喊|叫|找)/.test(text);const key = intents ? this.matchAlias(PROFILE_ALIASES, text) : null;
if (key && key !== this.data.currentProfileKey) 
{this.doSwitchProfile(key, true); 

4.4 拍照识物

const camera = wx.media.createCameraContext();
const photo = await camera.takePhoto({ quality: ‘high’, enableSystemPreview: false });
const prompt = 小朋友拍了一张照片,请用儿童友好的语气,简单介绍照片里是什么,一两句话就够了。;
const answer = await session.prompt(prompt, { payload: [dataUrl] });

4.5 长消息折叠

AR 屏固定高度,AI 也可能输出超长回复。数据层做折叠并配展开入口:

if ((m.content || ‘’).length > FOLD_CHARS) {
return { …m, collapsed: true, foldText: m.content.slice(0, FOLD_CHARS - 3) + ‘……’ };
}

五、交互与体验

  • 所有反馈都带声音:焦点移动、角色切换、AI 回复全部语音同步,孩子不用盯着屏幕也能操作;

  • 所见即所听:屏幕上的一行短文本 = 朗读内容,避免屏幕一句话、语音一大段;

  • 常驻两个按钮:底部只有说话/重置,恢复的手段也只有一个——重置;

  • 确认闭环:每次切换成功必回我变成某角色啦,消除到底换没换人的不确定性。

六、调试与验证

6.1 Craft

在 AIUI 工作台重点验证三条链路:

  1. 语音闭环:ASR → LLM 流式 → TTS,用最长回复压测;

  2. 导航状态机:焦点在角色/说话/重置间越界跳转是否符合预期;

  3. 会话切换:连切两次角色,确认记忆不串台。

6.2 真机调试记录

现象

根因

解法

第二次语音播报没声

上一次 utterance 未结束

speak 前先 cancel(),单例引用播放

长回复撑破聊天框 / 压到底部按钮

真机 scroll-view 滚动(auto-scroll / scroll-top)行为不可靠

弃用屏内滚动,改为「分页 + 折叠」,从数据层保证放得下

聚焦切换后角色头像下文字消失

ink:for + 动态 class 组合的渲染异常

改显式模板节点逐个渲染

帮我看看回相机不可用

缺 AGENTS.md 相机权限

补 camera/microphone/network 声明

七、成果与复盘

成果展示

QQ20260911-164845_compressed

  • 可运行的 AIUI 智能体:7 角色语音聊天 + 语音换人 + 拍照识物 + 长消息折叠;

  • 稳定的导航状态机与语音优先交互模型;

  • 一套真机适配经验:固定、分页、折叠、显式、双通道确认。

后续迭代

  • 长消息折叠在看长文时需多次点开,后续可考虑「语音说展开第几条」;

  • 拍照识物依赖网络与相机权限,离线能力待补;

  • 后续方向:角色记忆持久化(“朋友档案”)、更多音色与英文、家长端内容看板。

更多推荐