想象这样一个早晨:你从网上买了一台漂亮的咖啡机,快递拆开,里面没有说明书。你盯着密密麻麻的按钮,只能凭感觉乱按——结果喷了一身热水。这时你才意识到,那份薄薄的说明书才是机器的灵魂。 AI Agent 也一样。它不像人那样“看着像就会用”,它调用你开发的工具时,唯一的信息来源就是你写给它的那份“说明书”——工具描述。描述里写清楚了:这个工具是干什么的、需要哪些参数、会返回什么结果、怎么调用才正确。描述写得清楚,Agent 一击即中;写得含糊,Agent 就像面对没有说明书的咖啡机,乱猜一气,频频报错。 这篇文章,就带你学会怎么写一份让 Agent“一看就懂、一调就对”的工具描述——一份完美的“AI 版说明书”。

岗位关联

工具描述是 Agent 调用的起点和地基。写好它,你开发的工具才能真正被大模型稳定、准确地使用,是 Agent 应用开发者最核心的基本功之一。

目录
  1. 可视化演示
  2. 一、描述结构四要素
  3. 二、参数定义与约束
  4. 三、返回格式规范
  5. 四、调用示例编写
  6. 五、常见描述错误
  7. 六、最佳编写实践
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示工具描述的核心机制,通过输入/处理/存储/输出四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

工具描述:工具描述 工具描述结构规范与核心要素 参数类型定义与约束规范 核心机制可视化 工具描述整体架构与关键组件

一、描述结构四要素

拿到一份新家电的说明书,你最先翻到的一定是“产品功能”那一章:这台机器到底能干什么,适合什么场景。工具描述的第一段也是同理——先告诉 Agent“这个工具是做什么的、什么时候该用它”。比如“查询指定城市实时天气”,而不是“一个天气工具”,后者就像说明书上只写了“一台机器”四个字。

除了功能说明,一份完整的工具描述还包含另外三个层次:参数定义、返回格式、调用示例。这四件事对应 Agent 调用前的四个疑问:这个工具干嘛的?参数怎么传?结果长什么样?具体怎么调用?在 Function Calling(让大模型学会调用外部工具的机制)中,这些内容被组织成一个 JSON 结构,叫做工具 Schema——相当于把说明书整本压缩成一页纸。

就像说明书少了“注意事项”章节会让你踩坑,工具描述缺了任何一个要素,Agent 都会在某个环节卡壳。四要素齐了,这本“说明书”才算合格。

Q=w1×C+w2×P+w3×R+w4×EQ = w_1 \times C + w_2 \times P + w_3 \times R + w_4 \times E
工具描述的质量 Q,由四个维度加权求和得出:功能(C)、参数(P)、返回(R)、示例(E)。
  1. 质量分数 Q代表一份工具描述的整体完整度,分数越高,Agent 调用越可靠。
    QQ
  2. 功能覆盖度 C工具的用途、适用场景是否写得清楚明确。
    CC
  3. 参数完整度 P参数的类型、必填性、取值范围是否都交代了。
    PP
  4. 返回清晰度 R返回结构、字段含义、错误码是否一目了然。
    RR
  5. 示例丰富度 E是否提供了典型调用示例,让 Agent 有样学样。
    EE
  6. 权重 w每个维度的贡献比例,其中参数和示例通常权重最高。
    wi>0w_i > 0

二、参数定义与约束

说明书翻到“按键说明”那一页,每个按钮旁边都得标清楚:这是干什么用的、怎么按、能不能不按、按到什么程度算合适。参数的写法,就是把每个按钮的说明翻译给 Agent 听。

在工具 Schema 里,每个参数都要声明几点:类型是字符串还是数字,是否必填,取值范围有哪些,默认值是什么。比如“温度单位”这个参数,你写“字符串”还不够——Agent 还是会猜“摄氏度”“华氏度”“K”哪个才对;你要写明它只能取 celsius 或 fahrenheit 二选一。这就是给参数画了一个“圈”,把 Agent 的选择限制在合法区域内。

