当前位置: 首页 > news >正文

多加一个工具,只加一行:Agent 是怎么管理工具的?

多加一个工具,只加一行:Agent 是怎么管理工具的?
本文是「从零理解 Claude Code:20 个 Agent Harness 机制」系列的第 3 篇。
源码仓库:shareAI-lab/learn-claude-code

上一篇我们先搭起了最小 Agent Loop:模型调用bash,程序执行命令,再把结果交回模型。

这个版本已经能做事了,但它只有一个工具:bash

从能力上说,bash几乎什么都能做。

读文件可以用cat,写文件可以用重定向,改文件可以用sed,找文件可以用find

但我实际看下来,只有一个bash并不优雅。

因为模型明明想做的是读文件,却要先把这个意图翻译成一条正确的 Shell 命令。

catREADME.md

模型想修改一行代码,又得写出一段不容易出错的sed命令。

sed-i's/old_text/new_text/'app.py

命令写错一个引号、一个转义符,事情就会变得麻烦。

这一篇要解决的,就是工具分发问题:当 Agent 不再只有bash时,怎样继续保持主循环简单。

1.一个工具能做所有事,为什么还要拆开

先看一个很普通的任务:

读取 README.md 和 requirements.txt, 然后创建一个 summary.txt,总结这个项目是做什么的。

如果只有bash,模型可能需要连续调用:

catREADME.mdcatrequirements.txtecho"项目总结……">summary.txt

这当然可以完成任务。

但模型需要同时记住文件读取、重定向写入、引号转义等 Shell 细节。它做的不是单纯的代码理解,还要不断把自己的意图翻译成命令行语法。

这一章给 Agent 准备了 4 个更直接的工具:

工具用途
read_file读取文件内容
write_file写入文件
edit_file替换文件中的一段文本
glob按模式查找文件

再加上原本的bash,一共 5 个工具。

这样,模型想读README.md时,不必再拼命令:

read_file(path="README.md")

想写总结文件时,也不必处理 Shell 的重定向:

write_file( path="summary.txt", content="……" )

工具的名字更接近任务本身,模型需要处理的无关细节就少一些。

2.从单工具到多工具,核心变化只有一处

最小 Agent Loop 里,工具执行是写死的:

output=run_bash(block.input["command"])

因为当时只有bash,这么写没有问题。

但工具一多,这种写法就撑不住了。总不能写成这样:

ifblock.name=="bash":output=run_bash(**block.input)elifblock.name=="read_file":output=run_read(**block.input)elifblock.name=="write_file":output=run_write(**block.input)elifblock.name=="edit_file":output=run_edit(**block.input)

工具再多一点,这段判断会越来越长,主循环也会越来越乱。

这里用了一个很常见的做法:工具分发表。

TOOL_HANDLERS={"bash":run_bash,"read_file":run_read,"write_file":run_write,"edit_file":run_edit,"glob":run_glob,}

模型返回工具名后,程序去这个字典里查对应的处理函数:

handler=TOOL_HANDLERS.get(block.name)output=handler(**block.input)

这就是多工具 Agent 最核心的变化。

工具名负责找到处理函数,工具参数负责传给处理函数。

主循环不需要知道当前到底有几个工具,也不需要知道每个工具的具体实现。

3.加一个工具,到底要改哪里

read_file为例。

第一步,要告诉模型有这个工具,以及它需要什么参数:

{"name":"read_file","description":"Read file contents.","input_schema":{"type":"object","properties":{"path":{"type":"string"},"limit":{"type":"integer"},},"required":["path"],},}

模型会根据这里的名字、描述和参数结构,决定什么时候调用它。

第二步,程序里要有真正的实现:

defrun_read(path:str,limit:int|None=None)->str:lines=safe_path(path).read_text().splitlines()iflimitandlimit<len(lines):lines=lines[:limit]+[f"... ({len(lines)-limit}more lines)"]return"\n".join(lines)

最后,把它注册进分发表:

TOOL_HANDLERS={"read_file":run_read,}

这三处缺一不可。

位置少了会怎样
工具定义模型不知道有这个工具
处理函数程序没有真正的执行逻辑
分发映射模型调用后,程序找不到对应函数

所谓多加一个工具,只加一行,真正想表达的是:主循环只需要维持这一种分发方式。新增工具不会让 Agent Loop 再长出一串if else

4.跑一个任务看看工具是怎么配合的

继续用刚才的任务:

读取 README.md 和 requirements.txt, 然后创建一个 summary.txt,总结这个项目是做什么的。

模型可能会按下面的顺序行动。

第 1 轮:读取项目说明

read_file(path="README.md")

工具返回 README 内容。

第 2 轮:读取依赖文件

read_file(path="requirements.txt")

工具返回依赖列表。

第 3 轮:写入总结

write_file( path="summary.txt", content="这是一个用于学习 Agent Harness 的项目……" )

工具返回:

Wrote 48 bytes to summary.txt

第 4 轮:结束任务

模型看到文件已经写入成功,不再调用工具,直接告诉用户总结文件已创建。

这里有一个值得注意的细节。

模型可以一次发起多个工具调用。比如它可能同时请求读取README.mdrequirements.txt

