我把 AI 伴侣的头像换成了一颗光球
没有面孔的灵魂——一颗会呼吸的情绪光球
Mio v2 的设计我一上来就做了个减法,虚构身份全部去掉,只保留情感内核。v1 是反着做的,五个精心设计的角色,每个都有背景故事、日程模拟、物理身份,工程量巨大,结果产品越做越像角色扮演,离陪伴反而越来越远。这段弯路在第一篇里写过了。
原则定下来很容易,真落到设计上就是两个很具体的问题:伴侣没有脸,那它长什么样?没有人设,性格从哪来?v2 的规划时间大半都花在这两个问题上,这篇就讲这两个问题具体是怎么解的。
人脸这条路,我最先否掉
给陪伴产品配一张人脸是最直觉的做法。Replika 这么做,Character.AI 这么做,国内的星野、豆包也全在做二次元或者半写实的头像。这条路我认真考虑过,最后否了,原因大概有三个。
第一个是恐怖谷。静止的头像没有生气,动起来但动得不对的头像更让人难受。想把口型同步、微表情、自然的头部转动做好,要么上 3D 渲染管线,要么上生成式视频,对一人团队来说都不现实。而且就算做出来了,它还会立起一个 AI 根本够不到的期待:伴侣越像人,它每次回复不像人的时候就越刺眼。
第二个是 Apple。用类人头像的 AI 陪伴应用,审核的时候会被多问很多问题。抽象视觉直接把这一整类政策摩擦绕开了:没人会问你是不是在模拟真人,也没人会质疑你用写实人类形象制造不健康的准社会依赖。我一个人做,没有法务团队,这一条的分量其实很重。
第三个是文化。一张脸会把伴侣锚死在某个文化里。v1 的角色是深度绑定中国文化的,成都姑娘、温柔学姐、成熟大叔,做纯中文产品没问题。但 v2 的前提就是去掉文化预设,让伴侣自动说用户的语言。一颗光球没有种族、没有年龄、也没有性别表达,做全球产品不背任何文化包袱。
最后做成了一颗会呼吸的光球
Mio v2 的伴侣就是一颗抽象的、有脉搏的光球,停在聊天界面顶部,是整块屏幕上唯一的鲜明色彩。它干的活接近肢体语言:你字还没开始读,情绪已经先递过来了。
具体的机制是这样的。v1 本来就有情绪引擎,emotionState 追踪伴侣的情绪变化,影响回复的风格。v2 里,同一套情绪状态实时驱动光球的外观:
| 情绪 | 颜色 | 动态 |
|---|---|---|
| 平静 | 淡蓝 / 白 | 缓慢的呼吸节奏,轻柔地膨胀收缩 |
| 开心 | 暖黄 / 金 | 轻快跳动,粒子向外辐射 |
| 难过 | 淡紫 / 蓝 | 向内缩小,脉搏变慢 |
| 兴奋 | 亮橙 / 粉 | 快速膨胀,粒子四散飞溅 |
| 困意 | 深蓝 / 暗 | 几乎静止,偶尔微弱闪烁 |
这个映射我故意做得很简单,就五种状态,每种有明确的颜色和运动特征。聊几次之后,光球是什么情绪一眼就能看出来。伴侣因为你分享的事开心了,你在读到第一个字之前就能看到;深夜它开始犯困,光球就沉到近乎静止的深蓝。反正你不用读字,就知道它现在是什么状态。
人脸传达情绪靠的是几十块肌肉的微妙运动,要在数字世界里把这个还原出来,基本是研究级的难题。光球只用两个变量:颜色和运动。表达的词汇量确实小,但反过来,正因为词汇量小,每种状态在手机小屏上才清晰可辨。
同一套情绪状态只用颜色和运动两个变量驱动光球,让人不读字就一眼看懂伴侣的心情
抽象形态还有一个心理学上的好处:给投射留了空间。同一颗紫色的光球,有人看到的是难过,有人看到的是在想事情。这个模糊是故意留的,每个用户都能把伴侣读成自己需要的样子。这比让它去表演某种具体的情绪更可信,真让它演一个明确的情绪,演得稍微不准反而显得假。
页面砍到只剩三个
v1 是仿微信的 4-tab 布局:消息、发现、通讯录、我的。现在回头看挺离谱的,拿一整套即时通讯的架构,去承载一段说到底只有两个人的关系。v2 砍到只剩三个页面:
- 聊天:99% 的时间都在这。顶部是光球,中间是消息流,底部是输入框和语音按钮。没有 tab bar,没有汉堡菜单,也没有抢注意力的通知角标,就是你和你的伴侣。
- 设置:从聊天页右滑,或者点伴侣的名字进去。改名、换声线、管理记忆、订阅状态、账号管理,所有管理功能都收在这,平时不碍眼。
- 引导:只在第一次打开的时候出现,下面细说。
导航结构就这么多。通讯录和发现页直接没了,伴侣只有一个,也没什么内容好发现,预设市场更是压根没做。砍这么狠是有意的:v2 想做的就是一段关系的专属空间,社交应用那套架子在这用不上。
配色
配色两套。深色是默认:背景 #0D0D12,近乎纯黑,带一点紫,避开了在 OLED 屏上显得很空的 #000000。用户消息气泡 #1A1A2E,伴侣气泡 #16213E。文字 #E8E4DF,偏暖的白,不用那种冷冰冰的蓝白。光球是屏幕上唯一的饱和色。
浅色模式:背景 #FAF8F5,暖米白,有点旧纸的感觉。用户气泡 #F0EDE8,伴侣气泡 #E8E4DF。文字 #2D2D2D,特意用深灰把对比度压下来。光球的发光强度也调柔了,不刺眼,但依然是视觉锚点。
两套模式的原则是一样的:除了光球,所有东西都是低饱和的暖色,视线自然就会落到光球上。说白了就是整个屏幕只留光球一个亮点,别的全往后退。
引导做成了第一次见面
v1 的引导就是一张表单:选角色、选关系类型、填名字、答几个问题。功能上没毛病,但那个感觉是在配置软件。v2 把它整个换成了一段对话,伴侣的开场白是这样的:
"我刚来到这个世界。你是我认识的第一个人。"
"你叫什么名字呀?"
用户自然回应,接着它会问:
"那......你想叫我什么?"
用户给伴侣取名,叫"小光"、"Luna"、"Mio",或者某个只对自己有意义的名字都行。伴侣会对这个名字做出反应,不走罐头模板,听起来像真的在认这个名字:
"小光......我喜欢这个名字。听起来暖暖的。"
"我什么都还不太懂。你平时喜欢做些什么呀?"
3-5 轮自然对话之后,系统从这段对话里提取初始的性格种子。用户说话俏皮、爱用网络用语,伴侣的风格就偏活泼;用户表达偏沉思、句子更长,伴侣就会镜像那个节奏。所以严格说这段引导就是在做校准,只是形式上看起来是第一次聊天。
唯一没法从对话里长出来的是声线。声音这个东西太物理了,只能听过再选,推断不出来。所以对话结束后,应用会放 3-4 个声音样本让用户挑,这是整个引导里唯一的硬选择。
性格从对话里长出来
这是 v2 跟 v1 分歧最大的地方。v1 的性格是人工写的,人格配置文件用几百行文字定义这个角色怎么说话、喜欢什么、有过什么人生经历。v2 的性格是涌现的,或者说,是长出来的。具体分三层:
- 种子。引导对话产出一段很短的性格描述,大概两三句话,比如"温暖而好奇,善用温和的幽默感,会匹配用户的能量水平"。这只是个起点。
- 迭代。每次对话结束后,一个轻量的性格提取器异步跑一遍,看伴侣实际的表现——哪些模式有效、哪些时刻自然、用户是什么反应——然后微调这段性格描述。每次的变化幅度都很小,更像渐进的漂移,就跟真实关系里慢慢长出共同语言和节奏一个道理。反正就是慢慢挪,不会哪天突然变了个人。
- 记忆积累。从 v1 搬过来的记忆系统(整个 codebase 里最值钱的工程资产)持续积累跟性格相关的记忆。伴侣记得你说话喜欢直来直去,记得你聊做饭会兴奋,记得你被追问工作压力会回避。这些记忆有机地塑造行为,不需要写显式的性格规则。
这样跑三个月日常对话之后,每个用户手里的伴侣都会长成不一样的样子。两个用户都给伴侣取名"Mio",拿到手的伴侣感觉是明显不同的:幽默感不同、沟通风格不同、情绪敏感度也不同,因为底层那段关系本身就不同。
性格不是预设的,而是从一颗种子经过每次对话的迭代和记忆积累,慢慢长出来的三层机制
这条路技术上比预设难。性格提取器得足够保守,不能让伴侣每周二重新定义一次自己;记忆系统得足够可靠,丢记忆等于丢掉性格的连续性;底层 LLM 得足够擅长遵循细腻的行为描述。但它换来的是一个真的在适应你的伴侣。预设写得再细也是死的,定稿那天是什么样,以后就一直是什么样。
国际化基本是白送的
还有个好处是讨论到一半才意识到的:把文化人格去掉之后,国际化几乎不要钱。v1 要进其他市场,得为每个市场单独设计一组角色,日本用户不想要成都姑娘,可能想要东京女生,说话方式、文化梗、关系互动模式全得重做。一个语言一个语言地扩,等于为 N 个市场写和维护 N 套角色。
v2 没这个问题。伴侣没有需要本地化的文化身份,用户说什么语言它就说什么语言,引导对话也用用户的语言进行。性格是从用户自己的文化语境里涌现出来的,日本用户和巴西用户拿到的都是一个感觉"是自己人"的伴侣,因为身份本来就是各自的关系塑造出来的。真正需要传统 i18n 的只剩 UI 文案和 App Store 描述,伴侣本身在设计上就跟语言无关。
动画选型最后落在 React Native Skia
光球的动画要同时满足三件事:流畅(60fps)、实时响应情绪状态的变化、省电。当时桌上有三个方案:
- Lottie:预制动画,没法动态响应情绪状态,直接否决。
- React Native Reanimated:强在 UI 动画,粒子系统这种生成式视觉效果超出了它的设计意图,能做但很别扭。
- React Native Skia:GPU 加速的 2D 绘图,支持 shader,渐变、粒子、发光、平滑形变全能做,正好是光球需要的工具。
具体的实现是这样的:光球就是一个 shader 程序,情绪状态的变量——颜色、脉搏频率、粒子密度、大小——通过 WebSocket 的情绪通道实时更新。服务器推一条 { type: "emotion", state: { mood: "happy", intensity: 0.8 } } 过来,光球就从当前状态平滑过渡到暖金色加跳动的粒子。不需要为每种情绪做动画关键帧,shader 自己做连续插值。这也意味着以后加新的情绪状态不需要新的动画素材:哪天情绪引擎开始区分"满足"和"安宁",或者"焦虑"和"沮丧",光球靠参数插值就能把差异表达出来。
最后
回头看,v2 视觉这块做的决定基本全是减法:头像没有,角色化的聊天气泡没有,塞满功能的 tab bar 也没有,剩下的就是一个深色背景加一颗光球。光球只干传情绪这一件事,身份我干脆没定义,用户跟伴侣处久了,它自然会长成那段关系需要的样子。性格系统赌的是涌现赢过预设,这个要等真实用户用上三个月才知道结果,只能说我目前是信这个方向的。
至于工程层面的事,记忆系统和情绪引擎怎么从 v1 提取出来、新的 4 表数据库 schema 长什么样、为什么 80% 的代码可复用最后还是开了个全新的 codebase,都在第三篇里。