说明书里每个按键都标注清楚,“这是个旋钮,左转减小、右转加大,只能转到 1-5 档”——Agent 照着操作自然不出错。参数约束越明确,Agent 的“误操作”就越少。

Dallowed={v∣min⁡≤v≤max⁡}D_{\text{allowed}} = \{v \mid \min \le v \le \max \}
参数的合法取值域 D,是一个闭区间:下界 min 到上界 max 之间的值才允许传入。
  1. 合法取值域 D所有允许传入的参数值构成的集合,越界即为非法。
    DallowedD_{\text{allowed}}
  2. 参数值 v用户或 Agent 实际传入的某个具体数值。
    vv
  3. 下界 min参数允许的最小值,比如“温度不低于 -50”。
    min⁡\min
  4. 上界 max参数允许的最大值,比如“温度不高于 60”。
    max⁡\max
  5. 集合约束如果描述里不写范围,Agent 会以为任何值都合法,传一个荒谬的数字进来。
    v∈[min⁡,max⁡]v \in [\min, \max]

三、返回格式规范

家电说明书通常会有一个“指示灯说明”小表格:绿灯常亮表示正常运行,红灯闪烁表示故障,不同故障还有对应编号。工具描述里的返回格式说明,就是给 Agent 的“指示灯说明”。

Agent 调用工具后拿到返回数据,它需要判断:这次调用到底成功没有?数据里哪个字段是温度、哪个是天气?如果失败了,该如何向用户解释、该不该重试?如果描述里只说“返回查询结果”,Agent 面对一团乱麻,只能瞎猜——就像看说明书找不到“红灯闪两下是什么意思”。所以返回结构要写清楚:成功时返回哪些字段、字段类型是什么、失败时错误码和错误信息长什么样。

就像指示灯“一绿一红”让你一眼知道机器状态,清晰的返回格式让 Agent 拿到结果后能果断决定下一步:解析数据、向用户汇报,还是礼貌地道歉重试。模糊的返回说明,等于把 Agent 扔进一个没有指示灯的机房。

resp∈{ok, err},err↦(code, message)\text{resp} \in \{ \text{ok},\ \text{err} \},\quad \text{err} \mapsto (\text{code},\, \text{message})
返回结果要么是成功(ok),要么是失败(err);失败时,必须给出错误码和可读的错误信息。
  1. 返回结果 resp工具每次执行后返回给 Agent 的数据包。
    resp\text{resp}
  2. 成功分支 ok结构固定且字段完整,Agent 可直接解析使用。
    ok\text{ok}
  3. 失败分支 err一旦失败,返回体必须进入错误通道。
    err\text{err}
  4. 错误码 code机器可读的数字编号,如 404 表示“城市不存在”。
    code\text{code}
  5. 错误信息 message人能看懂的描述,Agent 可以原样转述给用户。
    message\text{message}

四、调用示例编写

说明书里最受欢迎的永远是“快速上手”那一页:三步带你把咖啡拉花做出来。纯文字描述再准确,也不如一个完整例子让人醍醐灌顶。对 Agent 来说,这个“例子”就是调用示例。

调用示例不是摆设,它相当于一种“模仿学习”素材——学术上叫 few-shot(给模型看几个输入输出对,它就能照着规律举一反三)。比如描述“查询天气工具”时附上一个示例:传入 {"city":"北京"},返回 {"temp":18,"weather":"晴"}。Agent 看了这个例子,就知道了三件事:参数写成什么格式、返回长什么样、字段代表什么含义。示例越贴近真实场景,Agent 学得越快。

图文并茂比通篇理论更让人心安,Agent 也一样。多写几个好例子,胜过在文字描述里反复强调“请一定传对参数”——行动示范比说教管用。