教学代码会按照模型返回的顺序逐个执行:

forblockinresponse.content:ifblock.type=="tool_use":handler=TOOL_HANDLERS.get(block.name)output=handler(**block.input)

这样做的好处是简单,便于理解。

真正的 Claude Code 会进一步判断哪些工具可以并发。例如同时读取两个不同文件通常可以并发;修改文件和运行测试之间则可能需要保持顺序。

这一篇先不展开并发,重点只是把工具如何注册、如何分发讲清楚。

5.文件工具为什么要做路径校验

在文件工具的实现里,还有一个小细节,叫safe_path

defsafe_path(p:str)->Path:path=(WORKDIR/p).resolve()ifnotpath.is_relative_to(WORKDIR):raiseValueError(f"Path escapes workspace:{p}")returnpath

它的作用是限制文件操作只能发生在当前工作目录中。

例如,模型请求读取:

../../some-secret-file

这个路径最终会跳出工作区,safe_path会拒绝它。

这不是完整的权限系统,但至少说明了一件事:给 Agent 工具时,不能只考虑工具能不能完成任务,还要考虑它能访问到哪里。

不过这一章也保留了一个明显的问题。

read_filewrite_fileedit_fileglob都会经过路径校验;bash仍然有更大的操作范围。

所以这里解决的是工具如何组织,还没有真正解决权限问题。

6.从单工具 Agent 到多工具 Agent,到底变了什么

内容单工具版本多工具版本
工具数量1 个bash5 个工具
执行方式直接调用run_bash()通过TOOL_HANDLERS查表调用
文件操作依赖 Shell 命令使用专门的读、写、改工具
路径限制没有文件工具会校验工作区路径
Agent Loopwhile True没有变化

看下来,多工具 Agent 并没有让模型变得更会思考。

它做的是另一件事:把模型能触达的外部能力,从一个很粗的bash,拆成几个更容易调用、也更容易约束的工具。

7.小结

这一章我觉得最值得记住的不是 5 个工具,而是工具分发这个思路。

主循环只负责维持模型和工具结果之间的来回。

至于模型请求的是读文件、写文件、搜索文件还是执行命令,交给分发表去处理。

handler=TOOL_HANDLERS.get(block.name)output=handler(**block.input)

这样以后新增工具时,不需要反复修改 Agent Loop。

下一篇会继续顺着这个问题往下:工具越来越多以后,哪些操作可以直接执行,哪些操作应该拦住并征求用户同意?

这就是权限检查要解决的事。


参考资料:

  • 工具分发:源码与文档
  • learn-claude-code 项目仓库
http://www.jsqmd.com/news/1232665/

相关文章:

  • TI DSP高分辨率PWM与捕获技术:从皮秒级原理到电机与电源应用
  • 洛谷P3741题解:贪心与枚举结合,高效求解字符串VK子串最大化问题
  • 跨平台C语言项目构建实战:从TinyTetris看Makefile与ncurses适配
  • Kimi LeetCode 3651. 带传送的最小路径成本 Python3实现
  • 零跑C10智能座舱与FSD减振技术深度解析
  • AI编程工具安全深度解析:从Claude Code风险到企业级防护实践
  • 家装除甲醛正规机构哪家好 2026年值得信赖的体验服务品质之选 - 工业推荐榜
  • Unity角色缩放功能实现:从按钮绑定到平滑动画与性能优化
  • 模型独立评估:从环境标准化到自动化流程的实战指南
  • 智能手机存储芯片涨价:原因、影响与应对策略
  • 2026泸州房屋渗漏水检测公司口碑榜TOP5推荐-正规防水补漏一站式维修:卫生间/厨房/阳台/屋顶/地下室/屋顶/天沟渗漏水精准测漏补漏上门 - 安佳防水
  • IDA Pro与BinDiff 6.0联调环境搭建及二进制差异分析实战指南
  • Ubuntu命令行操作基础与实用技巧
  • YOLO目标检测结果解析与优化实践
  • C/C++编译链接全流程解析:从源码到可执行文件的完整指南
  • C++指针与内存管理:从基础原理到智能指针实战应用
  • 使用pybind11将C++高性能模块封装为Python包实战指南
  • 2026年Java学习平台横评与选择指南
  • 核磁专用高纯液氦实力厂家2026口碑推荐,价格透明零套路避坑指南 - 工业推荐榜
  • CSS动画与JavaScript交互:实现运动会主题角色动画效果
  • 终极指南:3分钟让微信网页版重新可用,开源插件wechat-need-web完整教程
  • AI代理管理IDE:多代理系统开发工具的设计与实践
  • 深入解析SoC电源域管理:从概念到DRA7xP实战
  • 2026年 渝中区物流公司推荐榜单:高效配送/智能仓储服务首选,行业实力深度解析 - 甄选服务推荐
  • C++程序coredump分析与调试:从崩溃定位到性能优化实战
  • Xournal++:构建你的跨平台数字笔记工作流
  • C++高性能内存池实现:固定块与空闲链表设计详解
  • 港股医疗与科技板块异动股解析及交易策略
  • 供应链管理基础:从概念到数字化转型实践
  • C++日志库选型指南:spdlog与Quill性能、特性与场景深度对比