一个工具描述写得含含糊糊的 AI Agent,在该查订单时却去退了款、参数还填错,把工具用得乱七八糟:一次工具定义不清的深度复盘
那个问题是 Agent 上线后行为"飘忽不定"暴露出来的:我们给一个客服 Agent 配了一堆工具——查订单、查物流、申请退款、修改地址……可它的表现极不稳定:用户问"我的订单到哪了",它有时去查物流(对)、有时却去查订单详情(不太对)、偶尔还调用了"申请退款"(完全错!);更离谱的是,它调工具时参数经常填错——把订单号填进了用户 ID 的位置。我一开始怀疑是模型不行,换了更强的模型,好了一点但还是会错。直到我回头仔细看我给这些工具写的描述(description)和参数说明,才恍然大悟,后背发凉:我把工具的描述写得含含糊糊。比如"申请退款"工具,我的描述只写了"处理订单相关请求"——这描述既不说明它具体是干嘛的、也没说什么时候该用它,模型看了根本分不清它和"查订单"的区别,于是乱选;参数也只写了 id: string,没说这个 id 到底是订单号还是用户 ID,模型只能瞎猜,自然填错。问题的根,不在模型"不够聪明",而在我给它的工具"说明书"写得太烂——大模型是完全依据我写的工具描述和参数说明,来决定"用哪个工具、怎么填参数"的;我把说明书写得模糊,它就只能连蒙带猜。这篇就把这次"Agent 工具定义不清"的坑,从头到尾复盘一遍。
故障现场:含糊的工具描述和参数说明
问题代码,是一组描述写得含糊、模型无从分辨的工具定义:
# ✗ 出问题的工具定义: 描述含糊、参数说明不清
TOOLS = [
{
"name": "get_order",
"description": "处理订单相关请求", # ✗ 太含糊! 到底是查订单还是干嘛?
"parameters": {"id": {"type": "string"}} # ✗ id是订单号? 用户ID? 没说!
},
{
"name": "refund",
"description": "订单处理", # ✗ 和上面的描述几乎一样, 模型分不清!
"parameters": {"id": {"type": "string"}} # ✗ 同样没说id是什么
},
{
"name": "get_logistics",
"description": "物流", # ✗ 就俩字, 模型不知道什么时候该用它
"parameters": {"id": {"type": "string"}}
},
]
# 结果:
# - 用户问"订单到哪了" → 模型在 get_order/get_logistics/refund 之间【乱选】
# (描述都含糊雷同, 它分不清哪个对应"查物流");
# - 偶尔选了 refund(退款)→ 灾难!(它以为"订单处理"可能就是用户要的);
# - 参数 id 填错: 把订单号填进本该是用户ID的位置(描述没说清id是什么)。
# 为什么会这样:
# - 大模型决定"用哪个工具、怎么填参数", 【唯一的依据】就是你提供的:
# 工具的 name、description、参数的 schema 和说明;
# - 这些就是模型眼里这个工具的"说明书"——它【看不到工具的代码实现】, 只能靠这份说明书理解;
# - → 说明书写得含糊/雷同/不清, 模型就【无从准确判断和填写】, 只能连蒙带猜 → 乱用工具。
# 关键: Agent靠"工具的描述和参数说明"来决定用哪个工具、怎么填参数; 描述含糊/参数不清,
# 模型就会选错工具、填错参数——这不是模型笨, 是你给的"工具说明书"太烂。
第一次意识到是"我写的说明书太烂"时,我又懊恼又恍然:"我一直怪模型选错工具,原来是我没把工具讲清楚,它怎么可能选对?"这个坑最容易被归错因的地方在于:当 Agent 表现不好时,我们第一反应总是"模型不够强",于是想着换更贵的模型、调 prompt;却常常忽略了一个更根本的原因:我们给模型的"工具定义/信息"本身就是模糊、错误、或不足的。模型再聪明,也只能基于你给它的信息做判断;信息(工具说明书)烂,再强的模型也救不回来。下面就来拆解,工具定义对 Agent 有多关键、该怎么写好。
第一件事:搞懂 Agent 是怎么"选工具、填参数"的
我认真梳理了 Agent 调用工具的机制,才彻底理解工具定义为什么这么关键。
Agent 怎么决定"用哪个工具、怎么填参数"?
【核心: 模型只能看到工具的"描述+参数schema"(看不到实现); 它完全依据这份"说明书"来选工具、填参数】
1. Agent调用工具的流程:
- 你把所有工具的 name + description + 参数schema, 一起告诉模型;
- 模型根据【当前任务】和【这些工具说明书】, 判断"该用哪个工具、参数填什么";
- 它输出一个"工具调用"(工具名 + 参数); 你的代码再去真正执行这个工具。
2. 关键: 模型【只能看到说明书, 看不到工具的代码实现】:
- 它不知道 get_order 内部到底查了什么, 它【只知道你写的那句description】;
- → 你的 description 和参数说明, 就是模型理解这个工具的【全部信息来源】;
- → 说明书的质量, 直接决定模型能不能选对、填对。
3. 说明书烂会导致:
- 描述含糊("处理订单") → 模型不知道这工具具体干嘛、什么时候用;
- 多个工具描述雷同 → 模型分不清它们的区别, 乱选;
- 参数说明不清(id没说是啥) → 模型不知道填什么、填错;
- 缺少"何时使用"的指引 → 模型在多个工具间犹豫、选错。
4. 类比: Agent就像一个【新来的、很聪明但对你业务一无所知的实习生】;
- 你给他一堆工具(API), 他全靠你写的"工具使用手册"来决定用哪个、怎么用;
- 手册写得清楚(每个工具干嘛、何时用、参数啥意思、给例子)→ 他用得又快又对;
- 手册写得含糊雷同 → 再聪明的实习生也会用错——不是他笨, 是手册没讲清。
5. 推论: 工具定义(描述+参数schema)是Agent能力的【关键基础设施】;
- 它和prompt一样, 是你"指挥"模型的核心手段; 值得像写API文档一样认真写。
一句话: Agent只能依据工具的"描述+参数说明"(看不到实现)来选工具、填参数; 说明书含糊/雷同/不清,
模型就会选错填错(不是模型笨, 是说明书烂); 工具定义是Agent的关键基础设施, 要认真写清。
这套机制,是整个坑的根。Agent 调用工具的流程:你把所有工具的 name+description+参数 schema 告诉模型,模型根据当前任务和这些说明书判断"用哪个工具、参数填什么",输出工具调用、你的代码再执行。关键是:模型只能看到说明书、看不到工具的代码实现——它不知道工具内部干了什么,你的 description 和参数说明就是模型理解这个工具的全部信息来源,说明书质量直接决定模型能不能选对填对。说明书烂会导致:描述含糊(不知干嘛/何时用)、多工具描述雷同(分不清乱选)、参数说明不清(不知填啥填错)、缺"何时使用"指引(犹豫选错)。就像Agent 是个聪明但对你业务一无所知的新实习生,全靠你写的"工具使用手册"决定用哪个怎么用;手册清楚就用得又快又对、含糊雷同再聪明也会用错——不是他笨是手册没讲清。推论:工具定义是 Agent 能力的关键基础设施,和 prompt 一样是你指挥模型的核心手段,值得像写 API 文档一样认真写。一句话:Agent 只能依据工具的"描述+参数说明"(看不到实现)来选工具、填参数;说明书含糊/雷同/不清,模型就会选错填错(不是模型笨,是说明书烂);工具定义是 Agent 的关键基础设施,要认真写清。
第二件事:正解——把工具描述和参数说明写清楚,职责单一,加校验
搞懂了原理,正解就清晰了:工具描述写清"做什么、何时用、何时不用",参数 schema 写清每个参数的含义/格式/示例,工具职责单一、名字清晰,并对参数做运行时校验兜底。
# ✓ 正解: 清晰、单一职责、参数说明到位的工具定义
TOOLS = [
{
"name": "query_order_detail", # ★ 名字清晰: 查订单详情
"description":
"根据订单号查询【订单的详细信息】(商品、金额、下单时间、订单状态)。"
"当用户询问订单内容、金额、状态时使用。"
"【注意】这不查物流(用query_logistics)、也不退款(用apply_refund)。", # 何时用+何时不用
"parameters": {
"type": "object",
"properties": {
"order_no": { # ★ 参数名明确: order_no 而非含糊的id
"type": "string",
"description": "订单号, 形如 'ORD20260602001'(不是用户ID, 不是商品ID)", # 说清含义+格式+反例
}
},
"required": ["order_no"],
},
},
{
"name": "query_logistics",
"description": "根据订单号查询【物流配送进度】(发货、运输、签收状态)。"
"当用户问'我的东西到哪了/什么时候到/有没有发货'时使用。", # 明确的触发场景
"parameters": { "type": "object", "properties": {
"order_no": {"type": "string", "description": "订单号, 形如 'ORD20260602001'"}
}, "required": ["order_no"]},
},
{
"name": "apply_refund",
"description": "为指定订单【发起退款申请】(这是个【有副作用的写操作】, 会真的发起退款)。"
"【仅当】用户【明确要求退款/退货】时才使用; 用户只是查询时【绝不要】调用它。", # 强调副作用+严格触发条件
"parameters": { "type": "object", "properties": {
"order_no": {"type": "string", "description": "要退款的订单号"},
"reason": {"type": "string", "description": "退款原因"},
}, "required": ["order_no", "reason"]},
},
]
# → 描述说清"做什么+何时用+何时别用"、参数名明确含义清晰带示例、有副作用的工具特别强调;
# 模型据此就能准确地选对工具、填对参数。
# ====== 写好工具定义的几条要点 ======
# 1. 名字清晰、有动词: query_order_detail 比 get_order 好, 一看就知道干嘛(动词+对象)。
# 2. 描述写清三件事: "这工具【做什么】" + "【什么时候】该用它" + "【什么时候不该】用(和别的工具的区别)"。
# 3. 工具职责单一: 一个工具只干一件事; 别一个工具又查又改(模型难判断、也危险)。
# 4. 参数说明到位: 每个参数写清【含义、格式、示例】, 甚至反例("不是用户ID"); 名字别用含糊的id。
# 5. 用严格的参数schema: 类型、必填、枚举值、范围都约束上(JSON Schema), 减少模型乱填的空间。
# 6. 有副作用的工具特别标注: 明确"这是写操作/会产生真实影响", 并写清严格的触发条件; 高危的加人工确认。
# 7. 运行时校验兜底: 别完全信模型填的参数, 执行工具前再做一层参数校验(同对待外部输入)。
# 8. 工具别太多: 工具一多, 模型选择困难、易混淆; 按需精简, 或分组/分层。
# 核心: 工具定义是Agent的"工具使用手册"——名字清晰、描述写清"做什么+何时用+何时不用"、参数说明到位带示例、
# 职责单一、严格schema、副作用标注、运行时校验兜底; 把它当API文档一样认真写, 别让模型连蒙带猜。
修复的核心,是"把工具说明书写得让模型一看就懂、不用猜"。正解要点:名字清晰带动词(query_order_detail 比 get_order 好)、描述写清三件事(做什么+何时用+何时不该用)、工具职责单一(别又查又改)、参数说明到位(含义/格式/示例/反例,别用含糊的 id)、用严格 schema(类型/必填/枚举约束)、有副作用的特别标注(强调写操作+严格触发条件+高危人工确认)、运行时校验兜底(别完全信模型填的参数)、工具别太多(选择困难)。归根结底:工具定义是 Agent 的"工具使用手册"——名字清晰、描述写清"做什么+何时用+何时不用"、参数说明到位带示例、职责单一、严格 schema、副作用标注、运行时校验兜底;把它当 API 文档一样认真写,别让模型连蒙带猜。
第三件事:AI Agent 工具设计的其他常见坑
排查后我把 Agent 工具设计相关的其他常见坑也系统梳理了一遍。
AI Agent 工具设计的其他常见坑
# 1. 工具描述含糊/雷同(本文): 模型选错工具。→ 描述写清做什么+何时用+区别。
# 2. 参数说明不清: 模型填错参数。→ 参数写清含义/格式/示例, 名字明确, 严格schema。
# 3. 工具职责不单一: 一个工具又查又改, 模型难判断、且危险。→ 单一职责, 拆开。
# 4. 工具太多: 几十个工具模型选择困难、易混。→ 精简/分组/按场景动态提供子集。
# 5. 有副作用的工具没标注没确认: 模型可能误调退款/删除等。→ 标注副作用+严格触发+人工确认。
# 6. 完全信任模型填的参数: 不校验直接执行。→ 执行前做参数校验(当外部输入对待)。
# 7. 工具返回结果不友好: 返回一大坨原始数据, 模型难理解/塞爆context。→ 返回结构化、精炼的结果。
# 8. 工具失败没反馈: 工具执行失败没把错误信息返给模型, 它不知道该重试还是换法。→ 返回清晰的错误。
# 共同根源: 把Agent的能力寄托在"模型够聪明"上, 却忽视了"模型是基于你给的工具信息来行动的";
# 工具的定义、描述、参数、返回, 是模型行动的依据——这些信息的质量, 直接决定Agent的表现。
# 核心: 工具定义当API文档认真写(名字/描述/参数/示例/何时用); 职责单一、精简、严格schema、
# 副作用标注+确认、参数校验、返回精炼且带错误反馈; 给模型清晰的信息, 它才能做对的行动。
排查让我把 Agent 工具设计的其他坑也梳理清了。一、工具描述含糊/雷同(本文)。二、参数说明不清。三、工具职责不单一。四、工具太多(选择困难,分组/动态提供)。五、有副作用的工具没标注没确认。六、完全信任模型填的参数(执行前校验)。七、工具返回不友好(返回精炼结构化)。八、工具失败没反馈(返回清晰错误)。它们的共同根源是:把 Agent 的能力寄托在"模型够聪明"上,却忽视了"模型是基于你给的工具信息来行动的";工具的定义、描述、参数、返回是模型行动的依据,这些信息的质量直接决定 Agent 的表现。核心是:工具定义当 API 文档认真写;职责单一、精简、严格 schema、副作用标注+确认、参数校验、返回精炼且带错误反馈;给模型清晰的信息,它才能做对的行动。下面这张图,是这次工具定义不清坑的成因与解法:
第四件事:好工具定义的检查清单速查表
这次踩坑后,我把"一个好的 Agent 工具定义该满足什么"整理成一张清单表。
| 要素 | 反例 | 正例 |
|---|---|---|
| 名字 | get_order(含糊) | query_order_detail(动词+对象) |
| 描述-做什么 | "处理订单" | "查订单的商品/金额/状态" |
| 描述-何时用 | 没写 | "用户问订单内容时用" |
| 描述-何时不用 | 没写 | "不查物流/不退款" |
| 参数含义 | id: string | order_no: 订单号 形如 ORD... |
| 副作用标注 | 没标 | "写操作, 仅用户明确要求退款时用" |
这张清单把好工具定义的标准钉清了。核心是:一个好的工具定义,要让模型"无需猜测"就能准确判断"这个工具是不是我现在要用的、参数该填什么"——名字一看就懂、描述讲清做什么+何时用+何时不用、参数写明含义和格式、有副作用的特别标注;核心是把"模型需要知道才能正确使用"的信息,全部、清晰地提供给它。它给我的最大启发是:"给 AI 写工具定义",本质和"给人写清晰的接口文档/操作说明"是一回事——都是要站在使用者的角度,把'用对它所需的一切信息'清晰、无歧义地表达出来;"清晰的沟通/表达"这个能力,在 AI 时代不仅没贬值,反而更值钱了——因为你现在不仅要把事讲清楚给人,还要讲清楚给AI(prompt、工具描述、规则),而 AI 对"表达是否清晰"极其敏感。这让我重新认识了一项"软技能"的硬价值:在 AI Agent 时代,"把意图、规则、信息清晰准确地表达出来"的能力,成了一项核心的工程能力——无论是写 prompt、定义工具、还是设计 Agent 的行为约束,本质都是"用清晰的语言去精确地指挥 AI";"清晰表达 = 让 AI(和人)准确理解你的意图",而模糊的表达,会让再强的 AI 也偏离你的本意——"会清晰地表达",是驾驭 AI 的一项关键功夫。把工具定义当清晰的接口文档来写、重视 AI 时代清晰表达的硬价值——是这个坑带给我的认知。
第五件事:别把 Agent 的问题都归咎于"模型不够强"
这次最该反思的,是我一开始就把锅甩给了模型。我把"Agent 表现不好的常见原因"整理成表。
| 表现不好的原因 | 占比感受 | 解法方向 |
|---|---|---|
| 工具定义不清(本文) | 很常见 | 写清描述/参数 |
| prompt写得不好 | 很常见 | 优化prompt |
| 给的上下文/信息不足或太杂 | 常见 | 上下文工程 |
| 没有合适的工具可用 | 常见 | 补工具 |
| 流程/约束设计不当 | 常见 | 改编排/护栏 |
| 模型本身能力不够 | 较少是根因 | 换更强模型 |
这张表道出了一个常见的归因误区。核心是:当 Agent 表现不好时,"模型能力不够"往往不是最主要的原因;更常见的根因是我们这边的"工程"没做好——工具定义不清、prompt 不好、上下文不当、缺工具、流程设计差;这些"我们能控制、能优化"的因素,贡献了大部分的 Agent 问题。它给我的深刻启发是:面对 AI 系统表现不佳,有一种"甩锅给模型"的诱惑("是模型不行")——这很省事(反正不是我的错),但常常是错的、且让你错过了真正能改进的地方;因为模型是"给定的"(你换不换得起更强的另说),而"怎么用好这个模型"(工具、prompt、上下文、流程)才是你真正能掌控、能下功夫的地方;"把 Agent 的表现,更多地看成'我有没有把模型用好'的问题,而非'模型够不够强'的问题"。这给了我一种更有建设性的归因习惯:系统出问题时,先反求诸己——检查"我提供给它的信息、配置、约束、流程"是不是有问题,而不是急着把责任推给"不可控的外部因素"(模型、框架、运气)——因为"自己能改的部分",才是改进的真正杠杆;"遇到问题先找自己能控制的原因",不仅更可能找到真因,也让你始终握着"能让事情变好"的主动权。别轻易把 Agent 问题归咎于模型、先反求诸己检查自己能控制的工程因素——是这个坑带给我的归因认知。
第六件事:给 Agent 定义一个工具时,我现在的检查习惯
现在每当我给 Agent 定义一个工具,我都会按这张图把它过一遍:
这张图的精髓,是"名字清晰、描述讲清三件事、参数到位、副作用标注、校验兜底"。定义工具依次确认:名字一看就懂、描述讲清做什么+何时用+何时不用、参数含义格式示例齐全且严格 schema、有副作用就标注+严格触发+高危人工确认、执行前参数校验兜底。这套习惯,让我从"随手写个工具描述"变成了"把工具定义当接口文档认真写"——核心始终是:工具定义是 Agent 的说明书,要写清让模型不用猜,职责单一、副作用标注、参数校验。
我立下的几条规矩
这场"工具定义不清、Agent 乱用工具"的事故,换来了我做 Agent 时,刻进骨子里的几条铁律:
- 模型靠工具的描述和参数说明来选工具、填参数。它看不到工具实现。
- 工具名字清晰、带动词。query_order_detail 比 get_order 好。
- 描述讲清三件事:做什么、何时用、何时不用。尤其和相似工具的区别。
- 参数写清含义/格式/示例,用严格 schema。别用含糊的 id。
- 工具职责单一,有副作用的特别标注+严格触发+高危人工确认。
- 执行前对模型填的参数做校验。当外部输入对待,别完全信。
- Agent 表现不好先反求诸己。多半是工具/prompt/上下文,别轻易怪模型。
写在最后
回头看,这场由"工具描述写得含糊"引发的、Agent 乱用工具的事故,真正教给我的,远不止"工具定义要写清楚"这一个技巧。它让我对"当一个'智能体'表现不好时,问题常常不在它'笨',而在我没把'意图和信息'清楚地传达给它",有了一次刻骨的体会。我栽跟头,根源在于我把'沟通失败'误判成了'能力不足'。Agent 用错工具,我的第一反应是"这模型怎么这么笨"——我归咎于它的能力。可真相是:它一点都不笨,它只是没能从我含糊的工具说明书里,正确地理解我的意图;这不是"它理解能力差",而是"我表达得太差"——是一次'沟通'的失败,而非'能力'的失败。就像我给一个聪明的实习生一份烂手册,他做错了,错的是手册、不是他的智商。这让我领悟到一个在 AI 时代愈发重要的认知:当我们指挥一个"有理解能力的智能体"(无论是 AI 还是人)时,它的产出质量,极大程度上取决于我们"输入"给它的意图和信息的清晰度——"垃圾进,垃圾出(garbage in, garbage out)":你给的指令、信息、上下文越模糊,它的产出越可能跑偏;不是它不想做对,而是它无法从模糊的输入里,还原出你想要的那个清晰的意图;"很多'它没做对'的问题,根子是'我没说清'"。这给了我一种与智能体协作的根本自觉:想让 AI(或任何协作者)做对事,首先要逼自己把"要它做什么、怎么判断、有什么约束"想清楚、表达清楚——"清晰的意图"是"正确的产出"的前提;模糊的指挥,只会得到模糊的结果,然后你还误以为是对方能力不行;"把表达清楚、把信息给足,当成自己的责任",而不是指望对方去猜、再回过头怪对方猜错——这是高效协作(无论和人还是和 AI)的根本。认清 Agent 用错工具常是"我没说清"而非"它笨"、把清晰表达意图当成自己的责任——这,是我用一次工具定义不清的事故,换来的、关于 AI Agent、也关于如何与一切智能体高效协作的、最朴素也最深刻的领悟。如果这篇复盘,能让你下次给 Agent 加工具时,把描述和参数当一份认真的说明书来写,那我对着那个乱用工具的 Agent 排查的这段时间,就值了。
—— 别看了 · 2026