P(success∣E)>P(success∣∅)P(\text{success} \mid E) > P(\text{success} \mid \emptyset)
拥有示例 E 时调用成功的概率,高于没有任何示例时(空集)的成功概率。
  1. 成功概率 PAgent 在一次真实调用中做对全部步骤的可能性。
    P(success)P(\text{success})
  2. 条件分支 E工具描述中附带了典型调用示例的情况。
    ∣E\mid E
  3. 条件分支 ∅描述中没有任何示例的“裸奔”情况。
    ∣∅\mid \emptyset
  4. 不等关系示例对成功率有明显增益,本质是让 Agent 少走猜弯路。
    >>

五、常见描述错误

你一定见过这种“翻车说明书”:写着“按任意键继续”,其实只有底部小按钮可用;或者首页印满品牌故事,关键参数却藏在角落里。工具描述里的错误,往往也长这样。

最常见的四种坑,踩中任何一个都会让 Agent 抓狂。第一种是表述模糊——“处理数据”这种话等于没说,处理什么数据、怎么处理、达成什么效果,一概不知,Agent 只能干瞪眼。第二种是参数遗漏——没写类型、没标必填、没给范围,Agent 猜一个传进去,工具当场报错。第三种是过度冗长——把背景故事、实现原理全塞进来,真正关键的信息被淹没,大模型读起来反而抓住了错误重点。第四种是参数幻觉——描述里写的参数,工具后端根本没有实现,Agent 照描述传参,就像说明书承诺“支持语音控制”而机器压根没有麦克风。

一份翻车的说明书会被用户扔进垃圾桶,一份翻车的工具描述则会让 Agent 反复报错、让用户反复重试。写描述时,多问自己一句:“这句话,另一个完全不知情的人能看懂吗?”能,才过关。

H(S)=−∑ipilog⁡piH(S) = -\sum_{i} p_i \log p_i
信息熵 H 衡量描述的不确定性:描述越模糊笼统,Agent 理解的不确定性(熵)越高。
  1. 信息熵 H描述文本带给 Agent 的不确定程度,熵越高越迷茫。
    H(S)H(S)
  2. 概率 pᵢAgent 猜测“描述含义是第 i 种可能”的概率,可能越多越分散。
    pip_i
  3. 求和符号把所有可能情况的不确定性累加起来。
    ∑i\sum_{i}
  4. 对数项单一可能(p 接近 1)时对数值为 0,熵最小,描述最明确。
    −log⁡pi-\log p_i

六、最佳编写实践

顶级说明书作者有个共同点:他们永远蹲在“第一次用这台机器的人”的视角写,绝不假设读者懂任何背景。给 Agent 写工具描述,请把自己想象成在给一个空白的机器人讲步骤。

基于这个视角,有四条心法值得内化成习惯。第一,站在 Agent 的角度——描述要回答“什么情况下用我”,而不是炫耀“我有多强大”。第二,简明扼要——每句话都有信息量,不写废话,不被冗余淹没重点。第三,持续迭代——工具描述不是一锤子买卖,Agent 在真实场景里调用失误了,就回来打磨措辞,像产品经理迭代文案一样。第四,自动化测试验证——准备一批典型问题,每次改完描述就跑一遍回归,看 Agent 是否都能正确触发工具,用数据说话。

说明书大师不会写完就撒手不管,他会找几个真正的用户试读,看哪里还会按错,然后反复修订。工具描述同样需要“试读”——不过这次的读者是 Agent,而“试读报告”就是那一条条真实调用日志。把描述当成产品来打磨,Agent 才会越用越顺手。

Score=1N∑i=1NI[correct(f,ti)]\text{Score} = \frac{1}{N} \sum_{i=1}^{N} \mathbb{I}[\text{correct}(f, t_i)]
回归测试得分 Score:用 N 个测试用例分别跑一遍,每通过一个记 1 分,取平均。
  1. 平均分数 Score描述质量在测试集上的最终量化结果。
    Score\text{Score}
  2. 测试数量 N准备的真实调用测试用例总数。
    NN
  3. 求和累加逐个统计 N 个用例的通过情况。
    ∑i=1N\sum_{i=1}^{N}
  4. 示性函数 𝕀用例通过时记 1,失败记 0,像考官打勾画叉。
    I[correct(f,ti)]\mathbb{I}[\text{correct}(f, t_i)]

