基于树莓派与Node.js构建离线可定制语音助手:从硬件选型到技能扩展
2026/7/28 6:10:53 网站建设 项目流程

1. 项目缘起:为什么要在树莓派上折腾一个“有灵魂”的语音助手?

几年前,我买了个智能音箱,新鲜劲过了之后,总觉得它像个设定好程序的“复读机”。问天气、设闹钟还行,但稍微复杂点或者想让它干点私活,比如把我随口说的灵感记到自己的笔记软件里,或者控制我书桌上那盏非智能的台灯,它就彻底哑火了。市面上成熟的语音助手,功能强大但边界清晰,像一个装修精美的酒店房间,你住得很舒服,但没法按自己的心意砸墙改造。

于是,一个念头冒了出来:能不能自己造一个?一个完全听我指挥、能接入我所有私人服务和硬件、甚至能有点“个性”的语音助手。核心诉求就三点:完全离线、高度可定制、成本低廉。树莓派几乎是唯一的选择——它是一台完整的、可编程的微型电脑,功耗低,GPIO引脚能直接操控硬件,社区生态庞大。而Node.js,以其事件驱动、非阻塞I/O的特性,非常适合处理语音识别、网络请求这类高并发的异步任务,生态里又有海量的npm包可供调用,能快速搭起功能骨架。

这个项目,我称之为「volute」(词源有“螺旋上升”之意,寓意通过不断迭代,让助手的能力和“灵性”螺旋式增长)。它不是一个追求大而全的替代品,而是一个属于你自己的、可以无限扩展的“数字伙伴”起点。接下来,我会把从硬件选型、软件搭建、核心功能实现到赋予其“灵魂”的完整过程,以及我踩过的所有坑,毫无保留地分享出来。

2. 硬件准备与系统基石:为「volute」打造一个稳固的家

工欲善其事,必先利其器。硬件是「volute」的身体,操作系统和基础环境则是它的神经系统。

2.1 树莓派选型与外围设备搭配

对于语音助手项目,树莓派4B 4GB版本是目前性价比最高的选择。它的CPU和内存足够流畅运行Node.js服务、轻量级语音识别引擎以及一些额外的应用。树莓派5性能更强,但功耗和发热也更大,对于常开设备,4B的稳定性和性价比更优。

核心外设清单:

  1. USB麦克风阵列:这是提升体验的关键。普通的单麦克风在稍有环境噪音时识别率就骤降。我选用了一款三麦克风阵列的USB设备,它自带声源定位和降噪算法,能显著提升远场拾音效果。价格比单麦克风贵,但绝对物超所值。
  2. 扬声器:任何一款带有3.5mm音频接口或USB声卡的有源音箱都可以。如果追求一体化,也有直接插在GPIO上的PHAT DAC音频扩展板可选。
  3. 电源:务必使用官方或认证的5V/3A电源。供电不足会导致树莓派运行不稳定,尤其在CPU高负载进行语音识别时,可能引发莫名其妙的崩溃或识别错误。
  4. 存储:至少16GB的Class 10或A1级别的MicroSD卡。系统、Node环境、语音模型和日志都会占用空间。

注意:初次启动前,建议先通过HDMI连接显示器,或准备好网线进行有线连接,以便完成初始配置。Wi-Fi可以在系统内配置。

2.2 操作系统安装与基础优化

我选择Raspberry Pi OS (64-bit) Lite版本。作为服务器,我们不需要图形桌面,Lite版本更节省资源。使用 Raspberry Pi Imager 工具烧录系统时,有一个高级选项(Ctrl+Shift+X)非常实用:可以预先设置主机名、开启SSH、配置Wi-Fi和国家设置。这样烧录好的SD卡,插电启动后就能直接通过网络访问,实现“无头启动”。

系统烧录与首次登录后,必须做的几件事:

  1. 换源加速:默认源在国内访问很慢。修改/etc/apt/sources.list/etc/apt/sources.list.d/raspi.list,将archive.raspberrypi.orgdeb.debian.org替换为国内镜像源(如清华、中科大源)。完成后执行sudo apt update && sudo apt upgrade -y进行系统更新。

    # 示例:备份并编辑源列表 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo sed -i 's|deb.debian.org|mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list sudo sed -i 's|archive.raspberrypi.org|mirrors.tuna.tsinghua.edu.cn/raspberrypi|g' /etc/apt/sources.list.d/raspi.list
  2. 分配所有SD卡空间:使用sudo raspi-config,选择Advanced Options->Expand Filesystem,确保SD卡所有空间都被利用。

  3. 设置静态IP(可选但推荐):对于需要稳定局域网访问的设备,设置静态IP更方便。在/etc/dhcpcd.conf末尾添加配置(根据你的网络环境修改):

    interface wlan0 # 如果是无线网卡 static ip_address=192.168.1.100/24 static routers=192.168.1.1 static domain_name_servers=192.168.1.1 8.8.8.8
  4. 安装必要工具sudo apt install -y vim git curl wget htop

