工具定义与 Schema:OpenAPI/Swagger 规范、JSON Schema 定义工具参数、工具描述与意图匹配

好,我们进入第二章。这一章聊的是工具调用的「身份证」——工具定义与 Schema。

说白了,AI Agent 要调用一个工具,它得先知道这个工具是干什么的、需要什么参数、返回什么结果。这些信息不能靠猜,得有一套标准化的描述语言。这就是 OpenAPI/Swagger 规范和 JSON Schema 要做的事。

我刚开始做 Agent 编排时,觉得工具定义不就是写个接口文档吗?后来发现,差之毫厘,谬以千里。一个参数类型写错,AI 可能就给你传个字符串当数组用,整个流程就崩了。

2.1 为什么需要标准化的工具定义?

想象一下,你让一个实习生去拿快递。你只说「去拿个东西」,他肯定懵。你得说清楚:去哪拿、拿什么、拿几个、什么时候拿回来。

AI Agent 也一样。它面对的不是人类,是 API。API 不会猜你的心思。所以我们需要一份精确的「说明书」。

核心价值:标准化工具定义 = 机器可读的契约。它让 AI 能自动理解工具的能力边界,避免「鸡同鸭讲」。

目前业界最通用的标准,就是 OpenAPI 规范(以前叫 Swagger)。它最初用于 RESTful API 的文档化,现在成了 AI Agent 工具定义的基石。

2.2 OpenAPI/Swagger 规范:工具的门面

OpenAPI 规范定义了一个工具(API)的三大要素:

  • 端点(Endpoint): 工具在哪?比如 GET /api/weather
  • 操作(Operation): 工具能做什么?比如查询天气
  • 参数(Parameter): 需要什么输入?比如城市名、日期

来看一个最简单的例子。这是一个查询天气的工具定义:

openapi: 3.0.0
info:
  title: 天气查询工具
  description: 根据城市名称获取当前天气信息
  version: 1.0.0
paths:
  /weather:
    get:
      summary: 获取指定城市的天气
      operationId: getWeather
      parameters:
        - name: city
          in: query
          required: true
          description: 城市名称,例如 "北京"
          schema:
            type: string
      responses:
        '200':
          description: 成功返回天气数据
          content:
            application/json:
              schema:
                type: object
                properties:
                  temperature:
                    type: number
                    description: 当前温度(摄氏度)
                  humidity:
                    type: number
                    description: 湿度百分比

这段 YAML 告诉 AI:

  • 工具名叫「天气查询工具」
  • 调用方式是 GET 请求,路径是 /weather
  • 必须传一个参数 city,类型是字符串
  • 返回的数据包含温度和湿度

嗯,这里要注意。很多初学者会忽略 operationId。我个人习惯给它起一个语义明确的名字,比如 getWeather 而不是 queryData。因为 AI 模型在意图匹配时,会优先看这个 ID 和 summary 字段。

2.3 JSON Schema:参数的精确约束

OpenAPI 里定义参数时,底层依赖的是 JSON Schema。它才是真正定义「参数长什么样」的硬规则。

JSON Schema 可以约束:

  • 类型: 字符串、数字、布尔值、数组、对象
  • 取值范围: 最小值、最大值、枚举值
  • 格式: 邮箱、日期、URI
  • 嵌套结构: 对象里的属性、数组里的元素类型

举个例子。假设我们要定义一个「创建订单」的工具,参数比较复杂:

{
  "type": "object",
  "properties": {
    "userId": {
      "type": "string",
      "description": "用户ID,格式为UUID",
      "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
    },
    "items": {
      "type": "array",
      "description": "订单商品列表",
      "minItems": 1,
      "maxItems": 50,
      "items": {
        "type": "object",
        "properties": {
          "productId": { "type": "string" },
          "quantity": { 
            "type": "integer", 
            "minimum": 1, 
            "maximum": 100 
          },
          "price": { "type": "number", "minimum": 0 }
        },
        "required": ["productId", "quantity", "price"]
      }
    },
    "shippingAddress": {
      "type": "object",
      "properties": {
        "province": { "type": "string" },
        "city": { "type": "string" },
        "detail": { "type": "string" }
      },
      "required": ["province", "city", "detail"]
    }
  },
  "required": ["userId", "items", "shippingAddress"]
}

