大家好,我是老周。最近在推进一个语音交互类项目时,最大的感受是:普通对话机器人“按剧本走”很容易,但一旦用户问出超出预设的问题,整个闭环就会断掉。尤其是当产品要求智能体能够“自己判断该查什么、该算什么、该转而使用哪个工具”,同时还要用中文语音把结论流利地说出来时,方案的复杂度明显上升。很多网上资料要么只讲 ReAct 理论,给不出可运行链路;要么只贴一段 Chat Completion 代码,跟真实业务里的工具调用、异常回退、语音合成完全脱节。
这篇文章会把我在工程落地中沉淀的一套实现思路完整拆解出来。我会结合 Akamai Technologies 一位 AI Engineer 在智能体工程上的设计经验,围绕“推理循环 + 工具调用 + 中配原声语音输出”这条主线,带大家从 0 到 1 搭建一个具备自身推理能力的智能体。文章会包含完整 Python 项目、可复制的代码、关键参数解释、常见报错排查以及工程化建议。新手可以照着跑通流程,有经验的开发者也能直接把它改写成自己的业务底座。
1. 背景与核心概念
1.1 什么才是“拥有自身推理能力”的智能体
先放下术语,说一个很直观的区别。
普通聊天机器人拿到问题后,通常只有一个动作:把用户输入丢给大模型,拿到一段回答,结束。这叫“单轮生成”,模型不会因为缺少信息就去主动查资料,也不会因为结果不对就自我修正。
而“拥有自身推理能力”的智能体,它的工作方式更像一个真实员工:
- 先理解任务目标。
- 判断当前信息够不够。
- 不够时选择调用合适的工具。
- 拿到工具结果后,再次评估。
- 证据充分了就输出结论,不充分就继续下一步。
这个循环在学术界有个经典名称叫 ReAct,也就是 Reasoning and Acting,推理与行动交替进行。你可以把它理解成一种“思考-行动-观察”的循环协议。真正工程化的时候,还需要在循环里加上自我反思这一步,让模型判断“工具结果是否真的支撑我的结论”。
1.2 “中配 + 原声”到底是什么
“中配”这个词在智能体项目里,通常指中文语音输出能力。也就是智能体不是只在对话框里返回文字,而是把最终结论通过中文 TTS 实时合成语音,播报给用户。
“原声”则更进阶。它指的是在中文配音的同时,尽量保留说话人的真实音色、语气和情感风格。传统的 TTS 只有固定几种机器声线,用户一听就知道是机器人;而支持“原声保留”的语音链路,会让智能体用“用户自己的声音”讲中文。这在语音助手、视频配音、数字人、客服回访等场景里,体验差异非常大。
所以“中配 + 原声”翻译成技术语言其实就是两件事:第一,生成中文文本/语音响应;第二,在语音合成阶段通过声音迁移技术保留参考说话人的音色。本文会用免费的 Edge-TTS 演示中文语音输出链路,同时给出接入声音克隆能力的接口思路,让大家理解原声保留在整个架构中处于哪一层。
1.3 Akamai 工程师思路带来的启发
Akamai Technologies 大家可能更熟悉它的 CDN、云安全和边缘计算业务。但这几年,它的 AI 工程团队也在做大量与智能体相关的基础设施实践。我参考的是一位 AI Engineer 分享的智能体设计经验,核心观点可以概括成三句话:
- 不要把大模型当成“调度中心”用来发号施令,而要把模型当作“推理器”,通过迭代式工具调用解决问题。
- 不要让智能体在一个回合里硬答所有问题,要允许它分步行动,并且把每一步中间结果暴露出来,方便人工审计。
- 语音能力不是最后随便接一个 TTS 就完事,要把“文本生成”和“语音生成”两个阶段分开设计,避免大模型输出情绪化文本导致语音合成不稳定。
这篇文章的实现方案,就是基于这三条经验重构出来的。
2. 环境准备与版本说明
开始写代码前,先把实验环境梳理清楚。本文示例以常见环境为准,具体版本需要根据你本机实际情况调整,我会尽量把配置思路讲清楚。
2.1 基础环境
| 组件 | 建议版本/要求 | 说明 |
|---|---|---|
| 操作系统 | Windows / macOS / Linux | 本教程与操作系统无关 |
| Python | 3.9 及以上 | 主要使用 async 和类型标注 |
| pip | 最新版 | 用于安装 Python 依赖 |
| OpenAI SDK | 1.x 及以上 | 用于调用 OpenAI 兼容接口的大模型 |
| Edge-TTS | 最新版 | 免费文本转语音库,不需要额外申请 API Key |
2.2 大模型要求
本文中的智能体需要调用大模型接口,并且要求模型支持“工具调用”,也叫 Function Calling 或 Tool Calling。如果你使用的模型不支持,会导致循环无法进入工具分支。
兼容的大模型包括:
- OpenAI 系列模型,例如 gpt-4o-mini、gpt-4o。
- DeepSeek、通义千问、Kimi 等国内厂商的 OpenAI 兼容接口。
- 本地部署的 Ollama、vLLM 服务,需要确认模型支持 tools 参数。
如果使用本地模型,请确保你的部署版本支持 tools 参数。本文代码通过base_url统一配置接口地址,因此可以快速切换。
2.3 项目目录结构
准备一个干净的实验目录,名字可以叫agent_demo:
agent_demo/ ├── .env.example ├── requirements.txt ├── config.py ├── tools.py ├── agent.py ├── tts_engine.py └── main.py后面每一节会逐步填充这些文件。先用下面的命令安装依赖:
pip install openai python-dotenv edge-tts安装完成后,可以检查版本:
python -c "import openai, edge_tts; print('openai', openai.__version__); print('edge_tts ok')"如果你的openai是 0.x 老版本,请务必升级到 1.x,否则本文代码中的工具调用写法不兼容。
3. 核心原理拆解
3.1 推理循环:从“单轮问答”到“多步行动”
先看一个最小的伪代码流程:
用户输入 ↓ 大模型分析:是否需要调用工具? ↓ 需要 → 输出工具调用指令 ↓ 系统执行工具,拿到结果 ↓ 把结果回灌给大模型 ↓ 大模型反思:结果够不够? ↕ 足够 → 生成最终答案 不足 → 继续调用工具,最多循环 N 步这个循环里最关键的一个点,就是中间状态是可见的。你不仅知道模型最后说了什么,还知道它每一步调了什么工具、拿到了什么数据。这对排查问题非常重要。
在真实代码里,我们不会手动解析模型“要不要调用工具”的文本语义,而是让大模型返回结构化的工具调用请求。OpenAI 兼容接口中,这个能力叫tools参数。
3.2 工具调用的数据流
当我们需要让模型调用工具时,要提供给模型的不是普通文本,而是一份 JSON Schema 描述:
{ "type": "function", "function": { "name": "get_city_weather", "description": "查询指定城市的天气情况", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,例如北京、上海" } }, "required": ["city"] } } }大模型看到这份描述后,会自己判断是否需要调用,同时给出参数。请求返回时,如果模型决定调用工具,message.tool_calls里就会有相关信息,包括:
id:工具调用唯一标识,后续工具结果回灌时必须对应上。function.name:工具名。function.arguments:JSON 字符串形式的参数。
然后我们需要把工具执行结果追加到消息列表里:
{ "role": "tool", "tool_call_id": "call_xxx", "content": "晴,气温 8℃~20℃" }这样模型就能读到“自己刚才调用的工具到底返回了什么”,从而继续下一步推理。
3.3 自我反思:结果不满足时怎么办
很多新手写的智能体只做一次工具调用,拿到结果就直接生成答案。这在简单场景下没问题,但一旦工具返回“空数据”或“结果不足以直接回答用户”,就很容易出现幻觉。
正确的做法是在系统提示词里明确要求模型反思。例如:
- 工具结果是否回答了用户的问题?
- 返回的数据是否缺失关键字段?
- 是否需要继续调用另一个工具?
- 如果确实没有数据,能否如实告诉用户“信息不足”?
反思机制不是单独写一段魔法代码,而是通过在循环中持续把新信息喂给模型,并配合系统提示词的约束来实现。代码层面,只需要控制最大循环次数,避免模型无限调用工具。
3.4 语音链路:中文 TTS 与原声保留的关系
先区分两个阶段。
第一阶段的输出是“文本答案”,由大模型生成。第二阶段是把文本转成中文语音,由 TTS 引擎完成。工程上必须分成两步,因为大模型输出的文本可能包含 Markdown 符号、英文缩写、数字百分比,直接送给 TTS 会导致朗读异常。我们可以在中间增加一个文本清洗环节。
至于原声保留,本质上是“语音合成”阶段的参数不同。传统 TTS 使用固定 voice ID,声音与每个人无关;而支持声音克隆的模型会额外接收一段参考音频,从而克隆音色。比如开源社区的一些语音合成项目,通常会传一个参考音频文件路径或者参考音频的特征向量。
为了不过度依赖特定闭源服务,本文先用免费、无需 API Key 的 Edge-TTS 打通整条中文播报链路。当你需要接入“原声”能力时,只需要把tts_engine.py中的语音合成函数替换成支持声音克隆的模型接口即可,上层 Agent 逻辑完全不用改动。
4. 完整实战案例
现在开始搭建完整项目。这个实战案例会实现一个能推理、会查天气、会做计算、最后用中文语音播报结果的智能体。
4.1 创建项目结构
在任意工作目录下创建agent_demo文件夹:
mkdir agent_demo cd agent_demo然后在里面依次创建几个 Python 文件。我们不使用 IDE 特定功能,命令行加文本编辑器即可完成。
4.2 配置依赖与环境变量
先写requirements.txt:
openai>=1.0.0 python-dotenv>=1.0.0 edge-tts>=6.1.0再写.env.example文件。这个文件不会提交到代码仓库,只用来保存本机密钥:
API_KEY=your-api-key BASE_URL=https://api.openai.com/v1 MODEL_NAME=gpt-4o-mini MAX_STEPS=6如果你使用国内兼容接口,就把BASE_URL换成对应服务的地址,比如https://api.deepseek.com/v1。这里的MAX_STEPS是智能体推理循环的最大轮数,防止模型陷入死循环。
接下来编写config.py,负责读取环境变量:
# 文件路径:agent_demo/config.py import os from dotenv import load_dotenv load_dotenv() API_KEY = os.getenv("API_KEY", "") BASE_URL = os.getenv("BASE_URL", "https://api.openai.com/v1") MODEL_NAME = os.getenv("MODEL_NAME", "gpt-4o-mini") MAX_STEPS = int(os.getenv("MAX_STEPS", "6")) SYSTEM_PROMPT = """你是一个具备自身推理能力的智能体。 你可以在回答问题前调用工具获取外部信息。 请先分析用户问题,判断当前信息是否足够;如果信息不足,请调用合适的工具。 拿到工具结果后,必须结合结果进行一次反思:结果是否回答了问题,是否还需要补充工具调用。 只有当证据充分时,才生成最终答案。 如果工具结果确实无法回答用户问题,请如实告知用户信息不足,不要编造数据。"""4.3 编写工具层
工具层是整个智能体的双手。我们注册两个工具:一个查天气,一个做四则运算。文件路径为tools.py。
# 文件路径:agent_demo/tools.py import ast import json import operator def get_city_weather(city: str) -> str: """查询指定城市的天气情况,这里使用内置模拟数据演示。""" data = { "北京": "晴,气温 8℃~20℃,微风", "上海": "多云,气温 15℃~24℃,东南风3级", "广州": "小雨,气温 20℃~28℃,南风2级", "深圳": "多云,气温 22℃~30℃,南风3级", } if city in data: return data[city] return f"暂无 {city} 的天气数据,请检查城市名称。" def calculator(expression: str) -> str: """执行四则运算,仅支持数字和加减乘除。""" # 本地练习示例:使用 ast 做安全解析,避免直接 eval 执行任意代码 safe_ops = { ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv, } def _eval(node): if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)): return node.value if isinstance(node, ast.BinOp) and type(node.op) in safe_ops: left = _eval(node.lhs) right = _eval(node.right) if isinstance(node.op, ast.Div) and right == 0: raise ValueError("除数不能为0") return safe_ops[type(node.op)](left, right) raise ValueError("只支持四则运算,请检查表达式格式") try: tree = ast.parse(expression, mode="eval") result = _eval(tree.body) return str(result) except Exception as e: return f"计算失败:{e}" class ToolRegistry: """工具注册表:负责统一管理工具描述和工具执行函数。""" def __init__(self): self._schemas = [] self._funcs = {} def register(self, schema: dict, func): self._schemas.append(schema) name = schema["function"]["name"] self._funcs[name] = func def get_schemas(self): return self._schemas def execute(self, name: str, arguments_json: str) -> str: if name not in self._funcs: return f"工具 {name} 不存在" try: args = json.loads(arguments_json) return self._funcs[name](**args) except Exception as e: return f"工具执行异常:{e}"注意这里的几个设计点:
get_city_weather使用模拟数据,方便本地演示;生产环境可以换成真实天气 API 请求。calculator用ast解析表达式,而不是直接用eval,这是为了避免任意代码执行风险。ToolRegistry统一管理全部工具,后续哪怕接入十几个工具,Agent 循环代码都不用改。
4.4 编写 Agent 推理循环
现在进入核心文件agent.py。它的职责是:把用户问题、系统提示词、工具描述一起发给大模型,循环处理工具调用。
# 文件路径:agent_demo/agent.py from openai import OpenAI from config import API_KEY, BASE_URL, MODEL_NAME, MAX_STEPS, SYSTEM_PROMPT def build_client(): if not API_KEY: raise ValueError("API_KEY 不能为空,请检查 .env 配置文件") return OpenAI(api_key=API_KEY, base_url=BASE_URL) def run_agent(question: str, registry): client = build_client() messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": question}, ] for step in range(MAX_STEPS): print(f"[Step {step + 1}] 调用大模型进行推理...") response = client.chat.completions.create( model=MODEL_NAME, messages=messages, tools=registry.get_schemas(), tool_choice="auto", ) assistant = response.choices[0].message # 情况一:模型决定调用工具 if assistant.tool_calls: messages.append({ "role": "assistant", "content": assistant.content if assistant.content else None, "tool_calls": [ { "id": tc.id, "type": "function", "function": { "name": tc.function.name, "arguments": tc.function.arguments, }, } for tc in assistant.tool_calls ], }) for tc in assistant.tool_calls: tool_name = tc.function.name tool_args = tc.function.arguments print(f"[工具调用] name={tool_name}, args={tool_args}") result = registry.execute(tool_name, tool_args) print(f"[工具结果] {result}") messages.append({ "role": "tool", "tool_call_id": tc.id, "content": result, }) continue # 情况二:模型不调用工具,直接给出最终答案 if assistant.content: print(f"[最终答案] {assistant.content}") return assistant.content, step + 1 # 情况三:循环耗尽后仍然没有最终答案,做最后一次兜底 final_response = client.chat.completions.create( model=MODEL_NAME, messages=messages, ) final_text = final_response.choices[0].message.content print(f"[兜底答案] {final_text}") return final_text, MAX_STEPS这段代码的核心逻辑可以总结为三点。
第一,把assistant.tool_calls完整回放进messages,这是 OpenAI 工具调用的固定要求,不能省略。
第二,每条工具结果通过tool_call_id与对应的调用关联,大模型才能准确知道“某一次调用返回了什么”。
第三,tool_choice="auto"让大模型自主决定是否调用工具,这正好符合“自身推理能力”的要求。
4.5 编写语音输出模块
接下来是语音链路。tts_engine.py使用 Edge-TTS 把最终文本合成为中文 MP3。
# 文件路径:agent_demo/tts_engine.py import asyncio import edge_tts async def _save_speech(text: str, output_file: str, voice: str): communicate = edge_tts.Communicate(text, voice) await communicate.save(output_file) def generate_speech(text: str, output_file: str = "answer.mp3", voice: str = "zh-CN-YunxiNeural"): """将文本合成为中文语音文件。 参数说明: - text: 需要合成的文本 - output_file: 输出 MP3 文件路径 - voice: Edge-TTS 里的声音 ID,常见值: zh-CN-YunxiNeural 男生,年轻活力 zh-CN-XiaoxiaoNeural 女生,温柔自然 zh-CN-YunjianNeural 男生,成熟稳重 """ asyncio.run(_save_speech(text, output_file, voice)) print(f"语音已生成:{output_file}")如果后续要接“原声保留”能力,只需要替换generate_speech内部实现。比如某些声音克隆模型会接收ref_audio参数,那就把函数改成generate_speech(text, output_file, ref_audio),在内部读取参考音频并完成合成。上层main.py完全不受影响。
4.6 编写主入口
最后写main.py,把工具注册、智能体推理、语音合成三个模块串起来。
# 文件路径:agent_demo/main.py from tools import ToolRegistry, get_city_weather, calculator from agent import run_agent from tts_engine import generate_speech def build_registry(): registry = ToolRegistry() registry.register( schema={ "type": "function", "function": { "name": "get_city_weather", "description": "查询指定城市的天气情况", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "城市名称,例如北京、上海"} }, "required": ["city"], }, }, }, func=get_city_weather, ) registry.register( schema={ "type": "function", "function": { "name": "calculator", "description": "执行四则运算,适合回答数学计算类问题", "parameters": { "type": "object", "properties": { "expression": {"type": "string", "description": "数学表达式,例如 12*30+45"} }, "required": ["expression"], }, }, }, func=calculator, ) return registry if __name__ == "__main__": registry = build_registry() question = ( "北京今天天气适合跑步吗?" "如果适合,我计划跑步30分钟,想请你把30乘以1.5的结果也算出来," "并告诉我建议跑步的最短时间是多少分钟。" ) answer, used_steps = run_agent(question, registry) print(f"智能体完成推理,共使用 {used_steps} 步。") # 生成中文语音文件,保留“中配”链路 generate_speech(answer, "answer.mp3", voice="zh-CN-YunxiNeural")4.7 运行与验证
在项目根目录创建本地环境变量文件.env,复制.env.example内容并填入真实 API Key:
cp .env.example .env然后运行主程序:
python main.py预期你会看到类似下面的输出:
[Step 1] 调用大模型进行推理... [工具调用] name=get_city_weather, args={"city":"北京"} [工具结果] 晴,气温 8℃~20℃,微风 [Step 2] 调用大模型进行推理... [工具调用] name=calculator, args={"expression":"30*1.5"} [工具结果] 45.0 [Step 3] 调用大模型进行推理... [最终答案] 北京今天天气晴朗,气温在8℃到20℃之间,整体比较适合跑步。你计划跑步30分钟,30乘以1.5等于45分钟,所以我建议你最短可以跑45分钟。请注意早晚温度较低,运动前记得热身。 语音已生成:answer.mp3打开生成的answer.mp3就能听到中文播报。如果你想换女声,把voice改成zh-CN-XiaoxiaoNeural再运行一次即可。
5. 常见问题与排查思路
在本地运行或接入真实服务时,新手最常遇到下面几个问题。我用表格快速给出排查方向,再针对高频问题做详细说明。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
报错API_KEY 不能为空 | .env文件未创建,或变量名错误 | 检查.env是否与.env.example一致 |
| 模型返回 404 错误 | MODEL_NAME与你购买的模型名不一致 | 确认该模型是否支持工具调用,名称是否正确 |
| 模型从不调用工具 | 模型本身不支持 tools,或系统提示词太模糊 | 换成支持 Function Calling 的模型,精简系统提示词 |
| 工具结果不回灌 | 缺少tool_call_id映射 | 确认role: tool消息里带上了正确的tool_call_id |
| 无限循环 | 没有限制最大步数 | 设置MAX_STEPS,并在循环耗尽后兜底 |
| TTS 输出有错别字或杂音 | 文本里有特殊符号或英文缩写 | 在合成前做文本清洗,转换数字、百分比和符号 |
| 想保留原声音色但只有标准声音 | TTS 服务不支持声音克隆 | 更换支持参考音频参数的语音合成模型 |
5.1 模型总是拒绝调用工具
这种情况很常见。问题往往不是代码,而是模型选择或提示词。
有些模型虽然名字很新,但接口版本较老,或者当前部署环境没有启用工具调用能力。调试时可以先做一个最小测试,单独打印返回结果:
response = client.chat.completions.create( model=MODEL_NAME, messages=[{"role": "user", "content": "帮我查询北京的天气"}], tools=tools_schema, tool_choice="auto", ) print(response.choices[0].message.tool_calls)如果tool_calls是None,说明模型没有生成工具调用请求。这时先检查模型文档,确认支持 Tool Calling;再检查系统提示词,是否明确说明“可以调用工具”。
5.2 工具调用参数反复报错
有时候模型会生成错误的 JSON 参数,比如参数名写错、缺少 required 字段。这会触发ToolRegistry.execute的异常分支,把错误信息返回给模型。模型看到错误信息后,一般会在下一轮自动修正参数。这也是“自我反思”的一种表现。
但如果模型反复生成同一个错误参数,可以在工具 schema 里把描述写得更精确,例如:
{"description": "城市中文名称,例如北京、上海、广州、深圳"}描述越明确,模型生成参数的准确率越高。
5.3 Edge-TTS 合成失败
Edge-TTS 依赖网络连接,偶尔会因为网络波动失败。可以先单独测试:
import asyncio import edge_tts async def test(): await edge_tts.Communicate("测试语音", "zh-CN-YunxiNeural").save("test.mp3") asyncio.run(test())如果失败,一般重试即可。也可以在生产环境加入重试机制,比如失败后换用备用 voice 再合成一次。
6. 最佳实践与工程建议
6.1 给推理过程加观测日志
智能体一旦进入生产环境,就不能只打印[工具调用]这种临时日志。建议每轮推理都记录完整链路:
- 用户问题。
- 模型生成的推理内容。
- 调用的工具名称和参数。
- 工具返回结果。
- 每一步耗时。
- 最终答案文本。
这些数据既可以用于排障,也可以用于后续评估模型质量。推荐把日志写入结构化文件或日志平台,字段使用 JSON 格式,方便检索和分析。
6.2 限制工具权限
工具就是智能体的“手”,权限越大越危险。示例里的calculator已经用ast做了安全性处理,但在生产环境还要考虑更多边界,比如:
- 工具是否允许访问公网?
- 工具能否访问数据库?
- 工具是否涉及删除或修改操作?
- 工具调用是否需要进行用户身份校验?
一定遵循最小权限原则。每个工具只暴露最必要的功能,涉及写操作或删除操作的接口,必须在代码层增加二次确认。
6.3 为语音输出增加文本清洗环节
大模型输出常带有 Markdown 标记、换行符、英文括号、百分比符号。直接送入 TTS 会出现朗读错误。建议在generate_speech之前增加一个清洗函数:
def clean_for_speech(text: str) -> str: # 去除 Markdown 符号 text = text.replace("**", "").replace("`", "") # 去除多余换行 text = " ".join(text.split()) # 将英文逗号转成中文逗号,让 TTS 停顿更自然 text = text.replace(",", ",") return text这属于低成本高收益的优化,短暂就能明显改善中文语音听感。
6.4 控制推理成本
每次工具调用都会产生一次大模型请求,成本随循环轮数线性增长。建议从三方面控制:
- 设置
MAX_STEPS,建议默认 4 到 6。 - 在工具层做缓存,比如相同城市天气在 10 分钟内不要重复请求。
- 能一次调用完成的场景,不要强制模型分多步。
另外,生产环境要设置超时时间。大模型接口偶尔会变慢,如果 60 秒还没返回,应该主动断开并返回友好提示。OpenAI 客户端里可以配置timeout参数:
client = OpenAI(api_key=API_KEY, base_url=BASE_URL, timeout=30)6.5 关于声音克隆的合规提醒
“原声”能力很惊艳,但也涉及个人信息和语音安全。建议只在用户明确授权的情况下使用语音克隆。涉及用户真实声音的采集、存储和合成,必须做好数据脱敏、访问控制和留存期限管理。企业级项目上线前,最好与法务确认合规边界。
7. 总结与学习路线
这篇文章从问题出发,带你完整实现了一个具备自身推理能力的智能体。你掌握了 ReAct 思想的基本流程,了解了 Tool Calling 的数据结构,理解了tool_call_id在结果回灌中的作用,也跑通了一条“大模型推理 → 工具调用 → 中文语音合成”的可运行链路。
下一步你可以做三件事。
第一,把get_city_weather换成真实天气 API,看看外部服务异常时智能体会如何自我反思并兜底。
第二,在ToolRegistry中加入更多真实业务工具,比如查询订单状态、计算运费、读取商品库存,让智能体更贴近项目。
第三,把generate_speech替换成支持声音克隆的 TTS 模型,接入一段参考音频,实现真正的“中配 + 原声”效果。
不要停留在跑通示例这一步。建议你从今天开始,先给项目加上完整日志,再尝试把MAX_STEPS改成 3,看看模型在步数受限时会如何取舍信息。真正做过一轮这样的实验,你对智能体的理解会比读十篇概念文章都深。
如果本文对你有帮助,可以收藏备用。后续我还会继续更新关于工具权限控制、多智能体协作和语音交互评估的文章,感兴趣的话可以保持关注。