AI 应用场景

场景一:智能客服的订单查询助手

阶段:工具调用与信息检索

解决的问题:传统客服机器人只能回答话术库里的固定问题,遇到“我的快递到哪了”这类需要查实时数据的问题就无能为力。通过一个“查询订单物流”工具,配上清晰的工具描述——参数 order_id(字符串、必填、11 位数字)、返回结构(状态码 + 物流轨迹数组),Agent 就能准确调用查询接口并把结果转述给用户。

具体案例:用户在淘宝式电商平台问“订单 202501011234 到哪了”,Agent 看到工具描述中写明参数必填和格式要求,自动从对话中提取订单号并调用工具,返回“已到本市中转站”,用户无需再打人工客服。

场景二:数据分析助手的 SQL 查询工具

阶段:意图理解与结构化查询生成

解决的问题:业务人员不懂 SQL,又需要从数据库里取数。给 Agent 配一个“表格查询工具”,描述里写清参数 table_name 的可选枚举值(只能查白名单内的几张表)、filters 的 JSON 格式和示例,Agent 就能把自然语言“上个月华东区销售额”翻译成正确的查询参数。

具体案例:数据分析师说“帮我看下 5 月华东区订单总量”,Agent 依据工具描述中枚举约束,锁定 table_name="orders"、filters={"region":"华东","month":5},一次调用成功返回聚合结果,全程不需要人写一行 SQL。

Python 演示

python80 行
import jsonfrom typing import Any, Dict, List REQUIRED_FIELDS = ["name", "description", "parameters"]  def validate_tool_description(schema: Dict[str, Any]) -> List[str]:    """检查工具描述是否包含 Agent 调用所需的必要信息."""    errors = []    for field in REQUIRED_FIELDS:        if field not in schema:            errors.append("缺少必要字段: " + field)    if "parameters" not in schema:        return errors     params_obj = schema["parameters"]    if params_obj.get("type") != "object":        errors.append("parameters.type 应为 object")     props = params_obj.get("properties", {})    required_list = params_obj.get("required", [])    for name, meta in props.items():        if "type" not in meta:            errors.append("参数 [" + name + "] 缺少 type")        if "description" not in meta:            errors.append("参数 [" + name + "] 缺少 description")    for name in required_list:        if name not in props:            errors.append("required 中声明了未定义的参数 [" + name + "]")     if "examples" not in schema or not isinstance(schema["examples"], list):        errors.append("建议提供调用示例 examples, 帮助 Agent 理解用法")    return errors  def print_report(schema: Dict[str, Any]) -> None:    """打印可读的检查报告."""    errors = validate_tool_description(schema)    print("工具: " + schema.get("name", "(未命名)"))    if errors:        for e in errors:            print("  [x] " + e)    else:        print("  [ok] 工具描述合格, Agent 可以放心调用!")  GOOD_SCHEMA = {    "name": "query_weather",    "description": "查询指定城市当前天气状况, 返回温度与天气类型.",    "parameters": {        "type": "object",        "properties": {            "city": {"type": "string", "description": "城市名称, 例如: 北京, 上海."},            "unit": {                "type": "string",                "enum": ["celsius", "fahrenheit"],                "description": "温度单位, 默认 celsius."            }        },        "required": ["city"]    },    "examples": [        {"input": {"city": "北京"}, "output": {"temp": 18, "weather": "晴"}}    ]} BAD_SCHEMA = {    "name": "do_stuff",    "description": "处理数据.",    "parameters": {        "type": "object",        "properties": {            "stuff": {"description": "要处理的东西"}        }    }} if __name__ == "__main__":    print_report(GOOD_SCHEMA)    print_report(BAD_SCHEMA)
目的:一个工具描述健康检查器,自动检查功能说明、参数类型、必填声明和调用示例是否齐全,把“说明书质量”变成机器可判定的结果。
  1. REQUIRED_FIELDS = [...]定义工具描述必含的首要字段,相当于说明书不能缺封面。
  2. for field in REQUIRED_FIELDS:逐一核对必要字段是否都存在。
  3. params_obj.get("type") != "object"参数容器必须是 object 类型,否则 Agent 无法按名取参。
  4. if "type" not in meta:每个参数都必须有类型标注,缺失则提示。
  5. "type": "string", "enum": [...]用枚举约束把参数“圈”进合法范围。
  6. if "examples" not in schema缺少调用示例时给出温和提醒,鼓励提供示范。
  7. print_report(GOOD_SCHEMA)用合格样例验证检查器输出 “合格”。
  8. print_report(BAD_SCHEMA)用模糊描述样例展示如何揪出问题。

