组装好你的 Reachy Mini 后,你需要安装对话应用并开始与它交谈。在此之前,你必须将音频发送到服务器。但现在不必了。今天我们将带你了解如何在本地运行整个技术栈。该技术栈由语音到语音(speech-to-speech)驱动,即我们级联式的 VAD → STT → LLM → TTS 流水线,它暴露了一个兼容 Realtime API 的 `/v1/realtime` WebSocket。启动后端后,从用户界面将机器人指向该后端即可。
级联方案是当今开源领域中最灵活的选择,并且如果组件选取得当,它们也是最快的。我们会推荐我们最喜欢的组件,但级联方案的核心在于你可以自由替换它们。新模型每周都在发布。
摘要
- 为你的 Reachy Mini 部署一个本地语音后端。
- 我们使用我们的语音到语音(speech-to-speech)库,采用级联方案。
- 推荐配置:llama.cpp 搭配 Gemma 4、Silero VAD、Parakeet-TDT 0.6B v3 STT、Qwen3-TTS。
快速开始
这篇博客将引导你完全在本地运行与 Reachy Mini 的对话。无需云端,无需 API 密钥,数据不会离开你的机器。以下视频展示了实际运行效果:
本地提供 LLM 服务
为了提供 LLM 服务,我们将使用 Hugging Face 的 llama.cpp。如果你需要安装它,最简单的方式是运行 `brew install llama.cpp` 或 `winget install llama.cpp`,如需更多帮助,请查阅文档。首先,我们将运行:
llama-server -hf ggml-org/gemma-4-E4B-it-GGUF -np 2 -c 65536 -fa on --swa-full
完成!首次运行时会下载模型,后续启动会很快。
这些标志参数有什么作用?
- `-hf ggml-org/gemma-4-E4B-it-GGUF` — 直接从 Hub 拉取模型。首次运行下载,后续运行使用缓存。
- `-np 2` — 两个并行槽位。允许服务器处理第二个请求(例如快速打断),而不会阻塞在第一个请求上。
- `-c 65536` — 64k 上下文窗口,在槽位间共享。为长对话提供了充足的空间。
- `-fa on` — 启用 Flash Attention。速度更快,内存占用更低,在现代硬件上基本没有额外开销。
- `--swa-full` — 保留完整的滑动窗口注意力缓存,而不是重新计算。在 Gemma 上,以少量 RAM 为代价,显著加快提示词处理速度。
设置语音到语音(speech-to-speech)
我们首先安装这个库
uv pip install speech-to-speech
然后,在另一个终端中运行 LLM 服务的同时,我们可以直接运行:
speech-to-speech --responses_api_base_url "http://127.0.0.1:8080" --responses_api_api_key "" --mode local
现在你可以通过终端直接与模型对话了!首次启动时需要下载 Parakeet-TDT 0.6B v3 和 Qwen3TTS,但后续启动会非常快。
以下是本地对话模式的演示视频:
在 `--mode local` 模式下体验过后,你可以再次运行不带该选项的命令,为机器人提供语音到语音服务。
将 Reachy Mini 接入语音到语音功能
当 llama.cpp 和语音到语音功能运行起来后,你可以通过桌面应用启动机器人,并打开对话应用。在对话应用的界面中,你需要点击 HF 后端的"编辑连接"来选择本地模式。以下是操作演示视频:
大功告成。现在你可以与机器人对话了。流水线的每个环节都存在权衡:有的 TTS 模型速度更快但质量较低,有的 STT 模型速度较慢但质量更高。我们针对多语言场景进行了优化,而你可能希望针对单一语言进行优化。博客的其余部分将介绍如何进行定制。
深入探讨
为什么要运行自己的语音到语音服务器?
托管的实时后端固然方便,但运行自己的引擎能带来三大优势:
- 隐私保护。音频数据永远不会离开你的网络,整个流水线运行在你掌控的硬件上。
- 无 API 费用。无需按分钟或按 token 付费。
- 对流水线的完全控制。你可以替换任意组件:VAD、STT、LLM、TTS。只要 Hub 🤗 上有更好的模型发布,随时可以更换。
语音到语音代码库通过一个 CLI 命令就提供了所有这些功能。它会启动一个位于 `/v1/realtime` 的 WebSocket 服务器,该服务器使用 Reachy Mini 已经能够理解的相同协议进行通信。
我们推荐的默认配置:VAD、STT、TTS
级联语音流水线包含四个阶段:VAD、STT、LLM 和 TTS。对于其中三个阶段,我们选择了可靠的默认方案,这样你可以专注于 LLM:
| 阶段 | 选择 | 原因 |
|---|---|---|
| VAD | Silero VAD v5 | 体积小、精度高、可在 CPU 上运行。是开源语音智能体领域事实上的默认选择。 |
| STT | Parakeet-TDT 0.6B v3 | 支持流式处理、速度极快、英语质量出色。 |
| TTS | Qwen3-TTS | 富有表现力、低延迟、支持多语言、可定制语音。 |
这些是我们的推荐选择,如果你有偏好,可以随时替换成自己的方案。
选择你的 LLM
大语言模型是对系统延迟和整体性能影响最大的层级。我们支持两种方案:在本地运行模型(llama.cpp、MLX、Transformers、vLLM),或使用搭载 Responses API 的服务器(OpenAI、Gemini、HF 推理端点、llama.cpp、vLLM 等)。
Responses API:将大脑与语音循环解耦
系统的主要瓶颈在于大语言模型的推理延迟。为解决此问题,我们支持通过 Responses API 协议暴露的外部推理引擎。
因此,语音到语音引擎支持第二种模式:只要大语言模型遵循 Responses API 协议,它就可以运行在独立的进程中。你在一个终端启动模型服务器,在另一个终端启动语音循环,两者通过 HTTP 进行通信。
方案一:一个终端运行 llama.cpp,另一个终端运行语音到语音
终端 1:llama.cpp 服务器:
llama-server -hf ggml-org/gemma-4-E4B-it-GGUF -np 2 -c 65536 -fa on --swa-full
终端 2:语音到语音客户端:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "ggml-org/gemma-4-E4B-it-GGUF" \
--responses_api_base_url "http://127.0.0.1:8080/v1"
方案二:一个终端运行 vLLM,另一个终端运行语音到语音
需要 vLLM ≥ 0.21.0 版本。对 Responses API 协议的完整支持,包括语音到语音后端使用的工具调用流式传输,已在 vLLM 0.21.0 版本中实现。旧版本可以启动,但当助手尝试调用工具时就会出错。
在此流程中通过 vLLM 提供模型服务时,实际上需要三个标志:
- --enable-auto-tool-choice
- --tool-call-parser <tool_parser_name> —— 选择按模型族划分的解析器,将模型的原始输出转换为结构化的工具调用(例如,Qwen3 指令模型使用 qwen3_coder,Llama 3 使用 llama3_json,Hermes 风格模型使用 hermes 等)。
- --default-chat-template-kwargs '{"enable_thinking":false}' :对于支持该功能的模型,禁用 <think> 推理通道。对于更复杂的智能体任务,你可以将其设为 true 让模型进行推理;但对于追求自然感的对话,我们强烈建议保持关闭:每一个思考 token 都会转化为用户听到机器人开口说话前的静默延迟。
终端 1:vLLM 推理服务器(Qwen/Qwen3-4B-Instruct-2507):
vllm serve Qwen/Qwen3-4B-Instruct-2507 \
--port 8000 \
--host 127.0.0.1 \
--max-model-len 32768 \
--enable-auto-tool-choice \
--tool-call-parser qwen3_coder \
--default-chat-template-kwargs '{"enable_thinking":false}' \
--speculative-config '{"method":"qwen3_next_mtp","num_speculative_tokens":1}'
--speculative-config 这一行启用了多 token 预测(MTP)。这是可选的,但对端到端延迟有显著影响。只要模型支持,就请保持启用。
终端 2:语音到语音客户端:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "Qwen/Qwen3-4B-Instruct-2507" \
--responses_api_base_url "http://127.0.0.1:8000/v1"
选项三:Hugging Face 推理端点
协议相同,但模型运行在 Hugging Face 管理的 GPU 上。将任意聊天模型部署为推理端点,然后将语音循环指向该端点 URL:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "Qwen/Qwen3-4B-Instruct-2507" \
--responses_api_base_url "https://<your-endpoint>.endpoints.huggingface.cloud/v1" \
--responses_api_api_key "$HF_TOKEN"
选项四:Hugging Face 推理提供商
如果你不想管理自己的端点,可以使用推理提供商。Hugging Face 通过单一 URL 将你的请求路由到第三方后端(例如 Together、Fireworks、Replicate):
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "Qwen/Qwen3.6-35B-A3B:deepinfra" \
--responses_api_base_url "https://router.huggingface.co/v1" \
--responses_api_api_key "$HF_TOKEN"
选项五:OpenAI(或任何兼容 OpenAI 的提供商)
当你想在零基础设施的情况下测试前沿模型时,将同一个标志指向 OpenAI:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "gpt-5.4" \
--responses_api_api_key "$OPENAI_API_KEY"
`--responses_api_*` 标志对于任何实现该协议的提供商(OpenRouter、Together、Fireworks……)都同样适用。只需更换基础 URL 和 API 密钥,管道的其余部分保持不变。
在进程中运行大语言模型
选项一:在 MLX 上运行本地大语言模型(Apple Silicon)
如果你使用的是 Mac,MLX 是以合理延迟运行真实模型的最便捷方式。我们推荐 Qwen3-4B-Instruct-2507,它在 M 系列芯片上足够小巧,能实现即时响应,同时又具备足够的对话能力。
speech-to-speech \
--llm_backend mlx-lm \
--model_name "mlx-community/Qwen3-4B-Instruct-2507-bf16"
服务器默认监听 `ws://127.0.0.1:8765/v1/realtime`。保持其运行,将对话应用连接到本地后端,你就可以与机器人对话了。
选项二:在 Transformers 上运行本地大语言模型(CUDA / CPU / MPS)
思路相同,但使用原生 Transformers。如果你使用的是 CUDA 设备、Linux 系统,或者希望自由更换模型而无需为 MLX 重新转换权重,请使用此选项。
speech-to-speech \
--llm_backend transformers \
--model_name "Qwen/Qwen3-4B-Instruct-2507"
提示:Qwen3-4B-Instruct-2507 是另一个不错的大语言模型选择,因为它在单块消费级 GPU 上能提供良好的速度与质量平衡。你可以将 `--model_name` 指向后端支持的任何 Hugging Face 模型——例如更大的 Gemma、Qwen 或 Mistral 模型。
在笔记本上运行引擎,在机器人上运行应用
如果你在笔记本上运行语音引擎,而在 Reachy Mini Wireless 上运行对话应用,唯一需要改变的就是 URL。请确保引擎绑定到局域网地址(而不仅仅是 127.0.0.1),并在用户界面中选择 IP 时,从机器人端使用笔记本的 IP 地址。
如果你不知道自己的 IP,以下是查找方法:
macOS
ipconfig getifaddr en0 # wifi
ipconfig getifaddr en1 # ethernet (sometimes en0, varies)
Linux
hostname -I
Windows
ipconfig
在活动适配器下查找“IPv4 地址”。
你应该选择 192.168.x.x 或 10.x.x.x 这类地址。如果看到 169.254.x.x,说明你实际上并未连接到网络。
总结
现在你拥有一个完全本地的语音循环:
- 机器人通过 Silero 进行监听,
- 通过 Parakeet-TDT 0.6B v3 进行转录,
- 通过你选择的任意大语言模型进行思考——无论是本地的 MLX、本地的 Transformers、隔壁的 vLLM 或 llama.cpp 服务器,还是托管的 Responses API 端点,
- 并通过 Qwen3-TTS 进行回答。
请为 huggingface/speech-to-speech 和 pollen-robotics/reachy_mini_conversation_app 项目点星,并在讨论区告诉我们,你最终在你的机器人上运行了哪个开源级联方案。
After building your Reachy Mini, you'll install the conversation app and start talking to it. Until now, you had to send your audio to a server. But not anymore. Today we'll walk you through running the whole stack locally. This stack is powered by speech-to-speech, our cascaded VAD → STT → LLM → TTS pipeline that exposes a Realtime API-compatible /v1/realtime WebSocket. Once you launch the backend, point the robot at it from the UI.
Cascades are the most flexible option in the open-source landscape today, and with the right pieces they're also the fastest. We'll recommend the components we like best, but the whole point of a cascade is that you can swap them. New models drop every week.
TL;DR
- Deploy a local speech backend for your Reachy Mini.
- We use our
speech-to-speechlibrary, a cascade approach.- Recommended: llama.cpp with Gemma 4, Silero VAD, Parakeet-TDT 0.6B v3 STT, Qwen3-TTS.
Quick start
This blog walks you through running conversations with Reachy Mini fully locally. No cloud, no API keys, no data leaving your machine. Here's a video showing this live:
Locally serving the LLM
To serve the LLM, we'll use Hugging Face's llama.cpp. If you need to install it, the simplest way is brew install llama.cpp or winget install llama.cpp, for more help, check the docs. First, we'll run:
llama-server -hf ggml-org/gemma-4-E4B-it-GGUF -np 2 -c 65536 -fa on --swa-full
And done! The first time it will download the model, subsequent launches are fast.
What do those flags do?
-hf ggml-org/gemma-4-E4B-it-GGUF— pulls the model straight from the Hub. First run downloads it, subsequent runs use the cache.-np 2— two parallel slots. Lets the server handle a second request (e.g. a quick interruption) without blocking on the first.-c 65536— 64k context window, shared across slots. Plenty of headroom for long conversations.-fa on— flash attention. Faster and lower memory, basically free on modern hardware.--swa-full— keeps the full sliding-window attention cache instead of recomputing it. Trades a bit of RAM for noticeably faster prompt processing on Gemma.
Setting up speech-to-speech
We'll begin by simply installing the library
uv pip install speech-to-speech
Then, while we are serving the LLM in another terminal, we can simply run:
speech-to-speech --responses_api_base_url "http://127.0.0.1:8080" --responses_api_api_key "" --mode local
And you can start talking to the model through your terminal! The first time it will need to download Parakeet-TDT 0.6B v3 and Qwen3TTS, but subsequent launches are fast.
Here's a video showing the local conversation mode:
Now, after you've tried it in --mode local, you can run again the command without that option to serve speech-to-speech to the robot.
Connecting Reachy Mini to speech-to-speech
Once you have llama.cpp and speech-to-speech running, you can start the robot with the desktop app and launch the conversation app. In the UI from the conversation app, you need to choose the local mode by clicking on "edit connection" in the HF backend. Here's a video showing how to do it:
And you're done. You can start talking to your robot. Every stage of the pipeline is a trade-off: there are faster TTS models with lower quality, slower STT models with higher quality. We optimized for multilingual, you might want to optimize for a single language. The rest of the blog covers how to customize.
Going deeper
Why run your own Speech-to-Speech server?
Hosted realtime backends are convenient, but running your own engine unlocks three things:
- Privacy. Audio never leaves your network, the entire pipeline runs on hardware you control.
- No API costs. No per-minute or per-token fees.
- Full control over the pipeline. Swap any piece: VAD, STT, LLM, TTS. Whenever something better lands on the Hub 🤗.
The speech-to-speech repo gives you all of that in a single CLI. It boots a WebSocket server at /v1/realtime that speaks the same protocol Reachy Mini already knows how to talk to.
Our opinionated defaults: VAD, STT, TTS
A cascaded voice pipeline has four stages: VAD, STT, LLM, and TTS. For three of them, we pick solid defaults so you can focus on the LLM:
| Stage | Choice | Why |
|---|---|---|
| VAD | Silero VAD v5 | Tiny, accurate, runs on CPU. The de-facto default in the open-source voice-agent world. |
| STT | Parakeet-TDT 0.6B v3 | Streaming-friendly, very fast, great quality on English. |
| TTS | Qwen3-TTS | Expressive, low-latency, multilingual, supports custom voices. |
We are opinionated about these choices, feel free to swap them out for your own if you have a preference.
Choosing your LLM
The LLM is the layer with the most impact on latency and overall performance of the system. We support two options: run a model locally (llama.cpp, MLX, Transformers, vLLM), or use a server with a Responses API (OpenAI, Gemini, HF Inference Endpoints, llama.cpp, vLLM, etc).
The Responses API: decouple the brain from the voice loop
The main bottleneck in the system is LLM inference latency. To address that, we support external inference engines exposed through the Responses API protocol.
The speech-to-speech engine therefore supports a second mode where the LLM lives in a separate process as long as it speaks the Responses API protocol. You launch your model server in one terminal, you launch the voice loop in another terminal, and the two talk over HTTP.
Option 1: llama.cpp in one terminal, speech-to-speech in the other
Terminal 1: llama.cpp server:
llama-server -hf ggml-org/gemma-4-E4B-it-GGUF -np 2 -c 65536 -fa on --swa-full
Terminal 2: speech-to-speech client:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "ggml-org/gemma-4-E4B-it-GGUF" \
--responses_api_base_url "http://127.0.0.1:8080/v1"
Option 2: vLLM in one terminal, speech-to-speech in the other
Requires vLLM ≥ 0.21.0. Full support for the Responses API protocol, including tool-call streaming used by the speech-to-speech backend, landed in vLLM 0.21.0. Older versions will boot but trip up as soon as the assistant tries to call a tool.
When serving a model through vLLM for this pipeline, three flags are effectively required:
--enable-auto-tool-choice--tool-call-parser <tool_parser_name>— picks the per-family parser that turns the model's raw output into structured tool calls (e.g.qwen3_coderfor Qwen3 instruct models,llama3_jsonfor Llama 3,hermesfor Hermes-style models, ...).--default-chat-template-kwargs '{"enable_thinking":false}': disables the<think>reasoning channel for models that support it. For harder agentic tasks you can flip this totrueand let the model reason, but for a natural-feeling conversation we strongly recommend keeping it off: every thinking token is latency the user hears as silence before the robot starts speaking.
Terminal 1: vLLM inference server (Qwen/Qwen3-4B-Instruct-2507):
vllm serve Qwen/Qwen3-4B-Instruct-2507 \
--port 8000 \
--host 127.0.0.1 \
--max-model-len 32768 \
--enable-auto-tool-choice \
--tool-call-parser qwen3_coder \
--default-chat-template-kwargs '{"enable_thinking":false}' \
--speculative-config '{"method":"qwen3_next_mtp","num_speculative_tokens":1}'
The
--speculative-configline enables Multi-Token Prediction (MTP). It is optional, but it has a great impact on end-to-end latency. Leave it on whenever the model supports it.
Terminal 2: speech-to-speech client:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "Qwen/Qwen3-4B-Instruct-2507" \
--responses_api_base_url "http://127.0.0.1:8000/v1"
Option 3: Hugging Face Inference Endpoints
Same protocol, but the model runs on a managed GPU on Hugging Face. Deploy any chat model as an Inference Endpoint, then point the voice loop at the endpoint URL:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "Qwen/Qwen3-4B-Instruct-2507" \
--responses_api_base_url "https://<your-endpoint>.endpoints.huggingface.cloud/v1" \
--responses_api_api_key "$HF_TOKEN"
Option 4: Hugging Face Inference Providers
If you don't want to manage your own endpoint, use an Inference Provider. Hugging Face routes your request to a third-party backend (e.g. Together, Fireworks, Replicate) with a single URL:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "Qwen/Qwen3.6-35B-A3B:deepinfra" \
--responses_api_base_url "https://router.huggingface.co/v1" \
--responses_api_api_key "$HF_TOKEN"
Option 5: OpenAI (or any OpenAI-compatible provider)
When you want to test against a frontier model with zero infra, point the same flag at OpenAI:
speech-to-speech \
--mode realtime \
--stt parakeet-tdt \
--tts qwen3 \
--llm_backend responses-api \
--model_name "gpt-5.4" \
--responses_api_api_key "$OPENAI_API_KEY"
The --responses_api_* flags work the same for any provider that implements the protocol (OpenRouter, Together, Fireworks, …). Swap the base URL and the API key, keep the rest of the pipeline identical.
Running the LLM in-process
Option 1: Local LLM on MLX (Apple Silicon)
If you are on a Mac, MLX is the lowest-friction way to run a real model with sane latency. We recommend Qwen3-4B-Instruct-2507, which is small enough to feel instant on M-series chips and capable enough to hold a conversation.
speech-to-speech \
--llm_backend mlx-lm \
--model_name "mlx-community/Qwen3-4B-Instruct-2507-bf16"
The server listens on ws://127.0.0.1:8765/v1/realtime by default. Leave it running, connect the conversation app to the local backend, and you are talking to your robot.
Option 2: Local LLM on Transformers (CUDA / CPU / MPS)
Same idea, but using vanilla transformers. Use this if you are on a CUDA box, on Linux, or if you want to swap models freely without re-converting weights for MLX.
speech-to-speech \
--llm_backend transformers \
--model_name "Qwen/Qwen3-4B-Instruct-2507"
Tip.
Qwen3-4B-Instruct-2507is another good option for LLM because it gives a good speed/quality balance on a single consumer GPU. You can point--model_nameat any HF model the backend supports — for example a larger Gemma, Qwen, or a Mistral.
Running the engine on your laptop, the app on the robot
If you are running the voice engine on your laptop and the conversation app on a Reachy Mini Wireless, the only thing that changes is the URL. Make sure the engine binds to a LAN address (not just 127.0.0.1) and use the laptop's IP from the robot when you select the IP in the UI.
If you don't know your IP, here's how to find it:
macOS
ipconfig getifaddr en0 # wifi
ipconfig getifaddr en1 # ethernet (sometimes en0, varies)
Linux
hostname -I
Windows
ipconfig
Look for "IPv4 Address" under your active adapter.
You want the 192.168.x.x or 10.x.x.x one. If you see 169.254.x.x, you're not actually on the network.
Wrap up
You now have a fully local voice loop:
- A robot listening with Silero,
- transcribing with Parakeet-TDT 0.6B v3,
- thinking with whichever LLM you picked, whether that's local MLX, local Transformers, a vLLM or llama.cpp server next door, or a hosted Responses API endpoint,
- and answering with Qwen3-TTS.
Star huggingface/speech-to-speech and pollen-robotics/reachy_mini_conversation_app, and come tell us in the discussions which open-source cascade you ended up running on your robot.