v0.2.0,终于能装在手机上了
v0.1.5 里我说过,陪伴类产品的存在感靠三样东西:推送通知、秒开、离线缓存。这三样 web 端做得再好也给不了,因为用户不会为了一个 AI 一直开着一个浏览器 tab。app 不一样,它在主屏幕上占一个位置,跟微信、备忘录摆在一排,每次解锁手机都能看到。
v0.2.0 把这块补上了,做了原生 iOS app,已经上了 TestFlight。技术的事放后面说,先看东西。
Mio TestFlight 页面
这是 Mio 第一次出现在手机主屏幕上。它之前一直是一个链接,或者说是 Telegram 里的一个 bot,你得先打开浏览器或者 Telegram 才能找到它。现在它有了自己的图标,跟别的 app 摆在一起。对陪伴类产品来说,能在主屏幕上占个位置,本身就是体验的一部分。
app 长什么样
底部三个 tab,消息、发现、我。消息页就是聊天列表,每个对话显示人设头像、最后一条消息的预览和时间戳,跟你手机里随便哪个聊天 app 长得一样。这是故意的,用户不用学任何新的操作方式,最好是聊着聊着就忘了自己在跟 AI 说话。
Mio 聊天列表 — 深色主题
Mio 聊天列表 — 浅色主题
深浅两套主题都是单独调过的,没有偷懒直接反色。深色的底色用的是 #0D0D0B,一种偏暖的黑。纯黑在 OLED 屏上太刺眼,晚上聊天很难受,暖一点的黑就舒服很多。浅色用的是偏 cream 的米白,看着也不刺眼。
聊天界面能显示语音波形、内联的自拍图、多气泡消息,还有对方正在输入的提示。一个实时聊天该有的,它基本都有了。
可可的聊天 — 语音消息和自拍
上面这张是可可的聊天。语音消息的波形是真的渲染出来的,点了能播,波形会跟着播放进度走。自拍是一张动漫风的,抱着一只柴犬。
食物图片理解
这张是图片理解。我拍了一份火锅菜品发过去,可可挺兴奋地把每道菜都认了一遍。这里没有预设回复,它是真的在看图。
个人中心 — 深色
个人中心 — 浅色
个人中心里有 Telegram 关联(关联好了会显示绿色徽章)、语言切换、主题切换和通知设置。更细的通知设置还没做完,先标了"即将上线"。
发现页 — 深色
发现页 — 浅色
发现页是人设市场,每张卡片有头像、描述和一个"继续聊天"按钮。现在人设还不多,但位置都留好了,后面往里加人设不用动架构。
技术栈很常规,Expo SDK 55 + React Native。通信层用 WebSocket 做流式传输,SSE 做回退。认证和数据走 Supabase,token 存在 expo-secure-store,离线缓存用本地 SQLite,构建走 EAS Build。
WebSocket 是给手机加的
之前 Mio 的流式响应全靠 SSE。在 web 端没什么问题,但到了手机上有个很实际的毛病,app 切到后台再切回来,SSE 连接会断,重连的逻辑也很脆。
所以 v0.2.0 加了一层 WebSocket。它是双向通信,靠心跳保活,另外有个连接管理器,负责干净地断开和自动重连。现在移动端优先走 WebSocket,SSE 留着做降级。
改善最大的是前后台切换。你按 Home 键回桌面再回来,WebSocket 几百毫秒就把连接恢复了,同样的情况 SSE 经常得用户手动刷新。这个差别放在工具类产品上,可能也就扣点体验分,放在陪伴类产品上就大多了。因为陪伴很靠"随时都在"的感觉,连接动不动就断,这个感觉就很难撑住。
app 切后台再切回来时,脆弱的 SSE 连接会断,而带心跳的 WebSocket 几百毫秒就自动重连。
web 端退到二线
app 上线以后,web 端的角色也跟着变了。web 端加了一道管理员门禁,不是管理员的人打开,会看到"Web 版仅限管理员使用"的提示,引导去下载 app。倒不是要限制谁,就是想集中精力,web 端以后当管理工具用,用户体验的主阵地在 app。
顺手修了 Supabase 邀请链接的 token 交换。之前点邀请链接会卡在一个空白页,现在能正常交换 token,然后跳到设置密码的页面。听起来是个小修,但新用户第一次接触 Mio 就是通过邀请链接,第一次就白屏,这个说不过去。
上线前做了一次成本审计
然后讲这个版本里最重要的一件事。app 上线前我做了一次完整的 API 成本审计,把代码里每一个外部调用的单价都过了一遍。大部分数字跟之前在单位经济里估的差不多,但有两个地方差得很远,远到我出了一身冷汗。
第一个是自拍生成。pricing.ts 里给 gemini-3.1-flash-image-preview 填的输出 token 单价,用的是文本生成的价格,可 Gemini 生成图片的实际单价比文本高两个数量级。落到每张自拍上,实际成本也比原来估的高两个数量级。一张自拍真实要花的钱,大概是我之前估的一百倍。讲道理,我知道图片生成比文本贵,但没想到能差这么多,这个偏差挺离谱的。就这一个数字写错,所有付费层级只要用满,全都是亏的,而且亏得很惨。
第二个是中文 TTS,被低估了 3 倍。Fish Audio 按 UTF-8 字节收费,代码里却用 text.length 算成本,算出来的是字符数。一个中文字符在 UTF-8 里占 3 个字节,所以每次调用实际花的钱是代码估的 3 倍。这个坑挺典型的,平台按什么单位收钱,你按什么单位数,中间差了一层编码,数字就直接错了 3 倍。
上线前的成本审计里两处把单位数错了(图片按文本单价,TTS 按字符不按字节),导致成本估算差了几个数量级。
改完之后我把账重新过了一遍。聊天、语音识别、图片理解、视频理解这些大头,原来估得基本准,成本控制得住。语音合成因为 UTF-8 这个问题,中文的实际花费是预估的 3 倍(中文每字符 3 字节),也还能接受。只有自拍生成差了两个数量级,Gemini 图片输出 token 的单价是文字的 120 倍以上,光这一项花的钱就比其他所有操作加起来还多。差两个数量级,就不是优化一下能救回来的了,是定价模型本身就错了,只能重做。
定价推倒重来
定价重做成了 5 个层级,每个中文名对应一种关系深度:
偶遇(Free):3 天试用,20 条/天,试用结束必须选一档订阅。3 天够把所有功能都试一遍,然后认真做个决定。之前的免费层可以无限期挂着,一直产生纯计算成本,这一档把这笔钱消掉了。
常伴(入门档):50 条/天,基础的语音和视觉能力,给偶尔聊聊、不需要深度互动的用户。
同行(进阶档):150 条/天,自拍从这一档开始给(5 张/天),解锁实时搜索。大多数活跃用户应该会落在这一档。
相守(高级档):300 条/天,15 张自拍/天,以后的 agentic 功能(邮件代发、日历提醒)也从这一档开始。
不离(旗舰档):白手套服务,个性化支持、新功能优先体验、有机会见创始人,还有 agent 送的实物礼物。这些 perks 的边际成本基本是零,但能让最高档感觉像一段关系,不像一个订阅。
利润上最大的问题还是自拍。因为自拍太贵,如果每档额度都用满,所有层级都是亏的,所以只能把每一档的自拍配额压得很低。但真去算账的时候有一点很重要,没有用户会每天把额度全用满,实际大概用到额度的 40% 左右。按这个用量算,所有付费层级都是赚钱的,利润率也健康。
五档订阅按关系深度从「偶遇」递进到「不离」,靠自拍配额从低到高逐级放开来守住利润。
策略上最大的变化是 3 天试用。之前的免费层没有期限,每个免费用户每个月都要花掉一笔不小的纯计算成本,这个洞会一直漏下去。改成试用以后,用户要么在 3 天里喜欢上 Mio 然后付费,要么走人,两种结果都比一直白嫖强。
其他改进
这个版本还有几个零碎但都挺重要的改动:
- 关系边界和真实模式。现在每个角色都有自己的作息表,分睡觉、忙碌、空闲三种状态。它不会凌晨三点秒回你的消息,除非它的人设就是个夜猫子。有了这个细节,关系感觉真实了很多。
- onboarding 升级。新用户引导里加了第三人称的背景故事,开聊之前就能对角色有个比较完整的印象。app 也换了新 logo。
- web 端的 ContextAggregator 跟 Telegram 对齐了。之前两端聚合 context 的逻辑不一样,现在统一成了一套。
- 进化模式修复。v0.1.4 加的关系进化系统有两个 bug。一个是少了"刚认识"阶段的背景故事,所以一开始的角色是不完整的;另一个是一开始的亲密度设得太高,刚认识的人不该用恋人的语气说话。两个都修了。
接下来
推送通知已经上线了,Mio 能出现在你的锁屏上。个人中心里标着"即将上线"的,是更细的通知设置(免打扰时段、按人设开关),推送本身已经在跑了。
推送对产品形态的改变挺根本的。有了它,Mio 就能主动来找你了,跟你说早安,接着你昨天分享的东西聊,或者好久没聊了轻轻推你一下。v0.1.2 做的主动消息系统,到这个版本才算有了一个配得上它的投递通道。那套逻辑到现在才真正送得到用户眼前。