常见误区

误区觉得工具描述要“字多才专业”,把背景故事、实现原理、团队历史全写进去,以为大模型读得越多懂得越多。

正解大模型读描述时会平均分配注意力,冗余信息会稀释关键内容,甚至让 Agent 抓住一个无关细节去执行。好的描述像机场指示牌:字少、信息密度高、指向明确。能一句话说清的,绝不写两段。

为何常见:人们习惯用“篇幅”衡量用心程度,忘了描述的目标读者是追求效率的 AI,而不是逐字品读的人类。

误区认为只要标注了类型,Agent 就能正确传参,比如日期参数写 `string` 就完了。

正解string 只说了“这是字符串”,没说格式。日期到底是 2025-01-01 还是 20250101?枚举值有哪些?范围多大?描述里必须继续写清 format、enum、min、max 等约束,否则 Agent 只能自由发挥,传个牛头不对马嘴的格式回来。

为何常见:人一看“字符串”就自然知道写什么,误以为 Agent 也有这种常识,忽略了它本质是一个逐字读说明书的呆板执行者。

误区觉得只要工具实现了,返回什么交给 Agent 现场发挥就行,不写返回结构也不写错误码。

正解Agent 解析一行不知道结构的 JSON,就像看没有图例的仪表盘——每个数字都认识,但不知道含义。成功时字段是什么类型,失败时错误码和 message 在哪,都必须写清楚,Agent 才能决定继续解析还是转人工。

为何常见:开发者自己熟悉接口返回格式,产生了“别人也懂”的错觉,忘记了 Agent 唯一的了解渠道就是描述文本。

误区认为功能说明和参数定义写全了,调用示例是锦上添花甚至多此一举。

正解示例是给 Agent 的“标准答案示范”,质量再高的文字描述也替代不了。一个真实的输入输出对,同时示范了参数拼接格式、返回体结构和字段用法,等于给 Agent 画了一张完整路线图,成功率显著提升。实践中缺示例的描述,Agent 首次调用往往要试错好几次。

为何常见:人习惯了抽象理解,但机器学习本质上更依赖具体样例,写描述的人容易低估“照葫芦画瓢”的力量。

面试题

Q1. 工具描述在 AI Agent 中扮演什么角色?

单选题 · easy

  • A.让用户界面看起来更美观
  • B.帮 Agent 理解工具的使用方法← 正确答案
  • C.让程序运行速度变得更快
  • D.自动修复代码中各种缺陷

答案:B。工具描述是给 Agent 的“说明书”,核心作用是让 Agent 理解工具的功能、参数和返回格式。界面美观、运行速度、代码修复都和描述无关。Agent 不是靠看界面猜功能的,它只靠描述文本。

Q2. 参数定义中 type 字段负责什么?

单选题 · easy

  • A.声明参数的数据类型例如 string← 正确答案
  • B.设置按钮显示时的颜色值
  • C.规定页面元素的排列顺序
  • D.决定工具返回多少条结果

答案:A。type 声明参数的数据类型,如字符串、整数、布尔值,这是参数约束的第一道“圈”。它不负责界面样式、页面布局或返回数量,那些都由工具自身逻辑决定。

Q3. 调用示例相当于说明书里的什么?

