🏠 总目录📚 本教程 07 · 工具设计
📑 本页目录(点开跳转)

07 · 工具设计:能力的上限

35 分钟 | ⭐⭐ 核心 | 🔨 有可直接抄的代码


🎯 一句话

「Agent 的能力上限由我们给它的工具决定。」 工具设计是一门新学科:ACI(Agent-Computer Interface)——像做 UI 一样认真地做模型的界面。


🧠 一、核心认知转变

传统 API Agent 工具
使用者 确定性程序 非确定性模型
调用方式 严格按文档 可能换着花样、可能理解错、可能压根不调
错误处理 调用方负责 工具要引导模型自我修复
设计目标 完备、正交 贴合任务意图、省 token、防呆

🔑 一句话:API 的用户会读文档,工具的用户会「猜」。 好工具让猜对的概率最大化,让猜错的代价最小化。

📌 SWE-bench 冲榜团队公开表示:「花在优化工具上的时间比优化整体提示词还多。」

🤔 先把一个几乎每个人都会卡住的问题解决掉:「Function Calling 和 MCP 到底是什么关系?」 很多人以为它们是竞品、要二选一。不是——它们在三个不同的层上,你会同时用到全部三个。 🔗 答案在 08 · MCP 第二节,那里有 Function Calling / MCP / A2A 的三层分工表。 ⭐ 先记住结论,这一章后面才读得顺Function Calling 是模型和你的程序之间的协议(模型说"我要调 get_weather",也就是这一章在设计的那个东西); MCP 是你的程序和外部工具之间的协议(怎么把 get_weather 这个能力接进来,不用为每个工具写一遍胶水)。 所以这一章的五条设计原则在两边都成立——你自己写的函数要遵守,别人的 MCP Server 也一样。 ⚠️ 唯一的差别是:接第三方 MCP Server 时你往往改不了它的工具描述。 那就只能在自己这侧包一层——重写描述、裁掉用不上的参数,再暴露给模型。 (这和 08 章第五节 ⑥「第三方返回臃肿就包一层做裁剪」是同一招的两半:描述进去的那半在这一章的原则 ⑤,返回出来的那半在 08 章。)


🖐️ 二、五条设计原则

① 选对工具,而非更多工具

核心矛盾Agent 的上下文有限,计算机的内存无限——别把内存的活儿丢给上下文。

❌ 反上下文的工具 ✅ 围绕工作流的工具 省了多少
list_contacts() 返回全部 5000 条 search_contacts(query) 只返回相关的 5000 → 5 条
read_logs() 返回整个日志文件 search_logs(pattern) 返回匹配行 + 上下文 50000 → 20 行
list_users() + list_events() + create_event() schedule_event(attendees, duration) 内部处理找空档 3 轮 → 1 轮

判断标准

   一个工具应该对应【人类的一个任务意图】
   而不是【数据库的一张表】或【REST API 的一个端点】

   ⭐ 自检:「用户会说『帮我___』吗?」
      会 → 这是个好工具边界
      不会 → 你在暴露实现细节

② 命名空间

   asana_search / asana_create / asana_update
   jira_search  / jira_create  / jira_update

   ⭐ 好处:
   · 几十个工具时,前缀帮模型快速缩小范围
   · 明确边界:模型不会拿 asana 的 id 去调 jira

③ 返回有意义的上下文

# ❌ 技术标识符,模型抄写会出错
{"user_id": "a3f8b21c-4e5d-11ee-be56-0242ac120002",
 "mime_type": "application/vnd.ms-excel", "ts": 1753574400}

# ✅ 语义化 + 短索引
{"idx": 0, "name": "张伟", "file_type": "Excel 表格", "time": "2026-07-27 09:00"}

三条具体规则

规则 理由
用语义名称替代 UUID 模型抄写长随机串会出错(幻觉),短索引 0,1,2 不会
用人类可读格式 "Excel 表格""application/vnd.ms-excel" 省 token 也更准
提供 response_format 枚举 让模型自选详略,实测省约 1/3 token
def search_docs(query: str, response_format: str = "concise"):
    """
    response_format:
      "concise"  - 只返回标题和一句话摘要(默认,省 token)
      "detailed" - 返回完整正文
    """

④ 为 token 效率优化

四个手段:分页、过滤、范围选择、带指引的截断

# ✅ 截断时要告诉模型"还有更多"以及"怎么拿"
def format_results(results, limit, formatted):
    if len(results) > limit:
        return (f"{formatted[:limit]}\n\n"
            f"[还有 {len(results)-limit} 条结果未显示。"
            f"用更具体的 query 缩小范围,或用 offset={limit} 翻页]")

⑤ ⭐ 工具描述就是提示词

像给新入职同事写说明一样写:把隐性知识显式化、参数命名无歧义、给用法示例和边界。

