下面六个任务,判断每一个是否需要给 Agent 配工具才能真正完成,并说明理由(提示:问自己"模型手上有没有这份信息")。
Level 1:给六个任务分类- "帮我把这段英文邮件翻译成中文,语气客气一点"
- "帮我看看昨晚 3 点那次部署的日志里有没有报错"
- "帮我写一个校验邮箱格式的正则表达式"
- "帮我看看这个仓库里
package.json里依赖的 React 版本是多少" - "帮我把这份需求文档拆成 5 条验收标准"
- "帮我调用一下天气接口,看看北京明天会不会下雨"
学习目标:
- 说出「工具」在 Agent 里指的到底是什么,和普通的一段回复文字有什么区别
- 认出一个工具定义至少要包含哪三样东西
- 判断一个具体任务到底需不需要给 Agent 配工具
前置要求:会写基本 prompt、用过 Claude Code 之类的工具 | 下一课 第 2 课 >>
你在一个几十个文件的项目里,跟 Agent 说了这句话:
"把项目里所有 console.log 找出来。"
第一次,这个 Agent 只是一个接了 API 的聊天框,没有接任何工具。 它的回复是这样的:
我没办法直接访问你的文件系统,不过你可以在终端里运行下面的命令来查找:
这会递归搜索
src/目录下所有文件里包含console.log的行,并打印出文件名和行号。如果你的项目用了 TypeScript,记得把.ts/.tsx也包含进搜索范围。
写得没错,甚至挺贴心。但你要的不是一份怎么搜的说明,你要的是搜索结果。这一轮对话结束时,你的项目里到底哪几个文件有 console.log,你一个字都不知道,还得自己去开终端敲那行命令。
第二次,同一句话,丢给一个接了搜索工具的 Agent。 它的回复是这样的:
我在项目里搜了一遍,找到 7 处
console.log:
src/api/client.ts:42src/api/client.ts:88src/utils/logger.ts:12src/components/Cart.tsx:156src/components/Checkout.tsx:23src/hooks/useAuth.ts:67scripts/seed-db.js:5其中
src/utils/logger.ts:12那一处看起来是有意保留的日志封装,其余 6 处像是调试时留下的。要我帮你清掉吗?
两次问的是一模一样的问题。模型也没换、prompt 也没改。差别就一件事:第二次,这个 Agent 手里多了一样东西——工具(tool)。第一次它只能凭训练数据里见过的知识,猜一个"大概该怎么做"的命令讲给你听;第二次它真的跑了一遍搜索,看到了你项目此刻的真实内容,然后才开口。
这一课要讲清楚的就是:工具到底是什么、它凭什么能让 Agent 从"讲讲思路"变成"动手查了一遍"、以及什么任务其实根本不需要它。
先纠正一个直觉:搜到那 7 个文件的,不是模型本身。模型没有文件系统,没法自己打开一个目录、跑一遍正则匹配。真正跑那次搜索的,是运行这个 Agent 的宿主程序——可能是 Claude Code,也可能是你自己写的、调用 Claude API 的一个几十行的脚本。
**工具,就是宿主程序告诉模型"我这边可以帮你做这些事"的一份清单。**每一项写清楚三件事:这个能力叫什么名字、什么时候该用它、用的时候要传哪些参数。1
拿上面那次搜索举例,宿主程序在请求里塞给模型的工具清单,大概长这样:
这三个字段各管各的事:name 是模型选它时要写的标识符;description 是一段说明文字,告诉模型这个工具做什么、什么场合该用、行为上有什么特点;input_schema 是一份 JSON Schema,规定调用这个工具时要传哪些参数、每个参数是什么类型。1
模型没见过你的文件系统,但它见过这份清单。它读到 description 里写着"在项目源码目录中搜索……返回文件路径和行号",又看到你说"把项目里所有 console.log 找出来",两边一对,判断出该点这个工具,该传 pattern 等于 console\.log。这一步是模型做的——选工具、填参数,属于语言模型最擅长的事:读懂意图、匹配到合适的选项。
但选完之后呢?谁去真的翻文件?
这里有一条分界线,是这一课里最重要的一句话:模型从不亲自执行任何操作。它只是把"我想调用哪个工具、传什么参数"整理成一段结构化数据,交还给宿主程序;真正打开文件、跑命令、发请求的,是宿主程序自己的代码。2
具体到上面那次搜索,完整的过程是这样的:
search_files 这份工具清单,决定要调用它,参数是 {"pattern": "console\\.log"}。它把这个决定包成一段数据,作为这一轮回复的内容——注意,回复里没有搜索结果,因为模型手上根本没有搜索结果,它只是提了个请求。OpenAI 的文档把这个过程直接称为"应用程序和模型之间的多步骤对话":模型调用函数时,执行和取回结果的责任在你的应用程序这一边,不在模型这一边。3 Anthropic 这边说得更直白:模型什么都不执行,它发出一个结构化请求,你的代码(或者 Anthropic 自己的服务器)去跑这个操作,结果再流回对话里。2
顺带一提,"谁来执行"这件事本身还能再分一层。文档里把需要你的程序动手执行的工具叫"客户端工具",把 Anthropic 自己的服务器代为执行的(比如网页搜索)叫"服务器工具"。4 但无论哪种,模型这一侧的行为都没变——它还是只提议,不亲自动手,区别只在"谁替它把提议变成真实动作"。
拿你正在用的 Claude Code 当例子会更具体:它本身就是这样一个宿主程序,内置了读文件、写文件、跑终端命令、搜索代码等一组工具,模型每次决定用哪个,都是从这份固定的清单里挑,而不是凭空发明一个新能力出来。5 这份清单从哪来、每一项具体长什么样,我们第 3 课会挨个过一遍。
看完上面的过程,容易走向另一个极端:既然工具这么好用,是不是干脆什么都给 Agent 配上工具?不是的。判断的标准很简单,问自己一句话就够了:这个任务需要的信息或动作,模型自己手上有吗?
有些任务模型自己就能搞定,不需要接触外部世界:
这些任务用到的知识,模型在训练时已经见过足够多类似的例子,凭语言能力就能完成。给这类任务硬塞一个工具,模型该调用还得先判断"这次要不要调用",多一次判断就多一次可能选错的机会,纯粹是浪费。
另一些任务,模型无论多聪明都做不到,因为它缺的不是能力,是信息:
这一类任务,不管你把 prompt 写得多细致、多有诱导性,模型都变不出真实答案,因为它手上压根没有这份数据。唯一的办法是给它一条通道,让宿主程序替它去拿——这就是工具存在的理由。
这五类工具具体是什么样子——读、写、执行命令、搜索、调用外部服务——我们放到第 3 课挨个拆开讲;这一课你只需要记住"要不要配工具"这道判断题怎么问。
name、description、input_schema 三样东西,模型据此判断该不该调用、传什么参数。1Define tools — Claude API — https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools ↩ ↩2 ↩3
How tool use works — Claude API — https://platform.claude.com/docs/en/agents-and-tools/tool-use/how-tool-use-works ↩ ↩2 ↩3
Function calling — OpenAI API Guides — https://developers.openai.com/api/docs/guides/function-calling ↩ ↩2
Tool use with Claude — Overview — https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview ↩
Tools reference — Claude Code Docs — https://code.claude.com/docs/en/tools-reference ↩
package.json 里依赖的 React 版本是多少"记下想法、痛点、没懂的地方。只写进这门课的附录,正课文件不动。
grep -rn "console.log" src/{
"name": "search_files",
"description": "在项目源码目录中搜索匹配某个字符串或正则表达式的所有文件,返回每处匹配的文件路径和行号。适用于查找特定函数调用、变量名、TODO 注释等。",
"input_schema": {
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "要搜索的字符串或正则表达式,例如 console\\.log"
},
"path": {
"type": "string",
"description": "搜索的起始目录,默认为项目根目录"
}
},
"required": ["pattern"]
}
}