利用树莓派上构建本地AI语音助手,为偏远地区提供私密、离线的AI服务
一款完全离线、注重隐私的人工智能语音助手,运行在树莓派5上,专为非洲社区打造,能够理解并用特威语、加纳语、埃维语和英语进行交互,无需等待硅谷关注他们的语言。
如今市面上所有主流语音助手——Siri、Google Assistant、Alexa——都将非洲语言视作次要选项。你想用提威语交流?可惜了。加语?完全不可能。埃韦语?你是在做梦。
就连支持少数非洲语言的罕见助手,也依赖云端服务。你所说的每一个词都会被发送到海外,在他人的服务器上处理后返回。对于互联网不稳定、覆盖范围广泛的西非地区社区而言,这在对话开始前就已构成障碍。
Boafoc 可同时解决这两个问题。所有操作都在树莓派5上本地运行。拔掉以太网线,关闭Wi-Fi,Boafoc仍然可以正常工作。
工作原理
该系统是一个模块化管道,每个阶段都可独立切换至下一阶段。没有任何东西是黑箱,每个组件都可以独立更换。
配备8GB内存的Pi 5是同时运行3B量化大语言模型、Fast Whisper和Piper语音合成器而不受内存压力影响的最低舒适平台。虽然Pi 4在技术上也能实现,但使用起来不太舒适;而Pi 5则轻松应对,毫无压力。此外,Cortex-A76核心在音频流媒体、推理计算以及同时更新OLED屏幕时,对I/O吞吐量也有显著提升作用。
软件栈(全部免费且开源)
I2C硬件接线
所有传感器都连接到 Pi 5 的 I2C 总线 1,即 GPIO2(SDA,引脚 3)和 GPIO3(SCL,引脚 5)。
验证所有连接是否正常:
接线图
MPU6050的Errno 121(远程I/O错误)是由于跳线松动所致,而非驱动程序问题。在调试软件前,请务必先检查物理连接。
音频管道
Google VoiceHAT 使用 I2S 通过 GPIO 实现数字音频协议。它需要一个内核设备树覆盖层来激活声卡驱动程序。如果没有该覆盖层,将无法检测到麦克风。
但由于缺少实际的语音HAT,我使用了INMP441 MEMS麦克风和MAX98357A I2S放大模块,在Medium上撰写了以下文章,自行组装了一个设备。
在 /boot/firmware/config.txt 中添加以下行:
重启后,确认声卡已显示:
你应该看到:卡2:sndrpigooglevoi [Google语音HAT声卡...]
蓝牙音频设置
Boafoc 使用 PipeWire 将音频路由到蓝牙耳机。请安装所需的软件包:
使用 bluetoothctl 连接您的耳机:
将 XX:XX:XX:XX:XX:XX 替换为您的耳机的 MAC 地址。连接后,PipeWire 会自动将其设为默认输出。
VoiceHAT 挑战
VoiceHAT 以 48kHz、立体声、S32_LE(32位有符号)进行录制。而流水线中的每个AI模型都要求16kHz、单声道、int16格式。因此,每个音频帧处理的第一件事就是进行转换:
•将原始字节解析为 int32 样本
•右移16位——将S32转换为int16范围,去除低16位的噪声
•仅保留左声道——立体声变为单声道
•Decimate 3:1 - 48kHz 转为 16kHz
这在AI模型接收到音频之前,就通过一次numpy操作完成。它轻量高效,延迟几乎为零,对于16kHz的语音而言,音质完全足够。
唤醒词:“Boafoc”
唤醒词是“Boafoc”,这是为本项目专门定制的训练短语。该模型使用OpenWakeWord的训练流程训练而成,是一个自定义的.onnx文件(Boafoc.onnx)。
一个关键的实现细节:OpenWakeWord 的 Model() 类接受的是位置参数列表,而不是关键字参数。Model(["Boafoc.onnx"]) 可以正常工作,而 Model(wakeword_models=["Boafoc.onnx"]) 会抛出 TypeError。这一点在早期就让我感到困惑,而且从文档中并不明显。
语音活动检测
WebRTC VAD 在检测到唤醒词后运行,持续累积音频帧,直到检测到约600毫秒的静音。这标志着用户语音的结束,并触发自动语音识别(ASR)阶段。如果没有VAD,系统要么过早截断语音,要么会无限录制。
语音识别
模型选择
Boafoc 采用分层方法:
•Twi Wav2Vec2 CTranslate2 (int8) - 用于 Twi 语音。CTranslate2 int8 在 CPU 上比原始 PyTorch 模型快得多。
•Akan Whisper 用于在 Wav2Vec2 置信度较低时,作为 Akan/Twi 的回退方案,或作为二次检查。
•faster-whisper(基础版,int8)——适用于英语、高加索语以及任何自动检测的语言。int8 量化在 CPU 上相比 float32 大约快 2 倍。
所有模型在启动时加载,而非按需加载。这会增加30到60秒的启动时间,但在实际对话中意味着零延迟的模型加载。对于语音助手而言,这种权衡是显而易见的。
语言设置
活动语言设置在 .env 文件中:
语言模块在启动时读取此信息,并将音频路由到正确的ASR模型。无需运行时的语言检测,这使得系统运行更快且更可预测。
语言模型(大脑)
Boafoc 通过 Ollama 在本地运行 llama3.2:3b。这是实现可靠工具跟随行为的最小可行模型大小,较小的模型(1B、0.5B)经常无法正确遵循结构化输出格式,从而导致工具调用失败。
LLM处理以下内容:
•理解用户在询问什么
•决定是调用工具(如传感器、文件系统等)还是直接响应
•生成响应文本
•在适当的情况下,将加纳语短语自然融入英语回复中,例如来自提威语和埃维语的词汇和表达,使助手呈现出其文化特色。
文字转语音
TTS 根据语言上下文使用三种不同的引擎:
•Piper TTS - 用于英语及混合语言的响应。快速、高质量,输出原始PCM数据直接传输至aplay。
•Ewe MMS VITS(Meta的多语言语音)——用于Ewe语输出。MMS涵盖1100多种语言,其中包括多个西非语言。
•加纳NLP总部TTS——用于特威语/阿坎语输出的高质量加纳语音。
音频通过 PipeWire 音频系统传输到扬声器。对于蓝牙输出,使用了 aplay -D pulse 命令,但该命令需要单独安装 libasound2-plugins(这一点在 Piper 文档中并不明显,导致调试过程十分令人沮丧)。
硬件传感器工具
I2C传感器连接到可语音查询的工具。当你问“温度是多少?”时,Boafoc 会读取 AHT40 的数据,格式化结果并用语音播报出来。
OLED特别适合调试。在听到TTS响应之前,就能通过观察文字在屏幕上逐字显示来确认ASR是否正常工作。
文件系统工具 — 安全模型
Boafoc 可通过语音指令读取和写入本地文件。由于给 AI 无限制的文件系统访问权限是个糟糕的想法,该工具采用了八层安全模型:
•路径解析 - 不进行符号链接遍历,不尝试 [../] 转义
•沙箱执行 - 在 .env 中配置的绝对路径白名单
•大小限制 - 不会读取超过可配置限制的文件(默认 10MB)
•扩展黑名单 - .key、.pem、.env、.id_rsa 及类似文件将被永久禁止
•自动备份 - 在执行任何写入操作前创建带时间戳的 .bak 文件
•软删除 - 文件移至回收站,不会永久删除
•完整审计日志——每项操作均带有时间戳,并以JSON格式记录
•YAML 命令允许列表——仅可执行配置文件 fs_commands.yaml 中明确允许的操作
沙箱根目录在 .env 文件中按部署配置:
软件包管理
在 Debian Trixie + Pipenv + Python 3.13 环境下,正确的安装方法是:
必须先安装仅支持CPU的PyTorch,否则pip会自动选择CUDA版本,其体积是原来的3到4倍,在树莓派上无法正常运行:
若要无需 sudo 访问 GPIO,请将你的用户添加到 gpio 和 dialout 组,然后重启系统。对于 Pi 5,lgpio 是正确的 GPIO 后端,而较旧的 RPi.GPIO 库需要进行补丁。
项目结构
从零开始设置
步骤1:克隆并安装
步骤2:启用I2C并检查传感器
步骤3:设置Ollama并拉取模型
步骤4:GPIO访问(无需sudo)
步骤5:测试每个模块
每个层级都可以独立测试,而无需启动整个流水线。这使得调试变得简单直接,能够准确隔离出故障组件,而无需猜测正在运行的系统内部情况。
步骤6:配置与运行
所有设置都位于项目根目录下的一个 .env 文件中。只需修改该文件即可在不更改任何 Python 代码的情况下切换模式、模型或硬件。
步骤7:运行
性能(在 Pi 5 上)
该系统在8GB内存下运行舒适。主动散热器是必须的,但不得不排除它,冒着不安装的风险,因为没有它时持续的LLM推理温度可达约80°C。
本文编译自hackster.io





