Skip to content

03 · 给它手:工具怎么设计 ​

模型本身什么也做不了。它能干的每一件事,都来自你给的工具。所以工具这一层完全由你控制——也意味着它干错的事,多半也是你给的工具设计得不好。

工具调用是怎么回事 ​

一句话:模型只负责"提出要调什么",真正执行的是你的程序。

text
① 你告诉模型:手上有这几个工具,各自能干嘛、要传什么参数
② 模型判断:这一步该调 search_docs,参数是 {"query": "定价"}
③ 你的程序执行:真的去搜
④ 结果塞回上下文:模型看到搜索结果
⑤ 模型继续判断下一步

第 ② 步就是 Function Calling。注意第 ③ 步——执行权在你手上,这是你能设边界的物理基础(05 章)。

工具描述就是它的说明书 ​

模型靠什么决定调哪个工具?靠工具的名字和描述。 这跟 Skill 的 description 是完全一样的机制——写不好,它就选错、或者根本不选。

一个工具的定义通常包含三样:

作用写不好会怎样
名字标识起名含糊(get_data),它分不清几个工具的差别
描述决定它什么时候调这个最关键。糊了就乱调或不调
参数说明每个参数是什么、什么格式糊了它就乱传,或者漏传

对照 ​

text
❌ 名字:search
   描述:搜索。
   参数:query(字符串)

它不知道搜的是什么、搜到的是哪个范围、query 该写关键词还是自然语言。

text
✅ 名字:search_internal_docs
   描述:在公司内部文档库中做全文检索,返回最多 10 条匹配片段及其文档标题和链接。
        用于查找内部规范、流程说明、历史方案。**不能搜到公开网页**——
        需要公开信息时用 search_web。
   参数:
     query(字符串):检索关键词,用空格分隔,不要写成完整句子。
                     例:"报销 差旅 标准"
     limit(整数,可选):返回条数,默认 10,最大 50

三处改进:说清返回什么、说清不能干什么并指向替代工具、参数给了格式和例子。

写工具描述时,把Skill 篇 04 章那一整套原封不动搬过来:

  • 既写"做什么",也写"什么时候用";
  • 工具多的时候加排除条款("公开信息用 search_web");
  • 用具体的词,别用抽象的词;
  • 参数给例子,比给类型有用。

工具描述和 Skill description 是同一件事的两个位置。

工具设计的五条规矩 ​

一、一个工具一件事 ​

text
❌ manage_file(action, path, content)    action 可以是 read / write / delete / move
✅ read_file(path)
   write_file(path, content)
   delete_file(path)

拆开的三个理由:它选错的概率低;你能对 delete 单独加确认(05 章);日志里一眼看出它干了什么。

那个 action 参数版本,日志里全是 manage_file,你得点进去看参数才知道它是读还是删。

二、数量控制在十几个以内 ​

工具太多有两个问题:每个的描述都要常驻上下文,几十个工具就是不小的开销;而且选择困难——相似的工具一多,它选错的概率明显上升。

超过二十个,考虑分组:按任务阶段给不同的工具集,或者用一个"目录型"工具让它先查有哪些工具可用。

三、返回结果要精简,但要够判断 ​

工具返回的东西会原样进上下文。一个返回整页 HTML 的工具,几圈就能把桌子占满(07 章)。

text
❌ 返回:整个网页的 HTML
✅ 返回:页面标题 + 正文纯文本(截断到 2000 字)+ 原始 URL
       截断时注明"(已截断,完整内容见 URL)"

但也别精简过头——它得能判断"这次调用成功了没有、要不要换个方式再试"。返回一个空字符串,它不知道是没找到还是出错了。

四、错误要说人话 ​

工具报错时,返回的信息是给模型看的,目的是让它知道下一步该怎么办:

text
❌ Error: 400
✅ 错误:query 参数不能为空。请提供检索关键词后重试。

❌ Error: not found
✅ 未找到匹配文档。建议:换更宽的关键词,或改用 search_web 查公开信息。

第二种写法里那句"建议",能直接省掉它两三圈瞎试。

五、危险的动作,工具层面就拦住 ​

别指望靠提示词说"不要删文件"。 提示词是软约束,工具是硬约束:

  • 不想让它删,就别给 delete_file 这个工具;
  • 必须给,就让这个工具返回一个待确认的动作,而不是真的执行——由人点头之后再执行。

这是本章最重要的一条

提示词里的"不许做 X",和"根本没有做 X 的工具",是两种完全不同强度的东西。

能靠不给工具解决的,就不要靠说服解决。

常见的一组工具 ​

大多数 Agent 的工具集是这几类的组合:

类别例子风险
读搜索、读文件、查数据库、读网页低。主要风险是读到不该读的(05 章)
写写文件、建记录、发消息中。要能撤回,或者要人确认
删 / 改删除、覆盖、更新状态高。默认不给,或者必须人确认
执行跑命令、跑代码、调外部 API最高。必须沙箱 + 白名单
对外发邮件、发消息、提交表单、支付最高。一律人工确认,无例外

设计工具集时先做一次分类:把你打算给的工具按上面五类摆一遍。

"高"和"最高"那两类,逐个问一句:"这个真的必须给它吗?"

多数时候答案是:这一步可以由人来做,或者可以让 Agent 只产出一个"待执行清单",由人批量执行。

一个折中做法:先产出计划,再执行 ​

对付高风险动作,有个很实用的模式:

text
Agent 不直接执行危险动作,而是产出一份「计划文件」:
  - 要删哪几个文件
  - 要发哪几条消息,发给谁,内容是什么

人看一遍这份计划 → 确认 → 由程序按计划批量执行

好处:Agent 的自主性保住了(它自己想清楚该干什么),风险也控住了(真正的动作由人点头)。而且计划是文本,好看、好改、好留档。

这跟 Workflow 篇 07 章"把要判断的和已经没问题的分开列"是同一个思路。

下一步 ​

04 · MCP:一个统一的插头 —— 工具从哪儿来,以及怎么不用每接一个系统就写一遍。

一份讲通用概念的入门手册 · 不绑定任何一家模型或工具 · 例子可直接照抄