我的经验: 参数描述越详细,AI 调用越准确。尤其是 description 字段,别写「用户ID」就完了。我会写成「用户唯一标识,从登录接口获取的 UUID 字符串」。AI 看到这个,就知道去哪找这个值。

2.4 工具描述与意图匹配:让 AI 听懂人话

定义好参数只是第一步。更难的是让 AI 知道「什么时候该用这个工具」。这就靠工具描述了。

工具描述是写给 AI 模型看的,不是给人看的。它决定了意图匹配的准确率。

来看一个对比:

描述方式 示例 AI 理解效果
太简单 查询天气 用户说「今天冷吗?」可能匹配不上
太啰嗦 这是一个用于查询天气的工具,它可以通过城市名称获取天气数据,包括温度、湿度、风速等 关键词分散,可能误匹配
精准描述 根据城市名称查询实时天气,返回温度、湿度、风力。适用于询问「今天天气怎么样」「冷不冷」「要不要带伞」等场景 高准确率匹配

我曾经踩过一个坑。有个工具描述写的是「发送邮件」,结果用户说「帮我发个通知」,AI 死活不调用这个工具。后来我把描述改成「发送邮件通知,支持文本和 HTML 内容,适用于发送系统通知、验证码、营销邮件等场景」,准确率直接翻倍。

避坑指南: 工具描述里不要写「如果……那么……」这种条件逻辑。AI 模型不是规则引擎,它靠语义理解。你写「当用户要求发送验证码时使用此工具」,不如直接写「发送验证码邮件」。把场景写进描述,而不是写逻辑。

2.5 知识结构:工具定义的核心要素

我把工具定义的核心要素整理成了一张表,方便你对照检查:

要素 说明 常见错误
工具名称 简短、唯一、语义化 用拼音或缩写,如 getWth
工具描述 包含触发场景、输入输出说明 只写功能,不写场景
参数定义 类型、格式、取值范围、是否必填 缺少 description,AI 不知道参数含义
返回结构 定义返回数据的 Schema 不定义返回结构,AI 无法解析结果
错误处理 定义可能的错误码和错误信息 忽略错误场景,AI 调用失败后不知所措

2.6 工具定义的整体流程

下面这张图展示了从需求到工具定义的完整链路:

工具定义与意图匹配流程 工具定义与意图匹配流程 需求分析 定义 OpenAPI JSON Schema 编写工具描述 意图匹配 参数填充 调用执行 💡 关键点: • 工具描述直接影响意图匹配的准确率,建议包含触发场景关键词 • JSON Schema 的 description 字段帮助 AI 理解参数含义,不要省略 • 返回结构定义让 AI 能正确解析结果,避免后续步骤出错

2.7 实战建议:如何写出高质量的工具定义

最后,分享几个我实际项目里总结出来的经验:

  1. 描述要「场景化」:别只写功能,写清楚用户在什么场景下会触发这个工具。比如「查询天气」不如「用户想知道今天要不要带伞、穿多少衣服时使用」。
  2. 参数名要「自解释」:用 cityName 而不是 c,用 startDate 而不是 sd。AI 模型对语义敏感,好的参数名能提升填充准确率。
  3. 枚举值要写全:如果参数只有固定几个选项,用 enum 列出来。比如天气工具的城市列表,写死支持的几个城市,AI 就不会乱传。
  4. 返回结构别偷懒:很多同学只定义请求参数,不定义返回结构。结果 AI 拿到返回数据后不知道怎么用。你想想看,它连返回字段叫什么都搞不清楚,怎么提取信息?

一个小技巧: 写完工具定义后,用自然语言描述一遍这个工具是干什么的,然后让 ChatGPT 或 Claude 根据你的描述去匹配。如果它匹配错了,说明你的描述需要优化。我每次上线新工具都会做这个测试,屡试不爽。