2.3 Node.js环境部署:拒绝版本管理器的坑

在树莓派上安装Node.js,很多人推荐用nvm(Node Version Manager)。但在生产环境或长期运行的服务上,我强烈建议直接安装二进制版本。nvm虽然灵活,但其环境变量加载方式有时会与系统服务(如systemd)产生冲突,导致服务启动时找不到node命令。

推荐方法:从NodeSource安装稳定LTS版本

# 1. 添加NodeSource仓库(以Node.js 20.x LTS为例) curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - # 2. 安装Node.js和npm sudo apt install -y nodejs # 3. 验证安装 node --version # 应输出 v20.x.x npm --version

安装完成后,可以配置npm的全局安装路径和镜像源,避免权限问题和加速下载。

# 配置npm全局安装路径到用户目录,避免sudo mkdir -p ~/.npm-global npm config set prefix '~/.npm-global' # 将路径添加到环境变量,编辑 ~/.bashrc 添加:export PATH=~/.npm-global/bin:$PATH echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc source ~/.bashrc # 更换npm镜像源 npm config set registry https://registry.npmmirror.com

至此,一个干净、稳定、高效的基础系统就准备好了。接下来,我们将进入核心的软件架构部分。

3. 核心架构搭建:让「volute」能听、会说、会思考

一个语音助手的工作流程可以抽象为:拾音 -> 语音转文本(STT)-> 意图理解(NLU)-> 执行逻辑 -> 文本转语音(TTS)-> 播放。我们将用Node.js构建一个轻量但健壮的系统来处理这个流水线。

3.1 音频输入与处理:让树莓派“听得清”

首先,我们要确保系统能正确识别并使用我们的USB麦克风阵列。

# 安装音频工具,查看设备 sudo apt install -y alsa-utils arecord -l # 列出录音设备

记下USB麦克风对应的卡号(card X)和设备号(device Y)。我们需要创建一个ALSA配置文件,将其设为默认设备。创建或编辑~/.asoundrc

