💻 程序员
我做了个端侧二次元 AI 伴侣:小蠢
音频
我做了个端侧二次元 AI 伴侣:小蠢
0:00/0:00
✦ ✦ ✦
接一个更强的云端 LLM 效果会好很多,任何 OpenAI 兼容接口都行(Ollama、LM Studio、vLLM 或云端 API)

我想试试虚拟人方向
市面上的数字虚拟人,我总觉得可以做得更好
- 传统的 Live2D 强烈依赖画师,动作也有限,而且我也不会做
- 很多虚拟人其实是生成好的视频,再换个嘴型
在体验过 Grok 里的 Ani 之后,我觉得 3D 方向的虚拟人不错,后来 Ani 从 Grok 下线,搬去了单独收费的 App
那就自己做一个吧,反正用 VRoid Studio 捏人也简单
一开始我就决定不要后端,模型、听写、动作、记忆全在浏览器里跑,部署就是 Cloudflare 上一个静态站,原因有两个:
- 想试试端侧模型到底能做到什么程度
- 二次元伴侣这类东西,大家多少有些不想给别人看的需求,涉及隐私,也可能涉及 NSFW 内容,数据留在自己设备上更安心
小蠢能做什么
从你发出一句话到她开口比划,要过三块:想(LLM)、说(TTS)、动(EMAGE)。用语音输入的话,前面再加一块听(STT)
除了 TTS,其他几块都在浏览器里跑,各自待在自己的 Worker 里,不抢渲染线程

想:WebLLM 跑在 WebGPU 上
- 理解你说的话,生成她的回复
- 默认 MiniCPM5 2B,显存不够或在手机上自动降到 Qwen2.5 0.5B
- 引擎跑在 Web Worker 里,逐 token 流式输出,多轮对话复用 KV Cache,后续轮次几乎不用等
- 小模型上下文一长就容易复读跑偏,所以短期只带最近 2 轮,长期信息存在 IndexedDB,拼进系统提示词
- 换成 OpenAI 兼容接口后,WebLLM 就不加载了,能省下 1~2 GB 显存
说:Edge-TTS 流式合成
- 把回复变成声音,这是全链路唯一要实时联网的一块
- LLM 边吐字边按标点切句,第 1 句的声音和动作一好就开口,后面的边念边准备
- 用我自己手写的 WebSocket 客户端,经 Cloudflare Workers 转发
- 下一句没到时,她会停在上一段动作的最后一个姿势,不会突然站直
动:EMAGE 全身手势
- 根据声音生成全身动作,让她边说边比划
- 音频喂给 Worker 里的 EMAGE,每 64 帧推理一个窗口,推完一段送一段
- 跑在 ONNX Runtime 的 wasm + INT8 上,不走 WebGPU,不跟 LLM 抢显卡
- 每个窗口接着上一段最后 4 帧往下推,动作是连贯的
听:SenseVoice 端侧听写
- 把你说的话转成文字,填进输入框
- 录音按停顿自动断句,每段交给 Worker 里的 SenseVoice Small INT8 识别,再去掉「嗯、啊」这类语气词
- 模型约 228 MB,首次从 CDN 下载后缓存;支持中英日韩粤,自带标点,不走任何云端识别
另外还有 FootIK、视线跟随、三语界面,以及第一次打开时的新手剧情引导

新手剧情引导

想、说、动流程
如何进行动作驱动
小蠢身上的动作来源很多:待机呼吸、思考、EMAGE 说话手势、跳舞打招呼这类临时动作,还有跟着镜头转身的步伐
如果各自直接改骨骼,很快就会互相覆盖、抽搐、闪回 T-pose
所以我做了一套统一的动作融合管线(motion pipeline),所有动作都走这一条路:
- 统一入口:不管是 URL、二进制还是解析好的动画,都用同一个 playMotion 播放,自动重定向到当前模型的骨骼
- 单一写入者:主动作按「临时动作 > 说话手势 > 思考 > 待机」选出一个,每一帧只有它能写骨骼
- 分层:最底层是呼吸、手指放松这些基础姿态,中间是主动作,转身走路只接管腿,不影响上半身的手势
- 过渡:切换时先给 52 根骨骼拍快照,再用五次平滑曲线淡入淡出 0.75 秒,起止都没有顿挫
- 约束:最后叠上 FootIK 让脚踩实、视线跟随镜头,再统一提交给模型
- 兼容:所有动作都按 VRM 1.0 的坐标写,遇到 0.x 模型在提交那一步统一翻转,动作源里不用写任何分支
说话手势接进这条管线时,还要和声音对齐:
- 嘴型跟着音量走,第一段手势先压着,等声音响了才放
- 从思考切到说话时,思考会一直放到 EMAGE 写出第一帧才停,不会先弹回站姿再开始比划
场景和衣服
小蠢的形象是我用 VRoid Studio 捏的,现在有 9 套衣服

