在 Rokid 眼镜上从零造一个 AIUI 英语陪练:480×352 单绿屏上的沉浸式学习智能体

方向:开发经验 / 实战教程
项目:FlexiLingo —— 基于 Rokid Glasses + AIUI 框架的沉浸式英语学习智能体(v0.5.74,6 大页面 + AI 实战,已部署真机)


一、为什么在眼镜上学英语

通勤、排队、散步——这些碎片时间最不适合掏出手机(屏幕太亮、容易分心、单手操作难)。而 AR 眼镜天生适合"把内容放在眼前、把双手解放出来"。问题是:眼镜上做"学习"产品,交互和手机完全不同——没有触摸屏、没有大键盘、单色低分辨率屏幕,一切都要靠镜腿滑动 + 点按 + 语音

FlexiLingo 就是冲着这个命题来的:在 Rokid 眼镜上做一个"安静、准确"的英语陪练——教材文本常驻眼前,AI 只在用户请求领读、解释、反馈时才开口。核心闭环:

书库 → 课程列表 → 全文 Markdown 铺屏 → AI 从头领读
→ 逐句跟读(ASR 评分)→ 逐词 X 光反馈 → 生词入袋 → 艾宾浩斯复习

外加一个多模态的 AI 实战:拍照识物 → 视觉模型生成英文句 → 三轮英文 Small Talk。

二、技术架构:一次说清

  • 眼镜端:AIUI .aix 应用(Ink 框架,QuickJS 运行时)。7 个单文件页面(home / library / reader / review / vocab / settings / practice),每个页面 = 模板 + 逻辑 + 样式三合一。
  • 云端:Node 学习服务(教材、进度、SM2 复习调度、逐词评分、词卡释义)+ Python 网关(设备身份、词汇口袋)+ Rust 辅助 API,nginx 统一入口。
  • 数据:新概念英语 1-4 册 + 小王子等 8 本书,每课按句子切分、带词频与练习题。

三、真机踩坑实录(本文最值钱的部分)

AIUI 的 Ink 框架在真机上有一批"文档里没有、跑起来才知道"的硬约束。以下每一条都对应一次线上事故:

1. 真实视口是 480×352,不是 480×640

很多方案文档按 480×640 设计,真机一跑全塌。一切布局必须按 480×352 固定坐标 + 预折行 + 固定行高,永远不要依赖 Ink 自动换行。

2. 同页多个 ink:for 会共享 item 绑定 → 列表黑屏

真机返回课程列表时,列表区域整片黑掉——因为同一页面里的多个循环列表共享了 item 变量。解法:所有列表改用固定静态行字段courseRow0..5chapterRow0..5bookRow0..5、20 个词槽……),由 JS 预计算每一行的类名与文本。validator 里直接写死红线:模板禁止出现 ink:for

3. 真机忽略 white-space: nowraptext-overflow: ellipsis

长文本会换行撑破固定高度 → 字体重叠。所有正文必须在 JS 里按像素宽度预折行(中文按标点断行、英文按空格断行),固定行高 + overflow:hidden

4. 镜腿"一次滑动"会先发 GlobalHook,50~120ms 后才发方向键

如果直接把 GlobalHook 当点按处理,一次滑动会同时触发"移动 + 确认"。全站统一契约:GlobalHook 挂起约 180ms,方向键到达即取消确认;重复 GlobalHook 一律视为回声抑制。六页共用一套输入防抖,仿真脚本逐页验证。

5. 点头/摇头被自然头动误触,0.5.42 果断停用

最初用姿态传感器做点头=确认、摇头=返回,真机实测自然头动(低头看路、转头)频繁误触发,用户直接投诉"完全不受我控制"。最终决策:点头/摇头整体停用,镜腿滑动 + 点按 + 语音成为唯一输入链路,代码保留但用开关整体关闭。这是产品克制力的一个例子:不是"能不能做",而是"该不该用"。

6. ASR 是系统单会话,且中文同音字防不胜防

  • 控制指令只在"唤醒乐奇"或 2.5~12 秒短窗口内监听,绝不常驻。
  • 真机把"生词本"听成过:笙资本 / 生瓷本 / 生字本 / 生死的 / 生子本 / 生辞本 / 单词本……同音容错表逐条从真机日志里捞出来补进路由,并规定"收藏优先于打开"。
  • 跟读 ASR 会在自然停顿后把半句标成 final:按目标句词数做完整度门槛,不足就续听拼接,禁止把半句或中文误转写直接送去评分;连续三次无结果依次"重听 → 重新示范 → 自动跳过"。

7. 设备端 LLM 的 JSON 输出不可靠,词卡释义必须"可验证"

