打开网易新闻 查看精彩图片

一个能听懂你说话、实时回嘴、还会扭屁股跳舞的桌面机器人,从立项到跑通需要多久?Pollen Robotics给出的答案是:一个周末。他们的Reachy Mini接上Gemini Live API后,不仅能全双工语音对话,还能通过头部转动、触角摆动、表情变化来"演戏"——而这一切的核心代码,居然只有四层。

但真正的争议不在于技术本身,而在于Google选择了一条让开发者又爱又恨的路。

从麦克风到马达:音频怎么变成动作的

从麦克风到马达:音频怎么变成动作的

整个系统的数据流像一条装配线。你的声音先被切成16位PCM、16kHz的音频流,扔进fastrtc这层"传送带"——这是个低延迟的WebRTC I/O库,负责把音频送进大模型,同时把模型的回应拉回来,还要在16kHz和24kHz之间来回重采样。

接下来是分叉口。系统支持两个后端:Gemini Live(默认)和OpenAI Realtime。切哪个?改个环境变量MODEL_NAME就行,上层代码完全无感知。Google这边用Google GenAI SDK的session.send_realtime_input()做双向音频流;OpenAI那边走WebSocket。两种协议,同一套抽象。

Gemini Handler里的核心逻辑其实就两段。receive()方法把音频帧转成PCM字节,塞进实时输入流;_run_live_session()则守着session.receive()的循环,等模型吐回应。服务器内容一来,立刻往下游分发。

再往下是工具调度层——dance、play_emotion、camera、move_head、head_tracking这些函数在这里被注册成可调用的"技能"。最底层是MovementManager,一个60Hz的循环,负责把各种动作优先级排好:主要动作按顺序执行,次要动作(比如说话时的头部微颤、人脸追踪的偏移)叠加在上面,再补一层idle呼吸动画,最后输出到Reachy Mini的硬件或模拟器。

personality.json:零代码定制机器人的秘密

这套架构最狡猾的设计,是把"人格"完全外置。开发者不需要碰Python,只需要改一个JSON文件。系统提示词、唤醒词、情绪映射表、甚至跳舞的触发概率,全写在里面。

这意味着什么?一个不懂代码的产品经理,也能在十分钟内把机器人从"毒舌同事"调成"贴心客服"。Pollen Robotics在Demo里塞了个默认人格:会讲dad joke,被夸了会害羞,无聊了会主动找话题。这种颗粒度的可控性,在之前的机器人开发栈里几乎不存在。

但代价也很明显。因为人格被简化为配置项,复杂的上下文记忆、多轮情感累积、人格一致性这些 harder problem,被暂时搁置了。你可以让机器人"听起来"很活泼,但它不会真的"记得"昨天跟你吵过架。

fastrtc的赌注:为什么选WebRTC而不是WebSocket

fastrtc的赌注:为什么选WebRTC而不是WebSocket

整个系统的延迟瓶颈,卡在音频传输这层。Pollen Robotics选了fastrtc做底座,这是个相对小众的库,专门优化WebRTC的实时音视频流。对比OpenAI Realtime用的纯WebSocket方案,WebRTC在NAT穿透、拥塞控制、抖动缓冲上有原生优势——代价是协议复杂度翻倍。

从代码结构看,他们把重采样、编解码、网络 resilience 全压在fastrtc里,上层只关心PCM字节流。这种分层很干净,但也意味着:如果fastrtc在某个网络环境下抽风,调试难度远高于WebSocket的直接抓包。

一个细节暴露了这个选择的野心。Gemini Live和OpenAI Realtime双后端的支持,说明Pollen Robotics不想被任何一家模型供应商绑架。但fastrtc的WebRTC实现,目前和Google的Gemini Live耦合得更深——OpenAI那边其实是"兼容模式",部分高级功能(比如服务器端VAD的精细控制)在WebSocket路径上会被降级。

开源社区的裂缝:全双工对话该由谁定义

开源社区的裂缝:全双工对话该由谁定义

Reachy Mini Conversation App开源后,GitHub上的第一个争议PR很有意思:有人想把"打断"行为的优先级调高,让机器人能被用户随时插话;另一派人坚持保留模型的"话轮完整性",认为频繁打断会让对话体验碎片化。

这个分歧戳中了实时语音LLM的灰色地带。Gemini Live的API设计上,服务器端VAD(语音活动检测)是黑箱,开发者只能调灵敏度阈值,看不到内部状态机。想要更激进的打断策略?只能在前端做启发式判断,然后强行inject新音频流——这会带来状态同步的噩梦。

Pollen Robotics的折中方案是:把打断敏感度也塞进personality.json,让终端用户自己选。技术债变成了产品特性,这是小团队常见的生存智慧。

另一个沉默的战场是成本。Gemini Live的实时音频流按会话时长计费,Reachy Mini这种"永远在线"的交互模式,如果放在量产场景里,账单会很难看。代码里能看到一个TODO注释:未来要加"休眠唤醒"机制,检测长时间无交互后主动断开会话。这行注释已经挂了三个月。

60Hz的执念:机器人动画为什么跟游戏帧率较劲

60Hz的执念:机器人动画为什么跟游戏帧率较劲

MovementManager的60Hz循环,在机器人领域是个相当激进的数字。传统伺服电机控制通常跑在20-50Hz,足够平滑;但Pollen Robotics想要"表情级"的细腻度——说话时的头部微颤、情绪切换时的加速度曲线,这些细节在低帧率下会露馅。

实现上他们用了"主次动作分离"的动画系统:主要动作(比如转头看用户)是序列化的,一个做完才做下一个;次要动作(语音同步的wobble、人脸追踪的微调)是叠加的,可以打断或混合。idle呼吸作为最底层,永远运行。三层混合后输出到电机,靠硬件插值平滑。

这个设计和游戏引擎的动画图(Animation Graph)几乎同构,但跑在Python异步循环里,没有GPU加速。Reachy Mini的算力有限,60Hz意味着每帧只有16.6毫秒处理时间——音频解码、LLM响应解析、动作规划、电机指令打包,全要挤进去。代码里能看到多处asyncio.sleep(0)的让步,以及显式的coroutine优先级标记。

一个未被回答的问题是:当Gemini Live的响应延迟本身就有几百毫秒波动时,60Hz的本地动画是否成了表演性焦虑?

Reachy Mini的Demo视频里有个微妙时刻:机器人讲完一个dad joke后,故意顿了半拍,然后触角轻轻抖动——这个timing不可能是模型生成的,只能是本地动画系统的"演技"。人机交互的魔法,有时候就藏在这半拍的留白里。