为什么同样的工具,有的 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 Schema | Tool Call |
|---|---|---|
| 角色 | 输入给模型 | 模型输出 |
| 作用 | 定义工具能力 | 请求执行工具 |
| 谁创建 | 开发者 | 模型 |
| 时序 | 调用模型前提供 | 模型响应时返回 |
完整流程
- 开发者定义 Tool Schema(工具说明书)
- 用户提问:“北京天气怎么样?”
- 将 Schema 和用户消息一起发给模型
- 模型返回 Tool Call(请求调用 get_weather,city=北京)
- 我们的程序执行真实 API 调用,拿到天气数据
- 将结果返回给模型
- 模型生成最终回复:“北京今天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 的理解过程如下:
- 用户输入问题,连同 Tool Schema 一起输入给 AI 大模型。
- AI 大模型解析所有工具的 name 和 description 信息,并建立工具索引,知道有哪些工具可用。
- AI 大模型根据用户的问题,匹配最合适的工具:比较用户意图与 description 的匹配度。
- 如果匹配成功,则提取参数:根据 properties 中的 type、description 提取用户输入中的值。
- 输出tool_calls。
高质量 Tool Schema 的五大原则
原则一:命名即意图
让 AI 看一眼就知道这个工具是干什么的:
| ✅ 好命名 | ❌ 差命名 | 说明 |
|---|---|---|
| get_weather | weather | 动词开头,明确是获取操作 |
| send_email | 动词开头,明确是发送操作 | |
| search_user_by_id | user | 明确操作目标和查询条件 |
| calculate_expression | calc | 避免缩写,完整表达功能 |
命名规范示例
- 格式:动词_对象_限定条件
- 示例:
- 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就是理解不了的场景?欢迎在评论区分享你的案例,我们一起分析优化!
对于文章中错误的地方或有任何疑问,欢迎在评论区留言讨论!