本地多工具智能 Agent 与语音交互系统(实训 B 方向)
本项目使用 Python 3.10 实现一个完整的本地智能 Agent 系统。系统以本地 Qwen3.5-4B 为决策核心,将 Agent 总控、Tools Schema、八类本地 Skill、长期记忆、KV Cache、音频预处理、Faster-Whisper 语音识别和 CosyVoice2 语音合成串联为统一工作流。用户可以输入文本或麦克风语音,Agent 会自主规划并调用工具,最终返回文字回答,也可以通过独立 CosyVoice 子进程生成语音。
⚠️ 使用前必须按实际电脑与服务器修改配置
仓库中的绝对路径、SSH 地址和端口均为团队开发环境示例,不能直接照搬。运行前必须检查
agent/configs/model.yaml、agent/configs/tts.yaml和agent/configs/voice_chat.yaml:将模型、tokenizer、CosyVoice Python/仓库/模型/参考音频改为当前电脑或服务器的实际路径;将connection.host改为本人可访问的用户名@服务器地址,将connection.port改为目标服务器实际开放的 SSH 端口,并同步修改connection.remote_root、connection.python和connection.template。详细字段见“1.3 首次运行前必须检查的私有路径”。
完整任务的数据流如下:
文本 / 麦克风音频
→ 音频预处理与 ASR(仅音频输入)
→ 加载全局记忆和会话记忆
→ Qwen3.5-4B 规划任务
→ B3 校验并调用 B2 Skills
→ 工具结果返回模型继续推理
→ 生成最终回答
→ 保存消息、轨迹、Memory 和报告
→ CosyVoice2 子进程合成语音(按需启用)
模块边界如下:
| 模块 | 入口文件 | 职责 |
|---|---|---|
| B1 | code/b1_agent_runtime.py |
Agent 总控、消息管理、循环控制和产物汇总。 |
| B2 | code/b2_run_skill.py |
独立运行五个基础 Skill。 |
| B3 | code/b3_tool_layer.py |
生成 tools schema,校验并执行 tool calls。 |
| B4 | code/b4_local_agent_llm.py |
使用 mock 或本地 LLM 生成标准 AIMessage,不执行工具。 |
| B5 | code/b5_memory.py |
查找、截断、保存 memory 文档并维护索引。 |
| 完整演示 | code/run_full_demo.py |
调用 B1 跑通完整 Agent,并生成汇总报告。 |
| 语音服务端 | code/voice_chat_server.py |
接收音频、调用 ASR 和 Agent,并维护多轮会话。 |
| Windows 语音客户端 | code/voice_chat_windows_client.py |
麦克风录音、SSH 通信、本地/远程 TTS 和扬声器播放。 |
| TTS Worker | skills/text_to_speech.py、skills/tts_worker.py |
从 Agent 环境启动独立 CosyVoice 子进程并生成 WAV。 |
B4的mock模式不真实加载、运行模型,作为无 GPU、无模型或模块联调时的调试模式。prompt_json模式则加载本地模型真实运行。
1. 环境准备
Agent 与 CosyVoice 建议使用两个独立的 Conda 环境。Agent 环境负责本地模型、工具调用、Memory 和语音识别;CosyVoice 环境只负责 TTS。两套环境分离可以避免 PyTorch、Transformers、音频库等依赖版本互相冲突。
1.1 Agent 环境
在项目根目录执行:
conda create -n agent python=3.10 -y
conda activate agent
pip install -r agent/requirements.txt
本项目默认使用 Qwen3.5-4B。agent/configs/model.yaml 中提供的是团队服务器路径,其他使用者必须将 model.model_name_or_path 和 model.tokenizer_name_or_path 改为自己机器上的模型目录。
1.2 独立 CosyVoice TTS 环境
本项目采用子进程方式运行本地 TTS:Agent 环境中的 agent/skills/text_to_speech.py 不直接导入 CosyVoice,而是读取 agent/configs/tts.yaml,使用 runtime.python_executable 指定的 CosyVoice Python 启动 agent/skills/tts_worker.py。因此,仅安装 agent/requirements.txt 不能运行 TTS,还需要单独准备 CosyVoice 环境。
conda create -n cosyvoice python=3.10 -y
conda activate cosyvoice
pip install -r CosyVoice/requirements.txt
Linux 如果遇到 SoX 依赖问题,还需要安装系统库:
# Ubuntu / Debian
sudo apt-get install sox libsox-dev
# CentOS
sudo yum install sox sox-devel
安装后,将 agent/configs/tts.yaml 中的 Python 路径改成该环境的真实解释器:
runtime:
# Windows 示例
python_executable: "C:/Users/<你的用户名>/anaconda3/envs/cosyvoice/python.exe"
# Linux 示例:使用时保留其中一项即可
# python_executable: "/home/<你的用户名>/miniconda3/envs/cosyvoice/bin/python"
还需要确认 voice.cosyvoice_repo、voice.model_dir 和各音色的 prompt_wav 指向真实存在的 CosyVoice 代码、模型及参考音频。当前仓库已经包含 CosyVoice/ 和 CosyVoice2-0.5B/,如果目录结构不变,可以继续使用配置中的相对路径。
1.3 首次运行前必须检查的私有路径
仓库配置保留了团队开发机器和服务器的示例路径,不能直接照搬到其他电脑。至少检查以下字段:
| 配置文件 | 字段 | 当前内容的性质 | 应修改为 |
|---|---|---|---|
agent/configs/model.yaml |
model_name_or_path、tokenizer_name_or_path |
团队服务器绝对路径 | 本机 Qwen3.5-4B 模型目录 |
agent/configs/tts.yaml |
runtime.python_executable |
团队成员 Windows Conda 路径 | 本机 CosyVoice 环境的 Python |
agent/configs/tts.yaml |
cosyvoice_repo、model_dir、prompt_wav |
项目相对路径 | 若目录被移动,改为实际路径 |
agent/configs/voice_chat.yaml |
connection.host、port |
团队 SSH 服务器地址和端口 | 自己可访问的服务器账号、地址和端口 |
agent/configs/voice_chat.yaml |
connection.remote_root |
团队服务器项目路径 | 服务器上的项目根目录 |
agent/configs/voice_chat.yaml |
connection.python |
团队服务器 Agent 解释器 | 服务器 Agent 环境的 Python |
agent/configs/voice_chat.yaml |
connection.template |
团队项目中的运行模板路径 | 远程项目内实际存在的 runtime JSON 路径 |
agent/configs/voice_chat.yaml |
audio.sample_rate、TTS 与 conversation 配置 |
团队演示参数 | 根据本机音频设备、TTS 部署位置和会话需求调整 |
agent/configs/voice_chat.yaml 中的 IP、用户名、SSH 端口和远程目录均属于部署示例。运行语音客户端之前必须替换,否则客户端会尝试连接团队原服务器,或因端口、目录和解释器不匹配而启动失败。
演示命令均从 agent/code 目录执行:
cd agent/code
1.4 整体系统运行方法
以下是团队项目最常用的完整运行入口。B2–B5 的独立命令主要用于模块调试,首次使用建议先按本节跑通整体流程。
方式一:完整文本 Agent Demo
确认 Qwen 模型路径和配置后,从 agent/code 目录执行:
python run_full_demo.py \
--input ../data/runtime_input_4.json \
--tools_config ../configs/tools.yaml \
--memory_config ../configs/memory.yaml \
--model_config ../configs/model.yaml \
--llm_mode prompt_json \
--outdir ../outputs/full_demo
runtime_input_4.json 会让真实模型选择 table_analyzer 分析示例 CSV。一次完整任务依次经过 B1 Runtime、B5 Memory、B4 本地模型、B3 Tool Layer 和 B2 Skill,最终在 agent/outputs/full_demo/ 生成回答、消息流、工具结果、执行轨迹和汇总报告。
可以替换 --input 运行其他整体任务:
| Runtime 文件 | 整体任务 |
|---|---|
runtime_input.json |
读取本地文档并总结 |
runtime_input_2.json |
调用安全计算工具 |
runtime_input_3.json |
检索本地资料 |
runtime_input_4.json |
分析 CSV 表格 |
runtime_input_5.json |
格式转换并生成文件 |
runtime_input_audio.json |
音频预处理 → ASR → Agent → 最终回答 |
runtime_input_tts.json |
Agent 完成任务后调用 CosyVoice2 生成 WAV |
若只想检查编排流程而不加载 GPU 模型,可临时使用 --llm_mode mock;正式演示应使用 prompt_json。
方式二:完整语音对话
语音模式通常采用“Windows 客户端 + GPU 服务器 Agent”的部署方式。先完成以下检查:
- 修改
voice_chat.yaml中的 SSH 地址、端口、远程项目目录和远程 Agent Python; - 确认远程服务器可以运行 Qwen 和 Faster-Whisper;
- 本地 TTS 模式下,确认
tts.yaml指向本机 CosyVoice Python、代码和模型; - 在
voice_chat.yaml的tts.voice中选择音色:default或funingna; - 根据需要选择
tts.mode、tts.stream_mode和conversation.mode。
随后在项目根目录的 Windows PowerShell 中执行:
python .\agent\code\voice_chat_windows_client.py --config .\agent\configs\voice_chat.yaml
客户端会自动完成:麦克风录音 → SSH 发送音频 → 服务器预处理与识别 → Agent 调用工具并回答 → 本地或远程 CosyVoice 合成 → 扬声器播放。
常用的临时模式切换示例:
# 本地流式合成,使用 funingna 音色,连续多轮对话
python .\agent\code\voice_chat_windows_client.py `
--config .\agent\configs\voice_chat.yaml `
--tts-mode local `
--tts-stream-mode stream `
--tts-voice funingna `
--conversation-mode append
# 切换为 default 音色和整段合成
python .\agent\code\voice_chat_windows_client.py `
--config .\agent\configs\voice_chat.yaml `
--tts-mode local `
--tts-stream-mode full `
--tts-voice default
运行成功判断
文本完整 Demo 成功时,应满足:
- 进程退出码为 0;
outputs/full_demo/demo_report.md中状态为success;messages.json包含system → user → assistant → tool → assistant消息链;tool_messages.json中目标工具状态为success;final_answer.md包含最终回答;- 启用 TTS 时输出目录中存在可播放的 WAV 文件。
语音模式成功时,终端会先返回识别文本和 Agent 回答;启用 TTS 后还会显示音频块进度及实际使用的 voice ID,并通过扬声器播放。
2. 公共数据格式
2.1 SkillResult
B2 和 B3 使用以下 JSON 对象记录一次 Skill 执行:
{
"skill_name": "calculator",
"status": "success",
"input": {"expression": "23 * 17 + 9"},
"output": {"result": 400},
"error": null,
"latency_ms": 0.5
}
失败时 status 为 error、output 为 null,error 包含异常类型和错误信息。
2.2 AIMessage
工具调用型 AIMessage:
{
"role": "assistant",
"content": "",
"tool_calls": [
{
"id": "call_001",
"name": "file_reader",
"args": {"path": "docs/agent_intro.txt", "max_chars": 2000}
}
]
}
最终回答型 AIMessage 的 content 非空,tool_calls 为空数组。
2.3 ToolMessage
{
"role": "tool",
"tool_call_id": "call_001",
"name": "file_reader",
"content": "{\"skill_name\":\"file_reader\",...}",
"status": "success"
}
content 是序列化后的 SkillResult JSON 字符串;tool_call_id 用于关联前面的 AIMessage tool call。
3. B2:Skill 独立演示
入口:code/b2_run_skill.py
3.1 通用命令行输入
| 参数 | 说明 |
|---|---|
--skill |
Skill 名称:calculator、file_reader、local_file_search、table_analyzer 或 format_converter。 |
--input |
对应 Skill 的 JSON 输入文件。顶层必须是 JSON 对象。 |
--outdir |
B2 输出目录。 |
--data_root |
可选的数据根目录;未提供时使用项目的 data/。 |
3.2 每个 Skill 的输入文件
| Skill | 正常输入文件 | 关键输入字段 | 异常输入样例 |
|---|---|---|---|
| calculator | data/tool_inputs/tool_input_calculator.json |
expression:数学表达式字符串。 |
tool_input_calculator_error.json |
| file_reader | data/tool_inputs/tool_input_file_reader.json |
path:相对 data/ 的 txt/md 路径;max_chars:最大返回字符数。 |
tool_input_file_reader_error.json |
| local_file_search | data/tool_inputs/tool_input_file_search.json |
query、root_dir、file_types、top_k。 |
tool_input_file_search_error.json |
| table_analyzer | data/tool_inputs/tool_input_table_analyzer.json |
path:CSV/TSV 路径;max_rows_preview;describe。 |
tool_input_table_analyzer_error.json |
| format_converter | data/tool_inputs/tool_input_format_converter.json |
text;target_format:markdown 或 json;可选 output_filename。 |
tool_input_format_converter_error.json |
文件类 Skill 的相对路径以 data/ 为根。例如 docs/agent_intro.txt 实际对应 data/docs/agent_intro.txt。
3.3 演示命令
python b2_run_skill.py --skill calculator --input ../data/tool_inputs/tool_input_calculator.json --outdir ../outputs/B2_skills
python b2_run_skill.py --skill file_reader --input ../data/tool_inputs/tool_input_file_reader.json --outdir ../outputs/B2_skills
python b2_run_skill.py --skill local_file_search --input ../data/tool_inputs/tool_input_file_search.json --outdir ../outputs/B2_skills
python b2_run_skill.py --skill table_analyzer --input ../data/tool_inputs/tool_input_table_analyzer.json --outdir ../outputs/B2_skills
python b2_run_skill.py --skill format_converter --input ../data/tool_inputs/tool_input_format_converter.json --outdir ../outputs/B2_skills
3.4 B2 输出
| 输出文件 | 格式 | 说明 |
|---|---|---|
outputs/B2_skills/calculator_result.json |
JSON 对象(SkillResult) | calculator 最近一次运行的输入、结果或错误、耗时。 |
outputs/B2_skills/file_reader_result.json |
JSON 对象(SkillResult) | file_reader 最近一次运行结果;业务输出包含内容、字符数、来源和截断标志。 |
outputs/B2_skills/local_file_search_result.json |
JSON 对象(SkillResult) | 文件搜索结果;每项包含路径、匹配分数和命中片段。 |
outputs/B2_skills/table_analyzer_result.json |
JSON 对象(SkillResult) | 表格行列数、列名、预览和数值列统计。 |
outputs/B2_skills/format_converter_result.json |
JSON 对象(SkillResult) | 转换后的 Markdown 或 JSON 文本,以及生成文件路径。 |
outputs/B2_skills/skill_run_log.jsonl |
JSONL | B2 运行历史;每行记录时间、Skill、状态、结果路径和耗时。 |
同一个 Skill 再次运行时会覆盖对应的 *_result.json;日志采用追加写入。异常样例被正常捕获并写入 error SkillResult,CLI 仍返回 0。
4. B3:Tools Schema 与工具执行
入口:code/b3_tool_layer.py
4.1 输入文件
| 输入文件 | 说明 |
|---|---|
configs/tools.yaml |
定义 toolsets、每个工具的 Python 模块/函数、描述、输入参数、必填参数、返回说明和 data_root。 |
data/messages/ai_message_with_tool_calls.json |
工具执示演示的输入,正常file_reader调用的样例,包含标准 AIMessage 及其 tool_calls。 |
data/messages/b3_tool_call_format_converter_valid.json |
正常 format_converter 调用样例,验证 B3 注入 output_dir 并生成文件。 |
data/messages/b3_tool_call_unknown_tool.json |
未知工具错误样例。 |
data/messages/b3_tool_call_missing_required.json |
缺少必填参数错误样例。 |
B3 会根据 Skill 函数签名自动注入 data_root 和 output_dir;前者用于读取文件类Skill定位输入文件夹data/,后者用于format_converter输出生成文件。
4.2 演示命令
生成tools_schema:
python b3_tool_layer.py --tools_config ../configs/tools.yaml --toolset basic_tools --export_schema --outdir ../outputs/B3_tools
执行tool_calls:
python b3_tool_layer.py --tools_config ../configs/tools.yaml --toolset basic_tools --tool_calls ../data/messages/ai_message_with_tool_calls.json --execute --outdir ../outputs/B3_tools
基础样例:
python b3_tool_layer.py --tools_config ../configs/tools.yaml --toolset basic_tools --tool_calls ../data/messages/b3_tool_call_format_converter_valid.json --execute --outdir ../outputs/B3_tools/format_converter_valid
python b3_tool_layer.py --tools_config ../configs/tools.yaml --toolset basic_tools --tool_calls ../data/messages/b3_tool_call_unknown_tool.json --execute --outdir ../outputs/B3_tools/unknown_tool
python b3_tool_layer.py --tools_config ../configs/tools.yaml --toolset basic_tools --tool_calls ../data/messages/b3_tool_call_missing_required.json --execute --outdir ../outputs/B3_tools/missing_required
错误样例不会让 CLI 崩溃;错误会写入 tool_messages.json 和 tool_call_log.jsonl 中的 status=error SkillResult。
4.3 B3 输出
| 输出文件 | 格式 | 说明 |
|---|---|---|
outputs/B3_tools/tools_schema.json |
JSON 数组 | 当前 OpenAI 风格的函数工具说明schema;x-returns 描述工具返回值。 |
outputs/B3_tools/tool_schema_report.json |
JSON 对象 | schema 导出报告,包含 toolset、工具数量和工具名称列表。 |
outputs/B3_tools/tool_messages.json |
JSON 数组 | 本次执行生成的 ToolMessage 列表。 |
outputs/B3_tools/tool_call_log.jsonl |
JSONL | 每个 tool call 的完整执行记录,含未转义 SkillResult、状态、参数和耗时。 |
schema/report/tool messages 会被最近一次运行覆盖;tool-call 日志追加写入。
5. B5:Memory 查找与保存
入口:code/b5_memory.py
5.1 输入文件
| 输入文件 | 说明 |
|---|---|
configs/memory.yaml |
记忆根目录、全局/对话目录、索引路径和最大注入字符数。 |
memory/memory_index.json |
memory_id → 元数据 的索引,记录类型、标题、摘要、路径和时间。 |
memory/global/*.md |
全局记忆文档。 |
memory/conversations/*.md |
对话记忆文档。 |
data/memory_inputs/memory_save_input.json |
保存对话类型记忆的样例,包含 conversation ID、保存类型及三个来源文件路径。 |
data/memory_inputs/memory_save_global_input.json |
保存全局类型记忆的样例,会写入项目正式记忆目录 memory/global/ 和 memory/memory_index.json。 |
data/memory_inputs/sample_messages.json |
演示保存记忆时使用的消息数组。 |
data/memory_inputs/sample_trace.json |
演示保存记忆时使用的 trace 对象。 |
data/memory_inputs/sample_final_answer.md |
演示保存记忆时使用的最终回答。 |
configs/memory_small_limit.yaml |
复用当前 memory/,仅降低 max_memory_chars 用于截断演示。 |
演示B5的查找模式时,直接通过命令行参数传入。memory_save_input.json 中的三个来源路径相对于该 JSON 文件所在目录解析,不依赖 B1 输出。
5.2 演示命令
查找记忆:
python b5_memory.py --config ../configs/memory.yaml --select_memory_ids mem_conversation_conv_000 --use_global_memory true --query "Agent 系统如何调用工具?" --outdir ../outputs/B5_memory
python b5_memory.py --config ../configs/memory.yaml --select_memory_ids mem_missing_001 --use_global_memory false --query "验证缺失 memory id 的错误记录。" --outdir ../outputs/B5_memory/missing_id
python b5_memory.py --config ../configs/memory_small_limit.yaml --select_memory_ids mem_course_001 --use_global_memory false --query "验证 max_memory_chars 截断。" --outdir ../outputs/B5_memory/truncate
保存对话记忆
python b5_memory.py --config ../configs/memory.yaml --save_type conversation --save_input_path ../data/memory_inputs/memory_save_input.json --outdir ../outputs/B5_memory
python b5_memory.py --config ../configs/memory.yaml --save_type global --save_input_path ../data/memory_inputs/memory_save_global_input.json --outdir ../outputs/B5_memory/save_global
B5 保存命令会更新项目正式记忆目录:生成或覆盖 memory/conversations/*.md / memory/global/*.md,并新增或更新 memory/memory_index.json。memory_save_global_input.json 使用唯一 conversation_id=demo_global_memory_001,避免覆盖已有示例。
5.3 B5 输出
| 输出文件 | 格式 | 说明 |
|---|---|---|
outputs/B5_memory/selected_memory.json |
JSON 对象 | 本次选中的记忆内容、字符统计、截断标志和缺失 ID 错误。 |
outputs/B5_memory/memory_log.jsonl |
JSONL | 记忆查找与保存历史。 |
outputs/B5_memory/saved_memory.json |
JSON 对象 | 已保存记忆的 ID、类型、标题、摘要、文档路径、来源路径和时间。 |
memory/conversations/conv_sample_001.md |
Markdown | 独立保存命令生成的对话记忆文档,内含最终回答、messages 和 trace。 |
memory/global/demo_global_memory_001.md |
Markdown | 全局保存样例生成的全局记忆文档。 |
memory/memory_index.json |
JSON 对象 | 保存后新增或更新对应记忆元数据。 |
selected_memory.json 和 saved_memory.json 会覆盖;memory_log.jsonl 追加;索引和 Markdown 记忆文档会新增或更新。
6. B4:真实调用模型 / Mock 调试决策
入口:code/b4_local_agent_llm.py
B4 只生成 AIMessage,不执行工具。
6.1 输入文件
| 输入文件 | 说明 |
|---|---|
configs/model.yaml |
统一真实模型配置:服务器本地 Qwen3.5-4B、Transformers、bf16、prompt_json。 |
data/messages/messages_no_tool.json |
第一阶段独立运行输入,只含 system/user,真实模型应生成 tool call。 |
data/messages/messages_with_tool.json |
第二阶段独立运行输入,已含 ToolMessage,真实模型应生成最终回答。 |
data/messages/messages_with_error_tool.json |
已含失败 ToolMessage,验证模型直接说明失败并保持 tool_calls=[]。 |
data/messages/tools_schema_basic.json |
B4个人演示使用的预设tools_schema工具说明,不依赖B3的预先运行。 |
6.2 演示命令
真实加载调用模型: B4 第一阶段,生成 tool_call:
python b4_local_agent_llm.py --model_config ../configs/model.yaml --messages ../data/messages/messages_no_tool.json --tools_schema ../data/messages/tools_schema_basic.json --mode prompt_json --outdir ../outputs/B4_llm/no_tool_real
B4 第二阶段,生成 final_answer:
python b4_local_agent_llm.py --model_config ../configs/model.yaml --messages ../data/messages/messages_with_tool.json --tools_schema ../data/messages/tools_schema_basic.json --mode prompt_json --outdir ../outputs/B4_llm/with_tool_real
B4处理工具调用失败的ToolMessage结果
python b4_local_agent_llm.py --model_config ../configs/model.yaml --messages ../data/messages/messages_with_error_tool.json --tools_schema ../data/messages/tools_schema_basic.json --mode prompt_json --outdir ../outputs/B4_llm/error_tool_real
mock调试模式:
python b4_local_agent_llm.py --model_config ../configs/model.yaml --messages ../data/messages/messages_no_tool.json --tools_schema ../data/messages/tools_schema_basic.json --mode mock --outdir ../outputs/B4_llm
python b4_local_agent_llm.py --model_config ../configs/model.yaml --messages ../data/messages/messages_with_tool.json --tools_schema ../data/messages/tools_schema_basic.json --mode mock --outdir ../outputs/B4_llm
mock 不加载模型、不占用显存,适合无 GPU、无本地模型或其他模块同学联调。
6.3 B4 输出
| 输出文件 | 格式 | 说明 |
|---|---|---|
outputs/B4_llm/<case>/raw_model_output.json |
JSON 对象 | 原始生成文本、解析候选、模式、backend、状态、错误和生成时间。若status为 error,说明模型输出未能解析成合法 AIMessagemock。mock模式也会生成该记录。 |
outputs/B4_llm/<case>/ai_message.json |
JSON 对象(AIMessage) | 规范化后的工具调用或最终回答。 |
outputs/B4_llm/<case>/llm_run_log.jsonl |
JSONL | B4 独立运行历史及产物路径。 |
mock调试的演示命令共用 ../outputs/B4_llm,因此第二条会覆盖第一条的 raw_model_output.json 和 ai_message.json,但日志会追加。
7. B1:Agent Runtime
入口:code/b1_agent_runtime.py
B1 支持两种明确的执行模式:fixture 用于完全隔离的个人演示,直接消费预设 memory、tools schema、AIMessage 和 ToolMessage;integrated 用于全系统演示,只通过 B3、B4、B5 的公开函数进行编排。
7.1 直接输入文件
个人演示 fixture 模式
| 输入文件 | 说明 |
|---|---|
data/b1_fixtures/b1_fixture_input.json |
B1 个人演示入口,设置 execution_mode=fixture 并引用全部预设响应。 |
data/b1_fixtures/preset_memory.json |
模拟 B5 返回的 selected memory。 |
data/b1_fixtures/preset_ai_messages.json |
模拟 B4 依次返回的工具调用 AIMessage 和最终回答 AIMessage。 |
data/b1_fixtures/preset_tool_messages.json |
按 tool_call_id 模拟 B3 返回的 ToolMessage。 |
data/messages/tools_schema_basic.json |
模拟 B3 返回的固定 tools schema。 |
全系统演示 integrated 模式
| 输入文件 | 说明 |
|---|---|
data/runtime_input.json |
file_reader 主线任务,读取 docs/agent_intro.txt 并总结三条中文要点。 |
data/runtime_input_0.json |
无工具倾向任务,验证模型直接回答。 |
data/runtime_input_2.json |
calculator 任务。 |
data/runtime_input_3.json |
local_file_search 任务。 |
data/runtime_input_4.json |
table_analyzer 任务。 |
data/runtime_input_5.json |
format_converter 任务。 |
configs/tools.yaml |
传给 B3,确定可用工具及数据根目录。 |
configs/memory.yaml |
传给 B5,确定 memory 路径和长度上限。 |
configs/model.yaml |
统一真实模型配置。 |
7.2 间接读取文件
| 文件 | 读取原因 |
|---|---|
prompts/local_tool_agent.txt |
fixture 和 integrated 输入指定的 SystemMessage 模板。 |
memory/memory_index.json、memory/global/*.md |
仅 integrated 模式读取;B5 查找并返回 memory 上下文。 |
data/docs/agent_intro.txt |
integrated file_reader 流程实际读取;fixture 模式使用预设 ToolMessage。 |
7.3 演示命令
个人演示 fixture 模式:
python b1_agent_runtime.py --input ../data/b1_fixtures/b1_fixture_input.json --outdir ../outputs/B1_fixture
该命令不会调用 B2–B5。
全系统 integrated 调试模式:
python b1_agent_runtime.py --input ../data/runtime_input.json --tools_config ../configs/tools.yaml --memory_config ../configs/memory.yaml --model_config ../configs/model.yaml --llm_mode mock --outdir ../outputs/B1_runtime
该命令以 B1 为入口真实调用 B3、B4、B5,但 LLM 使用mock;正式全系统演示推荐使用下一节的真实模型 full demo,或将'--llm_mode mock'改为'--llm_mode prompt_json'。
7.4 B1 输出
个人演示 fixture 模式
| 输出文件 | 格式 | 说明 |
|---|---|---|
outputs/B1_fixture/messages.json |
JSON 数组 | B1 根据预设响应维护出的完整消息序列,顶层固定为数组。 |
outputs/B1_fixture/trace.json |
JSON 对象 | B1 的分支判断、消息追加、工具轮次和最终状态。 |
outputs/B1_fixture/final_answer.md |
Markdown | 从预设最终 AIMessage 提取的最终回答。 |
fixture模式只生成以上三个文件,不生成 runtime log、memory文档或其他模块的产物。
全系统演示 integrated 模式
| 输出文件 | 格式 | 说明 |
|---|---|---|
outputs/B1_runtime/messages.json |
JSON 数组 | 完整消息序列,顶层固定为数组。 |
outputs/B1_runtime/trace.json |
JSON 对象 | 运行状态、工具轮次、LLM 次数、每轮 AI/ToolMessage、memory 保存状态和错误。 |
outputs/B1_runtime/final_answer.md |
Markdown | 最终给用户的回答。 |
outputs/B1_runtime/selected_memory.json |
JSON 对象 | B1 调用 B5 后保存的 memory 选择结果。 |
outputs/B1_runtime/tools_schema.json |
JSON 数组 | B1 调用 B3 后保存的当前工具 schema。 |
outputs/B1_runtime/tool_schema_report.json |
JSON 对象 | 当前 toolset 的 schema 摘要。 |
outputs/B1_runtime/tool_messages.json |
JSON 数组 | 本次 Agent 运行累计产生的 ToolMessage。 |
outputs/B1_runtime/tool_call_log.jsonl |
JSONL | B3 工具执行明细。 |
outputs/B1_runtime/saved_memory.json |
JSON 对象 | B5 保存本轮对话后的结果。 |
outputs/B1_runtime/memory_log.jsonl |
JSONL | B1 运行期间的 memory 查找和保存记录。 |
outputs/B1_runtime/runtime_log.jsonl |
JSONL | B1 每次完整任务的状态、模式、轮次、调用数和总耗时。 |
outputs/B1_runtime/llm_calls/llm_call_NNN_raw_model_output.json |
JSON 对象 | 第 N 次 B4 调用的原始输出记录。 |
outputs/B1_runtime/llm_calls/llm_call_NNN_ai_message.json |
JSON 对象 | 第 N 次 B4 调用生成的标准 AIMessage。 |
outputs/B1_runtime/llm_calls/llm_run_log.jsonl |
JSONL | 本次 B1 运行内所有 B4 调用的日志。 |
memory/conversations/conv_001.md |
Markdown | B1 按 save_memory=conversation 保存的对话 memory。 |
memory/memory_index.json |
JSON 对象 | B1 保存 memory 后更新的索引。 |
8. 完整一键演示
入口:code/run_full_demo.py
8.1 输入文件
输入与 B1 相同:
data/runtime_input.jsonconfigs/tools.yamlconfigs/memory.yamlconfigs/model.yaml- 以上配置间接引用的 prompt、memory 和演示文档
8.2 命令
python run_full_demo.py --input ../data/runtime_input.json --tools_config ../configs/tools.yaml --memory_config ../configs/memory.yaml --model_config ../configs/model.yaml --llm_mode prompt_json --outdir ../outputs/full_demo
该正式命令会按 runtime_input.json 中的 save_memory=conversation 更新 memory/conversations/conv_001.md 和 memory/memory_index.json。重复演示前请确认是否接受覆盖该 conversation memory。
8.3 输出
run_full_demo.py 使用 outputs/full_demo 作为 B1 integrated 模式的 outdir,因此会生成 integrated 模式的完整 artifacts,并额外生成:
| 输出文件 | 格式 | 说明 |
|---|---|---|
outputs/full_demo/demo_report.md |
Markdown | 汇总 conversation、运行状态、消息流、工具轮次、LLM 次数、memory 数量、工具数量、最终回答和文件清单。 |
典型成功演示的 messages.json 角色顺序为:
system → user → assistant(tool_calls) → tool → assistant(final)
8.4 本地 TTS 与语音交互配置
TTS 子进程运行方式
调用 text_to_speech 时,Agent 会将请求写入临时 JSON,再用 CosyVoice 环境的 Python 启动 TTS Worker。agent/configs/tts.yaml 中:
persistent_worker: false:每次合成启动一次独立子进程,结束后释放模型;占用更容易回收,但每次都要重新加载模型。persistent_worker: true:复用常驻子进程和已加载模型,适合连续对话,后续语音生成更快。load_jit、fp16:控制 CosyVoice 加速和精度选项,需结合运行设备支持情况设置。min_chunk_chars、max_chunk_chars、hard_max_chunk_chars:控制流式 TTS 的文本切块长度。inter_chunk_silence_sec:控制合并语音块之间的静音时长。
也可以临时使用环境变量覆盖主要路径,而不修改 YAML:
$env:COSYVOICE_PYTHON="C:\path\to\envs\cosyvoice\python.exe"
$env:COSYVOICE_REPO="C:\path\to\assignment_B\CosyVoice"
$env:COSYVOICE_MODEL="C:\path\to\assignment_B\CosyVoice2-0.5B"
$env:COSYVOICE_PROMPT_WAV="C:\path\to\prompt.wav"
音色切换
项目内置 default 和 funingna 两个音色配置,定义在 agent/configs/tts.yaml 的 voice.voices 下。每个音色由参考音频 prompt_wav 和对应文本 prompt_text 组成,二者应与实际音频内容一致。
修改语音客户端默认音色:
# agent/configs/voice_chat.yaml
tts:
voice: "default" # 可改为 funingna
也可以在启动时临时覆盖:
python .\agent\code\voice_chat_windows_client.py --config .\agent\configs\voice_chat.yaml --tts-voice default
在 Runtime JSON 中启用最终回答 TTS 时,可通过 tts_voice 选择音色:
{
"enable_tts": true,
"tts_voice": "funingna"
}
新增音色时,在 agent/configs/tts.yaml 的 voice.voices 下增加新的 ID,并配置匹配的 prompt_wav 与 prompt_text,随后把 tts_voice 或 tts.voice 改为该 ID。
TTS 和会话模式切换
agent/configs/voice_chat.yaml 支持以下模式:
| 字段 | 可选值 | 说明 |
|---|---|---|
tts.mode |
local |
在 Windows 本地通过独立 CosyVoice 子进程合成并播放;当前项目默认模式 |
tts.mode |
remote |
在远程服务器合成,再将音频结果传回客户端 |
tts.mode |
none |
关闭语音合成,只显示识别文本和回答 |
tts.stream_mode |
stream |
回答按文本块合成,生成一块就播放一块 |
tts.stream_mode |
full |
完整回答合成为一个 WAV 后再播放 |
tts.language |
auto、zh、en |
自动判断、中文零样本或英文跨语言合成 |
conversation.mode |
append |
同一服务进程持续追加消息,适合多轮对话与 KV Cache 复用 |
conversation.mode |
restart |
每轮重新执行一次独立 Agent Runtime,通过已保存 Memory 衔接上下文 |
这些设置也可以通过命令行覆盖,无需修改配置文件:
# 本地流式 TTS,使用 funingna 音色,并保留连续对话上下文
python .\agent\code\voice_chat_windows_client.py `
--config .\agent\configs\voice_chat.yaml `
--tts-mode local `
--tts-stream-mode stream `
--tts-language auto `
--tts-voice funingna `
--conversation-mode append
# 关闭 TTS
python .\agent\code\voice_chat_windows_client.py `
--config .\agent\configs\voice_chat.yaml `
--tts-mode none
如不想修改 tts.yaml,语音客户端还支持 --local-tts-python、--local-cosyvoice-repo、--local-tts-model、--local-prompt-wav 和 --local-prompt-text,可在启动时覆盖本地 TTS 的环境、模型和参考音频路径。
单独验证本地流式 TTS
建议在运行完整语音对话前先验证 CosyVoice 子进程:
python .\agent\code\stream_tts_demo.py `
--text "你好,这是本地语音合成测试。" `
--language zh `
--tts-voice default `
--cosyvoice-python "C:\path\to\envs\cosyvoice\python.exe" `
--cosyvoice-repo ".\CosyVoice" `
--model-dir ".\CosyVoice2-0.5B"
终端应逐块显示 TTS 事件并播放语音;加入 --no-play 可以只生成和检查音频,不调用扬声器。
9. CLI 退出码
| 退出码 | 含义 |
|---|---|
| 0 | 成功,或业务错误已被捕获并写入结构化产物。 |
| 1 | 配置、输入文件、解析、模块加载、模型依赖或输出目录等致命错误。 |
| 2 | argparse 参数使用错误。 |
10.附录 outputs/ 文件说明
本节描述输出目录中的文件。
10.1 outputs/B1_fixture/
| 输出文件 | 直接生成者 | 含义 | 格式 |
|---|---|---|---|
messages.json |
b1_agent_runtime.py fixture 模式 |
使用预设模块响应构造的完整 Agent 消息序列。 | JSON 数组 |
trace.json |
b1_agent_runtime.py fixture 模式 |
B1 个人演示的轮次、分支、AIMessage 和 ToolMessage 轨迹。 | JSON 对象 |
final_answer.md |
b1_agent_runtime.py fixture 模式 |
B1 从预设最终 AIMessage 中得到的回答。 | Markdown |
10.2 outputs/B2_skills/
| 输出文件 | 生成代码 | 含义 | 格式 |
|---|---|---|---|
calculator_result.json |
b2_run_skill.py |
calculator 最近一次 SkillResult。 | JSON 对象 |
file_reader_result.json |
b2_run_skill.py |
file_reader 最近一次 SkillResult。 | JSON 对象 |
local_file_search_result.json |
b2_run_skill.py |
local_file_search 最近一次 SkillResult。 | JSON 对象 |
table_analyzer_result.json |
b2_run_skill.py |
table_analyzer 最近一次 SkillResult。 | JSON 对象 |
format_converter_result.json |
b2_run_skill.py |
format_converter 最近一次 SkillResult,包含 formatted_text 和 generated_file_path。 |
JSON 对象 |
skill_run_log.jsonl |
b2_run_skill.py |
五类 Skill 的累计运行日志。 | JSONL |
10.3 outputs/B3_tools/
| 输出文件 | 生成代码 | 含义 | 格式 |
|---|---|---|---|
tools_schema.json |
b3_tool_layer.py --export_schema |
basic_tools 的模型工具说明。 |
JSON 数组 |
tool_schema_report.json |
b3_tool_layer.py --export_schema |
工具 schema 数量与名称摘要。 | JSON 对象 |
tool_messages.json |
b3_tool_layer.py --execute |
本次 tool calls 对应的 ToolMessage。 | JSON 数组 |
tool_call_log.jsonl |
b3_tool_layer.py --execute |
tool calls 的累计执行明细。 | JSONL |
10.4 outputs/B4_llm/
| 输出文件 | 生成代码 | 含义 | 格式 |
|---|---|---|---|
<case>/raw_model_output.json |
b4_local_agent_llm.py |
B4 独立运行案例的原始输出和解析状态。 | JSON 对象 |
<case>/ai_message.json |
b4_local_agent_llm.py |
B4 独立运行案例的规范化 AIMessage。 | JSON 对象 |
<case>/llm_run_log.jsonl |
b4_local_agent_llm.py |
B4 独立运行案例的运行日志。 | JSONL |
10.5 outputs/B5_memory/
| 输出文件 | 生成代码 | 含义 | 格式 |
|---|---|---|---|
selected_memory.json |
b5_memory.py 查找模式 |
最近一次 memory 选择及截断结果。 | JSON 对象 |
saved_memory.json |
b5_memory.py 保存模式 |
最近一次 memory 保存结果和目标路径。 | JSON 对象 |
memory_log.jsonl |
b5_memory.py |
memory 查找/保存累计日志。 | JSONL |
10.6 outputs/B1_runtime/
| 输出文件 | 直接生成者 | 含义 | 格式 |
|---|---|---|---|
messages.json |
b1_agent_runtime.py |
完整 Agent 消息序列。 | JSON 数组 |
trace.json |
b1_agent_runtime.py |
完整运行轨迹、轮次、状态和错误。 | JSON 对象 |
final_answer.md |
b1_agent_runtime.py |
最终回答。 | Markdown |
runtime_log.jsonl |
b1_agent_runtime.py |
B1 累计任务日志。 | JSONL |
selected_memory.json |
b5_memory.load_memory,由 B1 指定 outdir |
注入消息前选择的 memory。 | JSON 对象 |
memory_log.jsonl |
b5_memory.py,由 B1 调用 |
本轮 memory 查找及保存日志。 | JSONL |
saved_memory.json |
b5_memory.save_memory,由 B1 调用 |
本轮对话 memory 保存结果。 | JSON 对象 |
tools_schema.json |
b3_tool_layer.get_tools_schema,由 B1 调用 |
本轮可用工具 schema。 | JSON 数组 |
tool_schema_report.json |
b3_tool_layer.py,由 B1 调用 |
本轮工具集摘要。 | JSON 对象 |
tool_messages.json |
B3 生成、B1 汇总 | 本轮所有 ToolMessage。 | JSON 数组 |
tool_call_log.jsonl |
b3_tool_layer.execute_tool_calls,由 B1 调用 |
本轮工具执行明细。 | JSONL |
llm_calls/llm_call_001_raw_model_output.json |
b4_local_agent_llm.generate_ai_message |
第一次 LLM 决策的原始输出。 | JSON 对象 |
llm_calls/llm_call_001_ai_message.json |
b4_local_agent_llm.generate_ai_message |
第一次标准 AIMessage,包含 tool call。 | JSON 对象 |
llm_calls/llm_call_002_raw_model_output.json |
b4_local_agent_llm.generate_ai_message |
第二次 LLM 决策的原始输出。 | JSON 对象 |
llm_calls/llm_call_002_ai_message.json |
b4_local_agent_llm.generate_ai_message |
第二次标准 AIMessage,包含 final content。 | JSON 对象 |
llm_calls/llm_run_log.jsonl |
b4_local_agent_llm.py,由 B1 调用 |
本轮两次 LLM 调用日志。 | JSONL |
10.7 outputs/full_demo/
| 输出文件 | 直接生成者 | 含义 | 格式 |
|---|---|---|---|
messages.json |
b1_agent_runtime.py,由 run_full_demo.py 调用 |
完整演示消息序列。 | JSON 数组 |
trace.json |
b1_agent_runtime.py |
完整演示运行轨迹。 | JSON 对象 |
final_answer.md |
b1_agent_runtime.py |
完整演示最终回答。 | Markdown |
runtime_log.jsonl |
b1_agent_runtime.py |
完整演示运行日志。 | JSONL |
selected_memory.json |
b5_memory.load_memory |
完整演示选择的 memory。 | JSON 对象 |
memory_log.jsonl |
b5_memory.py |
完整演示的 memory 查找/保存日志。 | JSONL |
saved_memory.json |
b5_memory.save_memory |
完整演示保存的对话 memory 信息。 | JSON 对象 |
tools_schema.json |
b3_tool_layer.get_tools_schema |
完整演示使用的工具 schema。 | JSON 数组 |
tool_schema_report.json |
b3_tool_layer.py |
完整演示工具集摘要。 | JSON 对象 |
tool_messages.json |
B3 生成、B1 汇总 | 完整演示产生的 ToolMessage。 | JSON 数组 |
tool_call_log.jsonl |
b3_tool_layer.execute_tool_calls |
完整演示工具执行明细。 | JSONL |
llm_calls/llm_call_001_raw_model_output.json |
b4_local_agent_llm.py |
第一次 LLM 原始输出。 | JSON 对象 |
llm_calls/llm_call_001_ai_message.json |
b4_local_agent_llm.py |
第一次 AIMessage,包含 tool call。 | JSON 对象 |
llm_calls/llm_call_002_raw_model_output.json |
b4_local_agent_llm.py |
第二次 LLM 原始输出。 | JSON 对象 |
llm_calls/llm_call_002_ai_message.json |
b4_local_agent_llm.py |
第二次 AIMessage,包含最终回答。 | JSON 对象 |
llm_calls/llm_run_log.jsonl |
b4_local_agent_llm.py |
完整演示 LLM 调用日志。 | JSONL |
demo_report.md |
run_full_demo.py |
对完整演示状态、数据流、最终回答和文件清单的汇总。 | Markdown |