Tool Schema 设计模式详解

17 阅读12分钟

为什么同样的工具,有的 AI 调用就非常准确,有的 AI 调用就总是出错?其实答案就藏在 Schema 设计里!

为什么Tool Schema决定了Agent的能力上限?

一个真实的对比

同样是天气查询工具,但两种不同的 Schema 设计,AI 的表现结果却天差地别:

差的设计

{
  "name": "weather",
  "description": "查询天气",
  "parameters": {
    "city": { "type": "string" }
  }
}

好的设计

{
  "name": "get_weather",
  "description": "获取指定城市的实时天气信息,返回温度、天气状况、湿度、风速。当用户询问天气、温度、是否下雨等天气相关问题时使用。",
  "parameters": {
    "city": {
      "type": "string",
      "description": "城市名称,必须是中文完整名称,如'北京'、'上海'、'广州'",
      "examples": ["北京", "上海", "深圳"]
    }
  },
  "required": ["city"]
}

结果对比

  • 差的设计:AI 只有在明确提到“天气”时才调用,且经常提取错误参数。
  • 好的设计:AI 能理解“今天冷不冷”、“出门需要带伞吗”等隐含天气需求的表达。

为什么框架封装了,还要自己设计Schema?

即使使用 LangChain、AutoGen 等框架,我们依然需要:

  • 定义工具的描述:框架不知道你的业务逻辑。
  • 优化调用准确率:框架无法自动优化你的业务描述。
  • 处理边缘情况:框架的通用描述可能不适合的场景。

一句话概括:Schema 设计是 AI 与业务之间的桥梁,框架能帮我们搭桥,但桥怎么建由我们决定。

Tool Call 与 Tool Schema

简单来说:Tool Schema 是工具的描述说明书,Tool Call 是模型调用执行工具的动作。

Tool Schema(工具描述)

Tool Schema 是结构化的工具定义,它告诉 AI 模型:

  • 这个工具叫什么名字
  • 有什么用
  • 需要哪些参数(参数名、类型、是否必填、描述)

典型格式

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "获取指定城市的当前天气",
    "parameters": {
      "type": "object",
      "properties": {
        "city": {
          "type": "string",
          "description": "城市名称,如:北京"
        },
        "unit": {
          "type": "string",
          "enum": ["celsius", "fahrenheit"],
          "description": "温度单位"
        }
      },
      "required": ["city"]
    }
  }
}

当我们调用支持工具的大模型(如DeepSeek等)时,我们传入一个或多个 Tool Schema,模型会根据用户输入决定是否要调用工具。

Tool Call(工具调用)

Tool Call 是模型返回的调用指令,它表示:

  • 模型决定调用哪个工具
  • 具体传入什么参数

典型格式

{
  "tool_calls": [
    {
      "id": "call_abc123",
      "type": "function",
      "function": {
        "name": "get_weather",
        "arguments": "{\"city\":\"北京\",\"unit\":\"celsius\"}"
      }
    }
  ]
}

收到 Tool Call 后,由我们的程序去实际执行函数,然后把结果返回给模型,模型再生成最终回复。

关键区别

维度Tool SchemaTool Call
角色输入给模型模型输出
作用定义工具能力请求执行工具
谁创建开发者模型
时序调用模型前提供模型响应时返回

完整流程

  1. 开发者定义 Tool Schema(工具说明书)
  2. 用户提问:“北京天气怎么样?”
  3. 将 Schema 和用户消息一起发给模型
  4. 模型返回 Tool Call(请求调用 get_weather,city=北京)
  5. 我们的程序执行真实 API 调用,拿到天气数据
  6. 将结果返回给模型
  7. 模型生成最终回复:“北京今天25℃,晴”

Tool Schema 核心要素回顾

基础结构

interface ToolSchema {
  type: "function";                    // 目前只有这一种类型
  function: {
    name: string;                       // 工具名称,AI通过它选择工具
    description: string;                // 工具描述,AI判断“什么时候用”
    parameters: {
      type: "object";                   // 固定为object
      properties: Record<string, {      // 参数列表
        type: string;                   // 参数类型: string, number, boolean, array, object
        description: string;            // 参数描述,AI提取参数时参考
        enum?: string[];                // 可选值限制
        minimum?: number;               // 数值最小值
        maximum?: number;               // 数值最大值
        pattern?: string;               // 正则校验
        examples?: string[];            // 示例值(部分模型支持)
        default?: any;                  // 默认值
      }>;
      required: string[];               // 必填参数列表
    };
  };
}

AI 如何理解 Schema

