1. 项目概述:从想法到可交互的智能体

最近在捣鼓一些AI应用落地的点子,发现了一个挺有意思的痛点:我们和AI的交互,大多还停留在打字上。想象一下,你在厨房做饭,手上沾满了面粉,突然想查个菜谱;或者你在开车,想临时规划一条新路线。在这些场景下,掏出手机或对着电脑打字,既不方便也不安全。于是,一个念头冒了出来:能不能做一个能用声音直接控制的AI智能体?就像电影里的贾维斯,动动嘴皮子,它就能帮你处理各种事情。

这个项目,我称之为“语音控制AI智能体”。它的核心目标很简单: 让用户通过最自然的语音交互方式,来驱动一个具备逻辑思考和行动能力的AI程序完成任务 。这不仅仅是简单的语音转文本然后丢给大语言模型(LLM)那么简单。它需要一套完整的系统:能清晰地“听”懂你的话,能“思考”你话里的意图并规划步骤,还能“执行”具体的操作,比如搜索信息、控制智能家居、或者操作电脑上的软件,最后还得把结果“说”给你听。

整个项目我用Python搭建,因为它有极其丰富的生态库,从语音处理到AI模型调用,几乎都能找到成熟的开源工具。这个智能体适合任何对AI应用开发、语音交互自动化感兴趣的朋友,无论你是想做个私人助理提升效率,还是想探索多模态AI落地的可能性,这里面的思路和代码都能给你直接的参考。接下来,我就把自己从零搭建这个系统的全过程、踩过的坑以及核心的实现逻辑,毫无保留地分享出来。

2. 系统架构与核心组件选型

要构建一个能听、会想、能做的语音AI智能体,我们不能把它当成一个单一的程序,而应该看作一个由多个专业模块协同工作的系统。一个好的架构设计是项目成功的一半,它能确保各个部分职责清晰,易于调试和扩展。

2.1 整体架构设计思路

我设计的架构主要分为四个核心层,数据流像一条生产线一样依次经过它们:

  1. 语音输入层 :负责“耳朵”的功能。持续监听环境声音,检测到人声后,将音频流转换为计算机能处理的文本指令。这是交互的起点。
  2. 智能中枢层 :负责“大脑”的功能。这是最核心的部分,它接收文本指令,理解用户意图,并拆解成一系列可执行的步骤(或称为“智能体规划”)。这里需要一个大语言模型(LLM)作为推理引擎。
  3. 工具执行层 :负责“手”和“脚”的功能。根据“大脑”的规划,调用具体的工具(Tools)来完成任务。例如,调用搜索引擎API查资料、通过命令行执行一个脚本、或者控制一个智能插座。
  4. 语音输出层 :负责“嘴巴”的功能。将任务执行的结果或“大脑”的思考反馈,从文本再转换回语音,播放给用户听,完成交互闭环。

这个“输入-思考-执行-输出”的流水线,构成了智能体的基本工作循环。每一个环节的稳定性和效率,都直接影响最终体验。

2.2 关键技术与工具选型解析

选型的原则是:在满足功能需求的前提下,优先选择文档齐全、社区活跃、易于集成且性价比高的方案。

语音输入(语音转文本 - STT)

  • 候选方案 :开源的有 Vosk (离线、轻量)、 Whisper (OpenAI出品,精度高);云服务有 Google Speech-to-Text Azure Speech Services
  • 我的选择与理由 :我最终选择了 OpenAI的Whisper 。虽然它模型稍大,但其识别准确率,尤其是对中英文混合场景的支持,远超许多离线方案。为了平衡速度和精度,我使用了 whisper.cpp 的Python绑定 ( whisper-cpp-py ),它用C++实现了推理,速度比原版快很多,并且可以量化模型来进一步减小体积。对于需要高响应速度的语音控制,离线方案如Vosk是必须考虑的备选,但Whisper的精度优势对于复杂指令的理解至关重要。
  • 注意事项 :Whisper模型有 tiny , base , small , medium , large 多个尺寸。实测在普通CPU上, base 模型已有不错效果,延迟也可接受。若追求更低延迟,可考虑 tiny ,但需容忍偶尔的识别错误。

