main
个人模块 README — B3
模块 B3:说明生成与工具调用模块 | 负责人:周炜伦 20235904
1. 模块概述
1.1 模块名称
B3 — 说明生成与工具调用模块 (Tool Layer: Schema & Execution)
1.2 模块说明
B3 是 Skill(B2) 与 LLM(B4) 之间的桥梁层,承担两个核心职责:
- 生成工具描述(tools_schema):将
tools.yaml中的工具定义转换为 OpenAI Function Calling 格式的 JSON Schema,让 LLM 知道"有哪些工具、每个工具需要什么参数" - 执行工具调用(execute_tool_calls):接收 B4 返回的
tool_calls,校验工具名和参数合法性,调用 B2 的 Skill 函数,将结果封装为标准 ToolMessage 返回给 B1
B3 的核心定位:
┌──────────┐
tools.yaml ──► │ B3 │ ──► tools_schema (给 LLM 看)
│ │
tool_calls ──► │ Tool │ ──► ToolMessage (给 B1)
│ Layer │
└────┬─────┘
│ 调用 B2 Skill
▼
┌──────────┐
│ B2 │
└──────────┘
1.3 完成情况概览
| 类型 | 完成情况 |
|---|---|
| 基础要求 | ✅ 全部完成:读取 tools.yaml 生成 tools_schema(8个工具/含name+description+parameters+required+returns)、校验 tool_calls 并执行 B2 Skill、输出 JSON 格式记录 |
| 进阶要求 | ✅ 5 项全部完成:自动从 Python 函数签名生成 schema、可恢复错误重试(指数退避)、tool_call 结果缓存(SHA256 键+TTL)、批量统计压测(~110条覆盖全部工具)、不同 schema 详尽度对比实验 |
| 可独立运行的演示 | ✅ CLI 独立运行 + Web Demo(端口 8082)+ 统计压测按钮 |
| 与团队系统集成情况 | ✅ 通过 get_tools_schema() 和 execute_tool_calls() 被 B1 调用,是 B1 Agent Loop 中不可或缺的工具调用环节 |
2. 环境、模型与数据依赖
2.1 运行环境
| 项目 | 要求 |
|---|---|
| Python 版本 | 3.10 |
| 必要依赖 | PyYAML |
| 是否需要模型 | 不需要(B3 只做配置解析和参数校验) |
| 是否需要 GPU | 不需要 |
| 是否需要外部数据集 | 不需要 |
2.2 模型依赖
B3 不加载模型。它只做配置解析、参数校验和函数调用调度。
2.3 数据集或样例数据依赖
| 数据或文件 | 来源 | 项目内相对路径 | 用途 |
|---|---|---|---|
configs/tools.yaml |
项目自带 | agent/configs/ |
工具定义配置(toolsets + 每个工具的 module/function/description/parameters/returns) |
data/messages/ai_message_with_tool_calls.json |
项目自带 | agent/data/messages/ |
模拟 B4 返回的 tool_calls(用于独立演示) |
b3_tool_call_*.json |
项目自带 | agent/data/messages/ |
异常测试样例(unknown_tool/missing_required/safe_exec) |
2.4 安装步骤
conda create -n b3_env python=3.10 -y
conda activate b3_env
cd agent
pip install -r requirements.txt
3. 文件结构与接口边界
3.1 文件结构
agent/
├── code/
│ ├── b3_tool_layer.py # 核心:Schema生成+工具执行(324行)
│ ├── b3_cache.py # 进阶:tool_call结果缓存(SHA256键+TTL,70行)
│ ├── b3_stats.py # 进阶:工具调用统计(次数/成功率/平均耗时,101行)
│ └── b3_schema_generator.py # 进阶:从Python函数签名自动生成Schema(145行)
├── demo/
│ ├── b3_demo_server.py # Web Demo 服务器(端口 8082)+ 统计压测API
│ └── templates/b3_index.html # Web Demo 前端(含统计压测按钮)
├── experiments/
│ ├── compare_tool_schemas.py # 不同Schema详尽度对比实验
│ └── compare_schema_injection.py # 不同Schema注入位置对比实验
├── configs/
│ └── tools.yaml # 工具定义配置文件
└── B3_VERIFICATION.md # 模块验证说明书
3.2 接口边界
| 类型 | 来源 / 去向 | 数据格式 | 说明 |
|---|---|---|---|
| 输入 | B1 → get_tools_schema() |
函数调用(tools_config路径 + toolset名) | B1 在 Agent Loop 开始时调用一次 |
| 输入 | B1 → execute_tool_calls() |
函数调用(tool_calls列表 + tools_config) | B1 在每次 B4 返回 tool_calls 时调用 |
| 输出 | get_tools_schema() → B1 |
list[dict](OpenAI Function Calling 格式) |
传给 B4 做工具绑定 |
| 输出 | execute_tool_calls() → B1 |
list[dict](ToolMessage 列表) |
追加到 messages 后再次调用 B4 |
| 调用 B2 | B3 → run_skill() |
Python 函数调用 | 通过 B2 的 SKILL_MODULES 注册表 |
4. 基础要求实现与演示
4.1 基础功能说明
| 功能 | 入口函数 | 说明 |
|---|---|---|
| 导出 Schema | get_tools_schema() |
读取 tools.yaml → 按 toolset 筛选 → 生成 OpenAI 格式的 JSON Schema 列表 |
| 执行工具调用 | execute_tool_calls() |
接收 tool_calls → 校验工具名 → 校验参数类型/必填 → 调用 B2 → 封装 ToolMessage |
4.2 基础功能实现路径
| 文件 / 函数 | 作用 |
|---|---|
b3_tool_layer.py:_load_tools_config() |
读取 tools.yaml,校验 tools 和 toolsets 两个顶层 key |
b3_tool_layer.py:_resolve_toolset() |
从 toolsets 中取出指定 toolset 的工具名列表 |
b3_tool_layer.py:_parameter_schema() |
将 tools.yaml 中的参数定义转为 JSON Schema(type/properties/required/additionalProperties) |
b3_tool_layer.py:get_tools_schema() |
遍历工具名,为每个工具生成 OpenAI 格式的 schema 记录 |
b3_tool_layer.py:_validate_args() |
校验参数:必填项检查 + 类型检查 + 未知参数检查 |
b3_tool_layer.py:execute_tool_calls() |
主执行流程:标准化 → 缓存查 → 校验 → B2 调用 → ToolMessage 封装 |
4.3 基础功能演示命令
cd agent/code
# 导出 Schema
python b3_tool_layer.py --tools_config ../configs/tools.yaml \
--toolset basic_tools --export_schema --outdir ../outputs/B3_tools
# 执行工具调用
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
观察要点:
tools_schema.json包含 8 个工具的完整定义tool_messages.json中每个 ToolMessage 的status=success- B3 从
tools.yaml读取data_root配置,自动注入给 B2
4.4 基础功能输出格式
| 输出文件 | 格式 | 说明 |
|---|---|---|
tools_schema.json |
JSON 数组 | 8 个工具的 OpenAI Function Calling 格式描述 |
tool_schema_report.json |
JSON 对象 | toolset、tool_count、tools 名称列表 |
tool_messages.json |
JSON 数组 | 本次执行的 ToolMessage 列表 |
tool_call_log.jsonl |
JSONL | 每个 tool_call 的完整执行记录 |
5. 进阶要求实现与演示
5.1 选择的进阶要求
| 进阶要求 | 是否完成 | 对应文件 | 简要说明 |
|---|---|---|---|
| 进阶1:自动 Schema 生成 | ✅ | b3_schema_generator.py |
从 Python 函数 type hints + docstring 自动推断参数类型和描述 |
| 进阶2:可恢复错误重试 | ✅ | b3_tool_layer.py:execute_tool_calls() |
指数退避重试(TimeoutError/ConnectionError 等),input/fatal 类不重试 |
| 进阶3:Tool Call 缓存 | ✅ | b3_cache.py |
SHA256 键 + TTL 过期 + 磁盘持久化 |
| 进阶4:批量统计压测 | ✅ | b3_stats.py + b3_demo_server.py |
自动生成 ~110 条 tool_calls 覆盖全部 8 个工具,含正常/边界/错误场景 |
| 进阶5:Schema 对比实验 | ✅ | experiments/compare_tool_schemas.py |
minimal/standard/detailed 三种详尽度对比 |
5.2 进阶1:自动 Schema 生成
b3_schema_generator.py 无需手写 tools.yaml,直接从 Python 函数签名生成 Schema:
- 参数类型:通过
inspect.signature()+ type hints 推断(str→string,int→integer,bool→boolean等) - 参数描述:从 docstring 的
Args:段解析 - 必填参数:默认值
<Parameter.empty>的即为必填
# 全部 8 个工具
python b3_schema_generator.py --all --outdir ../outputs/B3_tools/auto_schema
# 单个工具
python b3_schema_generator.py --module skills.calculator --function calculator --outdir ../outputs/B3_tools/auto_single
5.3 进阶2:可恢复错误重试
execute_tool_calls() 支持 --retry 参数:
# 只在遇到可恢复错误时重试(TimeoutError/ConnectionError等)
# 指数退避:delay = retry_delay * (2^attempt)
# 不可恢复错误(input/fatal 类)直接返回,不浪费重试
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/retry_test --retry 3 --retry_delay 0.5
5.4 进阶3:Tool Call 结果缓存
b3_cache.py 实现基于 SHA256 的缓存:
- 键:
SHA256(tool_name + sorted(args))[:16] - TTL:默认 300 秒,过期自动删除
- 存储:
{outdir}/.tool_cache/{hash}.json
# 第一次:cache miss → 执行 Skill → 缓存
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/cache_test --cache
# 第二次:cache hit → 直接返回缓存
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/cache_test --cache
5.5 进阶4:批量统计压测
点击 B3 前端 "📊 统计压测" 按钮,后端自动生成 ~110 条 tool_calls,覆盖全部 8 个工具的正常/边界/错误场景:
| 工具 | 用例数 | 覆盖 |
|---|---|---|
| calculator | 20 | 加减乘除、幂运算、括号、浮点、取模 |
| file_reader | 22 | 3 个正常文件 × 多次 + 不存在文件 + 非 txt 文件 |
| local_file_search | 16 | 15 个关键词 + 不存在目录 |
| table_analyzer | 6 | CSV 分析 × 5 + 不存在文件 |
| format_converter | 11 | JSON × 5 + Markdown × 5 + 空文本异常 |
| safe_executor | 17 | 列表/字符串/循环/类型转换 + import 违规 + 语法错误 |
| read_and_convert | 5 | JSON 转换 × 3 + Markdown 转换 × 2 |
| search_and_analyze | 8 | 正常 × 5 + 错误目录 + 无CSV目录 + 不匹配关键词 |
执行完后返回完整的 tool_stats_report.md:
# Tool Call Statistics Report
| Tool | Calls | Success | Error | Rate | Avg(ms) | Min(ms) | Max(ms) |
|------|-------|---------|-------|------|---------|---------|---------|
| calculator | 20 | 20 | 0 | 100.0% | 0.15 | 0.03 | 0.52 |
| file_reader | 22 | 20 | 2 | 90.9% | 0.51 | 0.21 | 1.23 |
...
5.6 进阶5:Schema 对比实验
experiments/compare_tool_schemas.py 生成三种详尽程度的 Schema 并对比:
| Level | 做法 | Schema 大小 |
|---|---|---|
| minimal | 去掉所有 description 和 x-returns | ~2540 chars |
| standard | 原样保留 tools.yaml 定义 | ~7728 chars |
| detailed | 追加类型约束和额外说明 | ~8403 chars |
cd experiments
python compare_tool_schemas.py --outdir ../outputs/exp_schema_compare
6. 与团队系统的集成说明
B3 通过两个公开函数被 B1 调用:
# B1 调用位置:b1_agent_runtime.py 第370行
from b3_tool_layer import execute_tool_calls, get_tools_schema
# 第381行:获取工具描述
tools_schema = get_tools_schema(str(tools_file), runtime["toolset"], str(output_dir))
# 第533-535行:执行工具调用
tool_messages = execute_tool_calls(
tool_calls, str(tools_file), runtime["toolset"], str(output_dir),
use_cache=True, track_stats=True, retry=1,
)
B3 内部通过 b2_run_skill_fn() 调用 B2 的 Skill 函数。tools.yaml 中的 data_root 配置(../data)被 B3 解析后注入给 B2,确保 B2 的 resolve_data_path() 能找到正确的数据目录。
7. 已知问题与后续改进
| 问题 | 当前原因 | 后续改进 |
|---|---|---|
| 自动 Schema 生成无 x-returns 详情 | 仅从函数签名推断,无法获取返回值结构 | 可解析 docstring 的 Returns 段 |
| 缓存仅基于 name+args | 不区分 data_root,不同数据目录下同参数调用会命中同一缓存 | 可将 data_root 纳入缓存键 |
| 统计压测需手动触发 | 前端按钮调用,非自动 | 可添加每次 B1 调用后自动汇总的统计 |
Languages
Python
74.2%
HTML
25.8%