单选题 · easy

  • A.封面上的出版社信息
  • B.演示操作步骤的图文教程← 正确答案
  • C.售后服务电话的号码
  • D.包装箱上的生产日期

答案:B。调用示例好比说明书里的“快速上手”图文教程,给出输入和对应输出,Agent 照着例子就能学会怎么用。出版社信息、售后电话、生产日期都和“教你怎么用”无关。

Q4. 工具描述没有写清返回格式,会导致什么?

单选题 · mid

  • A.Agent 无法解析结果并决定下一步← 正确答案
  • B.工具执行速度大幅下降变慢
  • C.服务器内存直接溢出崩溃
  • D.用户无法登录管理后台

答案:A。返回格式是 Agent 判断成功失败、提取数据的依据。没写清返回结构,Agent 拿到 JSON 也只能干瞪眼。它不影响执行速度,也不会导致内存溢出或登录问题,那些是工具实现层面的事。

Q5. “参数幻觉”指的是哪种现象?

单选题 · mid

  • A.模型想象出根本不存在的参数并传参← 正确答案
  • B.参数描述字体太小导致看不清楚
  • C.参数默认值为空字符串没有填
  • D.参数列表顺序随机变换不固定

答案:A。参数幻觉指描述里写了后端不存在的参数,或描述太模糊让模型脑补出无中生有的参数,传过去后工具直接报错。它和字体、默认值、列表顺序都无关,是描述与实现脱节导致的。

Q6. 以下哪项最符合高质量工具描述的风格?

单选题 · mid

  • A.处理一些用户提交的数据
  • B.查询城市实时天气并返回温度← 正确答案
  • C.做各种各样有用的事情
  • D.功能很多,自行查看文档吧

答案:B。高质量描述要具体到“做什么、输入什么、输出什么”。“查询城市实时天气并返回温度”信息密度高、边界清晰。其余选项笼统含糊,甚至把理解成本推给 Agent,都属于典型反面教材。

Q7. 必填参数漏写在 required 列表中会怎样?

单选题 · hard

  • A.Agent 认为可选取而漏传参数← 正确答案
  • B.参数名自动变成大写字母
  • C.工具描述无法通过格式校验
  • D.参数值会被强制加密存储

答案:A。required 列表是 Agent 判断“哪些参数必须传”的唯一依据。漏写了,Agent 就以为该参数可选,可能不传,工具执行时因缺参报错。它不会改大小写,也不会触发格式校验或加密,那些不在描述语义范围内。

Q8. 迭代工具描述时,最可靠的做法是什么?

单选题 · extreme

  • A.每次修改后用真实用例回归验证← 正确答案
  • B.让 UI 设计师检查文案是否美观
  • C.把描述加密后存进远程数据库
  • D.只在发布新版本时简单看一眼

答案:A。描述改的是“文字”,影响的是“调用行为”,所以必须用真实用例去测回归效果。美观审查、加密存储、发布时看一眼都无法验证 Agent 是否真的调用正确,只有跑用例才行。

Q9. 一份完整工具描述应包含哪些部分?

多选题 · mid

  • A.工具功能用途的说明← 正确答案
  • B.参数类型与约束的定义← 正确答案
  • C.返回数据的结构和错误码← 正确答案
  • D.公司内部财务审计报表

答案:ABC。四要素中的功能、参数、返回是必备项,加上调用示例更佳。财务审计报表和 Agent 调用毫无关系,属于把无关内容塞进描述的反面示范。

Q10. 以下哪些属于工具描述的常见编写错误?

多选题 · hard

  • A.功能描述过于笼统模糊← 正确答案
  • B.参数缺少类型与取值范围← 正确答案
  • C.示例与真实返回结构不一致← 正确答案
  • D.描述文件采用 JSON 结构存储

答案:ABC。笼统描述、参数缺约束、示例与真实返回对不上,都会误导 Agent,属于高频错误。用 JSON 承载描述是行业标准做法,是正确的工程实践,不是错误。