智能体工具构建器
Agent 工具构建师 (Agent Tool Builder)
工具是 AI Agent 与世界交互的方式。一个设计良好的工具,决定了 Agent 是能高效工作,还是会产生幻觉、静默失败,或者消耗比必要多 10 倍的 Token。
本技能涵盖了从 Schema 到错误处理的工具设计全过程。包括 JSON Schema 最佳实践、真正能帮助 LLM 的描述编写、验证机制,以及正成为 AI 工具通用语言的 MCP 标准。
核心洞察:工具描述比工具实现更重要。LLM 永远看不到你的代码——它只能看到 Schema 和描述。
原则
- 为了提高 LLM 的准确率,描述质量 > 实现质量
- 尽量将工具数量控制在 20 个以内——过多会导致混淆
- 每个工具都需要明确的错误处理——静默失败会损害 Agent 的性能
- 返回字符串而非对象——LLM 处理的是文本
- 执行前设置验证关卡——拒绝、修复或升级,绝不静默失败
- 使用 LLM 测试工具,而不仅仅是单元测试
能力
- agent-tools (Agent 工具)
- function-calling (函数调用)
- tool-schema-design (工具 Schema 设计)
- mcp-tools (MCP 工具)
- tool-validation (工具验证)
- tool-error-handling (工具错误处理)
范围
- multi-agent-coordination $\rightarrow$ multi-agent-orchestration (多 Agent 协调 $\rightarrow$ 多 Agent 编排)
- agent-memory $\rightarrow$ agent-memory-systems (Agent 记忆 $\rightarrow$ Agent 记忆系统)
- api-design $\rightarrow$ api-designer (API 设计 $\rightarrow$ API 设计师)
- llm-prompting $\rightarrow$ prompt-engineering (LLM 提示 $\rightarrow$ 提示工程)
工具链
标准
- JSON Schema - 使用场景:所有工具定义。注:工具 Schema 的通用格式。
- MCP (Model Context Protocol) - 使用场景:构建可复用的跨平台工具。注:Anthropic 推出的开放标准,已被广泛采用。
框架
- Anthropic SDK - 使用场景:基于 Claude 的 Agent。注:Beta 版工具运行器处理了大部分复杂性。
- OpenAI Functions - 使用场景:基于 OpenAI 的 Agent。注:使用 strict 模式以保证 Schema 的绝对合规。
- Vercel AI SDK - 使用场景:多供应商工具处理。注:抽象了不同供应商之间的差异。
- LangChain Tools - 使用场景:基于 LangChain 的 Agent。注:可将 MCP 工具转换为 LangChain 格式。
模式
工具 Schema 设计
为工具创建清晰、无歧义的 JSON Schema。
使用场景:为 Agent 定义任何新工具时。
工具 Schema 最佳实践:
1. 详细的描述(最重要)
""" 错误示例 - 太模糊: { "name": "get_stock_price", "description": "获取股票价格", "input_schema": { "type": "object", "properties": { "ticker": {"type": "string"} } } }正确示例 - 全面详尽:
{
"name": "get_stock_price",
"description": "检索给定股票代码的当前股价。股票代码必须是 NYSE 或 NASDAQ 等美国主要证券交易所上市公司的有效代码。返回最新的美元交易价格。当用户询问当前或近期股价时使用。本工具不提供历史数据、公司信息或预测。",
"input_schema": {
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "股票代码,例如苹果公司的 AAPL。"
}
},
"required": ["ticker"]
}
}
"""
2. 参数描述
""" 每个参数都需要包含:- 它是什么
- 期望的格式
- 示例值
- 边界情况/限制
{
"location": {
"type": "string",
"description": "城市和州/国家。格式:美国请使用 'City, State'(例如 'San Francisco, CA'),国际请使用 'City, Country'(例如 'Tokyo, Japan')。请勿使用邮编或坐标。"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位。若未指定,则默认为用户所在地区的设置。美国用户使用 'fahrenheit',其他用户使用 'celsius'。"
}
}
"""
3. 尽可能使用 Enums
""" Enums 可将 LLM 限制在有效值范围内:"priority": {
"type": "string",
"enum": ["low", "medium", "high", "critical"],
"description": "任务优先级"
}
"action": {
"type": "string",
"enum": ["create", "read", "update", "delete"],
"description": "要执行的 CRUD 操作"
}
"""
4. 必填 vs 可选
""" 明确标注哪些是必填项:{
"type": "object",
"properties": {
"query": {...}, // 必填
"limit": {...}, // 可选,带默认值
"offset": {...} // 可选
},
"required": ["query"],
"additionalProperties": false // 严格模式
}
"""
带有输入示例的工具
使用示例引导 LLM 调用工具
适用场景:包含嵌套对象或对格式敏感输入的复杂工具
工具使用示例 (Anthropic Beta 功能):
"""
示例向 Claude 展示了 Schema 无法表达的具体模式。
在复杂操作中,可将准确率从 72% 提升至 90%。
"""
{
"name": "create_calendar_event",
"description": "创建日历事件,支持可选的参会者和提醒",
"input_schema": {
"type": "object",
"properties": {
"title": {"type": "string", "description": "事件标题"},
"start_time": {
"type": "string",
"description": "ISO 8601 日期时间,例如 2024-03-15T14:00:00Z"
},
"duration_minutes": {"type": "integer", "description": "事件时长(分钟)"},
"attendees": {
"type": "array",
"items": {"type": "string"},
"description": "参会者的电子邮件地址"
}
},
"required": ["title", "start_time", "duration_minutes"]
},
"input_examples": [
{
"title": "团队站会",
"start_time": "2024-03-15T09:00:00Z",
"duration_minutes": 30,
"attendees": ["[email protected]", "[email protected]"]
},
{
"title": "快速沟通",
"start_time": "2024-03-15T14:00:00Z",
"duration_minutes": 15
},
{
"title": "项目评审",
"start_time": "2024-03-15T16:00:00-05:00",
"duration_minutes": 60,
"attendees": ["[email protected]"]
}
]
}
示例设计原则:
- 使用真实数据,而非占位符
- 展示最小化、部分填充和完整定义的模式
- 保持简洁:每个工具提供 1-5 个示例
- 侧重于模糊场景
工具错误处理
返回有助于 LLM 恢复的错误信息
适用场景:任何可能失败的工具
错误处理最佳实践:
返回具有信息量的错误
""" 错误示例: {"error": "Failed"} {"error": true}正确示例:
{
"error": true,
"error_type": "not_found",
"message": "在天气数据库中未找到地点 'Atlantis'。请提供真实的城市名称,例如 'San Francisco, CA'。",
"suggestions": ["San Francisco, CA", "Los Angeles, CA"]
}
"""
Anthropic 工具结果错误示例
""" { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "Error: Location 'Atlantis' not found 在天气数据库中。 请提供一个真实的城市名称,例如 'San Francisco, CA'。", "is_error": true } """需要处理的错误类别
""" 1. 输入验证错误 - 缺失必要参数 - 格式无效 - 数值超出范围2. 外部服务错误
- API 不可用
- 触发频率限制 (Rate limited)
- 请求超时
3. 业务逻辑错误
- 资源未找到
- 权限被拒绝
- 冲突/重复
4. 内部错误
- 未预料的异常
- 数据损坏
"""
实现模式
""" from dataclasses import dataclass from typing import Union@dataclass
class ToolResult:
success: bool
content: str
error_type: str = None
suggestions: list[str] = None
def to_response(self) -> dict:
if self.success:
return {"content": self.content}
return {
"content": f"Error ({self.error_type}): {self.content}",
"is_error": True
}
def get_weather(location: str) -> ToolResult:
# 验证输入
if not location or len(location) < 2:
return ToolResult(
success=False,
content="Location must be at least 2 characters",
error_type="validation_error"
)
try:
data = weather_api.fetch(location)
return ToolResult(
success=True,
content=f"Temperature: {data.temp}°F, Conditions: {data.conditions}"
)
except LocationNotFound:
return ToolResult(
success=False,
content=f"Location '{location}' not found",
error_type="not_found",
suggestions=weather_api.suggest_locations(location)
)
except RateLimitError:
return ToolResult(
success=False,
content="Weather service rate limit exceeded. Try again in 60 seconds.",
error_type="rate_limit"
)
except Exception as e:
return ToolResult(
success=False,
content=f"Unexpected error: {str(e)}",
error_type="internal_error"
)
"""
MCP 工具模式
使用 Model Context Protocol 构建工具
适用场景:创建可复用的跨平台工具
MCP 工具实现:
"""
MCP (Model Context Protocol) 是 Anthropic 推出的开放标准,用于
将 AI 智能体连接到外部系统。一次构建,随处使用。
"""
基础 MCP 服务器 (TypeScript)
""" import { Server } from "@modelcontextprotocol/sdk/server"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";const server = new Server({
name: "weather-server",
version: "1.0.0"
});
// 定义工具
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "get_weather",
description: "获取指定地点的当前天气。返回
温度、天气状况和湿度。适用于关于特定城市的
天气查询。",
inputSchema: {
type: "object",
properties: {
location: {
type: "string",
description: "城市和州/省,例如 'San Francisco, CA'"
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
default: "fahrenheit"
}
},
required: ["location"]
}
}
]
}));
// 处理工具调用
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_weather") {
try {
const weather = a
wait fetchWeather(args.location, args.unit);
return {
content: [
{
type: "text",
text: JSON.stringify(weather)
}
]
};
} catch (error) {
return {
content: [
{
type: "text",
text: Error: ${error.message}
}
],
isError: true
};
}
}
throw new Error(Unknown tool: ${name});
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
"""
MCP 优势
"""- 跨 LLM 供应商的通用兼容性
- 可复用的工具库
- 支持 Streaming 和 SSE 传输
- 内置的可观测性
- 工具访问控制
Tool Runner 模式
使用 SDK tool runners 进行自动处理
适用场景:构建无需手动管理的工具循环
TOOL RUNNER (Anthropic SDK Beta):
"""
Tool runner 自动处理工具调用循环:
- 当 Claude 调用工具时执行该工具
- 管理对话状态
- 处理错误重试
- 提供流式传输支持
"""
Python 示例
""" import anthropic from anthropic import beta_toolclient = anthropic.Anthropic()
@beta_tool
def get_weather(location: str, unit: str = "fahrenheit") -> str:
'''获取指定地点的当前天气。
Args:
location: 城市和州,例如 San Francisco, CA
unit: 温度单位,'celsius' 或 'fahrenheit'
'''
# 实现代码
return json.dumps({"temperature": "72°F", "conditions": "Sunny"})
@beta_tool
def search_web(query: str) -> str:
'''在网络上搜索信息。
Args:
query: 搜索查询词
'''
# 实现代码
return json.dumps({"results": [...]})
Tool runner 处理循环
runner = client.beta.messages.tool_runner( model="claude-sonnet-4-5", max_tokens=1024, tools=[get_weather, search_web], messages=[ {"role": "user", "content": "What's the weather in Paris?"} ] )处理每条消息
for message in runner: print(message.content[0].text)或直接获取最终结果
final = runner.until_done() """TypeScript 与 Zod
""" import { Anthropic } from '@anthropic-ai/sdk'; import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod'; import { z } from 'zod';const anthropic = new Anthropic();
const getWeatherTool = betaZodTool({
name: 'get_weather',
description: 'Get the current weather in a given location',
inputSchema: z.object({
location: z.string().describe('City and state, e.g. San Francisco, CA'),
unit: z.enum(['celsius', 'fahrenheit']).default('fahrenheit')
}),
run: async (input) => {
// 类型安全的输入!
return JSON.stringify({temperature: '72°F'});
}
});
const runner = anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5',
max_tokens: 1024,
tools: [getWeatherTool],
messages: [{ role: 'user', content: "What's the weather in Paris?" }]
});
for await (const message of runner) {
console.log(message.content[0].text);
}
"""
并行工具执行
同时运行多个工具
适用场景:可以并行运行的独立工具调用
PARALLEL TOOL EXECUTION:
"""
默认情况下,Claude 可以在一次响应中调用多个工具。
这大大降低了独立操作的延迟。
"""
处理并行结果
"""Claude 返回多个 tool_use 块:
response.content = [ {"type": "text", "text": "I'll check both locations.. ."}, {"type": "tool_use", "id": "toolu_01", "name": "get_weather", "input": {"location": "San Francisco, CA"}}, {"type": "tool_use", "id": "toolu_02", "name": "get_weather", "input": {"location": "New York, NY"}}, {"type": "tool_use", "id": "toolu_03", "name": "get_time", "input": {"timezone": "America/Los_Angeles"}}, {"type": "tool_use", "id": "toolu_04", "name": "get_time", "input": {"timezone": "America/New_York"}} ]并行执行
import asyncioasync def execute_tools_parallel(tool_uses):
tasks = [execute_tool(t) for t in tool_uses]
return await asyncio.gather(*tasks)
results = await execute_tools_parallel(tool_uses)
在单个用户消息中返回所有结果(至关重要!)
tool_results = [ {"type": "tool_result", "tool_use_id": "toolu_01", "content": "72°F, Sunny"}, {"type": "tool_result", "tool_use_id": "toolu_02", "content": "45°F, Cloudy"}, {"type": "tool_result", "tool_use_id": "toolu_03", "content": "2:30 PM PST"}, {"type": "tool_result", "tool_use_id": "toolu_04", "content": "5:30 PM EST"} ]正确:所有结果在一条消息中
messages.append({"role": "user", "content": tool_results})错误:分多条消息发送(会破坏并行执行模式)
messages.append({"role": "user", "content": [tool_results[0]]})
messages.append({"role": "user", "content": [tool_results[1]]})
"""鼓励并行工具调用
""" 在系统提示词中添加: "为了最大限度提高效率,每当你需要执行多个独立操作时,请同时调用所有相关工具,而非顺序调用。" """禁用并行调用(必要时)
""" response = client.messages.create( model="claude-sonnet-4-5", tools=tools, tool_choice={"type": "auto", "disable_parallel_tool_use": True}, messages=messages ) """验证检查
工具描述必须详尽
严重程度:WARNING
工具描述应至少 100 个字符
消息:工具描述太短。请添加关于使用场景、参数和返回值的详细信息。
必须提供参数描述
严重程度:WARNING
每个参数都应有描述
消息:参数缺失描述。请描述其含义及预期格式。
Schema 应指定必填字段
严重程度:INFO
明确定义哪些字段是必填的
消息:Schema 未指定必填字段。请添加 'required' 数组。
工具实现需要错误处理
严重程度:ERROR
工具函数应处理异常
消息:工具函数缺少 try/except 块。请添加错误处理。
错误结果需要 is_error 标志
严重程度:WARNING
返回错误时,将 is_error 设置为 true
消息:错误结果缺少 is_error 标志。请添加 'is_error': true。
工具应返回字符串
严重程度:WARNING
返回 JSON 字符串,而非字典/对象
消息:返回了字典而非字符串。请使用 json.dumps() 或 JSON.stringify()。
工具应验证输入
严重程度:WARNING
在执行前验证 LLM 提供的输入
消息:工具函数没有可见的输入验证。请在执行前进行验证。
SQL 查询必须使用参数化
严重程度:ERROR
绝不要将用户输入直接拼接进 SQL
消息:SQL 查询似乎使用了字符串拼接。请使用参数化查询。
外部调用需要超时设置
严重程度:WARNING
HTTP 请求和外部调用应设置超时时间
消息:外部 API 调用缺少超时设置。请添加 timeout 参数。
MCP T
工具必须包含输入模式 (Input Schema)严重程度:错误 (ERROR)
所有 MCP 工具都需要 inputSchema
消息:MCP 工具定义缺失 inputSchema。
协作
委派触发条件
- 用户需要协调多个工具 ->
multi-agent-orchestration(跨智能体的工具编排)
- 用户需要在工具调用之间保持持久化记忆 ->
agent-memory-systems(工具状态管理)
- 用户正在构建语音智能体工具 ->
voice-agents(音频/语音特定工具要求)
- 用户需要计算机控制工具 ->
computer-use-agents(桌面自动化工具)
- 用户想要测试其工具 ->
agent-evaluation(工具测试与评估)
相关技能
可与以下技能协同工作:multi-agent-orchestration, api-designer, llm-architect, backend
使用场景
- 用户提到或暗示:智能体工具 (agent tool)
- 用户提到或暗示:函数调用 (function calling)
- 用户提到或暗示:工具模式 (tool schema)
- 用户提到或暗示:工具设计 (tool design)
- 用户提到或暗示:MCP 服务器 (mcp server)
- 用户提到或暗示:MCP 工具 (mcp tool)
- 用户提到或暗示:工具使用 (tool use)
- 用户提到或暗示:为智能体构建工具 (build tool for agent)
- 用户提到或暗示:定义函数 (define function)
- 用户提到或暗示:
input_schema
- 用户提到或暗示:
tool_use
- 用户提到或暗示:
tool_result
局限性
- 仅在任务明确符合上述范围时使用此技能。
- 不要将输出视为环境特定验证、测试或专家评审的替代方案。
- 如果缺失必要的输入、权限、安全边界或成功标准,请停止并请求澄清。