# S05 TodoWrite 代码讲解 这一节只讲相对 S04 新增的内容: **让 Agent 在多步骤任务中先规划,再执行,并持续更新任务状态。** --- ## 1. 本节新增内容 - `CURRENT_TODOS`:内存中的当前任务列表。 - `_normalize_todos()`:校验和解析模型传来的 todos。 - `run_todo_write()`:更新任务列表并打印状态。 - `todo_write` 工具定义:让模型可以显式写计划。 - `rounds_since_todo`:检测模型太久没更新计划时提醒它。 --- ## 2. Todo 数据结构 `CURRENT_TODOS` 是: ```python CURRENT_TODOS: list[dict] ``` 每个 todo 是一个字典: ```python { "content": "读取项目结构", "status": "in_progress" } ``` `status` 只能是三种: ```python pending in_progress completed ``` --- ## 3. `todo_write` 工具 schema 模型调用工具时,传入的数据大概是: ```python { "todos": [ {"content": "查看文件", "status": "completed"}, {"content": "修改代码", "status": "in_progress"}, {"content": "运行验证", "status": "pending"} ] } ``` 模型不是直接改 `CURRENT_TODOS`,而是提出一次 `tool_use`。 程序收到后调用: ```python run_todo_write(todos) ``` --- ## 4. `_normalize_todos(todos)` 这个函数负责把输入整理成标准列表。 为什么需要它? 模型有时可能传真正的 list: ```python [{"content": "...", "status": "pending"}] ``` 也可能传 JSON 字符串: ```python '[{"content": "...", "status": "pending"}]' ``` 所以 `_normalize_todos()` 会尝试解析,并检查: - `todos` 必须是列表。 - 每一项必须是字典。 - 每一项必须有 `content` 和 `status`。 - `status` 必须是允许的状态。 --- ## 5. `run_todo_write(todos)` 这个函数做两件事: ```python 1. 校验 todos 2. 更新 CURRENT_TODOS ``` 更新后会打印当前任务状态,让人能看到 Agent 的计划变化。 --- ## 6. `rounds_since_todo` `rounds_since_todo` 是一个计数器。 每一轮模型调用工具后,如果没有调用 `todo_write`,计数器就增加。 当它超过阈值: ```python if rounds_since_todo >= 3: messages.append({"role": "user", "content": "请更新你的待办事项。"}) ``` 这相当于给模型一个提醒: ```python 你已经执行几步了,该更新计划了 ``` --- ## 7. 本节课堂重点 TodoWrite 不是为了好看,而是让 Agent 有“任务状态”。 没有 TodoWrite 时,模型只是在连续调用工具。 有了 TodoWrite 后,模型开始显式维护: ```python 计划是什么 现在做到哪一步 哪些已经完成 哪些还没开始 ```