# ❌ 开发者视角的描述
"""Query the events table."""

# ✅ 使用者视角的描述
"""查询日历事件。

用于回答"某人某天有什么安排""会议室X什么时候空闲"这类问题。
- 时间范围最长 90 天,超过会报错
- 不包含已取消的事件(除非 include_cancelled=True)
- 返回按开始时间升序排列

示例:查询张伟下周的会议
  query_events(attendee="张伟", start="2026-08-04", end="2026-08-10")
"""

📌 官方战绩仅仅精化工具描述,就曾让 Claude Sonnet 3.5 拿下 SWE-bench Verified 的 SOTA。 这是全领域投入产出比最高的优化之一——不用改代码,只改文档字符串。


🛡️ 三、防呆设计(Poka-yoke)

让错误用法在结构上不可能发生,而不是在文档里警告:

容易出错的设计 防呆改法 为什么
接受相对路径 强制绝对路径 模型搞不清"当前目录"是哪
自由字符串参数 改成 enum: ["draft","published"] 拼错直接被 schema 拦住
create() 后要记得 commit() 合并成一个原子操作 模型会忘第二步
危险操作直接执行 confirm: bool 必填参数 强制模型显式表达意图
时间用字符串 给出明确格式 + 示例,或用相对描述 "next monday" 格式歧义是高频错误源
# ✅ 防呆示例:三重保护
def delete_records(
    table: str,              # enum 限定
    where: str,              # 必填,不允许空(防止全表删除)
    confirm: bool,           # 必填 True,强制显式确认
    max_rows: int = 100,     # 硬上限,超过直接拒绝
):
    if not where.strip():
        return "错误:where 不能为空。如需清空全表请用 truncate_table 工具。"
    ...

🩺 四、错误信息:写给模型看的教学材料

这是最容易被忽略、收益却极高的一环。

# ❌ 给人看的报错
raise ValueError("Invalid input")

# ✅ 给模型看的教学
def bad_expression_error():
    return (    "错误:expression 参数含不支持的字符 ['s','i','n']。\n"
            "本工具只支持数字和 + - * / ** ( ),不支持函数。\n"
            "如需三角函数请用 advanced_calc 工具。\n"
            "正确示例:calculator(expression='3.14 * 2**2')")

好错误信息的四要素

   ① 错在哪         「含不支持的字符 ['s','i','n']」
   ② 规则是什么      「只支持数字和 + - * / ** ( )」
   ③ 该怎么办 ⭐     「如需三角函数请用 advanced_calc」
   ④ 正确示例        「calculator(expression='3.14 * 2**2')」

🔑 判断标准模型看完这条错误,能不能一次就改对? 能 → 好错误信息。不能 → 它会瞎试,浪费好几轮。


🔁 五、评估驱动的工具改进循环

工具好不好,不靠感觉,靠这个循环:

   ① 快速做出原型工具
        ↓
   ② 造一批【真实的多步评估任务】(不是 demo 题)
        ↓
   ③ 跑评估,收集完整转录
        ↓
   ④ 读转录:模型在哪困惑?哪里绕弯?哪个参数总用错?
        ↓
   ⑤ ⭐ 让 Claude 读转录,自己重构工具和描述
        ↓
   ⑥ 留出测试集验证 → 回到 ③

📌 官方实测让 Claude 根据转录优化过的工具,性能超过了专家手写的版本。 用 Agent 改进 Agent 的工具,是 2026 年的标准操作。

第 ④ 步该盯什么(读转录的检查表):

症状 说明它需要什么
反复调同一个工具改参数 描述里没说清参数含义/取值范围
调了工具但没用返回结果 返回格式不好懂,或信息不是它要的
手动组合多个工具做一件事 该提供一个组合工具(原则 ①)
一直不调某个工具 描述没说清它什么时候有用
调用后报错然后放弃 错误信息没告诉它怎么改

🎭 六、「think」工具:一个值得知道的小历史

2025 年官方发现:给 Agent 一个什么都不做think 工具 (唯一作用是让模型写下思考),在复杂多步任务上显著提效。

def think(thought: str) -> str:
    """记录你的思考过程。不执行任何操作,仅用于整理思路。"""
    return "已记录。"      # ← 真的什么都不做

为什么有用:给了模型一个显式的暂停-整理位第 4 章:思考需要 token 承载)。

⚠️ 后来的模型有了原生扩展思考,这个技巧多数场景已被取代。 但它是「工具可以塑造行为,而不只是提供能力」的经典例证—— 这个思路今天仍然有用(比如给一个 plan 工具强制它先规划)。


🔨 七、动手:给一个工具做体检

拿你系统里(或第 1 章里)的一个工具,过六关:

# 检查 修法
1 返回里有模型用不上的字段吗? 砍掉或加 response_format
2 有裸 UUID / 时间戳 / MIME 类型吗? 换语义化名称或短索引
3 错误信息告诉模型怎么改了吗? 按四要素重写
4 描述拿给没见过这系统的同事,他能用对吗? 补隐性知识 + 加示例
5 有哪种误用可以从结构上堵死? 防呆化(枚举/必填/绝对路径)
6 这个工具对应一个任务意图还是一张数据表 按意图重新划分边界

🕳️ 八、六个常见坑

症状
工具太多 模型选错工具、上下文被定义撑爆 合并成意图级工具;上 Tool Search(第 8 章)
返回体积失控 前几轮就烧光预算 分页/过滤/带指引的截断
描述是给开发者写的 模型用不对 改成使用者视角 + 示例
错误信息无法行动 模型报错后瞎试 四要素重写
参数含义靠猜 反复调同一工具改参数 参数名 + docstring 明确取值范围
一比一镜像 API 简单意图要调三个工具 按意图重新分组

📚 延伸阅读

👉 接进真实产品时:工具的入参出参怎么用 Schema 约束住、校验失败怎么带着错误重试,在 16c · 接进真实产品 —— 那一章还讲了「Schema 只保证格式对,不保证内容对」这个最容易漏的坑。



✅ 检查点

  1. 工具的用户和 API 的用户本质区别是什么?
  2. 「返回全部联系人」的工具坏在哪?判断工具边界的自检问题是什么?
  3. 为什么返回里的 UUID 要换掉?
  4. 好的错误信息有哪四个要素?判断标准是什么?
  5. 评估驱动改进循环的第 ⑤ 步是什么?为什么它有效?
  6. 读转录时,「模型反复调同一个工具改参数」说明什么问题?
  7. think 工具为什么有用?它今天还有意义吗?
👀 答案
  1. API 用户是确定性程序、会读文档严格调用;工具用户是模型,它会「猜」——可能换花样、理解错、或压根不调。好工具让猜对概率最大、猜错代价最小。
  2. 把计算机内存的活儿丢给了有限的上下文——模型被迫逐 token 读完 5000 条。自检问题:「用户会说『帮我___』吗?」会 → 好边界;不会 → 你在暴露实现细节。
  3. 模型抄写长随机串会出错(幻觉)。用语义名称或短索引 0,1,2 可显著减少。
  4. ①错在哪 ②规则是什么 ③该怎么办 ④正确示例。判断标准:模型看完能不能一次改对
  5. 让 Claude 读评估转录后自己重构工具和描述。有效因为转录里有真实的困惑证据,且官方实测 AI 优化版超过专家手写版。
  6. 描述里没说清参数含义或取值范围——它在靠试错猜参数。
  7. 给模型一个显式的暂停-整理位,让思考有 token 承载。原生扩展思考出现后多数场景已被取代,但「工具可以塑造行为而不只提供能力」这个思路仍然有用。

🛑 可以停在这里

走神救援

工具决定能力上限,这门学科叫 ACI,要像做 UI 一样认真做模型的界面。核心认知:API 用户读文档,工具用户会猜——好工具让猜对概率最大、猜错代价最小(冲榜团队说过:花在优化工具上的时间比优化提示词还多)。五原则:①按任务意图选工具不按数据表(自检:用户会说"帮我___"吗;Agent 上下文有限而计算机内存无限——返回全部 5000 条联系人要改成只返回 5 条5 万行日志要改成 20 行匹配行,三个工具 3 轮要并成 1 轮)②命名空间(asana_/jira_ 前缀帮模型缩小范围,也防它拿 asana 的 id 调 jira)③语义化返回(UUID 换短索引防幻觉,「Excel 表格」比长 MIME 又省 token 又准,加 response_format 省 1/3 token)④token 效率(分页/过滤/带指引的截断——要告诉它还剩多少条、怎么拿)⑤描述就是提示词(像给新同事写说明;仅改描述曾拿下 SWE-bench Verified 的 SOTA,不改代码只改文档字符串,投产比最高)。防呆:让误用结构上不可能(绝对路径/枚举/原子操作/必填 confirm/where 不许为空+max_rows 硬上限)。错误信息四要素:错在哪+规则+该怎么办+示例,标准是"模型能否一次改对",不能它就瞎试烧掉好几轮。改进靠循环:原型→造真实多步评估任务→读转录(反复改参数=没说清取值范围;调了不用结果=返回难懂;手动拼工具=该给组合工具;一直不调=没说清何时有用;报错就放弃=错误信息没说怎么改)→⭐让 Claude 自己重构工具,官方实测超过专家手写版

下一节 👉 08-MCP-接入外部世界.md

打卡记录保存在你的浏览器里,首页能看到总进度