pcm.!default { type asym playback.pcm "hw:0,0" # 播放设备,根据aplay -l调整 capture.pcm "hw:1,0" # 录音设备,根据arecord -l调整,card 1, device 0 } ctl.!default { type hw card 1 # 控制卡号 }

在Node.js中,我们使用node-record-lpcm16这个包来录制原始的PCM音频流。它底层调用sox或arecord,效率很高。

npm install node-record-lpcm16

核心录音代码片段:

const record = require('node-record-lpcm16'); const fs = require('fs'); // 创建可写流,将录音保存为文件(用于调试) const fileStream = fs.createWriteStream('test.wav', { encoding: 'binary' }); const recording = record.record({ sampleRate: 16000, // 大多数STT服务要求的采样率 channels: 1, // 单声道 audioType: 'wav', // 输出格式 recorder: 'arecord', // 指定使用arecord device: 'hw:1,0', // 指定录音设备 }); recording.stream().pipe(fileStream); // 录音5秒后停止 setTimeout(() => { recording.stop(); console.log('录音结束'); }, 5000);

实操心得node-record-lpcm16在树莓派上有时会因为找不到sox而报错。最稳妥的方法是显式指定recorder: 'arecord',并确保device参数正确。录制时采样率设为16000Hz,这是后续语音识别服务的黄金标准,能平衡音质和数据处理量。

3.2 语音识别(STT)引擎选型:离线是硬道理

在线STT(如Google、Azure的API)识别率高,但延迟和隐私是问题。对于「volute」,离线识别是核心诉求。经过对比,我选择了Vosk

为什么是Vosk?

  1. 完全离线:模型下载后,无需网络。
  2. 多语言支持:包含中文小模型(约40MB),识别效果在树莓派上可接受。
  3. Node.js绑定完善vosknpm包API清晰,易于集成。
  4. 资源消耗相对可控:小模型在树莓派4B上,CPU占用约30-50%,响应时间在1-3秒。

安装与使用:

# 安装Vosk的Node.js绑定 npm install vosk # 下载中文小模型(约40MB) wget https://alphacephei.com/vosk/models/vosk-model-small-cn-0.22.zip unzip vosk-model-small-cn-0.22.zip

识别代码示例:

const vosk = require('vosk'); const fs = require('fs'); const { Readable } = require('stream'); // 加载模型 const MODEL_PATH = './vosk-model-small-cn-0.22'; if (!fs.existsSync(MODEL_PATH)) { console.error(`模型未找到: ${MODEL_PATH}`); process.exit(1); } const model = new vosk.Model(MODEL_PATH); const rec = new vosk.Recognizer({ model: model, sampleRate: 16000 }); // 假设audioBuffer是从麦克风获取的16000Hz、16bit、单声道PCM数据 const audioBuffer = ...; const readable = new Readable({ read() { this.push(audioBuffer); this.push(null); // 结束流 } }); readable.pipe(rec); rec.on('data', (data) => { const result = JSON.parse(data.toString()); if (result.text) { console.log('识别结果:', result.text); // 将result.text传递给意图理解模块 } }); rec.on('end', () => { console.log('识别结束'); });

性能调优:Vosk识别是CPU密集型任务。可以通过限制识别时长(如只识别用户说完后的2-3秒音频)、使用关键词唤醒(后面会讲)来降低持续负载。对于更复杂的场景,可以研究基于Raspberry Pi的AI加速棒(如Intel NCS2)或Coral USB Accelerator来运行更重的模型,但Vosk小模型对于简单指令已足够。

3.3 意图理解(NLU)与技能(Skill)系统:让「volute”懂你”

识别出文字只是第一步,理解用户的意图才是关键。我们不需要像ChatGPT那样复杂的通用AI,而是需要一个技能(Skill)系统。每个技能负责处理一类特定的意图。

实现一个简单的规则匹配引擎:

  1. 定义技能:每个技能是一个独立的模块,包含patterns(匹配用户语句的正则表达式或关键词数组)和handler(处理函数)。
  2. 意图路由:主程序将识别到的文本,按顺序与所有技能的patterns进行匹配。匹配成功,则调用对应的handler
  3. 上下文管理(进阶):简单的上下文可以通过会话状态来实现。例如,用户问“今天天气怎么样?”,系统回答后,可以进入一个“天气查询”上下文,当用户紧接着说“那明天呢?”,系统能理解这是在问明天的天气。

示例:创建一个“问时间”技能

// skills/timeSkill.js module.exports = { name: '时间查询', patterns: [/现在几点/, /当前时间/, /几点了/], handler: async (text, context) => { const now = new Date(); const timeStr = now.toLocaleTimeString('zh-CN', { hour12: false }); return `现在时间是 ${timeStr}`; } };

主路由逻辑:

// core/nluRouter.js const skills = [require('../skills/timeSkill'), require('../skills/weatherSkill')]; // 加载所有技能 function routeIntent(userText, context) { for (const skill of skills) { for (const pattern of skill.patterns) { if (pattern.test(userText)) { console.log(`匹配到技能: ${skill.name}`); return skill.handler(userText, context); } } } return '抱歉,我没听懂你的意思。'; // 默认回复 } // 使用 const reply = await routeIntent('现在几点了?', currentContext); console.log(reply); // 输出:现在时间是 14:35:20

这个系统非常轻量且易于扩展。要增加新功能,比如控制GPIO灯,只需新建一个lightSkill.js,定义匹配模式(如“打开灯”、“关灯”),在handler里写控制GPIO的代码即可。

3.4 文本转语音(TTS)与音频输出:让「volute」开口说话

离线TTS的选择相对较少。我测试了say.js(调用系统命令,音质生硬)和pico2wave(轻量,支持中文但音色单一),最终选择了fluent-ffmpeg结合本地语音合成引擎的方案,虽然重一些,但灵活性最高。

方案:使用eSpeak NG生成语音,再经FFmpeg优化后播放

# 安装依赖 sudo apt install -y espeak-ng ffmpeg npm install fluent-ffmpeg speaker
// tts/speaker.js const { exec } = require('child_process'); const Speaker = require('speaker'); // 用于播放PCM音频流 function speak(text, lang = 'zh') { return new Promise((resolve, reject) => { // 1. 使用espeak生成WAV文件 const wavFile = `/tmp/tts_${Date.now()}.wav`; const espeakCmd = `espeak-ng -v ${lang} -w ${wavFile} "${text}"`; exec(espeakCmd, (err) => { if (err) return reject(err); // 2. 使用FFmpeg将WAV转换为树莓派声卡支持的格式(如S16LE,16000Hz)并通过管道播放 const ffmpeg = require('fluent-ffmpeg'); const speaker = new Speaker({ channels: 1, bitDepth: 16, sampleRate: 16000, }); ffmpeg(wavFile) .audioChannels(1) .audioFrequency(16000) .format('s16le') // 原始PCM格式 .on('error', reject) .on('end', () => { setTimeout(() => { fs.unlinkSync(wavFile); // 清理临时文件 resolve(); }, 100); }) .pipe(speaker, { end: true }); }); }); } // 使用 await speak('你好,我是伏特。');

踩坑实录:直接播放espeak生成的音频,有时会出现爆音或播放不完整。原因是音频格式与声卡缓冲区不匹配。通过FFmpeg统一转码为标准的16位、16kHz单声道PCM流,再通过speaker包播放,稳定性大幅提升。speaker包直接调用ALSA,延迟极低。

4. 唤醒词与持续监听:从“一直听”到“听召唤”

让设备持续进行全量语音识别,CPU会一直高负荷运转,且会误触发。我们需要一个唤醒词机制:平时设备处于低功耗监听状态,只检测特定的唤醒词(如“小伏小伏”);检测到后,再进入全量指令识别模式。

4.1 使用Porcupine实现低功耗唤醒

Picovoice的Porcupine是一款优秀的离线唤醒词引擎,对树莓派支持友好,资源占用极低。它提供预编译的Node.js绑定,并允许自定义唤醒词(需付费),也有免费的通用唤醒词(如“Hey Google”, “Alexa”的变体,或中文“你好小美”)。

安装与集成:

# 安装@picovoice/porcupine-node npm install @picovoice/porcupine-node

你需要去Picovoice官网注册获取一个免费的AccessKey。然后,我们可以创建一个唤醒监听服务:

// wakeword/porcupineService.js const Porcupine = require('@picovoice/porcupine-node'); const { createAudioStream } = require('../audio/recorder'); // 封装好的音频流 class WakeWordDetector { constructor(accessKey, keywordPath = 'porcupine_models/你好-小美_zh_raspberry-pi_v3_0_0.ppn') { this.porcupine = new Porcupine( accessKey, [keywordPath], // 唤醒词模型路径数组 [0.5] // 灵敏度,0-1,越高越容易触发也可能误触 ); this.isListening = false; } async startListening(audioStream, onDetected) { if (this.isListening) return; this.isListening = true; // 假设audioStream是16000Hz, 16-bit, 单声道的PCM数据流 for await (const audioFrame of audioStream) { if (!this.isListening) break; // Porcupine要求一次处理特定长度的音频帧(例如512个样本) const index = this.porcupine.process(audioFrame); if (index !== -1) { console.log(`唤醒词检测到! 索引: ${index}`); this.isListening = false; // 检测到后停止监听 onDetected && onDetected(index); break; } } } stop() { this.isListening = false; this.porcupine.release(); } }

4.2 构建状态机:休眠、唤醒、聆听、执行

有了唤醒检测和全量识别,我们需要一个状态机来管理设备的工作流程:

  1. SLEEP(休眠):仅运行Porcupine进行低功耗唤醒词监听。
  2. WAKE(唤醒):检测到唤醒词,播放一个简短的提示音(如“嘟”),进入LISTENING状态。
  3. LISTENING(聆听):启动Vosk进行全量语音识别,持续3-5秒或检测到静音端点(VAD)。
  4. PROCESSING(处理):将识别到的文本交给NLU路由,执行技能,生成回复。
  5. SPEAKING(说话):调用TTS播放回复。播放完毕后,返回SLEEP状态。

关键实现:静音检测(VAD)在LISTENING状态,我们不能无限时录音。需要检测用户何时说完。一个简单的方法是计算音频帧的能量,当能量持续低于阈值一段时间,则认为说话结束。

// utils/vad.js function simpleVAD(audioFrame, threshold = 100, silenceFrames = 20) { // 计算音频帧的能量(幅度的平方和) let energy = 0; for (let i = 0; i < audioFrame.length; i += 2) { const sample = audioFrame.readInt16LE(i); energy += sample * sample; } const isSpeech = energy > threshold; // 状态机:记录连续静音帧数 if (!isSpeech) { this.silenceCount = (this.silenceCount || 0) + 1; } else { this.silenceCount = 0; } // 如果连续静音帧数超过阈值,判定为说话结束 return this.silenceCount > silenceFrames; }

将VAD集成到录音循环中,一旦检测到静音,就停止录音并进入PROCESSING状态。这个状态机的实现,是整个项目从“玩具”走向“可用”的关键一步,它让交互变得自然。

5. 技能扩展与“灵魂”注入:从工具到伙伴

基础框架搭好后,「volute」只是一个语音控制的命令行。要让它有“灵魂”,我们需要扩展技能,并加入一些个性化的交互逻辑。

5.1 实现实用技能示例

技能一:智能家居控制(通过GPIO)树莓派的GPIO引脚可以直接控制继电器模块,进而控制台灯、风扇等设备。我们需要onoff这个npm包。

npm install onoff
// skills/lightSkill.js const Gpio = require('onoff').Gpio; const LED_PIN = 17; // 根据实际接线修改 let led = null; try { led = new Gpio(LED_PIN, 'out'); } catch (err) { console.warn('GPIO初始化失败,可能不在树莓派上运行:', err.message); } module.exports = { name: '灯光控制', patterns: [/打开灯/, /关灯/, /灯(开|关)/], handler: async (text) => { if (!led) return '硬件控制未就绪。'; if (text.includes('打开') || text.includes('开')) { led.writeSync(1); // GPIO输出高电平 return '灯已打开。'; } else if (text.includes('关闭') || text.includes('关')) { led.writeSync(0); // GPIO输出低电平 return '灯已关闭。'; } return '请说打开灯或关灯。'; } };

技能二:个性化信息查询(对接外部API)让「volute」能告诉你今天的头条新闻、股价,或者你最喜欢的博主是否更新了视频。这里以查询天气为例,使用和风天气的免费API。

// skills/weatherSkill.js const axios = require('axios'); module.exports = { name: '天气查询', patterns: [/(.*?)天气(怎么样)?/, /今天(天气|气候)/], handler: async (text) => { // 简单地从文本中提取城市名(这里用固定城市,更复杂可以用NLP实体识别) const city = '北京'; const apiKey = '你的和风天气KEY'; try { const response = await axios.get(`https://devapi.qweather.com/v7/weather/now?location=101010100&key=${apiKey}`); const data = response.data; if (data.code === '200') { const weather = data.now; return `北京现在天气${weather.text},温度${weather.temp}摄氏度,体感温度${weather.feelsLike}度,风力${weather.windScale}级。`; } else { return '天气查询失败,请检查网络或配置。'; } } catch (error) { console.error('天气查询错误:', error); return '抱歉,天气查询服务暂时不可用。'; } } };

5.2 赋予“灵魂”:上下文记忆与个性化回复

“灵魂”体现在它能否记住之前的对话,并做出有“个性”的回应。我们可以实现一个简单的对话上下文和情感状态机。

简易上下文管理器:

// core/contextManager.js class ContextManager { constructor() { this.session = {}; // 存储当前会话数据 this.memory = []; // 存储历史对话轮次 this.mood = 'neutral'; // 简单的情感状态:neutral, happy, tired } set(key, value) { this.session[key] = value; } get(key) { return this.session[key]; } // 记录一轮对话 logInteraction(userInput, botResponse, intent) { this.memory.push({ time: Date.now(), input: userInput, response: botResponse, intent: intent }); // 保持最近N轮对话 if (this.memory.length > 10) { this.memory.shift(); } // 根据交互内容简单更新情感状态(示例逻辑) if (intent === 'greeting') this.mood = 'happy'; if (userInput.includes('烦死了')) this.mood = 'tired'; } // 基于上下文和情感生成个性化回复前缀 getPersonalizedPrefix() { const prefixes = { neutral: ['', '好的。', '嗯。'], happy: ['很高兴为你服务!', '乐意效劳!'], tired: ['哦...', '知道了。'] }; const choices = prefixes[this.mood]; return choices[Math.floor(Math.random() * choices.length)]; } }

在NLU路由中,在处理技能回复前,先获取个性化前缀,拼接到最终回复里。

const context = new ContextManager(); const rawReply = await skill.handler(userText, context); const finalReply = context.getPersonalizedPrefix() + rawReply; context.logInteraction(userText, finalReply, skill.name);

这样,当你连续问几个问题后,再说“打开灯”,它可能会回答“哦... 灯已打开。”,带有一点拟人的情绪反馈。你还可以扩展这个上下文管理器,让它记住你的名字、偏好(比如你总是问北京的天气),实现更个性化的交互。

6. 系统集成与后台服务化:让「volute」7x24小时待命

我们不可能一直开着SSH终端运行Node脚本。需要将「volute」变成一个系统服务,开机自启,稳定运行。

6.1 使用PM2进行进程管理

PM2是一个强大的Node.js进程管理器,能守护进程、记录日志、监控资源。

# 全局安装PM2 npm install -g pm2 # 在项目根目录创建启动脚本 start.sh #!/bin/bash node index.js # 给脚本执行权限 chmod +x start.sh # 用PM2启动应用,并命名为volute pm2 start ./start.sh --name volute # 设置开机自启(针对当前用户) pm2 startup # 执行上面命令输出的提示命令(例如 sudo env PATH=...) pm2 save

现在,volute服务会在后台运行,即使退出SSH也不会停止。可以通过pm2 logs volute查看日志,pm2 monit监控资源。

6.2 应对常见问题与优化

问题一:音频设备冲突如果同时有其他服务(如蓝牙音频)占用声卡,会导致录音或播放失败。可以通过ALSA配置指定硬件设备(如前文所述),或使用pulseaudio进行音频路由管理(更复杂)。

问题二:内存泄漏长时间运行后,Node.js进程内存可能缓慢增长。定期重启是简单有效的办法。可以用PM2设置定时重启:

pm2 start ./start.sh --name volute --cron-restart="0 */12 * * *" # 每12小时重启一次

问题三:网络依赖像天气查询这类技能依赖网络。需要增加网络状态检测和超时处理,在网络不可用时提供降级回复(如“网络好像有点问题,无法查询天气哦”)。

问题四:误唤醒与误识别调整Porcupine的灵敏度阈值。在NLU路由中,增加置信度判断。如果匹配到的技能模式非常模糊,可以回复“你刚才是说XX吗?我没太听清。”,进行二次确认。

7. 项目总结与未来遐想

回顾整个「volute」的构建过程,从一块裸板树莓派,到它能听懂我的话、控制我桌面的灯光、告诉我天气,甚至带点小情绪地回应,这种成就感是购买成品无法比拟的。这个项目的核心价值不在于复现一个多强大的语音助手,而在于它提供了一个完全开放、可深度定制的框架。

你现在拥有的,是一个由Node.js驱动的、模块化的语音交互中枢。你可以像搭积木一样添加新技能:写一个技能连接到你的智能家居中枢(Home Assistant)控制所有设备;写一个技能调用本地大语言模型(比如用llama.cpp在树莓派上跑小参数模型)进行闲聊;甚至写一个技能让它在你回家时,用TTS播报你订阅的RSS内容。

我个人的几点实操体会:

  1. 音频是最大的坑:USB麦克风的选择、ALSA/PulseAudio的配置、录音参数的设置,每一步都可能出问题。务必先确保arecordaplay命令行工具能正常工作,再写代码。
  2. 离线与在线的权衡:完全离线意味着能力和响应速度的妥协。对于核心唤醒和简单指令,离线是必须的。但对于复杂查询(如“帮我找一下关于量子计算的科普文章”),可以设计一个“联网技能”,在用户授权后,将问题发送到云端AI服务(如开放的LLM API)获取答案,再通过本地TTS播放。这样既保护了隐私,又扩展了能力边界。
  3. 性能监控很重要:用htoppm2 monit长期观察CPU和内存占用。Vosk识别期间CPU冲高是正常的,但如果空闲时也持续很高,就要检查是否有循环任务没被正确释放。

这个项目没有终点。你可以把它看作一个起点,一个属于你自己的、不断进化的数字生命雏形。下一步,我打算尝试集成一个本地的小规模语音合成模型,让它的声音不再那么机械;或者加入简单的视觉模块(用树莓派摄像头),让它具备“看”的能力。乐趣,就在于这无尽的折腾之中。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询