第 19 章
Tool Search Tool:BM25 + 正则双引擎支持万级工具库的动态加载
第十九章:工具设计模式:参数 Schema、描述优化与类型约束
19.1 工具设计的重要性
工具定义的质量直接决定了 Claude 使用工具的准确性。一个描述模糊的工具会导致 Claude 在不合适的场景调用它,或者传入错误格式的参数。反之,精心设计的工具 Schema 能让 Claude 在复杂场景下做出正确判断。
工具设计有三个核心目标:
- 语义清晰:Claude 必须能从名称和描述中准确理解工具的用途和限制
- 参数约束完整:通过 JSON Schema 约束,最大化减少 Claude 传入无效参数的概率
- 错误容忍性:即使 Claude 传入略有偏差的参数,工具也能优雅处理
19.2 工具命名的最佳实践
命名规范
工具名称应遵循以下规则:
# 好的命名:动词_名词,语义清晰
good_names = [
"search_products", # 搜索产品
"create_invoice", # 创建发票
"get_user_profile", # 获取用户资料
"update_order_status", # 更新订单状态
"send_notification", # 发送通知
"calculate_shipping", # 计算运费
]
# 不好的命名:模糊或过于宽泛
bad_names = [
"process", # 处理什么?
"data", # 数据操作?
"helper", # 帮什么忙?
"do_thing", # 做什么事?
"api_call", # 调哪个 API?
]
避免名称冲突
当多个工具功能相近时,名称需要体现关键差异:
# 清晰区分搜索范围
tools_with_clear_scope = [
{
"name": "search_internal_knowledge_base",
"description": "在公司内部知识库中搜索文档和 FAQ。只包含已批准的内部文档。"
},
{
"name": "search_web",
"description": "通过搜索引擎搜索互联网上的公开信息。结果可能包含未经验证的内容。"
},
{
"name": "search_product_catalog",
"description": "在产品目录中搜索商品信息,包括价格、库存和规格。"
}
]
19.3 description 字段的优化策略
description 是工具设计中最容易被忽视却最重要的部分。它不只是人类可读的文档——它是 Claude 决定是否调用该工具的主要依据。
描述的五要素
一个好的工具描述应包含:
- 核心功能:工具做什么
- 使用场景:什么时候应该使用
- 输出格式:返回什么样的数据
- 限制说明:什么情况下不应使用
- 与相似工具的区别:如果有多个相关工具
# 示例:数据库搜索工具的优化描述
tool_with_optimized_description = {
"name": "search_customer_database",
"description": """在 CRM 系统中搜索客户记录。
【适用场景】
- 需要查找特定客户的联系方式、购买历史或账户状态
- 需要按条件筛选客户群体(如地区、消费金额、注册时间)
【返回数据】
返回匹配的客户记录列表,每条记录包含:customer_id、name、email、
phone、registration_date、total_purchases、status
【重要限制】
- 最多返回 100 条记录,超出时请使用 limit 参数控制
- 不包含已删除账户,如需查询请使用 search_deleted_customers 工具
- 搜索结果实时查询,不经过缓存
【与 search_orders 的区别】
此工具搜索客户信息,search_orders 工具搜索订单信息。如需同时查询,
先用此工具获取 customer_id,再传给 search_orders。""",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer", "default": 20}
},
"required": ["query"]
}
}
使用例子增强描述
在描述中加入具体例子,帮助 Claude 更准确理解参数格式:
{
"name": "parse_date_range",
"description": """解析用户描述的日期范围,返回标准格式的起止日期。
【参数 date_expression 示例】
- "最近一周" → {"start": "2026-04-21", "end": "2026-04-28"}
- "上个月" → {"start": "2026-03-01", "end": "2026-03-31"}
- "Q1 2026" → {"start": "2026-01-01", "end": "2026-03-31"}
- "2026年春节" → {"start": "2026-01-29", "end": "2026-02-04"}""",
"input_schema": {
"type": "object",
"properties": {
"date_expression": {
"type": "string",
"description": "用户输入的日期描述,支持自然语言"
},
"reference_date": {
"type": "string",
"description": "参考日期(ISO 8601 格式),用于解析相对日期如'昨天'。默认为今天。"
}
},
"required": ["date_expression"]
}
}
19.4 参数 Schema 的高级约束模式
基础类型与格式约束
advanced_schema_examples = {
"type": "object",
"properties": {
# 字符串格式约束
"email": {
"type": "string",
"format": "email",
"description": "用户邮箱地址"
},
"date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "日期,格式为 YYYY-MM-DD"
},
"phone": {
"type": "string",
"pattern": "^\\+?[1-9]\\d{6,14}$",
"description": "手机号码(国际格式)"
},
# 数值范围约束
"page_size": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 20,
"description": "分页大小"
},
"discount_rate": {
"type": "number",
"minimum": 0.0,
"maximum": 1.0,
"description": "折扣率,0.1 表示九折"
},
# 枚举约束
"order_status": {
"type": "string",
"enum": ["pending", "processing", "shipped", "delivered", "cancelled"],
"description": "订单状态"
},
# 数组约束
"tags": {
"type": "array",
"items": {"type": "string"},
"minItems": 1,
"maxItems": 10,
"uniqueItems": True,
"description": "标签列表,1-10个不重复标签"
},
# 字符串长度约束
"title": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "标题,不超过200个字符"
}
}
}
嵌套对象 Schema
nested_schema = {
"name": "create_shipping_order",
"description": "创建物流订单",
"input_schema": {
"type": "object",
"properties": {
"sender": {
"type": "object",
"description": "发件人信息",
"properties": {
"name": {"type": "string", "description": "姓名"},
"phone": {"type": "string", "description": "手机号"},
"address": {
"type": "object",
"properties": {
"province": {"type": "string"},
"city": {"type": "string"},
"district": {"type": "string"},
"street": {"type": "string"},
"postal_code": {"type": "string", "pattern": "^\\d{6}$"}
},
"required": ["province", "city", "street"]
}
},
"required": ["name", "phone", "address"]
},
"recipient": {
"type": "object",
"description": "收件人信息(结构与发件人相同)",
"properties": {
"name": {"type": "string"},
"phone": {"type": "string"},
"address": {
"type": "object",
"properties": {
"province": {"type": "string"},
"city": {"type": "string"},
"district": {"type": "string"},
"street": {"type": "string"},
"postal_code": {"type": "string"}
},
"required": ["province", "city", "street"]
}
},
"required": ["name", "phone", "address"]
},
"package": {
"type": "object",
"properties": {
"weight_kg": {"type": "number", "minimum": 0.1, "maximum": 50},
"dimensions": {
"type": "object",
"properties": {
"length_cm": {"type": "number"},
"width_cm": {"type": "number"},
"height_cm": {"type": "number"}
}
},
"declared_value": {"type": "number", "minimum": 0}
},
"required": ["weight_kg"]
}
},
"required": ["sender", "recipient", "package"]
}
}
oneOf / anyOf 条件 Schema
对于参数格式依赖其他参数的复杂场景:
conditional_schema = {
"name": "send_message",
"description": "通过不同渠道发送消息",
"input_schema": {
"type": "object",
"properties": {
"channel": {
"type": "string",
"enum": ["email", "sms", "wechat"],
"description": "发送渠道"
},
"recipient": {
"type": "string",
"description": "收件人:邮件填邮箱,短信填手机号,微信填 OpenID"
},
"content": {
"type": "string",
"description": "消息内容。短信不超过70字,邮件支持 HTML"
},
"subject": {
"type": "string",
"description": "邮件主题(仅 channel=email 时需要)"
}
},
"required": ["channel", "recipient", "content"],
# 条件约束:email 渠道时 subject 必填
"if": {
"properties": {"channel": {"const": "email"}}
},
"then": {
"required": ["subject"]
}
}
}
19.5 参数描述的优化技巧
描述参数时的常见错误
# 错误示例:描述过于简单
bad_parameter = {
"query": {
"type": "string",
"description": "查询字符串" # 太简单,Claude 不知道格式要求
}
}
# 正确示例:描述具体且完整
good_parameter = {
"query": {
"type": "string",
"description": """搜索关键词。支持以下语法:
- 普通关键词:直接输入,如 "iPhone 14"
- 精确匹配:用引号包围,如 '"苹果手机"'
- 排除词:用减号前缀,如 "手机 -二手"
- 字段搜索:用冒号分隔,如 "品牌:苹果"
最大长度 500 字符。""",
"maxLength": 500
}
}
通过描述引导参数选择
# 引导 Claude 在不确定时使用默认值
smart_defaults_tool = {
"name": "export_report",
"description": "导出数据报告",
"input_schema": {
"type": "object",
"properties": {
"format": {
"type": "string",
"enum": ["pdf", "excel", "csv", "json"],
"description": "导出格式。用户未指定时默认选择 pdf(适合查看);如果用户说要"处理数据"或"导入系统",选择 csv 或 excel。",
"default": "pdf"
},
"date_range": {
"type": "string",
"enum": ["today", "week", "month", "quarter", "year", "custom"],
"description": "时间范围。用户未指定时选择 month(最近30天)。",
"default": "month"
}
},
"required": ["format"]
}
}
19.6 工具组的设计模式
模式一:CRUD 工具组
对同一资源的增删改查应保持一致的命名和参数风格:
user_crud_tools = [
{
"name": "get_user",
"description": "通过 ID 获取单个用户的完整信息",
"input_schema": {
"type": "object",
"properties": {
"user_id": {"type": "string", "description": "用户 ID"}
},
"required": ["user_id"]
}
},
{
"name": "list_users",
"description": "列出用户,支持分页和过滤",
"input_schema": {
"type": "object",
"properties": {
"page": {"type": "integer", "minimum": 1, "default": 1},
"page_size": {"type": "integer", "minimum": 1, "maximum": 100, "default": 20},
"status": {"type": "string", "enum": ["active", "inactive", "all"], "default": "active"},
"search": {"type": "string", "description": "按姓名或邮箱搜索"}
}
}
},
{
"name": "create_user",
"description": "创建新用户账户",
"input_schema": {
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 1, "maxLength": 100},
"email": {"type": "string", "format": "email"},
"role": {"type": "string", "enum": ["admin", "editor", "viewer"], "default": "viewer"},
"send_welcome_email": {"type": "boolean", "default": True}
},
"required": ["name", "email"]
}
},
{
"name": "update_user",
"description": "更新用户信息。只传入需要修改的字段。",
"input_schema": {
"type": "object",
"properties": {
"user_id": {"type": "string", "description": "要更新的用户 ID"},
"name": {"type": "string", "minLength": 1, "maxLength": 100},
"email": {"type": "string", "format": "email"},
"role": {"type": "string", "enum": ["admin", "editor", "viewer"]},
"status": {"type": "string", "enum": ["active", "inactive"]}
},
"required": ["user_id"]
}
},
{
"name": "delete_user",
"description": "删除用户账户。此操作不可逆,请谨慎使用。删除前会自动转移该用户的所有资源。",
"input_schema": {
"type": "object",
"properties": {
"user_id": {"type": "string", "description": "要删除的用户 ID"},
"transfer_to_user_id": {
"type": "string",
"description": "将被删除用户的资源转移给此用户 ID(可选,不填则转移给系统管理员)"
}
},
"required": ["user_id"]
}
}
]
模式二:管道工具组
工具之间存在明确的依赖顺序:
pipeline_tools = [
{
"name": "upload_file",
"description": "上传文件,返回文件 ID。这是处理文件的第一步。",
"input_schema": {
"type": "object",
"properties": {
"file_path": {"type": "string", "description": "本地文件路径"},
"file_type": {"type": "string", "enum": ["csv", "excel", "json", "xml"]}
},
"required": ["file_path", "file_type"]
}
},
{
"name": "validate_file",
"description": "验证已上传文件的格式和数据完整性。需要先用 upload_file 获取 file_id。",
"input_schema": {
"type": "object",
"properties": {
"file_id": {"type": "string", "description": "由 upload_file 返回的文件 ID"},
"schema_id": {"type": "string", "description": "用于验证的 Schema ID(可选)"}
},
"required": ["file_id"]
}
},
{
"name": "import_file",
"description": "将验证通过的文件导入数据库。必须先通过 validate_file 验证。",
"input_schema": {
"type": "object",
"properties": {
"file_id": {"type": "string", "description": "由 upload_file 返回的文件 ID"},
"target_table": {"type": "string", "description": "目标数据表名"},
"conflict_strategy": {
"type": "string",
"enum": ["skip", "overwrite", "append"],
"default": "skip",
"description": "主键冲突时的处理策略"
}
},
"required": ["file_id", "target_table"]
}
}
]
19.7 用工具实现结构化输出
Tool Use 的一个重要用途是强制 Claude 输出结构化数据,而不是自由格式文本:
# 使用 tool_choice={"type": "tool"} 强制结构化输出
extraction_tool = {
"name": "extract_invoice_data",
"description": "从发票文本中提取结构化数据",
"input_schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"invoice_date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
"vendor_name": {"type": "string"},
"vendor_tax_id": {"type": "string"},
"total_amount": {"type": "number"},
"tax_amount": {"type": "number"},
"line_items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {"type": "string"},
"quantity": {"type": "number"},
"unit_price": {"type": "number"},
"total": {"type": "number"}
},
"required": ["description", "quantity", "unit_price", "total"]
}
}
},
"required": ["invoice_number", "invoice_date", "vendor_name", "total_amount"]
}
}
def extract_invoice(invoice_text: str) -> dict:
"""从发票文本提取结构化数据"""
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=[extraction_tool],
tool_choice={"type": "tool", "name": "extract_invoice_data"},
messages=[{
"role": "user",
"content": f"请从以下发票文本中提取数据:\n\n{invoice_text}"
}]
)
for block in response.content:
if block.type == "tool_use":
return block.input
raise ValueError("未能提取发票数据")
19.8 工具版本管理与向后兼容
随着系统演进,工具的 Schema 需要更新。以下是保持向后兼容的策略:
# 版本 1:只有 query 参数
tool_v1 = {
"name": "search_products",
"description": "搜索产品(v1)",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}
# 版本 2:添加新参数,保持 query 必填,新参数均有默认值
tool_v2 = {
"name": "search_products",
"description": "搜索产品。支持按类别过滤和价格范围筛选(v2)",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"},
"category": {
"type": "string",
"description": "产品类别(可选,不填则搜索全部类别)"
},
"min_price": {
"type": "number",
"description": "最低价格过滤(可选)"
},
"max_price": {
"type": "number",
"description": "最高价格过滤(可选)"
}
},
"required": ["query"] # 只有原有的必填参数
}
}
小结
高质量的工具设计是 Tool Use 系统成功的基础。核心原则是:
- 命名传达工具的动作和目标对象,避免歧义
- 描述包含使用场景、输出格式、限制条件和工具间差异
- Schema通过类型约束、枚举、范围限制,最大化减少无效参数传入
- 工具组保持一致的参数命名约定和结构风格
- 结构化输出场景优先使用
tool_choice: tool模式
下一章将探讨如何让 Claude 同时调用多个工具,实现并行处理的高效架构。