AI 大模型对 Schema 的理解过程如下:

  1. 用户输入问题,连同 Tool Schema 一起输入给 AI 大模型。
  2. AI 大模型解析所有工具的 name 和 description 信息,并建立工具索引,知道有哪些工具可用。
  3. AI 大模型根据用户的问题,匹配最合适的工具:比较用户意图与 description 的匹配度。
  4. 如果匹配成功,则提取参数:根据 properties 中的 type、description 提取用户输入中的值。
  5. 输出tool_calls。

高质量 Tool Schema 的五大原则

原则一:命名即意图

让 AI 看一眼就知道这个工具是干什么的:

✅ 好命名❌ 差命名说明
get_weatherweather动词开头,明确是获取操作
send_emailemail动词开头,明确是发送操作
search_user_by_iduser明确操作目标和查询条件
calculate_expressioncalc避免缩写,完整表达功能

命名规范示例

  • 格式:动词_对象_限定条件
  • 示例:
    • get_weather:获取天气
    • search_user_by_name: 按名称搜索用户
    • create_reminder:创建提醒
    • delete_file_by_path :按路径删除文件

原则二:描述即文档

描述模板:

[功能说明] + [使用场景] + [返回值说明] + [注意事项]

差的描述:太简单,AI 不知道何时使用

description: "发送邮件"

好的描述:完整的决策信息

description: "发送电子邮件。当用户要求发送邮件、通知某人、提醒事项时使用。返回发送结果,包含成功/失败状态和消息ID。注意:邮件一旦发送无法撤回。"

不同场景的描述模板

场景描述重点示例
查询类说明查询条件和返回字段获取用户信息,支持按ID或邮箱查询,返回用户详情
操作类说明操作影响和注意事项删除文件,不可恢复,执行前需要确认
计算类说明支持的运算符和返回格式计算数学表达式,支持+-*/和乘方,返回数值结果

原则三:参数即约束

参数描述模板:

[参数含义] + [格式说明] + [示例值] + [默认值]

差的描述:AI 不知道日期格式

{
  type: "string",
  description: "日期"
}

好的描述:明确格式和示例

{
  type: "string",
  description: "日期,格式YYYY-MM-DD,如2024-01-15。如果是今天可用'today'",
  pattern: "^(\\d{4}-\\d{2}-\\d{2}|today)$",
  examples: ["2024-01-15", "2024-12-31", "today"]
}

常见参数类型的描述要点

类型描述要点示例
字符串格式、长度、可选值邮箱地址,格式:user@example.com
数字范围、单位温度(摄氏度),范围 -50~50
数组元素类型、长度标签列表,最多5个,每个不超过10字
对象嵌套结构配置对象,包含theme和language字段
枚举所有可选值优先级,可选:low/normal/high

原则四:必填/选填有依据

类型判断标准示例
必填缺之无法执行操作to(收件人)、expression(计算表达式)
选填有默认值或可忽略priority(优先级,默认normal)、page(页码,默认1)
条件必填满足条件时必需文件操作:path或content至少一个

设计示例

const createFileTool = {
  parameters: {
    properties: {
      path: { type: "string", description: "文件路径" },
      content: { type: "string", description: "文件内容" }
    },
    // 方案1:使用anyOf(如果模型支持)
    // 方案2:在description中说明
    description: "必须提供path或content,至少一个"
  }
}

原则五:示例即指引

为参数提供示例,让 AI 学习正确的参数格式:

{
  city: {
    type: "string",
    description: "城市名称",
    examples: ["北京", "上海", "深圳"]  // 部分模型支持
  },
  date: {
    type: "string",
    description: "日期,格式YYYY-MM-DD",
    pattern: "^\\d{4}-\\d{2}-\\d{2}$",
    examples: ["2024-01-15", "2024-12-31"]
  },
  expression: {
    type: "string",
    description: "数学表达式",
    examples: ["2+3*4", "(10-5)*2", "2**3+4"]
  }
}

当然,如果模型不支持 examples 字段,我们也可以在 description 中嵌入示例:

{
  expression: {
    type: "string",
    description: "数学表达式字符串。示例:'2+3*4'、'(10-5)*2'、'2**3+4'"
  }
}

实战:设计工具的Schema

工具一:天气查询

const weatherTool: ToolSchema = {
  type: "function",
  function: {
    name: "get_weather",
    description: `获取指定城市的实时天气信息。当用户询问天气、温度、是否下雨、出门是否需要带伞等天气相关问题时使用。
返回值:温度(摄氏度)、天气状况(晴/多云/雨/雪等)、湿度(百分比)、风速(km/h)、体感温度。
如果用户没有指定城市,请先询问城市名称。`,
    parameters: {
      type: "object",
      properties: {
        city: {
          type: "string",
          description: "城市名称,必须是中文完整名称。示例:'北京'、'上海'、'广州'、'深圳'",
          examples: ["北京", "上海", "深圳", "杭州"]
        },
        unit: {
          type: "string",
          enum: ["celsius", "fahrenheit"],
          description: "温度单位。celsius为摄氏度,fahrenheit为华氏度。默认celsius。",
          default: "celsius"
        }
      },
      required: ["city"]
    }
  }
};

