工具说明、注册表与函数,是三件事
| 部分 | 谁使用 | 职责 |
|---|---|---|
| Tool Schema | 模型 | 描述可用工具及参数。 |
| Tool Registry | Python 调度代码 | 按工具名查找函数对象。 |
| 工具函数 | 程序执行 | 真正做计算并返回结果。 |
模型提出工具名和参数,不代表函数已经执行。注册表保存 calculator 函数对象,而不是提前调用 calculator();程序解析参数后再执行。课堂示例使用计算器,便于核对结果且不引入额外外部工具。
一次往返,怎样变成一个循环
课堂 Agent Loop 的控制流程
模型提出 tool_calls
→ 程序解析参数、查找工具
→ 执行本轮每个调用
→ 保留调用记录,补齐对应工具结果
→ 再次请求模型
→ 返回最终回答,或达到轮次上限- 外层 while 管模型决策轮次,内层 for 管本轮调用列表。
- 工具结果要与对应 tool_call_id 关联;只 print 到终端不会自动传给模型。
- max_steps 限制外层轮次,不是工具总数上限,也不是执行超时。
- 未知工具和执行异常有基础分支,但 JSON 解析、空回答等处理仍不完整。
真实日志:两个调用,一次后续回答
依据原笔记转写的成功日志摘要,不是实时运行输出
Step 1:模型一次提出两个 calculator 调用
multiply(12, 8) → 96
divide(96, 4) → 24.0
Step 2:模型无 tool_calls,返回最终答案 24这次记录证明程序处理了同一响应中的多个调用,并把结果交回模型。第二个调用中的 96 在第一条工具执行前已经由模型给出,不能据此声称实现了一般化的依赖调度。当前 for 也是顺序执行,不是工具并发。
“最大步数”报错,实际只跑了一轮
最初程序直接返回“达到最大执行步数”。加入 Step 日志后发现,工具给出了 96 和 24.0,却没有 Step 2。问题不是已经耗尽十轮,而是超限 return 缩进到了循环内部,第一轮结束就退出函数。
修正后,工具执行完成能进入下一轮模型请求,再得到最终回答。这个经历让我开始用执行路径定位问题,而不是把提示文字当作全部事实。
聊天历史、运行时上下文与轨迹
| 概念 | 当前实现 |
|---|---|
| Chat History | MySQL 保存当前用户输入和最终助手回答。 |
| Runtime Context | 当前 Python 列表包含历史、本轮输入及工具交互。 |
| Agent Trace | 部分信息体现在终端日志与上下文,尚未结构化持久化。 |
不能把运行后的 messages 全部重新插入数据库,否则既重复旧历史,也混入工具记录。最终回答中出现计算步骤,并不等于数据库保存了独立的工具轨迹。
接回 HTTP 服务之后,仍有明确边界
FastAPI 接收输入,Memory 读取历史,run_agent 完成模型与工具的往返,路由再保存本轮两条可见消息。当前课堂版超限会返回普通字符串,HTTP 200 不能单独作为任务成功的判据。
- 待完善:结构化完成状态、参数校验、超时和失败路径测试。
- 待完善:事务、会话权限与持久化 Trace。
- RAG、Streaming、复杂外部工具与企业级部署不在本阶段已完成范围。
查看 项目实践页,对照输入、结果和保存范围理解这次整合。
来源
本页依据个人笔记整理:《个人Agent学习笔记_MySQL_Memory到Agent整合_第35至53课》第 10—21、25 节(整理于 2026-09-11)。
试着做一个小练习
为循环的每轮加入 Step 标识;对照一次工具调用,找出模型响应、程序执行与最终回答。