跟踪 Tool Call 与 Session
实践目标
跟踪一次 read_file Tool Call,观察 Provider response、ToolRegistry、checkpoint、下一轮模型输入和最终 Session 之间的数据变化。
前置知识
- 完成上一个无工具 Turn;
- 理解 OpenAI function schema;
- 使用独立实验 workspace。
需要阅读的代码
nanobot/agent/tools/filesystem.py::ReadFileToolnanobot/agent/tools/registry.py::ToolRegistry.executenanobot/agent/runner.py::_execute_toolsnanobot/agent/runner.py::_run_toolnanobot/agent/runner.py::_emit_checkpointnanobot/agent/loop.py::_state_savetests/agent/test_runner_tool_execution.pytests/agent/test_runner_persistence.py
先写下预测
- Provider 第一次 response 中 Tool Call 长什么样?
- tool result 以哪个 role 加入 messages?
- Tool 执行后是否立即保存完整 Session?
- 第二次 Provider 请求比第一次多哪些消息?
- 最终用户会不会同时收到 tool result 和自然语言答复?
实践步骤
1. 准备只读 fixture
$nanobotLab = Join-Path $env:TEMP "nanobot-learning"
$fixture = Join-Path "$nanobotLab\workspace" "turn-observation.txt"
Set-Content -LiteralPath $fixture -Encoding utf8 -Value "marker=NANOBOT_TOOL_OK"这里只写实验 workspace,不修改 nanobot 源码。
2. 设置断点
AgentRunner._request_model()返回后;_execute_tools();ToolRegistry.execute()校验前后;ReadFileTool.execute();_emit_checkpoint();- 下一次
_request_model(); _state_save()。
3. 发出明确请求
python -m nanobot agent `
--config "$nanobotLab\config.json" `
--workspace "$nanobotLab\workspace" `
--session "learning:tool-call" `
--message "必须使用 read_file 读取 turn-observation.txt,然后只回复 marker 的值。"真实模型仍可能不按预期调用。若发生,保留该观察,再用测试中的 fake Provider 完成确定性跟踪。
4. 做一张消息形态表
| 时刻 | role | 关键字段 |
|---|---|---|
| 初始 | user | content |
| 第一次 Provider response | assistant | tool_calls |
| 工具执行后 | tool | tool_call_id、name、content |
| 第二次 Provider response | assistant | final content |
不要复制全部 prompt;只记录结构和简短摘要。
5. 查看 checkpoint
在 _emit_checkpoint() 后检查 Session metadata 中运行 checkpoint:
- phase;
- iteration;
- model;
- assistant_message;
- completed_tool_results;
- pending_tool_calls。
然后在正常 SAVE 后确认 checkpoint 是否被清理或物化为正式历史。
6. 查看 Tool schema
在第一次 Provider 请求前查看:
spec.tools.get_definitions()找到 read_file,比较其 schema 与模型返回 arguments。
预期观察
sequenceDiagram participant P as Provider participant R as AgentRunner participant T as ToolRegistry participant S as Session R->>P: messages + tool schemas P-->>R: assistant(tool_calls) R->>S: checkpoint awaiting_tools R->>T: execute read_file T-->>R: marker=NANOBOT_TOOL_OK R->>S: checkpoint tools_completed R->>P: + assistant tool_call + tool result P-->>R: final text R-->>S: SAVE final turn
关键结论:
- Tool schema 在模型请求前生成;
- Registry 在 Python 侧再次校验参数;
- Tool result 是下一轮模型的观察,不是默认直接回复用户;
- checkpoint 支持取消/中断恢复;
- 正常 SAVE 将本轮合法消息写入 Session。
完成条件
- 能指出两次 Provider 请求的 messages 差异;
- 能从 Tool Call id 关联 assistant call 与 tool result;
- 能解释 checkpoint 和最终 Session 的区别;
- 最终答复为
NANOBOT_TOOL_OK; - 没有修改源码。
验证方法
运行确定性测试:
Set-Location "example\nanobot\code-EN"
python -m pytest tests\agent\test_runner_tool_execution.py -q
python -m pytest tests\agent\test_runner_persistence.py -q选择一个 test 用调试器单步,与真实 DeepSeek 调用的对象结构对照。
复盘问题
- Tool schema 为什么既给模型看,又在本地校验?
- 如果 Tool 已经写文件后 Runner 取消,checkpoint 能否回滚文件?
- 为什么 final assistant message 不能省略?
- Tool result 过大时会怎样影响下一次模型请求?
下一篇:复现流式、取消与重试