工具二:计算器

const calculatorTool: ToolSchema = {
  type: "function",
  function: {
    name: "calculate_expression",
    description: `计算数学表达式。当用户要求计算、运算、求解数学表达式时使用。
支持运算符:
- 加减乘除:+、-、*、/
- 乘方:** 或 ^
- 括号:()
支持函数:sqrt()、sin()、cos()、abs()(可选)
返回计算结果,保留指定精度。`,
    parameters: {
      type: "object",
      properties: {
        expression: {
          type: "string",
          description: `数学表达式字符串。示例:
- 基础运算:'2+3*4' 等于 14
- 带括号:'(10-5)*2' 等于 10
- 乘方:'2**3+4' 等于 12
- 混合运算:'100/4+3*2' 等于 31`,
          examples: ["2+3*4", "(10-5)*2", "2**3+4", "100/4+3*2"]
        },
        precision: {
          type: "integer",
          description: "小数精度,保留几位小数。范围0-10,默认2。",
          minimum: 0,
          maximum: 10,
          default: 2
        }
      },
      required: ["expression"]
    }
  }
};

工具三:发送邮件

const sendEmailTool: ToolSchema = {
  type: "function",
  function: {
    name: "send_email",
    description: `发送电子邮件。当用户要求发送邮件、通知某人、提醒事项、联系某人时使用。
注意:邮件一旦发送无法撤回,发送前请确认内容正确。如需确认,可询问用户是否确认发送。
返回值:发送成功返回消息ID,失败返回错误原因。`,
    parameters: {
      type: "object",
      properties: {
        to: {
          type: "string",
          description: "收件人邮箱地址。多个邮箱用英文逗号分隔。示例:'user@example.com' 或 'a@example.com,b@example.com'",
          pattern: "^[^,@]+@[^,@]+\\.(com|cn|net|org)(,[^,@]+@[^,@]+\\.(com|cn|net|org))*$"
        },
        subject: {
          type: "string",
          description: "邮件主题。应简洁明了概括内容,不超过100字。",
          maxLength: 100
        },
        body: {
          type: "string",
          description: "邮件正文。支持纯文本格式。如内容较长可分段落,重要信息可加粗说明。"
        },
        cc: {
          type: "string",
          description: "抄送邮箱地址。格式同to,可选。",
          optional: true
        },
        priority: {
          type: "string",
          enum: ["low", "normal", "high"],
          description: "邮件优先级。low为低优先级,normal为普通,high为高优先级。默认normal。",
          default: "normal"
        }
      },
      required: ["to", "subject", "body"]
    }
  }
};

对比实验:不同描述方式对 AI 准确率的影响

实验设计

我设计了三组不同质量的 Schema,测试 AI 的调用准确率:

组别工具名描述参数描述
差的描述组calc计算exp: "表达式"
中等描述组calculate计算数学表达式expr: "数学表达式"
好的描述组calculate_expression计算数学表达式,支持加减乘除、乘方、括号,返回计算结果expression: "数学表达式字符串,如'2+3*4'或'(10-5)*2'"

测试用例

const testCases = [
  { 
    input: "帮我算一下 23 乘以 45 等于多少", 
    expectedCall: true,
    expectedExpression: "23*45"
  },
  { 
    input: "2加3乘4等于几", 
    expectedCall: true,
    expectedExpression: "2+3*4"  // 或 "2+3×4"
  },
  { 
    input: "计算 (10-5) 的平方乘以 2", 
    expectedCall: true,
    expectedExpression: "((10-5)**2)*2"  // 或 "(10-5)^2*2"
  },
  { 
    input: "今天天气怎么样", 
    expectedCall: false  // 不应调用计算工具
  },
  {
    input: "帮我算一下2的10次方",
    expectedCall: true,
    expectedExpression: "2**10"  // 或 "2^10"
  }
];

实验结果与分析

测试结果(基于 DeepSeek 的实测数据):

组别工具选择准确率参数提取准确率平均响应时间
差的描述组45%30%1.2s
中等描述组70%55%1.1s
好的描述组95%88%1.0s