宿主模型输出词卡 JSON 时英文释义恒为空 → 曾经把占位符 Meaning used in this lesson context. 当释义展示,被用户批"解释全是错的"。修复:词卡释义只接受服务端 /v1/vocab/define 的"课文来源校验"结果——服务端先验证原句确实属于收藏时的教材章节且包含目标词,再生成短英文释义与中文辅助;验证不过就明确显示"暂未取得可靠释义",绝不展示猜测。

8. 多模态 AI 实战的生命周期(两次原生 SIGSEGV 换来的教训)

拍照识物 → 视觉模型 → 三轮英文对话,看起来简单,真机上踩了两回崩溃:

  • 宿主收到 ASR final 后已自行结束会话,页面不得再 abort()
  • TTS 兜底结束后不得在同一 tick 里启动 ASR
  • 每个状态切换(Camera→TTS、TTS→ASR、ASR→LLM、LLM 销毁→TTS)留 650ms 可取消稳定期;
  • 每个真实场景只允许一次多模态 create(),后续两轮 Small Talk 全部页面本地确定性完成,绝不重复建会话。

四、交互设计:把"世界级 App 的行为模型"翻译成单色绿

参考 TikTok 的"打开即内容"、Instagram Stories 的段落进度感、Duolingo 的即时反馈与连击、ELSA 的逐词着色——但全部眼镜化改造

  • 首页首屏 = "继续学习"主卡(书名 + 课程 + 句级分段进度),一次点按直达上次句子,功能入口降级为迷你宫格;
  • 阅读页顶部 12 段句级进度条(已读亮绿 / 当前亮框 / 未读暗绿),位置感一眼可得;
  • 评分反馈分级:90+ 一句 4 字内鼓励、80-89 快速推进、低分停句可"点按重听 / 右滑跳过",绝不静默前进;
  • 逐词三档着色 + 发音规则提示(th 咬舌 / ed 尾音 / r 卷舌……),并诚实标注"跟读完整度"而非"发音分";
  • 单绿屏颜色 token 化(主绿 #5dff8b、正文 #f4fff7、次级 #9cac9f……),焦点三重编码(2px 绿边 + 填充变亮 + ▸ 标记)。

五、工程质量:把"真机踩坑"写成契约

  • aiui/AGENTS.md 就是项目的行为宪法:版本递增、每条硬约束带版本号与真机证据,改代码前先读它;
  • npm test 三件套:服务端单测 + 网关 pytest + 结构红线校验 + 两条交互仿真(滑动全链路 12 条断言、六页按键链路);
  • 布局用像素取证:抽取真实 CSS 渲染 480×352 截图做行带分析,找重叠/越界;
  • 每版先过测试再打包,真机 logcat 关键日志点(flow 状态 / ASR 转写 / 词卡解析 / 口袋计数)齐全,出问题 10 分钟内定位。

六、部署与迭代的真实节奏

30+ 个版本迭代里,最有价值的几个"教训型修复":

  • 选书后直进第一课 → 改为先展示课程列表;
  • 部署流程里的 pm clear 会清 localStorage → deviceKey 重置 → 生词本数据变孤儿 → 全面移除,改为云端先行 + 索引 md5 精确同步;
  • “返回课程列表黑屏”(ink:for)→ 静态行;“目录全部重叠”(静态行丢基类)→ validator 红线补基类;
  • readyfollow 的英文自动跟读曾把"Continent 什么意思?"当朗读吞掉 → 提问词识别守卫。

每一版都来自用户 10 分钟内的真机反馈,修复后立即部署设备 + 云端,形成了"用户报障 → 拉日志 → 定位 → 修复 → 回归红线 → 部署"的快速闭环。

七、数据与现状

  • 版本 v0.5.74,7 页面,已部署 Rokid 眼镜真机 + 云端;
  • 8 本教材、数百课、逐句切分;
  • 艾宾浩斯复习(SM2 服务端调度)、逐词评分、词卡、AI 实战(拍照 + 三轮英语对话)全部在线;
  • 测试全绿:server + pytest(16) + validate + 两条链路仿真。

八、开源与未来

  • 仓库:github.com/wuzhongni/flexilingo(AIUI + Node server + Python gateway + Rust)
  • 路线:弱句自动入复习卡 → 连击/完成庆祝 → 剧场模式(分角色朗读)→ 学习统计(streak / 今日目标)

给想入坑 AIUI 开发的同学一句话:眼镜端的"少即是多"比手机端更极端——每个功能都要问自己"用户在走路时、单手时、目光漂移时,真的需要它吗?“把交互契约写进文档、把真机约束写进测试,这个项目才能从"能跑"走到"好用”。


本文所有真机问题均为实际线上事故,修复版本号可查 git 历史。欢迎交流:评论区留言或 GitHub Issue。

更多推荐