智能中枢(大语言模型 - LLM)

  • 候选方案 :云端API如 OpenAI GPT-4/3.5 Anthropic Claude 、国内大模型API;本地部署如 Ollama (运行 Llama 3 , Qwen , Gemma 等)、 LM Studio
  • 我的选择与理由 :出于开发调试的便捷性和对数据隐私的考虑,我采用了 本地部署 的方案,使用 Ollama 来运行 Qwen2.5-7B-Instruct 模型。Ollama极大简化了本地大模型的下载、运行和管理。选择Qwen是因为它在中文理解和工具调用(Function Calling)方面表现优异,且7B参数规模在消费级显卡(如RTX 4060)或强CPU上即可流畅运行。如果追求极致的推理能力且不介意网络调用,GPT-4 API是目前最强的选择。
  • 核心配置 :在Ollama中创建自定义Model文件,关键是指定 system 提示词,用来定义智能体的角色、能力和行为规范。这是塑造智能体“性格”和“能力边界”的关键。

工具执行(Agent框架与工具集)

  • 候选方案 LangChain LlamaIndex Semantic Kernel ,或者直接使用LLM的原生Function Calling能力配合自定义代码。
  • 我的选择与理由 :我选择了相对轻量、直接的方案: 利用Qwen模型原生的Function Calling能力,结合Python的 inspect 模块和自定义装饰器来构建工具系统 。这样避免了重型框架的学习成本和冗余抽象。我定义了一个 @tool 装饰器,它能自动将Python函数转换为LLM能理解的工具描述(JSON Schema)。当LLM决定调用某个工具时,我的主程序会解析其返回的调用信息,动态执行对应的Python函数。
  • 工具示例 :我实现了几个基础工具: search_web(query) 用于网络搜索(借助 DuckDuckGo SerpAPI ), execute_command(cmd) 用于执行系统命令(需严格限制权限), get_weather(city) 用于查询天气(调用公开API)。工具集可以像搭积木一样无限扩展。

语音输出(文本转语音 - TTS)

  • 候选方案 :离线库如 pyttsx3 (免费但声音机械)、 VITS 等开源模型;云服务如 Azure Neural TTS Google Cloud TTS (声音自然)。
  • 我的选择与理由 :我选择了 pyttsx3 作为初版,因为它零配置、跨平台、完全离线。虽然声音是机械的合成音,但用于功能验证和原型开发完全足够。在后续优化中,可以无缝升级为像 Azure TTS 这样的服务,获得近乎真人、带情感的声音,只需替换几行调用代码。
  • 一个技巧 pyttsx3 在Linux上可能默认引擎有问题,需要安装 espeak ffmpeg 。在Windows和macOS上通常开箱即用。

流程协调与并发

  • 由于需要持续监听语音,同时不阻塞主线程进行LLM推理和工具执行,我使用了Python的 asyncio 异步编程库。语音监听在一个独立的线程或异步循环中,检测到语音活动(VAD)后,触发录音,录音结束后将音频数据放入一个异步队列。主事件循环从队列中取出音频进行处理(STT -> LLM -> 工具调用 -> TTS)。这种设计保证了系统的响应性。

3. 核心模块实现与代码拆解

有了架构蓝图和工具选型,接下来就是动手编码,将各个模块串联成一个有机整体。这里我分享最核心的几个模块的实现细节和关键代码。

3.1 语音监听与唤醒词设计

持续录音并处理所有音频是不现实且耗资源的,我们需要一个“唤醒”机制。我采用了 语音活动检测(VAD) 结合 自定义唤醒词 的双重策略。

首先,使用 webrtcvad 这个库进行轻量级的VAD检测。它可以帮助我们过滤掉环境静音和噪音,只在检测到人声时才开始高保真录音。

import webrtcvad
import collections
import pyaudio

class VoiceActivityDetector:
    def __init__(self, aggressiveness=2, frame_duration_ms=30, sample_rate=16000):
        self.vad = webrtcvad.Vad(aggressiveness)
        self.frame_duration_ms = frame_duration_ms
        self.sample_rate = sample_rate
        self.frame_size = int(sample_rate * frame_duration_ms / 1000) * 2  # 16-bit samples
        self.ring_buffer = collections.deque(maxlen=20)  # 存储最近几帧的VAD状态
        self.trigger_threshold = 0.6  # 缓冲区中语音帧比例超过此值,则认为检测到语音

    def is_speech(self, audio_chunk):
        """判断一个音频块是否包含语音"""
        return self.vad.is_speech(audio_chunk, self.sample_rate)

    def update_buffer(self, is_speech_frame):
        self.ring_buffer.append(1 if is_speech_frame else 0)
        if len(self.ring_buffer) == self.ring_buffer.maxlen:
            speech_ratio = sum(self.ring_buffer) / self.ring_buffer.maxlen
            return speech_ratio > self.trigger_threshold
        return False

