基于AssemblyAI与Groq构建语音控制AI智能体:从语音识别到任务自动化
语音识别与自然语言处理是人工智能领域实现人机自然交互的核心技术。其原理在于将音频信号转化为文本,再通过大语言模型理解语义与意图。这项技术的价值在于能够构建无需手动操作的自动化智能体,极大提升工作效率与交互体验。在应用场景上,它广泛适用于智能家居控制、个人语音助手、企业流程自动化以及无障碍交互设备。本文聚焦于利用AssemblyAI实现高精度语音转文本,并结合Groq LPU推理引擎的高速处理能力,
1. 项目概述:当AI能听懂你的话并为你做事
最近在捣鼓一个挺有意思的东西:一个能完全用语音控制的AI智能体。想象一下,你只需要对着麦克风说句话,比如“帮我查一下明天上午十点的会议安排,然后给团队发个提醒”,它就能自动理解你的意图,执行一连串的操作。这听起来像是科幻电影里的场景,但现在,用AssemblyAI和Groq这两个工具,我们完全可以在自己的电脑上把它搭建出来。
这个项目的核心,就是让机器不仅能“听见”你说的话,更要“听懂”你的意思,并“思考”如何行动。AssemblyAI负责前端的语音识别,把你说的话精准地转成文字;Groq则扮演后端的大脑,它是一个能高速运行大语言模型的推理平台,负责理解文字指令、规划任务步骤并生成执行代码或调用API。两者的结合,相当于给AI装上了“耳朵”和“大脑”,让它能真正响应你的语音命令,成为一个实用的个人助理原型。
无论你是对语音AI感兴趣的开发者,想为自己的智能家居项目增加自然交互能力,还是希望探索AI智能体(Agent)的自动化潜力,这个项目都是一个绝佳的起点。它不涉及复杂的硬件,主要考验的是你对API调用、任务编排和提示词工程的理解。接下来,我会带你一步步拆解这个项目的核心思路、技术选型背后的考量,并分享从零搭建到优化落地的完整过程,以及我踩过的那些坑。
2. 核心架构与工具选型解析
2.1 为什么是AssemblyAI + Groq?
市面上语音识别和AI推理的选项不少,比如OpenAI的Whisper API和ChatGPT API组合似乎更“全家桶”。但我选择AssemblyAI和Groq,是基于几个非常实际的考量。
首先, AssemblyAI在语音转文字的准确性和功能丰富度上表现突出 。它不仅仅是简单转写,还提供了说话人分离(谁在说话)、情感分析、内容总结等高级功能。对于构建一个语音控制Agent来说,清晰的说话人分离能避免多人对话的指令混淆,而情感分析或许能在未来用于判断用户指令的紧急程度。更重要的是,它的API设计非常清晰,响应速度快,对于实时或准实时的语音交互场景至关重要。相比之下,虽然Whisper开源且强大,但在生产环境的API稳定性、附加功能和易用性上,AssemblyAI提供了更省心的选择。
其次, Groq的核心优势在于其惊人的推理速度 。它使用独特的LPU(语言处理单元)推理引擎,运行一些开源大模型(如Llama、Mixtral)时,速度可比传统GPU快一个数量级。对于语音交互的Agent,低延迟是用户体验的生命线。你绝不想说完指令后,等上好几秒才有反应。Groq的高速响应能力,使得“语音输入-思考-行动输出”这个闭环能够近乎实时地完成,感觉更像是在和一个真正敏捷的助手对话。虽然Groq的模型可能不是参数最大的,但在速度与效果的平衡上,它非常适合需要快速响应的交互式应用。
最后,这个组合也体现了 “专精工具链” 的思路。AssemblyAI专注做好“听”(语音识别),Groq专注做好“想”(推理与规划),我们作为开发者则专注于“做”(业务逻辑与任务编排)。这种解耦让系统更健壮,也便于未来单独升级某一环节。
2.2 系统工作流设计
整个智能体的工作流可以清晰地分为四个阶段,形成一个完整的闭环:
- 语音捕获与预处理 :通过电脑或设备的麦克风实时采集用户的语音流。这里需要注意音频质量,过大的背景噪音会影响识别精度。通常我们会添加一个简单的VAD(语音活动检测)模块,只在检测到人声时才将音频流发送给后端,节省资源。
- 语音转文本(AssemblyAI) :将预处理后的音频数据(通常是WAV或MP3格式)通过HTTP请求发送到AssemblyAI的转录API。这里的关键是选择正确的模型和参数。对于实时性要求高的场景,可以使用其流式转录API,实现边说边转;对于指令性语音,准确度优先,则使用标准的异步转录API即可。API返回的结构化JSON结果中,就包含了我们需要的文字指令。
- 意图理解与任务规划(Groq) :这是智能体的“大脑”。我们将AssemblyAI返回的文本指令,连同我们定义好的系统提示词(System Prompt),一起发送给Groq的聊天补全API。系统提示词至关重要,它定义了AI的角色、能力范围和输出格式。例如,我们会告诉AI:“你是一个语音控制助手,可以执行查询天气、发送邮件、创建日历事件等任务。用户会用自然语言发出指令,你需要:1. 理解用户意图;2. 将复杂指令拆解为步骤;3. 对于可自动化的步骤,生成对应的Python函数调用代码或API请求参数。”
- 任务执行与反馈 :Groq返回的结果通常是一段结构化的文本或代码。我们的主程序需要解析这个结果。如果结果是代码(比如调用
requests.get()查询天气),则在一个安全的沙箱环境中执行它;如果结果是需要人工确认的参数(比如邮件的收件人和内容),则将其格式化后显示给用户,并等待语音确认。最后,将任务执行的结果(成功、失败、或需要的信息)通过文本转语音(TTS)模块播报出来,完成交互。
这个流程中,步骤3和4是核心难点,涉及到如何让大语言模型稳定地输出可执行的行动计划,这很大程度上依赖于提示词工程和输出格式的约束。
3. 环境搭建与核心依赖配置
3.1 基础环境准备
这个项目对编程语言没有强制要求,Python因其在AI和自动化领域的丰富生态而成为首选。你需要准备:
- Python 3.8+ :确保你的Python环境已就绪。
- API密钥 :
- AssemblyAI :去其官网注册账号,在控制台可以找到你的API密钥。它通常提供一定的免费额度,足够用于开发和测试。
- Groq :同样,去Groq Cloud官网注册,获取API密钥。关注其提供的免费模型和速率限制。
- 必要的Python库 :我们将通过
pip安装以下核心库。
pip install assemblyai groq python-dotenv requests pyttsx3 pyaudio
简单解释一下这些库的作用:
assemblyai和groq:官方的Python SDK,封装了API调用,比手动发HTTP请求更方便。python-dotenv:用于管理环境变量,安全地存储你的API密钥,避免硬编码在代码中。requests:用于执行AI规划出的HTTP请求任务(如调用天气API)。pyttsx3:一个离线的文本转语音库,用于将AI的回复或执行结果读出来。选择它是因为无需额外API密钥,虽然音质不如一些云服务,但用于原型快速验证足够了。pyaudio:用于从麦克风捕获音频流。
注意 :
pyaudio在某些系统上安装可能比较麻烦。如果遇到问题,可以尝试先安装portaudio库(macOS:brew install portaudio;Linux:sudo apt-get install portaudio19-dev),然后再安装pyaudio。
3.2 项目结构与配置管理
一个好的项目结构能让代码更清晰。建议创建如下目录和文件:
voice_ai_agent/
├── .env # 存储敏感信息(API密钥)
├── main.py # 主程序入口
├── config.py # 配置文件,读取环境变量
├── audio_handler.py # 语音录制和播放模块
├── stt_engine.py # 语音转文本模块(封装AssemblyAI)
├── ai_planner.py # AI规划与推理模块(封装Groq)
├── task_executor.py # 任务执行模块
└── skills/ # 技能库目录
├── __init__.py
├── weather.py # 查询天气技能
├── calendar.py # 日历事件技能(示例)
└── web_search.py # 网络搜索技能(示例)
在 .env 文件中,这样配置你的密钥:
ASSEMBLYAI_API_KEY=your_assemblyai_api_key_here
GROQ_API_KEY=your_groq_api_key_here
在 config.py 中,安全地加载它们:
import os
from dotenv import load_dotenv
load_dotenv()
ASSEMBLYAI_API_KEY = os.getenv("ASSEMBLYAI_API_KEY")
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
if not ASSEMBLYAI_API_KEY or not GROQ_API_KEY:
raise ValueError("请检查 .env 文件中的 ASSEMBLYAI_API_KEY 和 GROQ_API_KEY 配置")
这种将配置、音频处理、AI逻辑、任务执行分离的方式,符合单一职责原则,调试和扩展都更方便。
4. 核心模块实现详解
4.1 语音捕获与转写模块实现
首先实现 audio_handler.py 。这里我们使用 pyaudio 录制音频,并保存为AssemblyAI支持的格式(如WAV)。
import pyaudio
import wave
import threading
import time
class AudioRecorder:
def __init__(self, chunk=1024, format=pyaudio.paInt16, channels=1, rate=16000):
self.CHUNK = chunk
self.FORMAT = format
self.CHANNELS = channels
self.RATE = rate
self.frames = []
self.is_recording = False
self.p = pyaudio.PyAudio()
self.stream = None
def start_recording(self):
"""开始录制音频"""
self.is_recording = True
self.frames = []
self.stream = self.p.open(format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
input=True,
frames_per_buffer=self.CHUNK)
print("录音开始... (按Ctrl+C停止)")
threading.Thread(target=self._record).start()
def _record(self):
"""内部录音循环"""
while self.is_recording:
data = self.stream.read(self.CHUNK, exception_on_overflow=False)
self.frames.append(data)
def stop_and_save(self, filename="output.wav"):
"""停止录音并保存为WAV文件"""
self.is_recording = False
if self.stream:
self.stream.stop_stream()
self.stream.close()
# 保存文件
wf = wave.open(filename, 'wb')
wf.setnchannels(self.CHANNELS)
wf.setsampwidth(self.p.get_sample_size(self.FORMAT))
wf.setframerate(self.RATE)
wf.writeframes(b''.join(self.frames))
wf.close()
print(f"录音已保存至: {filename}")
return filename
接下来,在 stt_engine.py 中实现与AssemblyAI的交互:
import assemblyai as aai
from config import ASSEMBLYAI_API_KEY
class SpeechToTextEngine:
def __init__(self):
aai.settings.api_key = ASSEMBLYAI_API_KEY
self.transcriber = aai.Transcriber()
def transcribe_file(self, audio_file_path):
"""转录本地音频文件"""
try:
transcript = self.transcriber.transcribe(audio_file_path)
if transcript.status == aai.TranscriptStatus.error:
print(f"转录错误: {transcript.error}")
return None
return transcript.text
except Exception as e:
print(f"调用AssemblyAI API时出错: {e}")
return None
# 如果需要实时流式转录,可以添加以下方法
# def transcribe_stream(self, audio_stream):
# ...
实操心得 :在实际测试中,我发现背景噪音对识别准确率影响很大。即使是安静的办公室,键盘声也可能被误识别为词语。后来我做了两处改进:一是在录音时增加一个简单的音量阈值过滤,低于阈值的帧视为静音丢弃;二是在发送给AssemblyAI时,启用其
audio_enhancer参数(config = aai.TranscriptionConfig(audio_enhancer=True)),这对提升嘈杂环境下的识别率有帮助。
4.2 AI规划与推理模块实现
这是项目的“大脑”, ai_planner.py 。我们需要精心设计给Groq的提示词(Prompt),让它扮演一个任务规划师。
from groq import Groq
from config import GROQ_API_KEY
import json
class AIPlanner:
def __init__(self, model="mixtral-8x7b-32768"): # Groq上可用的高速模型
self.client = Groq(api_key=GROQ_API_KEY)
self.model = model
self.system_prompt = """你是一个高级语音控制AI助手。你的职责是理解用户的自然语言指令,并将其转化为可执行的任务计划。
你可以调用的技能(工具)包括:
1. get_weather(city: str) -> str: 获取指定城市的当前天气。
2. send_email(to: str, subject: str, body: str) -> str: 发送电子邮件(需要后续确认)。
3. create_calendar_event(title: str, start_time: str, duration_minutes: int) -> str: 创建日历事件。
4. search_web(query: str) -> str: 在互联网上搜索信息并返回摘要。
5. calculate(expression: str) -> str: 执行数学计算。
用户指令可能是简单的(如“北京天气怎么样?”)或复杂的(如“查一下北京天气,如果下雨就提醒我带伞,并推迟下午的会议”)。
你必须以以下JSON格式回应,且只输出这个JSON对象:
{
"intent": "对用户意图的简短总结",
"is_complex": true/false,
"plan": ["步骤1的描述", "步骤2的描述", ...],
"immediate_action": {
"skill": "要调用的技能名称,如 get_weather",
"parameters": {"参数名": "参数值"},
"code_snippet": "可选的、直接执行的Python代码片段(仅当技能很简单时)"
},
"need_human_confirm": true/false,
"confirm_prompt": "需要用户确认时,对用户说的话"
}
规则:
- 如果指令简单且可直接执行(如查询天气),`immediate_action`必须填充,`need_human_confirm`通常为false。
- 如果指令复杂,`plan`要详细列出步骤,`immediate_action`可能是第一步,`need_human_confirm`可能为true。
- 如果指令涉及敏感操作(如发邮件),`need_human_confirm`必须为true,并在`confirm_prompt`中清晰列出待确认信息。
- 如果你无法理解指令,或要求执行不支持的技能,`immediate_action`为null,并在`intent`中说明。
"""
def plan(self, user_input):
"""接收用户文本指令,返回AI规划的结果"""
try:
completion = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": user_input}
],
temperature=0.1, # 低温度使输出更确定、更遵循格式
max_tokens=1024
)
response_text = completion.choices[0].message.content
# 尝试解析JSON
return json.loads(response_text.strip())
except json.JSONDecodeError as e:
print(f"AI返回的响应不是有效的JSON: {response_text}")
print(f"错误: {e}")
return {"error": "AI响应解析失败", "raw_response": response_text}
except Exception as e:
print(f"调用Groq API时出错: {e}")
return None
注意事项 :提示词工程是这里的灵魂。
temperature参数设置为较低值(如0.1),是为了让模型输出更稳定、更可预测的JSON格式。最初我用默认值0.7,经常得到格式混乱或随意发挥的文本,导致后续解析崩溃。另外,在系统提示词中明确列出可用技能和输出格式,相当于给AI划定了行动边界,这是让AI Agent行为可控的关键。
4.3 任务执行器与技能库实现
task_executor.py 负责解析AI的规划结果,并调用具体的技能函数。
import importlib
import subprocess
import sys
from skills import weather, web_search # 导入技能模块
class TaskExecutor:
def __init__(self):
self.skills = {
"get_weather": weather.get_weather,
"search_web": web_search.search_web,
# ... 注册其他技能函数
}
def execute(self, plan_result):
"""执行AI规划出的动作"""
if not plan_result or "error" in plan_result:
return "抱歉,我无法处理这个指令。"
intent = plan_result.get("intent", "")
action = plan_result.get("immediate_action")
if not action:
# 如果没有立即动作,可能是复杂计划或无法处理
if plan_result.get("need_human_confirm"):
return plan_result.get("confirm_prompt", "请确认此操作。")
else:
return f"我理解你想{intent}。这是一个多步骤任务,我的计划是:{';'.join(plan_result.get('plan', []))}。请告诉我是否继续?"
skill_name = action.get("skill")
params = action.get("parameters", {})
if skill_name in self.skills:
try:
# 调用对应的技能函数
result = self.skills[skill_name](**params)
return f"已完成。结果:{result}"
except Exception as e:
return f"执行技能'{skill_name}'时出错:{e}"
elif action.get("code_snippet"):
# 警告:直接执行AI生成的代码有安全风险!仅用于演示或受控环境。
try:
# 一种相对安全的方式:在子进程中用受限环境执行
# 这里简化处理,实际生产环境需要沙箱
print(f"警告:正在执行AI生成的代码片段:{action['code_snippet']}")
# 此处应替换为安全的沙箱执行逻辑
return "此操作需要执行代码,出于安全考虑,请在确认后手动执行。"
except Exception as e:
return f"代码执行出错:{e}"
else:
return f"未知的技能:{skill_name}"
# 示例技能:weather.py
import requests
def get_weather(city):
"""调用公开天气API示例(此处使用假想API)"""
# 实际使用时,请替换为真实的天气API,如OpenWeatherMap
api_url = f"https://api.example.com/weather?city={city}&units=metric"
try:
response = requests.get(api_url, timeout=5)
data = response.json()
# 解析数据...
temp = data.get('main', {}).get('temp', '未知')
desc = data.get('weather', [{}])[0].get('description', '未知')
return f"{city}当前天气:{desc},温度{temp}摄氏度。"
except requests.RequestException:
return f"无法获取{city}的天气信息。"
安全警告 :让AI生成并执行代码是极其危险的操作!上面的示例中,我虽然留了
code_snippet的解析,但在生产环境中, 绝对不要 轻易在主机环境中执行未经严格审查的AI生成代码。正确做法是:要么完全禁止代码执行,只允许调用预定义的安全API;要么使用 Docker 容器、沙箱环境进行完全隔离的执行,并对代码内容进行严格的安全扫描和限制(如禁用import os, sys, subprocess等)。
4.4 主循环与TTS反馈集成
最后,在 main.py 中将所有模块串联起来,形成交互循环。
import time
from audio_handler import AudioRecorder
from stt_engine import SpeechToTextEngine
from ai_planner import AIPlanner
from task_executor import TaskExecutor
import pyttsx3
class VoiceAIAgent:
def __init__(self):
self.recorder = AudioRecorder()
self.stt_engine = SpeechToTextEngine()
self.planner = AIPlanner()
self.executor = TaskExecutor()
self.tts_engine = pyttsx3.init()
self.tts_engine.setProperty('rate', 150) # 设置语速
def speak(self, text):
"""文本转语音"""
print(f"AI: {text}")
self.tts_engine.say(text)
self.tts_engine.runAndWait()
def run(self):
"""主运行循环"""
self.speak("语音助手已启动,请说出您的指令。")
while True:
input("按回车键开始录音... (或输入 'q' 退出)")
user_input = input().strip().lower()
if user_input == 'q':
break
# 1. 录音
self.recorder.start_recording()
input("正在录音... 按回车键停止。")
audio_file = self.recorder.stop_and_save()
# 2. 语音转文字
self.speak("正在处理您的语音...")
text_command = self.stt_engine.transcribe_file(audio_file)
if not text_command:
self.speak("抱歉,我没有听清,请再说一遍。")
continue
print(f"您说: {text_command}")
# 3. AI规划
self.speak("正在思考...")
plan = self.planner.plan(text_command)
# 4. 执行与反馈
result = self.executor.execute(plan)
self.speak(result)
if __name__ == "__main__":
agent = VoiceAIAgent()
try:
agent.run()
except KeyboardInterrupt:
print("\n程序退出。")
这个主循环实现了基本的“录音-识别-思考-执行-反馈”流程。你可以通过按回车来控制录音的起止,适合演示和调试。在实际产品中,需要替换为更智能的VAD来自动检测语音起止。
5. 进阶优化与实战技巧
5.1 提升语音交互的流畅度
基础的流程跑通后,你会发现几个影响体验的问题:录音需要手动控制、TTS播报时无法接收新指令、复杂任务处理生硬。以下是优化方向:
- 实现全自动的语音端点检测(VAD) :使用像
webrtcvad这样的库,可以实时判断音频流中何时有人声开始和结束,实现“即说即停”,无需手动按键。这能极大提升交互的自然感。 - 引入对话状态管理 :当前的Agent是“单轮对话”,执行完就忘记上下文。你需要维护一个对话历史列表,在每次调用Groq API时,将之前的对话记录也作为上下文传入。这样就能处理像“今天天气怎么样?”(回答后)“那明天呢?”这样的连续追问。
- 优化TTS与STT的并发 :使用多线程或异步编程。当TTS在播报结果时,可以在另一个线程中持续监听是否有用户打断(例如说“停”),这需要更精细的音频流管理。
5.2 设计更强大的技能系统与安全边界
简单的函数调用式技能很快会遇到瓶颈。你需要一个更健壮的技能系统:
- 技能描述与自动发现 :为每个技能编写一个标准的描述文件(如JSON Schema),说明其功能、输入参数、输出格式。AI Planner在初始化时,可以动态读取这些描述来构建系统提示词。这样,新增技能只需添加一个文件,无需修改核心提示词。
- 工具调用(Function Calling)标准化 :与其让AI输出自定义的JSON,不如适配OpenAI标准的工具调用格式。虽然Groq的API可能不完全原生支持,但你可以通过提示词引导AI输出相同结构的JSON,然后在执行端做映射。这能让技能调用更规范。
- 严格的安全沙箱 :对于任何涉及外部操作(如文件读写、网络请求、系统命令)的技能,必须在严格的沙箱中执行。可以使用
docker-py在隔离的Docker容器中运行代码,或者使用restrictedpython等工具限制可用的Python内置函数和模块。
5.3 处理复杂指令与任务分解
当用户说“帮我查天气,如果下雨就取消下午的公园行程并提醒我带伞”时,AI需要将其分解为:1. 查询天气;2. 判断是否下雨;3a. 如果下雨,执行取消行程(调用日历API)和设置提醒(调用通知API);3b. 如果不下雨,可能什么都不做或给出其他建议。
这要求你的系统提示词需要引导AI进行条件判断和步骤规划。一个更高级的架构是引入“工作流引擎”的概念。AI Planner只负责生成一个由基础技能节点组成的工作流DAG(有向无环图),然后由一个独立的Workflow Executor来按顺序或并行地执行这些节点,并处理节点之间的数据传递(例如,将“查询天气”节点的输出“rainy”传递给“判断”节点)。
6. 常见问题与调试实录
在开发过程中,我遇到了不少典型问题,这里分享排查思路和解决方案。
6.1 语音识别准确率低
- 现象 :简单的指令经常转错词,比如“打开灯”识别成“打开等”。
- 排查 :
- 检查音频质量 :用Audacity等工具录制一段测试音频,查看波形。如果音量太小或背景噪音太大,都会影响识别。确保录音时麦克风距离适中,环境相对安静。
- 检查采样参数 :AssemblyAI推荐16kHz采样率、单声道(Mono)。确保你的
pyaudio录音参数与之匹配(见上文AudioRecorder类的初始化)。 - 使用AssemblyAI增强功能 :在转录配置中开启
audio_enhancer=True。对于有口音或特定领域的术语,可以尝试上传自定义词汇表(Custom Vocabulary)来提高特定词汇的识别率。
- 解决 :我最终采用了“预加重滤波”来提升高频分量,并增加了手动增益控制。对于关键指令,可以设计一个简单的本地关键词匹配作为后备,当AssemblyAI的置信度低于某个阈值时,触发本地匹配逻辑。
6.2 AI Planner返回的JSON格式不稳定
- 现象 :Groq偶尔会返回非JSON文本,或者JSON键名错误,导致
json.loads()崩溃。 - 排查 :
- 打印原始响应 :在
ai_planner.py的plan方法中,捕获并打印response_text,观察AI到底输出了什么。很多时候是AI在JSON前后加了解释性文字。 - 检查temperature参数 :过高的
temperature(如0.8)会导致输出随机性大。尝试将其降至0.1或0.2。 - 强化提示词约束 :在系统提示词中反复强调“只输出JSON对象”,并使用“
json ...”这样的Markdown代码块格式来引导,有时效果更好。你甚至可以在提示词末尾加上“你的输出必须是:”,然后直接写一个完美的JSON示例。
- 打印原始响应 :在
- 解决 :我采用了“防御性解析”策略。在
json.loads()外面包裹try-except,如果解析失败,则使用正则表达式尝试从响应文本中提取第一个{...}之间的内容。这虽然不完美,但能挽救大部分格式不规范的响应。
import re
def safe_parse_json(response_text):
try:
return json.loads(response_text)
except json.JSONDecodeError:
# 尝试用正则提取可能的JSON对象
match = re.search(r'\{.*\}', response_text, re.DOTALL)
if match:
try:
return json.loads(match.group())
except:
pass
return {"error": "无法解析AI响应", "raw": response_text[:200]} # 截断部分原始文本供调试
6.3 任务执行中的网络与超时问题
- 现象 :调用天气API或发送邮件时,程序长时间挂起或无响应。
- 排查 :
- 为所有外部请求设置超时 :在使用
requests或任何网络库时, 务必 设置timeout参数(如timeout=(3.05, 27))。第一个是连接超时,第二个是读取超时。这能防止一个挂起的请求阻塞整个程序。 - 实现重试机制 :对于非关键任务,可以添加简单的重试逻辑(如最多重试3次,每次间隔递增)。
- 异步执行 :对于可能耗时的任务,使用
asyncio或线程池来异步执行,避免阻塞主线程和语音交互循环。
- 为所有外部请求设置超时 :在使用
- 解决 :我在
task_executor.py的每个技能函数内部,以及调用Groq和AssemblyAI的API处,都加上了带超时的try-except块,并记录日志。对于发送邮件等操作,改为将其加入一个后台任务队列,立即返回“请求已接收,正在处理”的语音反馈,提升用户体验。
6.4 资源消耗与成本控制
- 现象 :长时间运行后内存增长,或者API调用费用超出预期。
- 排查 :
- 监控API调用 :记录每次向AssemblyAI和Groq发送的请求长度和token数。Groq的计费通常与输入输出token数相关。过长的对话历史会显著增加token消耗。
- 音频文件管理 :程序生成的WAV音频文件会累积。需要定期清理,或在处理完成后立即删除。
- 对话历史裁剪 :不要无限制地增长对话历史。可以只保留最近3-5轮对话,或者当历史token数超过一定阈值时,尝试用AI总结之前的对话内容,用总结替代详细历史。
- 解决 :我实现了一个简单的对话上下文管理器,它维护一个token计数器。当添加新的用户/助理消息导致总token数超过阈值(如3000)时,会自动移除最早的一对对话,直到低于阈值。同时,设置了一个定时任务,每小时清理一次临时音频文件目录。
构建一个语音控制的AI Agent是一个融合了音频处理、大语言模型应用和自动化流程的综合性项目。从“听得见”到“听得懂”,再到“做得到”,每一步都有不少细节需要打磨。AssemblyAI和Groq的组合提供了一个高性能的起点,但真正的挑战在于如何设计一个稳定、安全、可扩展的任务规划和执行框架。这个项目最大的收获不是最终的代码,而是在调试过程中对提示词工程、错误处理和系统架构的深刻理解。你可以从我这个基础版本出发,加入更先进的语音唤醒、多模态理解(结合摄像头)、或者更复杂的自动化工作流,打造出真正属于你的智能助手。
更多推荐

所有评论(0)