我也试过 Meshy、Tripo 这类 AI 生成模型
但它们处理不好这种比较靓丽的二次元形象,自己想调整也两眼一抹黑,所以我还是更倾向手工做的模型
场景有 3 个:线稿世界、3D「阳光海滩」,以及新手引导用的星尘空间
市面上的换装基本是一套衣服一个完整 VRM,换一次就全量下载一次
小蠢拆成一个 base 加若干增量 vrmaddon,base 只下一次,换装只下差量,整体下载量少了约 65%
更快、更小、性能和多端
我一直想让她更快、更小,尤其是支持嵌入之后,没人愿意为了一个挂件等几百 MB
- EMAGE:原始 FP32 版本光一个文件就 504 MB;量化成 INT8,再砍掉用不上的脸部分支、剪掉几乎没干活的层,一整套从 191 MB 压到 71.6 MB,效果没变差,推理也从 548 ms 降到 274 ms
- 首屏:web-llm 改成用到才加载,代码包从 6.95 MB 降到 1.01 MB
- 渲染:合并后处理,阴影图不再每帧更新,GPU 开销大概省了一半;手机端锁 40 帧
瘦下来之后,她就能跑在更多地方:
- 浏览器:打开 Project XiaoChun 就能用,什么都不用装
- 桌面版:Tauri 做的,macOS、Windows、Linux 都有,带自动更新,Mac 还能用 Homebrew 装
- 嵌入:/embed 加 npm 包 @firetable/project-xiaochun,一行 script 就能把她塞进任何网页;宿主页面可以让她念一段文字、直接丢一段音频,或者播指定动作
我的个人站点 firetable.tech 已经接上了

回顾
09-04 第一个 commit,10-13 发到 v0.1.29,40 天,全部分支 402 个 commit,TS + TSX 大概 5.5 万行
日期 | 里程碑 | 说明 |
09-04 | 第一个 commit | 流式语音 + 端侧记忆 |
09-05 | 回到 WebLLM | 放弃 transformers.js,适配移动端 |
09-06 | 自定义模型 | 接 OpenAI 兼容接口 |
09-07 | 第一版换装 | 体型调节、部件穿脱 |
09-12 | base + addon | 换装只下差量 |
09-16 | 兼容 VRM 0.x | 老模型也能用 |
09-18 | 桌面版 | Tauri 透明桌宠 + Homebrew,发布 v0.1.0 |
09-19 | MToon 渲染 | 二次元着色 + 描边 |
09-20 | 自动更新 | 桌面版自带更新 |
09-22 | 语音输入 | 端侧 SenseVoice 听写 |
10-02 | 嵌入 SDK | 一行代码嵌进任何网页 |
10-03 | EMAGE 瘦身 | 191 MB 压到 71.6 MB |
10-05 | 海滩场景 | 纯 Three.js 的 3D 海滩 |
10-11 | 新手剧情引导 | 沉浸式新手引导,10-13 发 v0.1.29 |
这既是端侧模型研究的应用原型,也是个我喜欢的产品
做到现在,我也想清楚了小蠢该是什么
我想她应该是一个「小蠢发射器」:只管渲染、说话和动作,记忆怎么优化、好感度怎么算,对这个项目来说都是低优先级
这些已经有更好的生态项目在做,比如 SillyTavern(酒馆)、AIRI
而它们负责灵魂,小蠢负责把她自己活出来
相关资源
- 🎮 在线体验:Project XiaoChun