在VAD检测到人声后,录制的音频会先传递给一个更精确的 唤醒词检测模块 。这里我使用了 Porcupine 库,它支持创建自定义的唤醒词(例如“Hey Computer”)。只有唤醒词被准确识别,后续的指令音频才会被送给Whisper进行转录。这样可以避免智能体被背景对话或电视声音误触发。

注意 :唤醒词的选择很有讲究。最好选择2-4个音节、不易与日常词汇混淆的短语。你可以用Picovoice的Console免费生成自定义唤醒词的模型文件( .ppn )。

3.2 大语言模型提示词工程与工具定义

这是智能体的“灵魂”所在。我们需要通过 system 提示词,清晰地告诉LLM它是谁、它能做什么、以及它应该如何行动。

SYSTEM_PROMPT = """
你是一个高效的语音控制AI助手,名为“小智”。你的核心任务是理解用户的语音指令,并调用合适的工具来完成它。
请严格遵守以下规则:
1. 用户指令来自语音识别,可能不精确或含口语化错误。请结合上下文进行合理推断。
2. 你拥有以下工具,只能使用这些工具,不能编造不存在的功能:
{tools_prompt}
3. 如果用户指令需要多个步骤,请一步步规划,并依次调用工具。
4. 你的回复必须是非常简洁、直接的操作反馈或结果总结,适合用语音播报。不要有冗长的思考过程描述。
5. 如果指令不清晰或无法完成,请直接询问用户澄清。
"""

{tools_prompt} 是一个占位符,会在程序运行时,动态地将所有用 @tool 装饰器注册的函数描述信息填充进去。工具定义如下:

import json
import subprocess
from functools import wraps

# 简单的工具注册表
TOOL_REGISTRY = {}

