第三篇工具即双手 —— 从 Bash 到 Tool Dispatch Maps01 说一个 bash 就够了但没人真的只用 bash 写代码。全栈工程师 vs. 全栈工具你说帮我读一下 config.py 的第 10 行到第 20 行如果 Agent 只有一个 bash 工具它得敲sed -n 10,20p config.py。这当然可以。但就像你可以用螺丝刀钉钉子但有锤子的话为什么要用螺丝刀这就是 s02 的核心进化从一个万能工具到一套专用工具。Tool Dispatch Maps02 的核心创新是一张映射表TOOL_HANDLERS{bash:lambda**kw:run_bash(kw[command]),read_file:lambda**kw:run_read(kw[path],kw.get(limit)),write_file:lambda**kw:run_write(kw[path],kw[content]),edit_file:lambda**kw:run_edit(kw[path],kw[old_text],kw[new_text]),}一个函数名到处理函数的直接映射。没有 if-else 森林。当模型返回工具调用时handlerTOOL_HANDLERS.get(block.name)outputhandler(**block.input)ifhandlerelsefUnknown tool:{block.name}两行代码路由了一切。想加新工具加一行字典条目就行。专有工具的精妙之处read_file 比 bash cat 好在哪里安全边界safe_path() 阻止路径穿越输出控制limit 参数 50000 字符截断友好报错异常被捕获为字符串语义精准模型知道我在读文件那个 safe_path 函数defsafe_path(p:str)-Path:path(WORKDIR/p).resolve()ifnotpath.is_relative_to(WORKDIR):raiseValueError(fPath escapes workspace:{p})returnpath永远、永远、永远不要相信模型的输入。Agent Loop 没有变defagent_loop(messages:list):whileTrue:responseclient.messages.create(...)messages.append(response.content)ifresponse.stop_reason!tool_use:returnforblockinresponse.content:ifblock.typetool_use:handlerTOOL_HANDLERS.get(block.name)outputhandler(**block.input)messages.append(tool_result)和 s01 相比唯一的变化就是把 run_bash 换成了 TOOL_HANDLERS.get。这就是扩缩性的全部秘密。你不改核心循环。你只改工具注册表。如果说 Agent Loop 是操作系统内核那 TOOL_HANDLERS 就是系统调用表。从 4 个工具到 16 个工具s02 只有 4 个工具。到了 s12同一个 pattern 被扩展到了 16 个——基础工具、任务工具、worktree 工具、事件工具。但核心循环还是那几行没变。下一篇TodoManager —— 一个让模型自己写 TODO List 的工具以及一个讨人厌的提醒器。