拓冰建站拓冰建站
首页 / 资讯中心 / 正文

用声音控制AI Agent:从语音识别到工具调用的完整实战

这篇我们来做一个很有意思的动手项目用声音来控制 AI Agent。很多人已经在业务中接入了大模型也搭过类似 ChatGPT 的对话窗口但一旦到了厨房、车间、实验室这种不方便打字的场景文字交互就不太现实了。于是我整理了一套从录音、识别、Agent 推理到语音播报的完整闭环代码可以直接复制运行适合正在学习 Agent 开发、或者想在本地玩具项目里加上语音能力的同学。先说清楚我们要做出来的东西你对着麦克风说一句话比如“现在几点了”“看看系统 CPU 状态”“把客厅灯打开”程序会把语音转成文字交给 Agent 做意图理解自动调用对应工具最后再把结果用语音读出来。完整链路跑通之后你要再往上接智能家居、物联网设备或者换成自己的业务工具就只需要扩展工具函数不需要重写主流程。1. 背景与核心概念1.1 什么是 AI AgentAI Agent智能体这个概念最近讨论得非常多。简单理解Agent 不再是“你问一句、它答一句”的聊天机器人而是一个能理解目标、拆解步骤、调用外部工具来完成任务、并根据结果继续推理的程序。举个例子普通聊天模型遇到“帮我看看北京今天适不适合跑步”只能给你一段通用建议。但如果交给 Agent它可以做这样的事解析出用户想了解的是“北京天气 运动建议”调用天气查询工具拿到北京当天温度、风力、空气质量根据数据判断是否适合户外跑步把结果整理成自然语言告诉你。也就是说Agent 的核心能力是工具调用Function Calling / Tool Calling。LLM 负责“想”工具负责“做”。我们这次的项目正是围绕这个机制展开。1.2 为什么要用声音控制 Agent为什么要给 Agent 加上声音控制最直接的原因是语音是效率很高的自然交互方式。想一想这些场景你在厨房做饭手上全是油没办法敲键盘你在调试设备视线一直盯着仪器屏幕家里有老人或小朋友不会打字你在外场测试手里拿着工具不方便打开手机打字。在这些场景下用户真正需要的是“说出来就能干活”而不是“打开电脑、敲一段 prompt”。另一方面给 Agent 加语音能力本质上是在原有交互链路上加两个模块一个是语音转文字STT负责把用户的话变成模型能理解的文本一个是文字转语音TTS负责把 Agent 的回答念给用户听。这两个模块都是成熟技术组合起来就是一套完整的语音 Agent。用声音控制 Agent 还有一层价值它让 AI 应用从“聊天窗口”走向“语音助理”。这正好也是当前 Agent 开发里很受关注的方向——多模态输入、语音交互、终端设备控制。1.3 一条完整的语音 Agent 链路把完整流程拆开一共五步用户说话 → 麦克风采集 → 语音识别成文字 → Agent 推理与工具调用 → 结果转语音播报展开来看环节做什么常用技术方案音频采集从麦克风录制数字音频sounddevice、PyAudio语音识别 STT把音频转成文本faster-whisper、云 ASR APIAgent 推理理解用户意图决定是否调用工具OpenAI 兼容的工具调用接口工具调用执行本地函数返回结果给模型自定义 Python 函数语音合成 TTS把回答文本变成语音edge-tts、pyttsx3、云 TTS本文代码的核心思路是先把“文字 Agent”调通再在外面套一层语音模块。这样做的好处是无论 Agent 逻辑怎么变语音层都不用重写反过来你想换成蓝牙音箱、机器人终端也只需要替换音频输入输出部分。2. 技术选型与架构设计2.1 语音识别选型为什么用 faster-whisper语音识别目前最主流的方向是基于 Whisper 的本地推理方案。faster-whisper 是基于 CTranslate2 的 Whisper 加速实现比原版快不少对 CPU 也更友好。选择 faster-whisper 的理由本地运行不依赖外部语音识别接口隐私性更好支持中文开箱即用模型按需下载tiny到large-v3都有可以在速度和准确率之间取舍社区活跃Python API 很稳定。如果你在手机上或者低功耗设备上跑也可以用 sherpa-onnx 这类更轻量的方案。但作为技术教程示例faster-whisper 在电脑上最容易跑通。2.2 Agent 推理选型OpenAI 兼容工具调用Agent 部分我没有依赖 LangChain 这类重量级框架而是直接用“OpenAI 兼容接口”的工具调用协议写了一个最小循环。为什么这样设计DeepSeek、通义千问、Ollama、vLLM 等大多数大模型服务都提供了 OpenAI 兼容接口工具调用协议已经成为事实标准换模型只需改base_url和model字段不引入框架代码逻辑透明初学者能看清楚 Agent 每一步在干什么等项目复杂到需要多 Agent 协作、状态机管理时再引入 LangGraph 也来得及。本文示例会以某个 OpenAI 兼容服务为例来写调用代码实际使用时替换成你自己的 API Key 和模型名即可。2.3 TTS 选型edge-tts 和离线替代方案语音合成我选了 edge-tts这是一个基于微软 Edge 在线语音服务的 Python 库优点是音色自然、中文效果好、代码简单缺点是生成需要联网。如果你的使用环境完全不能联网可以改用 pyttsx3它调用系统自带 TTS 引擎完全离线但音色相对机械。两种方案我都在文章里给出说明你按实际环境取舍。2.4 整体架构图┌──────────────┐ PCM ┌────────────┐ 文本 ┌──────────────────┐ │ 麦克风采集 │ ─────── │ 语音识别 │ ─────── │ Agent 推理 │ └──────────────┘ └────────────┘ │ 工具调用循环 │ └────────┬─────────┘ │ 工具结果 ┌──────────────┐ MP3 ┌────────────┐ 回答文本 ┌─────▼─────────┐ │ 播放器 │ ─────── │ TTS 合成 │ ────────── │ 自然语言整理 │ └──────────────┘ └────────────┘ └───────────────┘整个项目就是围绕这个图来写代码的。3. 环境准备与项目结构3.1 环境要求建议使用 Python 3.10 或更高版本。需要准备一个可用的麦克风一台能联网的电脑用于下载 Whisper 模型、调用大模型 API、edge-tts 合成语音ffmpeg 命令faster-whisper 解码和 ffplay 播放都会用到。ffmpeg 安装方式因系统而异Windows到 ffmpeg 官网下载安装包把bin目录加入系统 PATHmacOSbrew install ffmpegUbuntu/Debiansudo apt install ffmpeg。安装完成后在终端输入ffmpeg -version能输出版本信息就是正常的。如果下载 Whisper 模型时网络不稳定可以设置 Hugging Face 镜像环境变量然后把模型目录切到镜像地址这部分和普通 Python 库的国内镜像加速是同一个思路。3.2 项目目录结构项目结构如下voice-agent/ ├── config.py # 全局配置 ├── tools.py # Agent 可调用的工具函数 ├── agent.py # Agent 推理与工具调用循环 ├── speech.py # 录音、识别、语音合成 ├── main.py # 主程序入口 └── requirements.txt # 依赖清单3.3 安装依赖在项目目录下创建requirements.txtsounddevice0.4.6 numpy1.24.0 faster-whisper1.0.0 openai1.14.0 edge-tts6.1.0然后安装pip install -r requirements.txt安装完成后可以先跑一段极简代码验证麦克风是否可用import sounddevice as sd print(sd.query_devices())输出中需要看到你的麦克风设备并且default_samplerate不为 0。如果没有设备需要检查系统音频权限Windows 下还要在系统设置里给终端软件开启麦克风权限。faster-whisper 第一次运行时会自动下载base模型到用户目录这个过程需要联网等待时间取决于网络状况。4. 完整实战从文字 Agent 到语音 Agent下面我们按照文件顺序编写代码。这一部分是整个项目的核心建议边读边复制到自己的项目里逐个文件对照理解。4.1 配置文件 config.py配置文件统一管理模型地址、录音参数、API Key 等变量。把可变参数放到配置文件里代码其他地方就不用到处改硬编码。# 文件路径config.py # 大模型接口配置改成你自己的服务地址和 Key # 支持 DeepSeek、通义千问、Ollama 等 OpenAI 兼容接口 LLM_BASE_URL https://api.deepseek.com/v1 LLM_API_KEY sk-xxxx # 替换成自己的 API Key LLM_MODEL deepseek-chat # 录音参数 SAMPLE_RATE 16000 # 16k 采样率Whisper 输入标准 RECORD_CHANNELS 1 # 单声道 RECORD_SECONDS 5 # 默认录音时长可按需调整 # 智能设备控制接口地址 # 本示例是占位地址真实项目中改成你的设备网关 DEVICE_API_BASE http://192.168.1.100:8080这里有个容易忽略的点Whisper 对 16kHz 单声道音频识别效果最稳定。虽然 faster-whisper 内部会做采样率转换但统一在采集端固定 16k你的录音模块就和识别模块解耦了后面换任何 ASR 服务都不需要改采集代码。4.2 工具模块 tools.py工具函数是 Agent 的“手脚”。我在示例里提供了三个工具get_current_time获取当前时间get_system_status获取本机 CPU 和内存状态control_smart_device控制智能设备示例为模拟接口。每个工具函数都对应一个 JSON Schema 描述模型根据描述决定什么时候调用、传什么参数。# 文件路径tools.py import datetime import json import platform import subprocess import urllib.request from config import DEVICE_API_BASE from zoneinfo import ZoneInfo def get_current_time(timezone: str Asia/Shanghai) - str: 获取指定时区的当前时间。 try: now datetime.datetime.now(ZoneInfo(timezone)) except Exception: now datetime.datetime.now() return now.strftime(%Y-%m-%d %H:%M:%S) def get_system_status() - str: 获取本机 CPU 和内存使用情况。 try: if platform.system() Linux: out subprocess.check_output( [sh, -c, top -bn1 | head -5], timeout5, ) return out.decode(utf-8, errorsignore) else: # Windows / macOS 用 psutil需要先 pip install psutil import psutil cpu_percent psutil.cpu_percent(interval1) mem psutil.virtual_memory() return fCPU 使用率 {cpu_percent}%内存使用率 {mem.percent}% except Exception as e: return f获取系统状态失败{e} def control_smart_device(device_id: str light_001, action: str on) - str: 向设备网关发送控制指令。 这里默认是演示模式真实接口未启用时会返回模拟结果。 接入真实设备后把 DEVICE_API_BASE 改成设备网关地址即可。 url f{DEVICE_API_BASE}/device/{device_id}/command payload json.dumps({action: action}).encode(utf-8) try: req urllib.request.Request( url, datapayload, headers{Content-Type: application/json}, methodPOST, ) with urllib.request.urlopen(req, timeout3) as resp: data resp.read().decode(utf-8) return f控制指令已发送{device_id} - {action}设备响应{data} except Exception as e: # 没有真实设备时返回模拟结果方便演示 Agent 调用工具的过程 return f[演示模式] 已准备向设备 {device_id} 发送 {action} 指令真实接口未启用{e} TOOLS [ { type: function, function: { name: get_current_time, description: 获取指定时区的当前时间, parameters: { type: object, properties: { timezone: { type: string, enum: [Asia/Shanghai, UTC], } }, }, }, }, { type: function, function: { name: get_system_status, description: 获取本机 CPU 和内存使用状态, parameters: { type: object, properties: {}, }, }, }, { type: function, function: { name: control_smart_device, description: 控制智能设备例如打开或关闭灯光, parameters: { type: object, properties: { device_id: {type: string}, action: {type: string, enum: [on, off]}, }, required: [device_id, action], }, }, }, ] def dispatch_tool(name: str, arguments_json: str) - str: 根据模型返回的参数执行本地工具函数。 参数说明 name工具名称需与 TOOLS 中声明的一致 arguments_json模型生成的工具参数JSON 字符串 args json.loads(arguments_json or {}) if name get_current_time: return get_current_time(**args) if name get_system_status: return get_system_status(**args) if name control_smart_device: return control_smart_device(**args) return f未找到工具: {name}这里有一点值得注意control_smart_device在真实接口不可用时返回了模拟结果。这样做的好处是你可以先在没有硬件的情况下跑通整个 Agent 流程看到“工具调用”这个动作真实发生了之后再把函数里的 HTTP 请求换成 MQTT、串口或者其他协议整个链路不需要改动。从安全角度考虑control_smart_device这类函数是要真正操作外部设备的。如果你在企业项目里做类似功能建议对device_id和action做白名单校验不能接受模型随意生成的设备 ID。4.3 Agent 核心模块 agent.py这个文件是整个项目的“大脑”。它的核心逻辑是工具调用循环把用户文本作为user消息发给大模型模型决定是直接回答还是要调用某个工具如果模型返回tool_calls我们就执行对应工具把结果以tool角色追加到对话里继续把完整对话发给模型直到模型生成最终回答。之所以要循环是因为一个复杂任务可能连续调用多个工具。比如用户说“帮我查下天气如果下雨就提醒我带伞”模型可能先查天气再根据天气结果决定下一步这在一个 round 里未必能完成。# 文件路径agent.py from openai import OpenAI from config import LLM_API_KEY, LLM_BASE_URL, LLM_MODEL from tools import TOOLS, dispatch_tool SYSTEM_PROMPT ( 你是中文语音助手。请根据用户指令调用可用工具完成任务 工具结果返回后把结果转成自然语言告诉用户。 回答要简洁适合语音播报不要输出过长或带 Markdown 格式的内容。 ) class VoiceAgent: def __init__(self): # 使用 OpenAI 兼容接口不同服务商只需改 base_url 和 model self.client OpenAI( api_keyLLM_API_KEY, base_urlLLM_BASE_URL, ) self.model LLM_MODEL self.max_rounds 5 # 防止模型陷入工具调用死循环 def ask(self, user_text: str) - str: 输入用户文本返回 Agent 回答文本。 messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_text}, ] for _ in range(self.max_rounds): resp self.client.chat.completions.create( modelself.model, messagesmessages, toolsTOOLS, tool_choiceauto, ) message resp.choices[0].message # 没有工具调用说明模型已经生成最终回答 if not message.tool_calls: return message.content or 模型没有返回文本 # 把模型输出追加到对话中保留完整上下文 messages.append(message) # 逐个执行工具调用 for tool_call in message.tool_calls: result dispatch_tool( tool_call.function.name, tool_call.function.arguments or {}, ) messages.append( { role: tool, tool_call_id: tool_call.id, content: result, } ) return 工具调用轮数过多已停止。请换个说法重试。这里需要解释一个关键概念为什么要用messages.append(message)后再追加 tool 消息。在 OpenAI 兼容协议里tool_calls和roletool的消息必须是成对出现的。模型在上一轮生成了一个tool_call你要把这一整条 assistant 消息原样放回对话中再把工具结果以tool_call_id关联到对应调用上。如果漏掉tool_call_id大部分模型服务会直接报错。另外SYSTEM_PROMPT里我特别要求“回答简洁适合语音播报”。这是语音 Agent 和文字聊天的一个重要区别模型输出的内容如果带**加粗**、代码块或超长段落TTS 读起来会很奇怪。在 system prompt 中约束输出风格是成本最低的优化手段。4.4 语音模块 speech.py语音模块负责三件事录音、识别、合成播报。录音用 sounddevice它比 PyAudio 的 API 更简洁支持直接录 numpy 数组方便和 faster-whisper 对接。识别用 faster-whisper加载base模型做 CPU 推理。如果你的电脑性能很好可以换成small或medium识别准确率更高如果追求低延迟就用tiny。合成用 edge-tts它需要异步调用。代码里我用一个简单的辅助函数封装了异步逻辑。# 文件路径speech.py import asyncio import subprocess import tempfile from pathlib import Path import numpy as np import sounddevice as sd from faster_whisper import WhisperModel from config import RECORD_CHANNELS, RECORD_SECONDS, SAMPLE_RATE # 加载本地语音识别模型 # 可选项tiny / base / small / medium / large-v3 # CPU 上建议配 compute_typeint8速度和准确率比较均衡 _whisper_model WhisperModel(base, devicecpu, compute_typeint8) def record_audio(seconds: int RECORD_SECONDS) - np.ndarray: 从麦克风录制指定时长的 16kHz 单声道音频返回 int16 数组。 print(f请开始说话最长 {seconds} 秒...) sample_count int(seconds * SAMPLE_RATE) audio sd.rec( sample_count, samplerateSAMPLE_RATE, channelsRECORD_CHANNELS, dtypeint16, ) sd.wait() audio audio.reshape(-1) print(录音结束。) return audio def transcribe(audio: np.ndarray) - str: Whisper 本地识别返回识别文本。 # int16 转 float32并归一化到 [-1, 1] audio_float audio.astype(np.float32) / 32768.0 segments, _info _whisper_model.transcribe(audio_float, languagezh) return .join(segment.text for segment in segments).strip() async def _edge_tts_save(text: str, out_path: Path): edge-tts 异步合成到文件。 import edge_tts tts edge_tts.Communicate(text, voicezh-CN-YunxiNeural) await tts.save(str(out_path)) def speak(text: str): 把文本合成为语音并播放。 if not text: return tmp_path Path(tempfile.gettempdir()) / agent_response.mp3 asyncio.run(_edge_tts_save(text, tmp_path)) # 优先用 ffplay 播放如果没安装 ffmpeg 可换成系统播放命令 subprocess.run( [ffplay, -nodisp, -autoexit, str(tmp_path)], checkFalse, stdoutsubprocess.DEVNULL, stderrsubprocess.DEVNULL, )录音这块有一个容易踩坑的点sd.rec用的是阻塞等待但如果你在录音过程中同时播放音频会造成回声或者系统音频错乱。这个示例里我们采用“先录音再识别再播报”的串行流程不会出现同时录放的问题。但你后续如果要实现“说话过程中随时打断”就得引入流式音频处理代码复杂度会上一个级别。另外faster_whisper.transcribe里我写了languagezh这是告诉模型“输入的是中文”。如果你希望程序自动识别中英文混合内容可以去掉这个参数让模型自己判断代价是首包延迟会稍微增加。4.5 主程序 main.py最后用主程序把各个模块串起来。这里采用“按回车开始录音”的方式避免写唤醒词模块把精力集中在 Agent 核心链路上。# 文件路径main.py from agent import VoiceAgent from speech import record_audio, speak, transcribe def main(): agent VoiceAgent() print(语音 Agent 已启动。) print(按 Enter 开始录音输入 q 后回车退出。) while True: command input(\n 按回车录音 / 输入 q 退出: ).strip().lower() if command q: break audio record_audio() text transcribe(audio) print(f[你] {text}) if not text: print([提示] 没有识别到文本请重新试一次。) continue answer agent.ask(text) print(f[Agent] {answer}) speak(answer) if __name__ __main__: main()这里有一个交互设计上的取舍先用按键触发录音是为了避免“一直录音导致的误触发”和“唤醒词工程复杂度”。但真实产品里你应该在录音前加一个轻量 VAD语音活动检测检测到音量超过阈值才开始正式识别再用唤醒词模型比如 Porcupine做用户唤起。这些我们放到最佳实践章节详细讨论。5. 运行演示与结果说明启动程序python main.py启动后终端会出现提示。按回车开始录音说一句话程序会自动完成后面的全部流程。下面是我整理的一份“用户意图 → 触发工具 → 预期输出”对照表你可以用来验证自己的程序是否正常用户说话内容应触发的工具Agent 回答示例现在几点了get_current_time现在是 2025-01-15 14:32:08看看系统负载get_system_statusCPU 使用率 12%内存使用率 56%打开客厅灯control_smart_device已向客厅灯发送打开指令今天的天气怎么样无工具模型不调用工具我没有实时天气工具无法查询天气第四种情况比较重要当 Agent 没有任何工具可以完成任务时模型会直接给出“没有相应能力”的回答。这说明模型在“是否调用工具”上具备判断力不会为了调用而调用。实际运行时的日志大概长这样语音 Agent 已启动。 按 Enter 开始录音输入 q 后回车退出。 按回车录音 / 输入 q 退出: 请开始说话最长 5 秒... 录音结束。 [你] 现在几点了 [Agent] 现在是 2025-01-15 14:32:08如果你说“打开客厅灯”并且没有配置真实设备接口你会看到 Agent 输出[演示模式]开头的回答同时终端里会显示工具执行的过程。这就是 Agent 工具调用链路已经跑通的标志。6. 常见问题与排查思路第一次跑语音 Agent最容易卡在环境依赖、模型下载和音频设备上。我把高频问题整理成表格并附上解决思路。问题现象常见原因解决思路安装 sounddevice 后录音无声音麦克风权限未开启或默认设备选错运行sd.query_devices()检查设备系统设置里允许麦克风访问faster-whisper 下载模型失败网络问题导致模型下载中断设置 Hugging Face 镜像环境变量或用代理下载后手动放置模型目录录音文件能生成但识别结果为空录音音量太小、背景噪声大、或语言参数不匹配靠近麦克风说话去掉languagezh参数自动判断提高录音采样率到 16000调用大模型接口报 401 / 429API Key 错误、账户无额度、请求频率太高核对LLM_API_KEY查看模型服务商控制台余额代码里增加重试机制工具调用时报 JSON 解析错误模型返回的参数不是合法 JSON在dispatch_tool外层增加 try-except把异常结果返回给模型让它重新生成edge-tts 报网络错误当前网络无法访问 Edge 语音服务改用 pyttsx3 离线合成或切换到云 TTS 服务ffplay 不存在导致无法播放语音系统没有安装 ffmpeg安装 ffmpeg或把播放命令换成mpv、afplay、os.startfile除了表格里这些问题还有一个经常被忽略的坑sounddevice在 Windows 上依赖 PortAudio如果你的 Python 环境是精简安装可能缺少 DLL 运行库。遇到这种情况建议直接重新安装完整版 Python或者用pip install sounddevice --upgrade检查是否安装成功。对于调试推荐加一行debugTrue开关把 Agent 每轮对话的messages完整打印出来。很多时候模型没有正确调用工具并不是代码问题而是工具描述写得不够清楚。比如control_smart_device里如果不写action的枚举值模型可能生成turn_on或open这类不在白名单里的参数导致调用失败。工具的 description 写得越明确模型调用的成功率越高。7. 最佳实践与工程建议代码跑通只是第一步。要真的把语音 Agent 用在项目或产品里下面几个工程问题也值得提前考虑。7.1 唤醒词与 VAD本文示例用“按回车开始录音”原因是代码最简单、最稳定。但用户体验上用户更希望像智能音箱一样直接喊“你好助手”然后说话。要实现这个体验需要两步唤醒词检测。可以使用 Porcupine 或 sherpa-onnx 自带的唤醒词模型监听麦克风数据流检测到指定唤醒词后开始正式录音VAD语音活动检测。检测到用户说话开始和结束避免把一整段静音全部录进识别模型。faster-whisper 本身自带简单的 VAD 过滤但如果你用云 ASR按音频时长计费提前切掉静音能省不少成本。7.2 多轮对话与记忆当前示例是一次性对话每次录音转文字后只把当前这一句发给 Agent。真实场景里用户会连续说“打开客厅灯”“太亮了调暗一点”第二句需要知道前文的“客厅灯”是什么这就要求 Agent 有多轮记忆。在现有代码上扩展多轮记忆并不复杂把main.py中的messages列表提升为 Agent 实例的成员变量每次用户说完话后追加到列表里同时控制保留最近 N 轮防止 context 无限膨胀。如果你想要更强的记忆能力比如跨会话记住用户偏好那就需要向量数据库和长期记忆模块了。这部分可以单独开一篇来写。7.3 Agent 工具的安全边界给 Agent 添加工具调用能力后安全问题必须重视。以control_smart_device为例模型可能会生成一个不存在的device_id或者action带一些意外字符。虽然大模型通常不会故意越权但在生产环境里工具函数必须做到参数白名单校验非法参数直接拒绝对可能改变状态的工具开灯、关机、发消息、删除数据先做确认或记录操作日志使用最小权限原则Agent 进程不要使用管理员账号运行涉及外部系统调用时API Token 不要写死在代码里放在环境变量或配置中心管理。这个原则同样适用于数据库操作、文件操作、HTTP 请求等工具。工具函数是 Agent 对外部世界的“手”这双手能做什么必须由开发者严格控制。7.4 延迟与成本优化语音交互对延迟很敏感。用户说一句话如果 5 秒后才听到回答体验会明显下降。延迟主要来自三个环节ASR 识别本地 Whisper 在 CPU 上识别 5 秒音频大约需要 1 到 3 秒具体取决于模型大小。用 GPU 推理、或者用实时流式语音识别接口可以显著降低这个延迟LLM 推理模型生成回答需要时间。选择响应更快的小模型或者使用带流式输出的接口让第一个字尽快出来TTS 合成edge-tts 需要完整的回答文本才能合成所以它天然依赖 LLM 串行输出。如果要进一步优化可以换用支持流式合成的 TTS 服务。成本方面本地 faster-whisper 免费但更吃机器性能云 ASR 按时长收费但延迟低、维护成本低。你可以按项目预算灵活选择代码结构上把 STT 封装在speech.py一个文件里切换方案时不需要动 Agent 部分。7.5 日志与可观测性语音 Agent 的调试比普通文字 Chatbot 难因为用户输入经过 ASR 后可能被错误转写问题不一定出在 Agent 逻辑上。建议从第一天就加日志保留原始音频文件和识别文本方便复盘 ASR 准确率打印 Agent 每轮messages方便排查工具调用问题记录 LLM 每次调用的耗时和 token 数方便成本监控对工具调用结果做结构化日志特别是control_smart_device这类会产生实际影响的工具。如果你部署成服务还可以加一个简单的 Web 管理页面既能实时查看日志又能手动触发音频回放排查问题会高效很多。8. 总结与下一步学习方向通过这篇文章我们从零搭建了一个完整的声音控制 Agent 项目核心链路包括麦克风录音、faster-whisper 本地识别、OpenAI 兼容接口的工具调用 Agent、edge-tts 语音合成播报。工程上我们还讨论了唤醒词、VAD、多轮记忆、工具安全、延迟优化和日志监控这些生产环境必须面对的问题。下一步如果你继续学习 Agent 开发我建议优先深入这三个方向第一把框架从手写循环换成 LangGraph。当 Agent 任务从“单次工具调用”变成“多步骤工作流”时状态管理、条件分支、人工确认这些能力会变得必要LangGraph 能帮你更好地组织这些逻辑。第二增加 Agent 记忆能力。短期记忆保留多轮上下文长期记忆用向量数据库存用户偏好让 Agent 越用越懂你。第三优化语音交互体验。实现唤醒词、流式识别、打断播报让整个交互更接近智能音箱的体验。语音 Agent 是一个典型的综合型项目你把 STT、LLM、工具调用、TTS 这四块串起来之后再做其他智能硬件或自动化的项目思路会清晰很多。建议现在就把代码跑起来说一句“现在几点了”真实的体验往往比看十篇教程都管用。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门