def tool(func):
    """装饰器:将函数注册为LLM可调用的工具"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)

    # 生成工具描述
    import inspect
    sig = inspect.signature(func)
    params = {
        "type": "object",
        "properties": {},
        "required": []
    }
    for name, param in sig.parameters.items():
        params["properties"][name] = {"type": "string", "description": f"参数 {name}"}
        if param.default == inspect.Parameter.empty:
            params["required"].append(name)

    tool_schema = {
        "type": "function",
        "function": {
            "name": func.__name__,
            "description": func.__doc__ or "No description",
            "parameters": params
        }
    }
    TOOL_REGISTRY[func.__name__] = {
        "function": wrapper,
        "schema": tool_schema
    }
    return wrapper

@tool
def search_web(query: str) -> str:
    """使用DuckDuckGo搜索网络信息。"""
    # 这里使用duckduckgo-search库
    from duckduckgo_search import DDGS
    with DDGS() as ddgs:
        results = list(ddgs.text(query, max_results=3))
        return "\n".join([f"{r['title']}: {r['body']}" for r in results])

@tool
def get_weather(city: str) -> str:
    """获取指定城市的当前天气情况。"""
    # 示例:调用一个公开的天气API,如 open-meteo.com
    import requests
    try:
        # 这里需要替换为真实的API调用逻辑和坐标获取
        url = f"https://api.open-meteo.com/v1/forecast?latitude=31.23&longitude=121.47&current_weather=true"
        response = requests.get(url)
        data = response.json()
        temp = data['current_weather']['temperature']
        windspeed = data['current_weather']['windspeed']
        return f"{city}当前天气:温度{temp}摄氏度,风速{windspeed}公里/小时。"
    except Exception as e:
        return f"查询天气失败:{e}"

3.3 智能体推理循环与工具调用

这是主控制循环,它负责协调STT、LLM和工具执行。我使用 asyncio 来管理整个异步流程。

import asyncio
import json
from ollama import AsyncClient

class AIAgent:
    def __init__(self, model="qwen2.5:7b"):
        self.client = AsyncClient()
        self.model = model
        self.conversation_history = []  # 维护简单的对话历史

    async def process_instruction(self, text_instruction: str):
        """核心处理流程:LLM推理 -> 解析工具调用 -> 执行 -> 合成回复"""
        # 1. 构建包含工具信息的完整系统提示
        tools_list = [info["schema"] for info in TOOL_REGISTRY.values()]
        system_msg = SYSTEM_PROMPT.format(tools_prompt=json.dumps(tools_list, indent=2))

        # 2. 构建消息历史
        messages = [{"role": "system", "content": system_msg}]
        messages.extend(self.conversation_history[-6:])  # 保留最近3轮对话作为上下文
        messages.append({"role": "user", "content": text_instruction})

        # 3. 调用LLM,启用function calling
        response = await self.client.chat(
            model=self.model,
            messages=messages,
            tools=tools_list,
            stream=False  # 为简化示例,关闭流式
        )

        message = response['message']
        self.conversation_history.append({"role": "user", "content": text_instruction})

        # 4. 检查LLM是否要求调用工具
        if hasattr(message, 'tool_calls') and message.tool_calls:
            tool_results = []
            for tool_call in message.tool_calls:
                func_name = tool_call.function.name
                func_args = json.loads(tool_call.function.arguments)
                if func_name in TOOL_REGISTRY:
                    print(f"[Agent] 调用工具: {func_name},参数: {func_args}")
                    try:
                        # 执行工具函数
                        result = TOOL_REGISTRY[func_name]["function"](**func_args)
                        tool_results.append(f"工具 {func_name} 返回: {result}")
                    except Exception as e:
                        tool_results.append(f"工具 {func_name} 执行出错: {e}")
                else:
                    tool_results.append(f"未知工具: {func_name}")

            # 5. 将工具执行结果作为新的上下文,再次发送给LLM,让其生成最终回复
            tool_result_msg = "\n".join(tool_results)
            messages.append(message)  # 加入LLM要求调工具的消息
            messages.append({"role": "tool", "content": tool_result_msg, "tool_call_id": tool_call.id})

            final_response = await self.client.chat(
                model=self.model,
                messages=messages,
                stream=False
            )
            final_text = final_response['message'].content
            self.conversation_history.append({"role": "assistant", "content": final_text})
            return final_text
        else:
            # 6. LLM直接回复,无需调用工具
            final_text = message.content
            self.conversation_history.append({"role": "assistant", "content": final_text})
            return final_text

这个 process_instruction 方法实现了完整的“思考-行动”循环。LLM首先分析指令,如果判断需要工具,它会返回一个结构化的工具调用请求。主程序解析这个请求,同步或异步地执行对应的Python函数,然后将执行结果反馈给LLM。LLM再根据工具返回的结果,组织成一段通顺、简洁的回复文本,最终交给TTS模块播报。

4. 系统集成与优化实践

将各个模块拼装起来,并让它们稳定、高效地协同工作,是项目从“能跑”到“好用”的关键。这里涉及到音频流处理、错误处理、资源管理和性能调优等多个方面。

4.1 异步事件循环与消息队列

为了避免语音监听阻塞LLM推理这种耗时操作,我设计了一个基于 asyncio.Queue 的生产者-消费者模型。

import asyncio
import queue
import threading
from whisper_cpp import Whisper

class VoiceAIApplication:
    def __init__(self):
        self.audio_queue = asyncio.Queue(maxsize=5)  # 音频数据队列
        self.whisper_model = Whisper(model_path="ggml-base.bin")  # 加载Whisper模型
        self.agent = AIAgent()
        self.is_listening = False

    async def audio_producer(self):
        """生产者:监听麦克风,检测到语音后录制并放入队列"""
        p = pyaudio.PyAudio()
        stream = p.open(format=pyaudio.paInt16,
                        channels=1,
                        rate=16000,
                        input=True,
                        frames_per_buffer=1024)
        vad = VoiceActivityDetector()
        print("开始监听...说唤醒词‘小智小智’")
        while self.is_listening:
            audio_chunk = stream.read(1024, exception_on_overflow=False)
            if vad.is_speech(audio_chunk):
                # 检测到语音,开始录制直到静音
                frames = [audio_chunk]
                silence_frames = 0
                while silence_frames < 20:  # 持续静音20帧后停止
                    chunk = stream.read(1024, exception_on_overflow=False)
                    frames.append(chunk)
                    if not vad.is_speech(chunk):
                        silence_frames += 1
                    else:
                        silence_frames = 0
                # 将完整的音频数据放入队列
                audio_data = b''.join(frames)
                await self.audio_queue.put(audio_data)
        stream.stop_stream()
        stream.close()

    async def audio_consumer(self):
        """消费者:从队列取出音频,进行STT和后续处理"""
        while self.is_listening:
            try:
                audio_data = await asyncio.wait_for(self.audio_queue.get(), timeout=1.0)
                # 1. 语音识别
                text = self.whisper_model.transcribe(audio_data, language='zh')
                print(f"[识别结果] {text}")
                # 2. 检查是否为唤醒词(此处简化,实际应用唤醒词检测)
                if "小智" in text:
                    print("[唤醒成功]")
                    # 3. 等待并录制用户指令(这里可加入第二次录音逻辑)
                    # 4. 将指令文本交给Agent处理
                    response_text = await self.agent.process_instruction(text)
                    print(f"[AI回复] {response_text}")
                    # 5. 语音合成输出
                    self.speak(response_text)
            except asyncio.TimeoutError:
                continue
            except Exception as e:
                print(f"[处理错误] {e}")

    def speak(self, text):
        """简单的TTS输出"""
        import pyttsx3
        engine = pyttsx3.init()
        engine.say(text)
        engine.runAndWait()

    async def run(self):
        self.is_listening = True
        # 在不同的线程/任务中运行生产者和消费者
        producer_task = asyncio.create_task(self.audio_producer())
        consumer_task = asyncio.create_task(self.audio_consumer())
        await asyncio.gather(producer_task, consumer_task)

这个结构确保了音频采集和AI处理可以并行不悖。即使LLM推理需要几秒钟,也不会影响系统继续监听环境声音。

4.2 性能调优与延迟优化

延迟是语音交互体验的杀手。从说出指令到听到回复,总延迟最好控制在2-3秒内。以下是几个关键的优化点:

  1. Whisper模型量化与加速

    • 使用 whisper.cpp quantize 工具将模型从FP16量化到INT8甚至INT4,模型体积和推理时间能减少一半以上,精度损失很小。
    • 命令示例: ./quantize ggml-base.bin ggml-base-q4_0.bin q4_0 。然后在代码中加载量化后的模型文件。
  2. LLM推理优化

    • 使用更小的模型 :7B参数模型是精度和速度的较好平衡点。如果对响应速度要求极高,可以尝试3B甚至1B参数的模型,但理解能力会下降。
    • 调整生成参数 :限制 max_tokens (最大生成字数),避免LLM“长篇大论”。设置合适的 temperature (如0.2)使输出更确定、简洁。
    • 利用GPU加速 :确保Ollama正确配置了CUDA或Metal支持。在 ollama run 命令前加 OLLAMA_GPU=1 环境变量。
  3. 音频处理优化

    • 降低采样率 :Whisper支持16kHz采样率,无需使用CD质量的44.1kHz。更低的采样率意味着更少的数据处理和更快的STT速度。
    • 优化VAD参数 :调整 webrtcvad aggressiveness 级别(0-3)。级别越高,对非语音过滤越严格,但也可能误切掉语音开头。需要在实际环境中测试找到最佳值。
  4. 流水线并行

    • 当LLM在思考并生成工具调用请求时,可以提前准备工具执行所需的环境或参数。工具执行时,可以并行准备TTS引擎。虽然Python的全局解释器锁(GIL)限制了真正的多线程并行,但I/O密集型操作(如网络请求)可以利用 asyncio 实现并发,从而压缩整体耗时。

5. 常见问题排查与实战心得

在开发和调试这个系统的过程中,我遇到了不少“坑”。这里把典型问题和解决方案记录下来,希望能帮你少走弯路。

5.1 语音识别不准或唤醒词误触发

  • 问题表现 :背景噪音(如键盘声、音乐)被识别为指令;唤醒词识别率低;或非唤醒词被误触发。
  • 排查与解决
    1. 环境噪音 :这是最常见的问题。首先,确保使用一个质量尚好的麦克风。其次,在代码中增加一个 噪音基线校准 环节。在程序启动时,先录制2秒“静音”环境音,计算其平均能量作为阈值。只有超过此阈值的音频帧才送入VAD检测。
    2. VAD参数调优 webrtcvad 的激进模式( aggressiveness )对安静环境和嘈杂环境的需求不同。在办公室环境,模式2可能合适;在街头,可能需要模式3。同时,调整 trigger_threshold (如从0.6调到0.7)可以提高触发门槛。
    3. 唤醒词模型训练 :如果使用Porcupine,确保生成的 .ppn 文件是针对正确语言和音频配置(如 sample_rate=16000 )的。可以尝试录制多段自己说唤醒词的音频来生成更个性化的模型。
    4. 后处理校验 :在唤醒词检测通过后,可以将识别出的文本指令再次进行一个简单的关键字校验。例如,如果指令中不包含任何动词或明显意图词(如“打开”、“查询”、“播放”),可以要求用户确认或直接忽略。

5.2 LLM不调用工具或调用错误

  • 问题表现 :LLM总是用自然语言回答“我将为你搜索...”,而不是返回结构化的工具调用请求;或者调用了错误的工具,参数格式不对。
  • 排查与解决
    1. 提示词(Prompt)问题 :这是首要原因。检查 system 提示词是否清晰、强硬地要求LLM必须使用工具。强调“只能使用上述工具”、“你的回复必须是工具调用或基于工具结果的总结”。在 user 指令中,有时也可以明确加上“请使用搜索工具查找...”。
    2. 工具描述(Schema)问题 :LLM通过工具描述来理解工具功能。确保 @tool 装饰器生成的函数描述( description )准确、简洁。参数名和描述也要清晰。例如, search_web(query: str) 的描述写“根据query字符串搜索网络信息”,就比“进行搜索”要好得多。
    3. 模型能力问题 :并非所有本地小模型都擅长Function Calling。Qwen、Llama 3等较新的模型对此支持较好。如果遇到问题,可以尝试换用更新或更大的模型。一个测试方法是,直接让LLM根据你的工具描述,输出一个符合格式的JSON,看它是否能理解。
    4. 参数解析错误 :LLM返回的JSON有时会有格式错误(如多余逗号、字符串未转义)。在 json.loads() 时一定要用 try...except 包裹,并做好错误处理,比如让LLM重新生成。

5.3 系统延迟过高或资源占用大

  • 问题表现 :从说完话到听到回复需要5秒以上;程序运行期间CPU或内存占用率很高。
  • 排查与解决
    1. 定位瓶颈 :使用简单的打印时间戳的方式,记录下“录音结束”、“STT开始”、“STT结束”、“LLM开始”、“LLM结束”、“TTS开始”、“TTS结束”这几个关键节点的时间。立刻就能看出时间主要耗在哪一环。
    2. STT瓶颈 :如果是Whisper慢,首先确认是否使用了量化模型。其次,检查是否每次都在重复加载模型?模型应该只在初始化时加载一次。
    3. LLM瓶颈 :确认Ollama服务是否运行在GPU上(可通过Ollama日志查看)。尝试减少 max_tokens num_predict 参数。如果内存不足,可以尝试使用 nvtop nvidia-smi 监控显存,考虑使用更小的模型或开启CPU卸载(如果Ollama支持)。
    4. I/O等待 :如果工具是网络请求(如搜索、查天气),这部分延迟不可避免。可以考虑为这些工具设置超时(如3秒),并在LLM提示词中说明“如果工具调用超时,请告知用户网络可能有问题”。
    5. 内存泄漏 :长时间运行后内存增长。检查音频数据、对话历史等是否被无限期保存在列表或缓存中。可以设置历史对话的轮数上限,或定期清理旧的音频缓存。

5.4 实战心得与扩展思路

  1. 从简单开始,逐步迭代 :不要一开始就追求完美的唤醒词、全能的工具集和超低的延迟。先用 pyttsx3 Whisper tiny GPT-3.5 API 搭出一个能跑通的“最小可行产品”(MVP)。验证核心流程(语音输入->LLM->语音输出)无误后,再逐个环节替换和优化。
  2. 上下文管理是关键 :简单的 conversation_history 列表在复杂多轮对话中会很快失效。你需要处理“指代”问题(如用户说“把它关掉”,LLM需要知道“它”指什么)。可以考虑引入更高级的上下文窗口管理或向量数据库来存储和检索相关历史片段。
  3. 工具安全是底线 :尤其是 execute_command 这类具有系统操作能力的工具,必须进行严格的权限控制和输入清洗。禁止执行 rm -rf / 这类危险命令,可以考虑建立一个允许列表(allowlist),只允许执行预先定义好的安全命令。
  4. 扩展性设计 :我的 @tool 装饰器设计就是为了方便扩展。要增加新功能,比如“播放音乐”,你只需要写一个 play_music(song_name) 的函数,并用 @tool 装饰它。重启后,LLM就能自动获得这个新工具的描述并学会调用它。你可以将工具模块化,甚至动态加载。
  5. 从“玩具”到“产品”的鸿沟 :将这个脚本变成一个7x24小时稳定运行的后台服务,需要更多工程化工作:完善的日志系统、健康检查、配置热加载、进程守护(用 systemd supervisor )以及一个简单的Web控制面板来监控状态和管理工具。

这个项目就像搭积木,每一个模块都有更优的替代方案等待你去探索。你可以用更快的STT引擎、更聪明的LLM、更自然的TTS声音,甚至加入视觉模块,让它成为一个真正的多模态智能体。希望我的这份实践记录,能成为你构建自己语音AI助手的一块坚实跳板。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