基于 LLM 与 ASR 从零搭建 Windows 智能语音助手
项目背景与架构设计
随着大语言模型(LLM)技术的快速发展,构建本地化的智能助手已成为可能。传统的命令行工具或简单的脚本已无法满足用户对自然交互的需求。本项目旨在利用 Python 生态中的成熟组件,在 Windows 系统上搭建一个具备语音输入、语义理解能力的智能体(Agent)。
核心架构
系统主要由以下三个模块组成:
- 语音识别模块 (ASR):负责将麦克风采集的音频流实时转换为文本。本方案选用
Sherpa-onnx,因其支持 ONNX Runtime,在 CPU 环境下也能保持高效的推理速度。 - 大语言模型模块 (LLM):负责接收识别后的文本,进行语义分析并生成回复。本方案采用
Agently框架来管理 Agent 状态及 Workflow。 - 交互控制模块:负责协调 ASR 与 LLM 的数据流转,实现'语音 - 文本 - 语音'的闭环。
环境准备
在开始编码之前,请确保您的开发环境满足以下要求:
- 操作系统:Windows 10/11
- Python 版本:建议 Python 3.9 及以上
- 依赖管理:推荐使用
venv创建虚拟环境以隔离依赖
安装基础依赖库:
pip install sounddevice sherpa_onnx Agently python-dotenv
一、接入语音识别 (ASR)
语音识别是智能助手的耳朵。我们使用 Sherpa-onnx 提供的在线识别接口,它支持端点检测(Endpoint Detection),能够自动判断用户何时说完一句话。
1. 模型下载
Sherpa-onnx 需要预训练模型文件。对于中文场景,推荐使用 Paraformer 模型。您可以从官方仓库或镜像站下载模型包,解压后需包含 encoder.int8.onnx, decoder.int8.onnx, tokens.txt 等文件。
2. 代码实现
创建一个名为 microphone_asr.py 的文件,用于封装语音处理逻辑。该类负责初始化识别器、监听麦克风流并进行实时转写。
#!/usr/bin/env python3
import os.path
import queue
from typing import Generator
import sounddevice as sd
import sys
import logging
import sherpa_onnx
logger = logging.getLogger(__name__)
class AsrHandler:
def __init__(self, model_path, debug=False):
self.recognizer = None
self.sentence_q = queue.Queue()
self.init_recognizer(model_path)
self.debug = debug
def init_recognizer(self, model_path):
# 加载模型路径配置
encoder = os.path.join(model_path, "encoder.int8.onnx")
decoder = os.path.join(model_path, "decoder.int8.onnx")
tokens = os.path.join(model_path, "tokens.txt")
self.recognizer = sherpa_onnx.OnlineRecognizer.from_paraformer(
tokens=tokens,
encoder=encoder,
decoder=decoder,
num_threads=2,
sample_rate=16000,
feature_dim=80,
enable_endpoint_detection=True,
rule1_min_trailing_silence=2.4,
rule2_min_trailing_silence=1.2,
rule3_min_utterance_length=300,
)
@staticmethod
def show_devices():
devices = sd.query_devices()
if len(devices) == 0:
logger.info("未找到麦克风设备")
sys.exit(0)
logger.info(f"默认输入设备:{devices[sd.default.device[0]]["name"]}")
def handle(self) -> Generator:
logger.info("麦克风 ASR 启动中,请说话...")
sample_rate = 48000
samples_per_read = int(0.5 * sample_rate)
stream = self.recognizer.create_stream()
last_result = ""
segment_id = 0
try:
with sd.InputStream(channels=1, dtype="float32", samplerate=sample_rate) as s:
while True:
samples, _ = s.read(samples_per_read)
samples = samples.reshape(-1)
stream.accept_waveform(sample_rate, samples)
while self.recognizer.is_ready(stream):
self.recognizer.decode_stream(stream)
is_endpoint = self.recognizer.is_endpoint(stream)
result = self.recognizer.get_result(stream)
if result and (last_result != result):
last_result = result
if self.debug: logger.info(f"Segment {segment_id}: {result}")
if is_endpoint:
if result:
if self.debug: logger.info(f"Segment {segment_id}: {result}")
segment_id += 1
yield result
self.recognizer.reset(stream)
except sd.PortAudioError as e:
logger.exception(f"无输入设备:{e}")
if __name__ == "__main__":
try:
asr_gen = AsrHandler(model_path="./models/asr/sherpa").handle()
for chunk in asr_gen:
print("ASR Result : ", chunk)
except KeyboardInterrupt:
print("\n程序已退出")
3. 参数调优说明
rule1_min_trailing_silence: 连续静音超过 2.4 秒判定为结束。可根据实际语速调整。sample_rate: 输入采样率设为 48kHz,内部会自动重采样至 16kHz,保证兼容性。
二、基于 Agently 接入大模型
为了管理对话状态和调用大模型,我们引入 Agently 框架。它提供了可视化的调试能力和简洁的 API。
1. 环境变量配置
为避免硬编码密钥,建议使用 .env 文件存储敏感信息。在项目根目录创建 .env 文件:
API_KEY=your_api_key_here
API_URL=https://api.your-provider.com/v1
MODEL=deepseek-chat
2. 调用大模型
创建 agent.py 文件,初始化 Agent 工厂并设置模型参数。
import os
import Agently
from dotenv import load_dotenv
load_dotenv()
agent_factory = Agently.AgentFactory()
agent_factory \
.set_settings("current_model", "OpenAI") \
.set_settings("model.OpenAI.auth", {"api_key": os.environ["API_KEY"]}) \
.set_settings("model.OpenAI.url", os.environ["API_URL"]) \
.set_settings("model.OpenAI.options", {"model": os.environ["MODEL"]})
agent = agent_factory.create_agent("agent_id_1", is_debug=True)
# 测试连接
response = agent.input("Hello, how are you?").start()
print(response)
三、整合 ASR 与 LLM
将上述两个模块结合,实现实时的语音对话流程。核心逻辑在于监听 ASR 生成的句子生成器,一旦检测到完整语句,立即发送给 LLM。
1. 主程序逻辑
import os
import Agently
from dotenv import load_dotenv
import logging
# 导入 ASR 类 (此处省略具体类定义,参考上文 AsrHandler)
# from microphone_asr import AsrHandler
load_dotenv()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
agent_factory = Agently.AgentFactory()
agent_factory \
.set_settings("current_model", "OpenAI") \
.set_settings("model.OpenAI.auth", {"api_key": os.environ["API_KEY"]}) \
.set_settings("model.OpenAI.url", os.environ["API_URL"]) \
.set_settings("model.OpenAI.options", {"model": os.environ["MODEL"]})
agent = agent_factory.create_agent("jarvis_agent", is_debug=True)
try:
# 初始化 ASR 处理器
asr_gen = AsrHandler(model_path="./models/asr/sherpa").handle()
logger.info("系统就绪,等待语音指令...")
for sentence in asr_gen:
logger.info(f"收到语音:{sentence}")
# 发送请求给 LLM
response = agent.input(sentence).start()
logger.info(f"模型回复:{response}")
# TODO: 此处可接入 TTS 模块播放回复
except KeyboardInterrupt:
print("\n程序终止")
四、安全与部署建议
1. 密钥管理
切勿将 API Key 提交到代码仓库。在生产环境中,应使用服务器环境变量或密钥管理服务(如 AWS Secrets Manager)。
2. 性能优化
- 并发处理:当前为单线程阻塞模式。若需提升响应速度,可使用
asyncio异步处理 ASR 流与 LLM 请求。 - 缓存机制:对于重复问题,可在 LLM 层增加缓存,减少 Token 消耗。
3. 常见错误排查
- 麦克风权限:Windows 系统需在隐私设置中允许应用访问麦克风。
- 模型加载失败:检查模型路径是否正确,确保 ONNX 运行时库已安装。
- 网络超时:LLM 请求可能因网络波动失败,建议添加重试机制。
五、总结与后续规划
本文完成了 Windows 智能语音助手的基础搭建,实现了语音输入到大模型输出的链路。通过 Sherpa-onnx 和 Agently 的组合,我们获得了一个轻量级且可扩展的 Agent 原型。
下一步计划
- TTS 集成:接入文本转语音模块(如 Edge-TTS),实现语音播报。
- 窗口控制:利用
pyautogui或uiautomation实现根据指令操作 Windows 窗体。 - 记忆功能:引入向量数据库,实现长短期记忆,让助手记住用户偏好。
通过持续迭代,该框架可演变为一个功能完备的个人数字助理。开发者可根据实际需求扩展更多垂直领域的插件能力。


