源码阅读与调试最低要求
学习目标
读完后,你应当能够:
- 从入口而不是类名猜测开始追踪源码;
- 使用
rg找定义、调用方、配置和测试; - 运行最接近问题的 pytest 测试;
- 选择有意义的断点和观察变量;
- 区分已证实事实、合理推断和未知项。
前置知识
- 能使用 PowerShell;
- 能运行 Python;
- 能阅读基本 traceback。
1. 先提出一个可跟踪的问题
不要从“读完整个 agent/ 目录”开始。选择一个具体问题,例如:
- CLI 的一条消息如何进入
AgentLoop? - session key 在哪里决定?
- Tool Call 在哪里被执行?
- API streaming 在哪里关闭?
- 同一 session 为什么不会同时写入?
问题越具体,阅读范围越小,得到的调用链越可靠。
2. 从入口和调用方开始
推荐顺序:
入口
→ 创建了哪些核心对象
→ 调用了哪个公共方法
→ 公共方法如何进入状态机或循环
→ 状态在哪里保存
→ 输出交给谁例如,追踪 CLI 单次消息:
- 在
nanobot/cli/commands.py找agent命令; - 找
process_direct调用; - 进入
AgentLoop.process_direct(); - 进入
_process_message(); - 查看
TurnState转换; - 进入
_run_agent_loop(); - 查看
AgentRunner.run(); - 回到
_state_save()和_state_respond()。
3. 使用 rg 搜索
在 example/nanobot/code-EN 中运行:
rg -n "class AgentLoop|def process_direct" nanobot
rg -n "process_direct\\(" nanobot tests
rg -n "session_key" nanobot/session nanobot/agent tests
rg -n "should_execute_tools" nanobot tests常见搜索顺序:
- 定义;
- 所有调用方;
- 配置字段;
- 相关测试;
- 错误信息或日志文本。
搜索日志文本
当运行时出现一条明确日志或错误时,直接搜索其中稳定的一小段文本,通常比猜函数名更快。
4. 测试是可执行的实现说明
测试可以证明某个边界已经被项目明确保护。例如:
| 想理解的问题 | 先看测试 |
|---|---|
| AgentLoop 与 Runner 如何衔接 | tests/agent/test_loop_runner_integration.py |
| Tool Call 如何执行 | tests/agent/test_runner_tool_execution.py |
| Runner 如何处理错误 | tests/agent/test_runner_errors.py |
| Session 是否原子保存 | tests/agent/test_session_atomic.py |
| Runtime Event 顺序 | tests/bus/test_runtime_events.py |
| Channel 插件如何发现 | tests/channels/test_channel_plugins.py |
| Subagent 生命周期 | tests/agent/test_subagent_lifecycle.py |
运行一个测试文件:
Set-Location "example\nanobot\code-EN"
pytest tests/agent/test_loop_runner_integration.py -q运行一个测试函数:
pytest tests/agent/test_runner_tool_execution.py::test_name -q实际函数名应先用 rg -n "^def test_|^async def test_" 核对,不要凭文档猜测。
5. 断点要放在状态边界
对于一次普通 Turn,优先观察:
| 位置 | 观察内容 |
|---|---|
AgentLoop.process_direct 或 _dispatch | 入口、session key、metadata |
_process_message | TurnContext 初始状态 |
_state_restore | session、checkpoint、媒体 |
_state_build | history、initial_messages、tool context |
AgentRunner._run_core | iteration、response、tool_calls |
_execute_tools | 工具选择、参数、并发策略 |
_state_save | 新消息、stop_reason、latency |
_state_respond | OutboundMessage |
不要一开始进入 Provider SDK 或 WebUI 组件内部。先确认核心状态在哪一步偏离预期。
6. 同时观察三份消息
调试上下文问题时,至少区分:
Session.messages:持久化会话;ctx.initial_messages:进入 AgentRunner 的初始输入;messages_for_model:治理、裁剪后实际发给模型的消息。
很多“模型忘记了”“工具结果丢了”问题,根因就在这三者的差异中。
7. 记录证据,而不是只写结论
推荐使用下面的记录格式:
### 观察
- 入口:`nanobot/cli/commands.py::agent`
- 调用:`AgentLoop.process_direct`
- 状态:`BUILD`
- 变量:`ctx.initial_messages`
- 测试:`tests/agent/test_loop_runner_integration.py`
### 结论
源码事实:……
### 尚未证明
- 是否所有 Channel 都使用相同 metadata;
- 是否外部插件保证相同生命周期。8. 不要在学习阶段修改源码来“验证猜测”
核心学习阶段优先使用:
- 断点;
- 现有日志;
- 临时交互检查;
- 现有测试;
- 最小只读脚本。
只有进入“源码学习实践”的扩展任务后,才在 learning-CN/examples 或隔离副本中进行明确、局部、可验证的修改;code-EN 源码快照始终保持只读。
Windows 注意事项
当前工作区使用 PowerShell。阅读和运行 nanobot 时注意:
- 使用
pathlib.Path思考路径,不假设/; - nanobot 的 ExecTool 在 Windows 使用
cmd /c; - CLI 会处理 stdout/stderr 的 UTF-8;
- MCP stdio 命令存在 Windows 路径归一化;
- 不要把 Linux 的 bubblewrap 行为套用到 Windows。
相关说明:
example/nanobot/code-EN/.agent/gotchas.mdexample/nanobot/code-EN/.agent/security.md
自检任务
不修改代码,完成以下搜索:
- 找到
AgentLoop.process_direct的所有生产调用方; - 找到
InboundMessage.session_key的定义; - 找到
ToolLoader扫描外部 entry point 的位置; - 找到 Session 原子替换目标文件的位置;
- 找到对应的至少一个测试。
完成后,你已经具备开始追踪 nanobot 的最低源码阅读能力。
下一步
返回 学习路线总览,进入“运行与源码地图”。