s05: TodoWrite --- 没有计划的 Agent,做着做着就偏了
问题
Agent 接到复杂任务后,执行中容易被测试失败带偏 ,忘记最初目标;对话越长,工具结果越占上下文,系统提示被稀释,长任务做到前几步就开始即兴发挥。
解决方案

S05 保留 S04 的工具分发、权限检查和 Hooks,再加入 todo_write 与 reminder 计数器 。todo_write 只更新计划状态,实际工作仍由原有工具完成。
新工具仍通过 TOOL_HANDLERS[block.name] 分发。连续三个工具调用轮次没有使用 todo_write 时,Harness 会把 reminder 追加到第三轮的工具结果中。
工作原理
todo 实现
TodoManager 持有内存中的任务列表,负责校验更新,并把渲染结果返回给模型。run_todo_write 同时把这份状态打印到终端:
python
# -- s05 新增:模型更新的结构化状态 --
class TodoManager:
def __init__(self):
self.items: list[dict] = []
def update(self, todos: list | str) -> str:
if isinstance(todos, str):
try:
todos = json.loads(todos)
except json.JSONDecodeError:
try:
todos = ast.literal_eval(todos)
except (SyntaxError, ValueError) as e:
raise ValueError("todos 必须是列表或 JSON 数组字符串") from e
if not isinstance(todos, list):
raise ValueError("todos 必须是列表")
if len(todos) > 20:
raise ValueError("最多允许 20 个待办事项")
validated = []
in_progress_count = 0
# enumerate 在遍历 todos 的同时,自动为每个元素配上序号(索引)
for index, todo in enumerate(todos):
if not isinstance(todo, dict):
raise ValueError(f"todos[{index}] 必须是对象")
content = str(todo.get("content", "")).strip()
status = str(todo.get("status", "pending")).lower()
if not content:
raise ValueError(f"todos[{index}] 需要 content")
if status not in ("pending", "in_progress", "completed"):
raise ValueError(f"todos[{index}] 的状态 '{status}' 无效")
if status == "in_progress":
in_progress_count += 1
validated.append({"content": content, "status": status})
if in_progress_count > 1:
raise ValueError("同一时间只能有一个待办事项处于进行中")
self.items = validated
return self.render()
def render(self) -> str:
if not self.items:
return "无待办事项。"
lines = []
for todo in self.items:
marker = {
"pending": "[ ]",
"in_progress": "[>]",
"completed": "[x]",
}[todo["status"]]
lines.append(f"{marker} {todo['content']}")
done = sum(todo["status"] == "completed" for todo in self.items)
lines.append(f"\n(已完成 {done}/{len(self.items)})")
return "\n".join(lines)
TODO = TodoManager()
def run_todo_write(todos: list | str) -> str:
try:
output = TODO.update(todos)
except ValueError as e:
return f"错误:{e}"
print(f"\n\033[33m## 当前任务\033[0m\n{output}")
return output
工具注册
工具定义和其他 5 个工具一起加入 dispatch map.
python
TOOLS = [
{"name": "bash", "description": "运行 shell 命令。",
"input_schema": {"type": "object", "properties": {"command": {"type": "string"}}, "required": ["command"]}},
{"name": "read_file", "description": "读取文件内容。",
"input_schema": {"type": "object", "properties": {"path": {"type": "string"}, "limit": {"type": "integer"}}, "required": ["path"]}},
{"name": "write_file", "description": "将内容写入文件。",
"input_schema": {"type": "object", "properties": {"path": {"type": "string"}, "content": {"type": "string"}}, "required": ["path", "content"]}},
{"name": "edit_file", "description": "在文件中替换一次精确文本。",
"input_schema": {"type": "object", "properties": {"path": {"type": "string"}, "old_text": {"type": "string"}, "new_text": {"type": "string"}}, "required": ["path", "old_text", "new_text"]}},
{"name": "glob", "description": "查找匹配 glob 模式的文件;** 表示递归匹配。",
"input_schema": {"type": "object", "properties": {"pattern": {"type": "string"}}, "required": ["pattern"]}},
# s05: 新工具
{"name": "todo_write", "description": "为当前编码会话创建和管理任务列表。",
"input_schema": {"type": "object", "properties": {"todos": {"type": "array", "maxItems": 20, "items": {"type": "object", "properties": {"content": {"type": "string", "minLength": 1}, "status": {"type": "string", "enum": ["pending", "in_progress", "completed"]}}, "required": ["content", "status"]}}}, "required": ["todos"]}},
]
TOOL_HANDLERS = {
"bash": run_bash, "read_file": run_read, "write_file": run_write,
"edit_file": run_edit, "glob": run_glob, "todo_write": run_todo_write,
}
Reminder
Reminder :连续三个工具调用轮次没有使用 todo_write 时,reminder 会追加到第三轮的结果中,随后计数器清零:
python
rounds_since_todo = 0 if used_todo else rounds_since_todo + 1
if rounds_since_todo >= 3:
# 标签唯一的"作用":提高被当作指令对待的概率,而不是保证
results.append({"type": "text",
"text": "<reminder>请更新你的待办事项。</reminder>"})
rounds_since_todo = 0
Agent 收到任务后的典型流程:先调 todo_write 列出所有步骤(全 pending)→ 做一个步骤,改成 in_progress → 做完改成 completed → 看下一个 pending → 继续。
先调
todo_write列出所有步骤 ------ 此处有疑问,见疑问一节。
关键洞察 :todo_write 不给 Agent 增加任何执行能力 。它增加的是规划能力。
每步输出打印
用户输入问题:重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)
text
"H:\AI\Agent\Coding Agent\learn-claude-code\.venv\Scripts\python.exe" "H:\AI\Agent\Coding Agent\learn-claude-code\s05_todo_write\code-zh.py"
s05: TodoWrite - 先规划后执行
输入问题,按回车发送。输入 q 退出。
s05 >> 重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)
text
[钩子] UserPromptSubmit:正在 H:\AI\Agent\Coding Agent\learn-claude-code\s05_todo_write 中工作
第一轮LLM输出
text
当前输出 response.content:
[
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"},
name="read_file",
type="tool_use",
toolset_name=None,
),
]
第一轮工具待执行
text
当前block:
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"},
name="read_file",
type="tool_use",
toolset_name=None,
)
[钩子] log_hook read_file(['H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_w)
第一轮结束历史消息
text
本轮结束后的messages:
[
{
"role": "user",
"content": "重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)",
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_56deed4759924c91aa2dfb23",
"content": 'def greet(name):\n message = "Hello, " + name\n print(message)\n\n\ngreet("Claude")',
}
],
},
]
第二轮LLM输出
text
当前输出 response.content:
[
TextBlock(
citations=None,
text="现在我将规划重构步骤并执行:",
type="text",
),
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
]
第二轮工具待执行
text
当前block:
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
[钩子] log_hook todo_write([[{'content': '分析当前代码结构,识别需要添加类型提示的部分', 'status': 'in_progre)
todo_write输出
text
## 当前任务
[>] 分析当前代码结构,识别需要添加类型提示的部分
[ ] 添加类型提示、文档字符串和主函数保护代码
[ ] 验证重构后的代码语法正确性
(已完成 0/3)
第二轮结束历史消息
text
本轮结束后的messages:
[
{
"role": "user",
"content": "重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)",
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_56deed4759924c91aa2dfb23",
"content": 'def greet(name):\n message = "Hello, " + name\n print(message)\n\n\ngreet("Claude")',
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在我将规划重构步骤并执行:",
type="text",
),
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_ed2252419a164fe4acdec104",
"content": "[>] 分析当前代码结构,识别需要添加类型提示的部分\n[ ] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 0/3)",
}
],
},
]
第三轮LLM输出
text
当前输出 response.content:
[
TextBlock(
citations=None,
text="""分析完成,当前代码结构需要:
- `greet()` 函数的 `name` 参数需要字符串类型提示
- `greet()` 函数返回 `str` 类型
- 需要添加完整的文档字符串
- 需要添加主函数保护代码(if __name__ == "__main__")""",
type="text",
),
ToolUseBlock(
id="call_2e3a349fbe11432e9895a58f",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "in_progress",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
]
第三轮工具待执行
text
当前block:
ToolUseBlock(
id="call_2e3a349fbe11432e9895a58f",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "in_progress",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
[钩子] log_hook todo_write([[{'content': '分析当前代码结构,识别需要添加类型提示的部分', 'status': 'completed)
todo_write输出
text
## 当前任务
[x] 分析当前代码结构,识别需要添加类型提示的部分
[>] 添加类型提示、文档字符串和主函数保护代码
[ ] 验证重构后的代码语法正确性
(已完成 1/3)
第三轮结束历史消息
text
本轮结束后的messages:
[
{
"role": "user",
"content": "重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)",
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_56deed4759924c91aa2dfb23",
"content": 'def greet(name):\n message = "Hello, " + name\n print(message)\n\n\ngreet("Claude")',
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在我将规划重构步骤并执行:",
type="text",
),
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_ed2252419a164fe4acdec104",
"content": "[>] 分析当前代码结构,识别需要添加类型提示的部分\n[ ] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 0/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="""分析完成,当前代码结构需要:
- `greet()` 函数的 `name` 参数需要字符串类型提示
- `greet()` 函数返回 `str` 类型
- 需要添加完整的文档字符串
- 需要添加主函数保护代码(if __name__ == "__main__")""",
type="text",
),
ToolUseBlock(
id="call_2e3a349fbe11432e9895a58f",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "in_progress",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_2e3a349fbe11432e9895a58f",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[>] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 1/3)",
}
],
},
]
第四轮LLM输出
text
当前输出 response.content:
[
TextBlock(
citations=None,
text="现在执行重构,添加类型提示、文档字符串和主函数保护:",
type="text",
),
ToolUseBlock(
id="call_9d3855e5cf114a5b8c51c288",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")
''',
},
name="write_file",
type="tool_use",
toolset_name=None,
),
]
第四轮工具待执行
text
当前block:
ToolUseBlock(
id="call_9d3855e5cf114a5b8c51c288",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")
''',
},
name="write_file",
type="tool_use",
toolset_name=None,
)
[钩子] log_hook write_file(['H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_w)
第四轮结束后的历史信息
text
本轮结束后的messages:
[
{
"role": "user",
"content": "重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)",
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_56deed4759924c91aa2dfb23",
"content": 'def greet(name):\n message = "Hello, " + name\n print(message)\n\n\ngreet("Claude")',
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在我将规划重构步骤并执行:",
type="text",
),
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_ed2252419a164fe4acdec104",
"content": "[>] 分析当前代码结构,识别需要添加类型提示的部分\n[ ] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 0/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="""分析完成,当前代码结构需要:
- `greet()` 函数的 `name` 参数需要字符串类型提示
- `greet()` 函数返回 `str` 类型
- 需要添加完整的文档字符串
- 需要添加主函数保护代码(if __name__ == "__main__")""",
type="text",
),
ToolUseBlock(
id="call_2e3a349fbe11432e9895a58f",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "in_progress",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_2e3a349fbe11432e9895a58f",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[>] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 1/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在执行重构,添加类型提示、文档字符串和主函数保护:",
type="text",
),
ToolUseBlock(
id="call_9d3855e5cf114a5b8c51c288",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")
''',
},
name="write_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_9d3855e5cf114a5b8c51c288",
"content": "已写入 391 字节到 H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
}
],
},
]
第五轮LLM输出
text
当前输出 response.content:
[
ToolUseBlock(
id="call_acb4d8b1ebd44291b6fb1539",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "in_progress",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
]
第五轮工具待执行
text
当前block:
ToolUseBlock(
id="call_acb4d8b1ebd44291b6fb1539",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "in_progress",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
[钩子] log_hook todo_write([[{'content': '分析当前代码结构,识别需要添加类型提示的部分', 'status': 'completed)
todo_write输出
text
## 当前任务
[x] 分析当前代码结构,识别需要添加类型提示的部分
[x] 添加类型提示、文档字符串和主函数保护代码
[>] 验证重构后的代码语法正确性
(已完成 2/3)
第五轮结束后的历史信息
text
本轮结束后的messages:
[
{
"role": "user",
"content": "重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)",
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_56deed4759924c91aa2dfb23",
"content": 'def greet(name):\n message = "Hello, " + name\n print(message)\n\n\ngreet("Claude")',
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在我将规划重构步骤并执行:",
type="text",
),
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_ed2252419a164fe4acdec104",
"content": "[>] 分析当前代码结构,识别需要添加类型提示的部分\n[ ] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 0/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="""分析完成,当前代码结构需要:
- `greet()` 函数的 `name` 参数需要字符串类型提示
- `greet()` 函数返回 `str` 类型
- 需要添加完整的文档字符串
- 需要添加主函数保护代码(if __name__ == "__main__")""",
type="text",
),
ToolUseBlock(
id="call_2e3a349fbe11432e9895a58f",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "in_progress",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_2e3a349fbe11432e9895a58f",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[>] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 1/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在执行重构,添加类型提示、文档字符串和主函数保护:",
type="text",
),
ToolUseBlock(
id="call_9d3855e5cf114a5b8c51c288",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")
''',
},
name="write_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_9d3855e5cf114a5b8c51c288",
"content": "已写入 391 字节到 H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
}
],
},
{
"role": "assistant",
"content": [
ToolUseBlock(
id="call_acb4d8b1ebd44291b6fb1539",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "in_progress",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_acb4d8b1ebd44291b6fb1539",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[x] 添加类型提示、文档字符串和主函数保护代码\n[>] 验证重构后的代码语法正确性\n\n(已完成 2/3)",
}
],
},
]
第六轮LLM输出
text
当前输出 response.content:
[
TextBlock(
citations=None,
text="现在验证重构后的代码语法正确性:",
type="text",
),
ToolUseBlock(
id="call_42545c1150a147308002e96e",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
ToolUseBlock(
id="call_8a41645d98ab480190716814",
caller=None,
input={
"command": 'python -m py_compile "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"'
},
name="bash",
type="tool_use",
toolset_name=None,
),
]
第六轮第一个工具待执行
text
当前block:
ToolUseBlock(
id="call_42545c1150a147308002e96e",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
)
[钩子] log_hook read_file(['H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_w)
第六轮第二个工具待执行
text
当前block:
ToolUseBlock(
id="call_8a41645d98ab480190716814",
caller=None,
input={
"command": 'python -m py_compile "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"'
},
name="bash",
type="tool_use",
toolset_name=None,
)
[钩子] log_hook bash(['python -m py_compile "H:\\AI\\Agent\\Coding Agent\\learn-c)
第六轮结束后的历史信息
text
本轮结束后的messages:
[
{
"role": "user",
"content": "重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)",
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_56deed4759924c91aa2dfb23",
"content": 'def greet(name):\n message = "Hello, " + name\n print(message)\n\n\ngreet("Claude")',
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在我将规划重构步骤并执行:",
type="text",
),
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_ed2252419a164fe4acdec104",
"content": "[>] 分析当前代码结构,识别需要添加类型提示的部分\n[ ] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 0/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="""分析完成,当前代码结构需要:
- `greet()` 函数的 `name` 参数需要字符串类型提示
- `greet()` 函数返回 `str` 类型
- 需要添加完整的文档字符串
- 需要添加主函数保护代码(if __name__ == "__main__")""",
type="text",
),
ToolUseBlock(
id="call_2e3a349fbe11432e9895a58f",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "in_progress",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_2e3a349fbe11432e9895a58f",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[>] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 1/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在执行重构,添加类型提示、文档字符串和主函数保护:",
type="text",
),
ToolUseBlock(
id="call_9d3855e5cf114a5b8c51c288",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")
''',
},
name="write_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_9d3855e5cf114a5b8c51c288",
"content": "已写入 391 字节到 H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
}
],
},
{
"role": "assistant",
"content": [
ToolUseBlock(
id="call_acb4d8b1ebd44291b6fb1539",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "in_progress",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_acb4d8b1ebd44291b6fb1539",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[x] 添加类型提示、文档字符串和主函数保护代码\n[>] 验证重构后的代码语法正确性\n\n(已完成 2/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在验证重构后的代码语法正确性:",
type="text",
),
ToolUseBlock(
id="call_42545c1150a147308002e96e",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
ToolUseBlock(
id="call_8a41645d98ab480190716814",
caller=None,
input={
"command": 'python -m py_compile "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"'
},
name="bash",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_42545c1150a147308002e96e",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")''',
},
{
"type": "tool_result",
"tool_use_id": "call_8a41645d98ab480190716814",
"content": "(无输出)",
},
],
},
]
第七轮LLM输出
text
当前输出 response.content:
[
ToolUseBlock(
id="call_4701b1b849904e12854cdeb4",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "completed",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
]
第七轮工具待执行
text
当前block:
ToolUseBlock(
id="call_4701b1b849904e12854cdeb4",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "completed",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
[钩子] log_hook todo_write([[{'content': '分析当前代码结构,识别需要添加类型提示的部分', 'status': 'completed)
todo_write输出
text
## 当前任务
[x] 分析当前代码结构,识别需要添加类型提示的部分
[x] 添加类型提示、文档字符串和主函数保护代码
[x] 验证重构后的代码语法正确性
(已完成 3/3)
第七轮结束后的历史信息
text
本轮结束后的messages:
[
{
"role": "user",
"content": "重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)",
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_56deed4759924c91aa2dfb23",
"content": 'def greet(name):\n message = "Hello, " + name\n print(message)\n\n\ngreet("Claude")',
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在我将规划重构步骤并执行:",
type="text",
),
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_ed2252419a164fe4acdec104",
"content": "[>] 分析当前代码结构,识别需要添加类型提示的部分\n[ ] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 0/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="""分析完成,当前代码结构需要:
- `greet()` 函数的 `name` 参数需要字符串类型提示
- `greet()` 函数返回 `str` 类型
- 需要添加完整的文档字符串
- 需要添加主函数保护代码(if __name__ == "__main__")""",
type="text",
),
ToolUseBlock(
id="call_2e3a349fbe11432e9895a58f",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "in_progress",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_2e3a349fbe11432e9895a58f",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[>] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 1/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在执行重构,添加类型提示、文档字符串和主函数保护:",
type="text",
),
ToolUseBlock(
id="call_9d3855e5cf114a5b8c51c288",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")
''',
},
name="write_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_9d3855e5cf114a5b8c51c288",
"content": "已写入 391 字节到 H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
}
],
},
{
"role": "assistant",
"content": [
ToolUseBlock(
id="call_acb4d8b1ebd44291b6fb1539",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "in_progress",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_acb4d8b1ebd44291b6fb1539",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[x] 添加类型提示、文档字符串和主函数保护代码\n[>] 验证重构后的代码语法正确性\n\n(已完成 2/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在验证重构后的代码语法正确性:",
type="text",
),
ToolUseBlock(
id="call_42545c1150a147308002e96e",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
ToolUseBlock(
id="call_8a41645d98ab480190716814",
caller=None,
input={
"command": 'python -m py_compile "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"'
},
name="bash",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_42545c1150a147308002e96e",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")''',
},
{
"type": "tool_result",
"tool_use_id": "call_8a41645d98ab480190716814",
"content": "(无输出)",
},
],
},
{
"role": "assistant",
"content": [
ToolUseBlock(
id="call_4701b1b849904e12854cdeb4",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "completed",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_4701b1b849904e12854cdeb4",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[x] 添加类型提示、文档字符串和主函数保护代码\n[x] 验证重构后的代码语法正确性\n\n(已完成 3/3)",
}
],
},
]
第八轮LLM输出
text
当前输出 response.content:
[
TextBlock(
citations=None,
text="""✅ **重构完成!**
已成功重构 `s05_todo_write/example/hello.py`,完成以下改进:
## 改进内容:
1. **类型提示** - 添加了参数类型 `name: str` 和返回类型 `-> str`
2. **文档字符串** - 添加了模块级、函数级文档字符串,包含 Args、Returns、Examples 说明
3. **主函数保护** - 添加了 `if __name__ == "__main__":` 保护代码块
## 重构前后对比:
| 项目 | 重构前 | 重构后 |
|------|--------|--------|
| 类型提示 | ❌ 无 | ✅ `name: str` + `-> str` |
| 文档字符串 | ❌ 无 | ✅ 模块级 + 函数级 |
| 主函数保护 | ❌ 无 | ✅ `if __name__ == "__main__":` |
| 代码行数 | 4行 | 29行 |
**语法验证通过** ✅(`py_compile` 无错误输出)
代码现在具备更好的可读性、可维护性和IDE智能提示支持!""",
type="text",
)
]
一次完整的交互记录
stop
text
stop 时的messages:
[
{
"role": "user",
"content": "重构s05_todo_write/example/hello.py:添加类型提示、文档字符串和主函数保护(先列3步再执行)",
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="我来帮你重构这个Python文件。让我先查看当前的文件内容,然后规划重构步骤。",
type="text",
),
ToolUseBlock(
id="call_56deed4759924c91aa2dfb23",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_56deed4759924c91aa2dfb23",
"content": 'def greet(name):\n message = "Hello, " + name\n print(message)\n\n\ngreet("Claude")',
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在我将规划重构步骤并执行:",
type="text",
),
ToolUseBlock(
id="call_ed2252419a164fe4acdec104",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "in_progress",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "pending",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_ed2252419a164fe4acdec104",
"content": "[>] 分析当前代码结构,识别需要添加类型提示的部分\n[ ] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 0/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="""分析完成,当前代码结构需要:
- `greet()` 函数的 `name` 参数需要字符串类型提示
- `greet()` 函数返回 `str` 类型
- 需要添加完整的文档字符串
- 需要添加主函数保护代码(if __name__ == "__main__")""",
type="text",
),
ToolUseBlock(
id="call_2e3a349fbe11432e9895a58f",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "in_progress",
},
{
"content": "验证重构后的代码语法正确性",
"status": "pending",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_2e3a349fbe11432e9895a58f",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[>] 添加类型提示、文档字符串和主函数保护代码\n[ ] 验证重构后的代码语法正确性\n\n(已完成 1/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在执行重构,添加类型提示、文档字符串和主函数保护:",
type="text",
),
ToolUseBlock(
id="call_9d3855e5cf114a5b8c51c288",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")
''',
},
name="write_file",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_9d3855e5cf114a5b8c51c288",
"content": "已写入 391 字节到 H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py",
}
],
},
{
"role": "assistant",
"content": [
ToolUseBlock(
id="call_acb4d8b1ebd44291b6fb1539",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "in_progress",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_acb4d8b1ebd44291b6fb1539",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[x] 添加类型提示、文档字符串和主函数保护代码\n[>] 验证重构后的代码语法正确性\n\n(已完成 2/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="现在验证重构后的代码语法正确性:",
type="text",
),
ToolUseBlock(
id="call_42545c1150a147308002e96e",
caller=None,
input={
"path": "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"
},
name="read_file",
type="tool_use",
toolset_name=None,
),
ToolUseBlock(
id="call_8a41645d98ab480190716814",
caller=None,
input={
"command": 'python -m py_compile "H:\\AI\\Agent\\Coding Agent\\learn-claude-code\\s05_todo_write\\example\\hello.py"'
},
name="bash",
type="tool_use",
toolset_name=None,
),
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_42545c1150a147308002e96e",
"content": '''"""
问候函数模块
提供简单的问候功能,向指定的名字对象输出问候语
"""
def greet(name: str) -> str:
"""
生成问候语并打印
Args:
name: 要问候的名字,应该是字符串类型
Returns:
str: 生成的问候语字符串
Examples:
>>> greet("Claude")
Hello, Claude
"""
message = "Hello, " + name
print(message)
return message
if __name__ == "__main__":
# 主函数保护:只有直接运行此脚本时才会执行以下代码
greet("Claude")''',
},
{
"type": "tool_result",
"tool_use_id": "call_8a41645d98ab480190716814",
"content": "(无输出)",
},
],
},
{
"role": "assistant",
"content": [
ToolUseBlock(
id="call_4701b1b849904e12854cdeb4",
caller=None,
input={
"todos": [
{
"content": "分析当前代码结构,识别需要添加类型提示的部分",
"status": "completed",
},
{
"content": "添加类型提示、文档字符串和主函数保护代码",
"status": "completed",
},
{
"content": "验证重构后的代码语法正确性",
"status": "completed",
},
]
},
name="todo_write",
type="tool_use",
toolset_name=None,
)
],
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_4701b1b849904e12854cdeb4",
"content": "[x] 分析当前代码结构,识别需要添加类型提示的部分\n[x] 添加类型提示、文档字符串和主函数保护代码\n[x] 验证重构后的代码语法正确性\n\n(已完成 3/3)",
}
],
},
{
"role": "assistant",
"content": [
TextBlock(
citations=None,
text="""✅ **重构完成!**
已成功重构 `s05_todo_write/example/hello.py`,完成以下改进:
## 改进内容:
1. **类型提示** - 添加了参数类型 `name: str` 和返回类型 `-> str`
2. **文档字符串** - 添加了模块级、函数级文档字符串,包含 Args、Returns、Examples 说明
3. **主函数保护** - 添加了 `if __name__ == "__main__":` 保护代码块
## 重构前后对比:
| 项目 | 重构前 | 重构后 |
|------|--------|--------|
| 类型提示 | ❌ 无 | ✅ `name: str` + `-> str` |
| 文档字符串 | ❌ 无 | ✅ 模块级 + 函数级 |
| 主函数保护 | ❌ 无 | ✅ `if __name__ == "__main__":` |
| 代码行数 | 4行 | 29行 |
**语法验证通过** ✅(`py_compile` 无错误输出)
代码现在具备更好的可读性、可维护性和IDE智能提示支持!""",
type="text",
)
],
},
]
stop钩子
text
[钩子] Stop:本次会话共使用 8 次工具调用
最终输出
text
最终输出==============================
✅ **重构完成!**
已成功重构 `s05_todo_write/example/hello.py`,完成以下改进:
## 改进内容:
1. **类型提示** - 添加了参数类型 `name: str` 和返回类型 `-> str`
2. **文档字符串** - 添加了模块级、函数级文档字符串,包含 Args、Returns、Examples 说明
3. **主函数保护** - 添加了 `if __name__ == "__main__":` 保护代码块
## 重构前后对比:
| 项目 | 重构前 | 重构后 |
|------|--------|--------|
| 类型提示 | ❌ 无 | ✅ `name: str` + `-> str` |
| 文档字符串 | ❌ 无 | ✅ 模块级 + 函数级 |
| 主函数保护 | ❌ 无 | ✅ `if __name__ == "__main__":` |
| 代码行数 | 4行 | 29行 |
**语法验证通过** ✅(`py_compile` 无错误输出)
代码现在具备更好的可读性、可维护性和IDE智能提示支持!
s05 >>
对话总结
整个对话历史可以概括为以下 6 个阶段:
-
用户下达任务(真人)
- User : "重构 hello.py,添加类型提示、文档字符串、主函数保护(先列 3 步再执行)"。
-
模型探索与规划
- Assistant : 表示要先看代码,调用
read_file读代码。 - User(环境): 返回了只有 4 行的原始代码。
- Assistant : 说"现在我将规划重构步骤",调用
todo_write列出了 3 个待办事项(分析结构、添加代码、验证语法)。
- Assistant : 表示要先看代码,调用
-
模型执行第一步(分析)
- Assistant : 调用
todo_write,把"分析结构"标为in_progress,其他为pending。 - User(环境): 返回打了勾的待办列表(0/3 完成)。
- Assistant : 输出分析结果(指出需要加
str提示等),并将"分析"标为completed,"添加代码"标为in_progress。 - User(环境): 返回列表(1/3 完成)。
- Assistant : 调用
-
模型执行第二步(修改文件)
- Assistant : 调用
write_file,直接写入了重构后的完整代码。 - User(环境): 返回"写入成功"。
- Assistant : 调用
-
模型执行第三步(验证)
- Assistant : 把"添加代码"标为完成,"验证"标为进行中(调用
todo_write)。 - User(环境): 返回列表(2/3 完成)。
- Assistant : 调用
read_file读取新文件,同时调用bash执行py_compile检查语法。 - User(环境): 返回了读取的代码 + 空输出(代表编译无报错,验证通过)。
- Assistant : 调用
todo_write,把"验证"也标为完成。 - User(环境): 返回列表(3/3 完成)。
- Assistant : 把"添加代码"标为完成,"验证"标为进行中(调用
-
任务收尾
- Assistant: 不再调用任何工具,直接输出一段格式漂亮的总结文字(包含前后对比表格),宣告任务完成。
- Stop 钩子触发 :检测到没有
tool_use了,打印"共使用 8 次工具调用",循环结束。
总结来看:
这次对话是一个非常经典的"Plan-and-Solve"模式。模型仅仅因为用户提示里加了一句"先列3步再执行 "(结合了 System Prompt 里的指引),就完美地自主执行了 探索 -> 规划 -> 分步执行 -> 及时更新状态 -> 验证 -> 总结 的完整闭环。这正是引入 TodoManager 这个工具带来的最大价值。
疑问
1 原文内容疑问
原文:Agent 收到任务后的典型流程:先调 todo_write 列出所有步骤(全 pending)→ 做一个步骤,改成 in_progress → 做完改成 completed → 看下一个 pending → 继续。
纠正:步骤不是 todo_write列的,而是 Agent列的。
LLM 是 Planner(规划者),todo_write 是 State Manager(状态管理器)。
其实每次都会对大模型输出的任务进行刷新,如果前后两次大模型交给todo_write的内容不同,以最新的为准。
追问:任务列表要靠大模型去记,万一它记错了呢
Agent 的任务规划完全由大模型主导,每次生成全新列表全量覆盖,为防止大模型"记错",系统构筑了四重防线 :一是格式校验 (Python 代码强制拦截多任务并发等违规操作);二是原初锚点 (历史记录中始终保留用户的初始 Prompt 防跑偏);三是状态注入 (代码将最新列表作为工具结果重新塞回上下文,强制刷新大模型的短期记忆);四是人类监督 (终端实时打印列表,人类随时可介入纠偏)。简言之,它是大模型凭记忆动态维护、代码做死板约束、人类兜底监督的"外部白板" 。