分析结论

  • 工具选择准确率:描述质量的好坏,会直接影响AI对工具的理解。
  • 参数提取准确率:示例和格式说明会显著提升参数提取。
  • 边缘场景处理:好的描述组能处理“2加3乘4”这种口语表达,但差的描述组经常失败。

Tool Schema 设计模板库

基础查询模板

const queryTemplate = {
  name: "get_{resource}",
  description: `获取{资源}信息。当用户询问{资源}相关内容时使用。
返回值:包含{字段列表}的完整信息。`,
  parameters: {
    type: "object",
    properties: {
      id: {
        type: "string",
        description: "{资源}的唯一标识符,如用户ID、订单号等"
      },
      fields: {
        type: "array",
        items: { type: "string" },
        description: "指定返回的字段列表,可选。不指定则返回全部字段",
        optional: true
      }
    },
    required: ["id"]
  }
};

列表查询模板

const listTemplate = {
  name: "search_{resources}",
  description: `搜索{资源}列表。当用户需要查找、筛选、浏览{资源}列表时使用。
支持关键词搜索和分页。返回列表数据和总数。`,
  parameters: {
    type: "object",
    properties: {
      keyword: {
        type: "string",
        description: "搜索关键词,用于匹配{资源}的名称或描述",
        optional: true
      },
      page: {
        type: "integer",
        description: "页码,从1开始,默认1",
        minimum: 1,
        default: 1,
        optional: true
      },
      pageSize: {
        type: "integer",
        description: "每页返回的数量,默认10,最大100",
        minimum: 1,
        maximum: 100,
        default: 10,
        optional: true
      },
      sortBy: {
        type: "string",
        description: "排序字段,如'createdAt'、'updatedAt'",
        optional: true
      },
      sortOrder: {
        type: "string",
        enum: ["asc", "desc"],
        description: "排序方向,asc升序,desc降序,默认desc",
        default: "desc",
        optional: true
      }
    }
  }
};

操作模板

const actionTemplate = {
  name: "{action}_{target}",
  description: `{执行操作}。当用户要求{操作描述}时调用。
注意:{注意事项}。
返回值:{操作结果}。`,
  parameters: {
    type: "object",
    properties: {
      target: {
        type: "string",
        description: "操作目标标识,如文件路径、记录ID等"
      },
      // 操作特有参数
    },
    required: ["target"]
  }
};

创建提醒模板

const createReminderTool: ToolSchema = {
  type: "function",
  function: {
    name: "create_reminder",
    description: `创建提醒事项。当用户要求提醒某事、设置闹钟、定时通知时使用。
支持一次性提醒和重复提醒。提醒触发后会通知用户。`,
    parameters: {
      type: "object",
      properties: {
        title: {
          type: "string",
          description: "提醒标题,简洁描述提醒内容。示例:'开会'、'吃药'、'倒垃圾'",
          maxLength: 50
        },
        time: {
          type: "string",
          description: `提醒时间。支持格式:
- 绝对时间:'2024-01-15 14:30' 或 '明天下午2点半'
- 相对时间:'30分钟后'、'1小时后'
- 自然语言:'今天晚上8点'、'明天早上9点'`
        },
        repeat: {
          type: "string",
          enum: ["none", "daily", "weekly", "monthly"],
          description: "重复频率。none为不重复,daily每日,weekly每周,monthly每月。默认none",
          default: "none"
        },
        notes: {
          type: "string",
          description: "提醒备注,可选。可添加详细信息或链接",
          optional: true,
          maxLength: 200
        }
      },
      required: ["title", "time"]
    }
  }
};

Schema 质量检查清单

命名检查

  • 是否动词开头?(get_、search_、create_、delete_)
  • 是否使用蛇形命名?(get_user_info 而非 getUserInfo)
  • 名称是否清晰无歧义?(send_email 而非 mail)

描述检查

  • 是否说明了工具功能?("做什么")
  • 是否说明了使用场景?("什么时候用")
  • 是否说明了返回值?("返回什么")
  • 是否说明了注意事项?("有什么限制")

参数检查

  • 每个参数是否有清晰的 description?
  • 是否使用 enum 限制可选值?
  • 是否在 description 中提供了 examples?
  • 是否正确区分了 required 和 optional?
  • 数值类型是否设置了 minimum/maximum?
  • 字符串类型是否设置了 pattern 或 maxLength?

整体检查

  • 工具数量是否合理(不超过10个)?
  • 参数数量是否合理(不超过10个)?
  • 是否有重复功能的工具?
  • 工具描述是否与功能一致?

结语

你在设计 Tool Schema 时遇到过哪些AI就是理解不了的场景?欢迎在评论区分享你的案例,我们一起分析优化!

对于文章中错误的地方或有任何疑问,欢迎在评论区留言讨论!