B3 Schema 与 B5 Memory 个人模块
东北大学综合实训Ⅱ - B 方向 Agent 智能体
负责人:王稳淞(20235870)
1. 模块概述
1.1 模块名称
B3:说明生成与工具调用模块 + B5:记忆文档存储与查找模块
1.2 模块说明
本仓库是我在 B 方向本地 Agent 框架中负责部分的独立交付仓库,包含 B3、B5 的基础要求、当前启用的进阶功能、演示输入和服务器验证产物。
- B3 位于模型决策与真实工具之间:把工具配置转换为 LLM 可读的
tools_schema,校验 B4 产生的tool_calls,调用 B2 Skill,并以标准ToolMessage返回执行结果。 - B5 位于 Agent 上下文入口和运行结束位置:加载全局/会话记忆、自动检索相关记忆、控制注入长度,并把一次运行的回答、消息和轨迹保存为可长期复用的 Markdown 记忆。
两部分共同解决了本地 Agent 的两个关键工程问题:一是让模型看到的工具说明与 Python 实现保持一致,二是让跨轮次运行能够检索、压缩和复用历史信息。
1.3 完成情况概览
| 类型 | 完成情况 |
|---|---|
| B3 基础要求 | 读取 tools.yaml;按 toolset 生成 OpenAI Function Calling 风格 Schema;接收、校验和执行 tool_calls;生成 ToolMessage 与 JSONL 日志 |
| B3 进阶要求 | Python 函数签名推断/合并 Schema;可恢复格式错误修复;相同 name + args 的成功结果缓存 |
| B5 基础要求 | 手动加载全局/会话记忆;长度预算与截断;保存 Markdown 记忆;维护 memory_index.json 与操作日志 |
| B5 进阶要求 | jieba 关键词 Top-K;本地 FastEmbed 中文向量检索;本地 Qwen 长记忆结构化摘要压缩 |
| 可独立演示 | code/b3_tool_layer.py、code/b5_memory.py、code/b35_webui_server.py |
| 团队集成 | B1 直接导入 B3/B5 函数;B5 上下文注入 System Message;B3 ToolMessage 回流 B1/B4;运行结束调用 B5 保存 |
2. 环境、模型与数据依赖
2.1 运行环境
| 项目 | 要求 |
|---|---|
| Python | 3.10 |
| 操作系统 | Linux 优先;macOS/Windows 可运行无 GPU 的基础与关键词演示 |
| 基础依赖 | PyYAML、jieba |
| 向量检索依赖 | numpy、fastembed、onnxruntime |
| LLM 压缩依赖 | PyTorch、Transformers、Accelerate |
| GPU | B3、B5 基础功能和向量检索不要求;Qwen 4B 压缩建议使用 GPU |
| 网络 | 首次下载模型需要;配置完成后可离线运行 |
2.2 模型依赖
| 模型 | 来源 | 项目内相对路径 | 用途 |
|---|---|---|---|
| Qwen3.5-4B | Qwen/Qwen3.5-4B | models/Qwen3.5-4B/ |
超长 Memory 的本地结构化摘要压缩 |
| BAAI/bge-small-zh-v1.5 | BAAI/bge-small-zh-v1.5 | models/embedding_models/fast-bge-small-zh-v1.5/ |
512 维中文语义向量检索 |
模型权重体积较大,按提交要求不纳入 Git。准备方式示例:
# Qwen 模型
huggingface-cli download Qwen/Qwen3.5-4B \
--local-dir models/Qwen3.5-4B
# 让 FastEmbed 建立其本地缓存目录
python -c "from fastembed import TextEmbedding; TextEmbedding(model_name='BAAI/bge-small-zh-v1.5', cache_dir='models/embedding_models/fast-bge-small-zh-v1.5')"
配置文件默认使用仓库相对路径。模型准备完成后,local_files_only: true 可保证推理阶段不访问外网。
2.3 数据与样例
| 数据或文件 | 来源 | 路径 | 用途 |
|---|---|---|---|
| B3 标准/异常 Tool Call | 自行构造 | data/messages/b3_*.json |
Schema、错误恢复、缓存和异常边界演示 |
| B5 长对话输入 | 自行构造 | data/memory_inputs/memory_save_long_input.json |
触发 LLM 摘要压缩 |
| 世界杯 Memory 集 | 自行构造 | memory_keyword_football/ |
关键词与向量检索的可复现对照样例 |
| 表格样例 | 项目自带 | data/tables/results.csv |
B3 调用 B2 table_analyzer |
| 服务器验证产物 | 实际运行 | evidence/outputs/ |
报告中的指标与截图证据 |
2.4 安装步骤
git clone https://gitea.bytevibe.dev/Wws/AgentWwsPart.git
cd AgentWwsPart
conda create -n agent-wws python=3.10 -y
conda activate agent-wws
pip install -r requirements.txt
如果只验收 B3 基础功能和 B5 关键词检索,可先安装最小依赖:
pip install PyYAML jieba
3. 文件结构与接口边界
3.1 文件结构
AgentWwsPart/
├── code/
│ ├── b3_tool_layer.py # B3 Schema、校验、恢复、缓存与工具执行
│ ├── b5_memory.py # B5 加载、检索、压缩与保存
│ ├── b35_webui_server.py # B3/B5 联合演示服务
│ └── common/ # JSON、路径、日志与公共消息结构
├── configs/
│ ├── tools.yaml # 工具定义与 toolset
│ ├── memory.yaml # 保存/压缩配置
│ ├── memory_keyword_football.yaml # 检索演示配置
│ └── model_b5_local.yaml # 本地 Qwen 配置
├── skills/ # B3 演示依赖的 B2 Skill 接口实现
├── data/
│ ├── messages/ # B3 输入样例
│ ├── memory_inputs/ # B5 保存与压缩输入样例
│ └── tables/ # 工具执行样例数据
├── memory/ # 基础全局/会话记忆
├── memory_keyword_football/ # 检索评测记忆集与索引
├── webui_b35/ # B3/B5 WebUI 静态资源
├── evidence/outputs/ # 精选服务器运行产物
├── docs/images/ # 架构图与结果图
├── TEAM_README.md # 团队项目说明
├── FINAL_REPORT.md # 个人结题技术报告
└── README.md # 当前个人模块说明
3.2 接口边界
| 类型 | 来源 / 去向 | 数据格式 | 说明 |
|---|---|---|---|
| B3 输入 | tools.yaml / B1 / B4 |
YAML、AIMessage.tool_calls |
获取工具定义或接收模型工具调用 |
| B3 输出 | B1 / B4 / 输出目录 | tools_schema、ToolMessage[]、JSONL |
提供模型可读 Schema 和可追踪执行结果 |
| B3 下游 | B2 Skill | Python 函数调用 | 注入 data_root / output_dir 后执行真实工具 |
| B5 输入 | B1 / CLI | memory ID、query、messages、trace、answer | 选择、检索或保存记忆 |
| B5 输出 | B1 / 输出目录 | JSON、Markdown | 返回选中上下文并记录保存结果 |
| B5 存储 | 本地 Memory 目录 | memory_index.json + *.md |
索引与正文分离,支持全局/会话两类记忆 |
4. 基础要求实现与演示
4.1 B3 基础功能
B3 基础流程为:
tools.yaml + toolset
-> 读取工具定义
-> 生成 OpenAI 风格 tools_schema
-> 接收 AIMessage.tool_calls
-> 校验工具名、required 参数和 JSON 类型
-> 调用 B2 Skill
-> SkillResult -> ToolMessage + tool_call_log.jsonl
核心实现:
| 文件 / 函数 | 作用 |
|---|---|
code/b3_tool_layer.py::get_tools_schema |
选择 toolset、构造函数 Schema、输出审计报告 |
code/b3_tool_layer.py::_validate_args |
检查必填字段、未知参数、JSON 类型和数组元素类型 |
code/b3_tool_layer.py::execute_tool_calls |
调用 Skill、包装错误、构造 ToolMessage 与日志 |
code/common/schemas.py |
统一 AIMessage、ToolMessage、SkillResult 数据结构 |
独立演示:
cd code
# 生成基础 Schema
python b3_tool_layer.py \
--tools_config ../configs/tools.yaml \
--toolset basic_tools \
--schema_source config \
--export_schema \
--outdir ../outputs/B3_basic_schema
# 执行标准 Tool Call
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_basic_execute
主要输出:tools_schema.json、tool_schema_report.json、tool_schema_audit.json、tool_messages.json、tool_call_log.jsonl。
4.2 B5 基础功能
B5 基础流程为:
memory.yaml + memory_index.json
-> 按 ID / 全局开关选择记忆
-> 校验路径不越界
-> 按 max_memory_chars 组装上下文
-> selected_memory.json
messages + trace + final answer
-> 构造 Markdown 记忆
-> 更新 memory_index.json
-> saved_memory.json + memory_log.jsonl
核心实现:
| 文件 / 函数 | 作用 |
|---|---|
code/b5_memory.py::_memory_paths |
解析并校验 Memory 根目录与字符预算 |
code/b5_memory.py::load_memory |
加载、去重、截断并记录异常 |
code/b5_memory.py::save_memory |
保存全局/会话 Markdown,维护索引与日志 |
code/b5_memory.py::_safe_conversation_id |
防止非法 conversation ID 导致路径穿越 |
独立演示:
cd code
# 按 ID 加载记忆
python b5_memory.py \
--config ../configs/memory_keyword_football.yaml \
--select_memory_ids mem_football_worldcup_goalkeeper \
--use_global_memory true \
--outdir ../outputs/B5_basic_load
# 保存一份会话记忆
python b5_memory.py \
--config ../configs/memory.yaml \
--save_type conversation \
--save_input_path ../data/memory_inputs/memory_save_input.json \
--outdir ../outputs/B5_basic_save
5. 进阶要求实现与演示
5.1 已完成的进阶要求
| 进阶要求 | 完成状态 | 对应实现 |
|---|---|---|
| B3-1 从 Python 函数自动生成 Schema | 已完成 | _json_schema_from_annotation、_infer_parameters_from_function、_schema_audit |
| B3-2 可恢复错误有限修复 | 已完成 | _coerce_value、_recover_tool_call |
| B3-3 Tool Call 结果缓存 | 已完成 | _cache_key、_read_cache、_write_cache |
| B5-1 关键词 Top-K | 已完成 | extract_keywords、search_memory_topk |
| B5-2 长记忆摘要压缩 | 已完成 | _summarize_with_llm、_compress_memory_document |
| B5-4 本地向量检索 | 已完成 | search_memory_vector_topk |
5.2 B3-1:函数签名推断、合并与审计
B3 支持三种 Schema 来源:
config:完全使用tools.yaml;inferred:读取 Python 函数签名、类型注解、默认值和 required 参数;merged:以真实签名为边界,同时保留 YAML 中更适合 LLM 的人工描述。
data_root 和 output_dir 属于运行时注入参数,不向 LLM 暴露。审计报告会检查缺失、多余、类型不一致和 required 不一致。
signature = inspect.signature(function)
for name, param in signature.parameters.items():
if name in INJECTED_PARAMETERS:
injected.append(name)
continue
schema = _json_schema_from_annotation(type_hints.get(name, param.annotation))
演示命令:
python code/b3_tool_layer.py \
--tools_config configs/tools.yaml \
--toolset extended_tools \
--schema_source merged \
--export_schema \
--outdir outputs/B3_schema_merged
服务器产物显示 10 个工具全部 aligned,warning_tools = 0:
查看报告。
5.3 B3-2:可恢复错误修复
执行前先严格校验;仅对确定可恢复的表示错误进行一次规范化,然后重新校验。支持:
- 工具名、参数名和字符串首尾空格;
- 数字字符串转
integer/number; true/false/yes/no转布尔值;- JSON 字符串转数组、对象或完整
args字典。
缺失 required 参数、未知工具等语义错误不会被猜测修复,而是转换为 status=error 的 ToolMessage,避免 Agent 主循环崩溃。
python code/b3_tool_layer.py \
--tools_config configs/tools.yaml \
--toolset basic_tools \
--tool_calls data/messages/b3_tool_call_recoverable_errors.json \
--execute \
--outdir outputs/B3_recovery
5.4 B3-3:成功结果缓存
缓存键由规范化后的 name + args 计算 SHA-256。参数 JSON 使用稳定排序,因此键顺序不同但语义相同的调用可命中同一缓存。系统只缓存成功结果,错误不会污染后续运行。
payload = json.dumps(
{"name": name, "args": args},
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
)
cache_key = hashlib.sha256(payload.encode("utf-8")).hexdigest()
5.5 B5-1:关键词 Top-K 检索
查询首先由 jieba 分词并过滤停用词。为提高精确度,系统统计关键词文档频率,把高频泛化词与特异词分组,并以以下权重评分:
score = title_hits × 3 + summary_hits × 2 + content_hits
结果同时保留命中词、标题/摘要/正文命中数、过滤阈值和读取异常,便于复现实验。
python code/b5_memory.py \
--config configs/memory_keyword_football.yaml \
--query "世界杯中门将的职责是什么?" \
--retrieval_mode keyword \
--top_k 2 \
--min_score 10 \
--outdir outputs/B5_keyword
现有结果扫描 7 篇文档,Top-1 为“世界杯门将扑救记忆”,得分 13: 查看 selected_memory.json。
5.6 B5-2:本地 Qwen 结构化摘要压缩
保存前先构造完整 Markdown;超过 compression.max_doc_chars 时,把 final_answer + messages + trace 交给本地 Qwen,要求只返回包含以下字段的 JSON:
answer_summary / key_facts / message_summary / trace_summary / open_issues
系统支持从不完整但可识别的模型文本中恢复字段,同时对最终文档再次执行字符预算检查。当前版本采用 LLM-only compression:本地 Qwen 失败时显式报错,不使用规则截断伪装成功。
python code/b5_memory.py \
--config configs/memory.yaml \
--model_config configs/model_b5_local.yaml \
--save_type conversation \
--save_input_path data/memory_inputs/memory_save_long_input.json \
--outdir outputs/B5_compress_llm
服务器验证结果:3662 -> 1325 字符,压缩率约 63.8%,parse_error = null。
保存报告 ·
LLM 摘要
5.7 B5-4:离线中文向量检索
本功能使用 FastEmbed + ONNX Runtime 在 CPU 上加载 BAAI/bge-small-zh-v1.5,对查询与候选记忆编码并计算归一化向量点积。模型和缓存准备完成后,local_files_only=true,无需外网。
python code/b5_memory.py \
--config configs/memory_keyword_football.yaml \
--query "足球比赛中守门员负责哪些任务,点球时如何做扑救判断?" \
--retrieval_mode vector \
--top_k 2 \
--use_global_memory true \
--outdir outputs/B5_vector
现有结果扫描 9 篇文档,Top-1 相似度为 0.739173:
查看 selected_memory.json。相似度用于排序,不被解释为固定概率。
5.8 综合验证结果
6. 与团队系统的集成
团队 B1 在 integrated 模式中直接导入:
from b3_tool_layer import get_tools_schema, execute_tool_calls
from b5_memory import load_memory, search_memory_topk, search_memory_vector_topk, save_memory
完整调用关系:
- B1 读取用户输入和配置;
- B5 按
manual/keyword/vector选择记忆,B1 将正文拼入 System Message; - B3 生成
tools_schema,供 B4 决策; - B4 返回
tool_calls后,B3 校验并调用 B2 Skill; - B3 将 ToolMessage 返回,B4 继续生成最终回答;
- 运行成功且启用保存时,B1 调用 B5 写回 Memory;
trace.json.memory_retrieval记录检索模式、Top-K 和实际选中 ID。
团队完整实现与 WebUI 位于:gary/agent。
7. B3/B5 联合 WebUI
python code/b35_webui_server.py --host 127.0.0.1 --port 18089
浏览器打开 http://127.0.0.1:18089/。WebUI 提供 Schema 导出、Tool Call 执行、手动加载、关键词检索、向量检索和 Memory 保存/压缩入口,并展示本次运行产物。
8. 已知问题与后续改进
| 问题 | 当前原因 | 后续改进 |
|---|---|---|
| 本地 Qwen 压缩资源消耗较高 | 4B 模型加载需要较多显存/内存 | 增加量化模型与异步压缩队列 |
| 向量检索每次重新编码候选文档 | 当前样例规模较小,优先保证逻辑透明 | 增加持久化向量索引和增量更新 |
| 关键词评分规则依赖领域词分布 | 手工停用词和固定权重对跨领域适应有限 | 引入 BM25、领域停用词配置和混合重排 |
| 自动 Memory 更新当前停用 | 合并与冲突策略尚未达到稳定交付标准 | 补充版本化、人工审核和可回滚机制后再启用 |
| README 旧稿曾包含已下线功能 | 早期实现范围大于最终个人交付范围 | 当前仓库以实际启用代码和验证产物为唯一依据 |

