文章摘要
系统讲解 AI Agent 工具调用的完整技术栈:从 Function Calling 基础原理到 MCP 协议标准,从单工具调用到多工具自主编排。涵盖架构设计、错误处理、容错机制、实战代码,以及 2026 年最新进展。
一、为什么 Agent 需要工具调用?
LLM 的本质局限:强大的语言理解,但缺乏行动能力。 大语言模型(LLM)在文本理解、推理、生成方面表现出色,但它们本质上只是"文字接龙"——根据输入预测下一个 token。这种架构决定了 LLM 有几个致命缺陷:
第一,知识截止问题。 LLM 的训练数据有截止日期,无法获取实时信息。GPT-4 的知识截止到 2023 年,Claude 3.5 的知识截止到 2024 年初。如果你问"今天北京的天气"或"最新的股票价格",纯 LLM 要么胡编乱造(幻觉),要么拒绝回答。
第二,无法执行动作。 LLM 可以告诉你如何发送邮件,但它自己不能发邮件。它可以写出查询数据库的 SQL,但它不能直接执行这条 SQL。LLM 被困在"只能说,不能做"的困境中。
第三,计算能力有限。 让 LLM 计算 1234 × 5678,它可能会出错。让 LLM 分析一个 10MB 的 CSV 文件,它根本做不到。LLM 不擅长精确计算和大规模数据处理。
第四,幻觉问题。 LLM 会编造事实、虚构引用、捏造数据。在没有外部验证机制的情况下,LLM 的输出不可完全信任。
工具调用:让 LLM 从"能说"到"能做"。 工具调用(Tool Use / Function Calling)是解决上述问题的关键机制。通过工具调用,LLM 可以:
- 获取实时信息:调用天气 API 获取当前天气,调用搜索引擎获取最新新闻
- 执行动作:发送邮件、创建文件、调用支付接口、操作数据库
- 精确计算:调用计算器、执行代码、运行数据分析脚本
- 验证事实:查询数据库、检索知识库、调用事实核查工具
2026 年的 Agent 工具调用现状: 根据 Anthropic 2026 年 6 月发布的递归自我改进报告,Claude 在生产环境中已经承担了80% 的代码编写工作。这些代码编写任务不仅仅是生成代码片段,而是包括调用 API、操作数据库、部署服务等完整的工具链操作。工具调用已经成为 Agent 的核心能力,没有工具调用的 Agent 就像没有手脚的大脑——能思考,但无法改变世界。
💡 一句话理解
设计 Agent 时,先列出 Agent 需要完成的任务,然后为每个任务设计对应的工具。工具是 Agent 与真实世界的桥梁。
⚠️ 常见踩坑
不要给 LLM 太多工具。工具过多会导致选择困难、调用错误、上下文爆炸。先从小而精的工具集开始,逐步扩展。
二、Function Calling 的演进
2023 年 6 月:OpenAI 开创 Function Calling。 OpenAI 在 GPT-3.5/4 API 中首次引入 Function Calling 机制。核心思想:开发者定义一组函数的 JSON Schema,LLM 在需要时输出函数调用请求,由外部执行后将结果返回给 LLM。
OpenAI Function Calling 的工作流程:
- 开发者在 API 请求中定义可用函数(名称、描述、参数 Schema)
- LLM 根据对话上下文决定是否调用函数
- 如果需要调用,LLM 输出函数名和参数(JSON 格式)
- 外部系统执行函数,获取结果
- 将结果返回给 LLM,LLM 基于结果生成最终回复
2023 年下半年:Anthropic 和 Google 跟进。 Anthropic 在 Claude 2/3 中引入 Tool Use,Google 在 Gemini 中引入 Function Calling。虽然名称不同,但核心机制类似:定义工具 Schema → LLM 决策调用 → 外部执行 → 结果返回。
关键差异:
- OpenAI:支持并行函数调用(parallel function calling),可以一次调用多个函数
- Anthropic:强调工具描述的重要性,提供更细粒度的工具控制
- Google:将 Function Calling 与 Google Cloud 生态深度集成
2024-2025 年:开源生态爆发。 LangChain、LlamaIndex、AutoGen 等框架提供了统一的工具调用接口,屏蔽了不同 LLM 提供商的差异。开发者可以编写一次工具定义,在 GPT-4、Claude、Gemini、Llama 之间无缝切换。
2026 年的工具调用趋势:
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
// 1. 定义工具 Schema
const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
{
type: "function",
function: {
name: "get_weather",
description: "获取指定城市的当前天气信息",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称,例如:北京、上海",
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "温度单位",
},
},
required: ["city"],
},
},
},
{
type: "function",
function: {
name: "search_flights",
description: "搜索航班信息",
parameters: {
type: "object",
properties: {
from: { type: "string", description: "出发城市" },
to: { type: "string", description: "到达城市" },
date: { type: "string", description: "日期 YYYY-MM-DD" },
},
required: ["from", "to", "date"],
},
},
},
];
// 2. 调用 LLM,传入工具定义
const response = await openai.chat.completions.create({
model: "gpt-4-turbo",
messages: [
{
role: "user",
content: "北京今天天气怎么样?我想明天飞去上海。",
},
],
tools: tools,
tool_choice: "auto", // LLM 自主决定是否调用工具
});
// 3. 处理工具调用请求
const message = response.choices[0].message;
if (message.tool_calls) {
// LLM 请求调用工具
for (const toolCall of message.tool_calls) {
const functionName = toolCall.function.name;
const functionArgs = JSON.parse(toolCall.function.arguments);
// 4. 执行工具(这里调用真实的 API)
const result = await executeTool(functionName, functionArgs);
// 5. 将结果返回给 LLM
const finalResponse = await openai.chat.completions.create({
model: "gpt-4-turbo",
messages: [
...messages,
message,
{
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify(result),
},
],
tools: tools,
});
console.log(finalResponse.choices[0].message.content);
}
}💡 一句话理解
工具描述(description)的质量直接影响 LLM 的调用准确性。写清楚工具的功能、参数含义、使用场景,就像写 API 文档一样。
⚠️ 常见踩坑
不同 LLM 提供商的 Function Calling 实现有细微差异(参数命名、并行调用支持、错误处理)。生产环境务必做充分的兼容性测试。
三、工具调用的核心架构
工具调用系统的四个核心组件: 一个完整的工具调用系统包括:Schema 定义层、路由决策层、执行引擎层、结果回传层。
1. Schema 定义层(Tool Definition)
Schema 是工具的"身份证",告诉 LLM:这个工具叫什么、能做什么、需要什么参数、返回什么结果。
Schema 设计原则:
- 单一职责:每个工具只做一件事,不要设计"万能工具"
- 语义化命名:工具名和参数名要自解释(get_weather 而非 func_001)
- 完整描述:description 要详细说明功能、限制、使用场景
- 参数验证:使用 JSON Schema 定义参数类型、必填项、枚举值、范围限制
2. 路由决策层(LLM Router)
LLM 充当"路由器",根据用户请求和上下文决定:
- 是否需要调用工具?
- 调用哪个工具?
- 传递什么参数?
- 是否需要并行调用多个工具?
路由策略:
- 自主路由:LLM 完全自主决定(tool_choice: "auto")
- 强制路由:必须调用特定工具(tool_choice: {"type": "function", "function": {"name": "xxx"}})
- 无路由:禁用工具调用(tool_choice: "none")
3. 执行引擎层(Tool Executor)
执行引擎负责:
执行模式:
- 同步执行:等待工具返回结果(适合快速 API)
- 异步执行:立即返回任务 ID,稍后查询结果(适合耗时操作)
- 流式执行:工具执行过程中实时返回部分结果(适合长任务)
4. 结果回传层(Result Formatter)
工具执行结果需要格式化后返回给 LLM:
// 工具 Schema 定义最佳实践
const weatherToolSchema = {
type: "function",
function: {
name: "get_weather",
description: "获取指定城市的当前天气信息,包括温度、湿度、风速、天气状况。支持实时天气和未来 7 天预报。",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称,支持中文和英文,例如:北京、Beijing、上海",
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "温度单位:celsius(摄氏度)或 fahrenheit(华氏度),默认 celsius",
default: "celsius",
},
forecast_days: {
type: "integer",
description: "预报天数,0 表示当前天气,1-7 表示未来天数",
minimum: 0,
maximum: 7,
default: 0,
},
},
required: ["city"],
additionalProperties: false, // 禁止未定义参数
},
},
};💡 一句话理解
使用 JSON Schema 的完整特性(type、enum、minimum、maximum、required)来约束参数,减少 LLM 输出非法参数的概率。
⚠️ 常见踩坑
工具执行引擎必须做参数验证和沙箱隔离。LLM 可能被提示注入攻击诱导调用危险工具或传递恶意参数。
四、MCP(Model Context Protocol):2026 年的工具标准化
什么是 MCP? MCP(Model Context Protocol)是 Anthropic 在 2024 年底推出的开放标准协议,旨在统一 LLM 与外部工具/数据源的交互方式。可以把 MCP 理解为"AI 工具的 USB 接口"——无论什么工具,只要遵循 MCP 协议,就能被任何支持 MCP 的 Agent 使用。
为什么需要 MCP? 在 MCP 出现之前,每个 LLM 提供商都有自己的工具调用格式,每个工具集成都需要定制开发。这导致:
- 工具碎片化:为 GPT-4 开发的工具不能直接用于 Claude
- 重复开发:每个 Agent 框架都要重新实现工具集成
- 互操作性差:不同系统之间的工具无法共享
MCP 的核心架构:
MCP 采用客户端-服务器架构:
- MCP Client(客户端):嵌入在 Agent/LLM 应用中,负责连接 MCP Server
- MCP Server(服务器):封装具体的工具实现,对外暴露标准化的接口
- Resources(资源):MCP Server 提供的数据源(文件、数据库、API)
- Tools(工具):MCP Server 提供的可调用函数
- Prompts(提示词模板):MCP Server 提供的预定义提示词
MCP 的工作流程:
- Agent 启动时,连接到配置的 MCP Server
- MCP Server 暴露可用的工具和资源列表
- Agent 根据任务需求,通过 MCP 协议调用工具
- MCP Server 执行工具,返回标准化结果
- Agent 基于结果继续推理或生成回复
2026 年 MCP 生态现状:
- 主流 LLM 支持:Claude、GPT-4、Gemini、Llama 都已支持 MCP
- 工具市场:出现 MCP 工具市场(如 mcp.so),提供数千个预构建的 MCP Server
- 企业采用:越来越多的企业将内部系统封装为 MCP Server,供 Agent 调用
- 框架集成:LangChain、LlamaIndex、AutoGen 都提供 MCP 客户端实现
MCP vs Function Calling:
- Function Calling 是 LLM 级别的能力,由 LLM 提供商定义
- MCP 是应用级别的协议,独立于 LLM 提供商
- 关系:MCP 底层可以使用 Function Calling 实现,但 MCP 提供了更高层次的抽象(资源管理、提示词模板、安全认证)
import { Server } from '@modelcontextprotocol/sdk/server';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types';
// 创建 MCP Server
const server = new Server(
{
name: "weather-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {}, // 声明支持工具调用
},
}
);
// 注册可用工具列表
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_weather",
description: "获取指定城市的当前天气信息",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称",
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "温度单位",
},
},
required: ["city"],
},
},
{
name: "get_forecast",
description: "获取未来 7 天天气预报",
inputSchema: {
type: "object",
properties: {
city: { type: "string", description: "城市名称" },
days: {
type: "integer",
description: "预报天数(1-7)",
minimum: 1,
maximum: 7,
},
},
required: ["city"],
},
},
],
};
});
// 处理工具调用请求
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_weather") {
// 调用真实的天气 API
const weather = await fetchWeatherData(args.city, args.unit);
return {
content: [
{
type: "text",
text: JSON.stringify({
city: args.city,
temperature: weather.temp,
humidity: weather.humidity,
condition: weather.condition,
}),
},
],
};
}
if (name === "get_forecast") {
const forecast = await fetchForecast(args.city, args.days);
return {
content: [
{
type: "text",
text: JSON.stringify(forecast),
},
],
};
}
throw new Error(`Unknown tool: ${name}`);
});
// 启动服务器
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP Server is running...");
}
main().catch(console.error);五、多工具编排模式
从单工具到多工具:编排的必要性。 简单的 Agent 可能只需要调用一个工具就能完成任务。但复杂的现实场景往往需要多个工具协同工作。例如:"帮我查一下北京明天的天气,如果下雨就取消航班,否则预订最早的航班"——这个任务需要天气查询、条件判断、航班搜索、预订系统四个工具的协同。
多工具编排的四种模式:
1. 串行编排(Sequential Orchestration)
工具按固定顺序依次调用,前一个工具的输出作为后一个工具的输入。
适用场景:工作流固定的任务,如 ETL(提取-转换-加载)、数据处理管道。
优点:逻辑清晰、易于调试、可预测。
缺点:灵活性差、无法根据中间结果动态调整。
示例:获取天气 → 判断是否适合出行 → 查询航班 → 预订酒店
2. 并行编排(Parallel Orchestration)
多个工具同时调用,结果汇总后统一处理。
适用场景:多个独立子任务可以同时执行,如同时查询多个数据源。
优点:提升执行效率、减少总耗时。
缺点:需要处理结果合并、冲突解决。
示例:同时查询天气、航班、酒店价格 → 汇总后推荐最优方案
3. 条件分支编排(Conditional Branching)
根据某个工具的执行结果,决定下一步调用哪个工具。
适用场景:需要根据中间结果做决策的任务。
优点:灵活、能处理复杂逻辑。
缺点:分支逻辑复杂时难以维护。
示例:如果天气好 → 查询户外景点;如果天气差 → 查询室内景点
4. 动态选择编排(Dynamic Selection)
由 LLM 根据当前上下文自主决定调用哪个工具、调用顺序。
适用场景:任务目标明确但执行路径不固定,需要 Agent 自主决策。
优点:最灵活、能处理开放式任务。
缺点:LLM 可能做出错误决策、难以保证执行质量。
示例:用户说"帮我规划北京三日游",Agent 自主决定查询景点、餐厅、交通、天气等工具的顺序和内容。
2026 年的编排趋势:
// 多工具编排示例:旅行规划 Agent
interface ToolResult {
success: boolean;
data?: any;
error?: string;
}
// 1. 串行编排:依次调用工具
async function sequentialOrchestration(
tools: Array<{ name: string; args: any }>,
executeTool: (name: string, args: any) => Promise<ToolResult>
): Promise<ToolResult[]> {
const results: ToolResult[] = [];
for (const tool of tools) {
const result = await executeTool(tool.name, tool.args);
results.push(result);
if (!result.success) {
// 如果某个工具失败,可以选择中断或继续
break;
}
}
return results;
}
// 2. 并行编排:同时调用多个工具
async function parallelOrchestration(
tools: Array<{ name: string; args: any }>,
executeTool: (name: string, args: any) => Promise<ToolResult>
): Promise<ToolResult[]> {
const promises = tools.map(tool => executeTool(tool.name, tool.args));
return await Promise.all(promises);
}
// 3. 条件分支编排:根据结果决定下一步
async function conditionalOrchestration(
executeTool: (name: string, args: any) => Promise<ToolResult>
): Promise<ToolResult> {
// 第一步:查询天气
const weatherResult = await executeTool("get_weather", { city: "北京" });
if (!weatherResult.success) {
return weatherResult;
}
// 根据天气条件决定下一步
if (weatherResult.data.condition === "rain") {
// 如果下雨,查询室内景点
return await executeTool("search_attractions", {
city: "北京",
type: "indoor",
});
} else {
// 如果天气好,查询户外景点
return await executeTool("search_attractions", {
city: "北京",
type: "outdoor",
});
}
}
// 4. 动态选择编排:由 LLM 自主决策
async function dynamicOrchestration(
userRequest: string,
availableTools: string[],
llmDecide: (context: string, tools: string[]) => Promise<{
tool: string;
args: any;
shouldContinue: boolean;
}>,
executeTool: (name: string, args: any) => Promise<ToolResult>
): Promise<ToolResult[]> {
const results: ToolResult[] = [];
let context = userRequest;
let shouldContinue = true;
while (shouldContinue) {
// LLM 根据当前上下文决定下一步
const decision = await llmDecide(context, availableTools);
// 执行选定的工具
const result = await executeTool(decision.tool, decision.args);
results.push(result);
// 更新上下文
context += `\n工具 ${decision.tool} 执行结果: ${JSON.stringify(result)}`;
shouldContinue = decision.shouldContinue;
}
return results;
}💡 一句话理解
选择合适的编排模式:任务路径固定用串行,独立子任务用并行,需要决策用条件分支,开放式任务用动态选择。
六、工具调用的错误处理与容错
工具调用失败是常态,而非例外。 在真实的生产环境中,工具调用可能因为各种原因失败:网络超时、API 限流、参数错误、权限不足、服务宕机。一个健壮的 Agent 系统必须能够优雅地处理这些错误,而不是崩溃或给出误导性结果。
工具调用失败的常见类型:
1. 参数错误(Parameter Error)
2. 执行超时(Timeout)
- 工具执行时间过长,超过设定的超时阈值
- 原因:外部 API 响应慢、网络问题、工具实现低效
- 处理:设置合理的超时时间、重试机制、异步执行
3. API 限流(Rate Limiting)
- 调用频率超过 API 提供商的限制
- 原因:短时间内大量调用、未做速率控制
- 处理:实现指数退避重试、缓存结果、批量调用
4. 权限错误(Permission Error)
- Agent 没有调用某个工具的权限
- 原因:未配置访问令牌、权限范围不足
- 处理:检查权限配置、提示用户授权、降级到无需权限的工具
5. 服务不可用(Service Unavailable)
- 外部服务宕机或维护
- 原因:服务提供商故障、网络问题
- 处理:重试机制、备用服务切换、优雅降级
容错策略:
1. 重试机制(Retry)
- 对于临时性错误(网络超时、API 限流),自动重试
- 使用指数退避策略:第一次等待 1 秒,第二次 2 秒,第三次 4 秒
- 设置最大重试次数,避免无限重试
2. 降级策略(Fallback)
- 如果主工具失败,切换到备用工具
- 例如:主天气 API 失败 → 切换到备用天气 API → 返回缓存的天气数据
3. 错误隔离(Error Isolation)
- 单个工具失败不应导致整个任务失败
- 对于多工具任务,标记失败的工具,继续执行其他工具
4. 用户反馈(User Feedback)
- 工具失败时,向用户清晰说明原因和可选方案
- 不要隐藏错误或编造结果
5. 上下文管理(Context Management)
生产环境的最佳实践:
💡 一句话理解
为每个工具实现统一的错误处理包装器(wrapper),标准化错误格式和重试逻辑,避免在每个地方重复编写错误处理代码。
七、实战:构建一个多工具 Agent
实战目标:构建一个旅行规划 Agent。 这个 Agent 能够:
- 查询目的地天气
- 搜索航班和酒店
- 推荐景点和餐厅
- 根据用户偏好和预算做出个性化推荐
- 处理工具调用失败和异常情况
技术栈选择:
- LLM:Claude 3.5 Sonnet(支持 Tool Use)
- 框架:LangChain(提供工具编排和错误处理)
- 工具:天气 API、航班搜索 API、酒店预订 API、景点推荐 API
- 语言:TypeScript
架构设计:
第一步:定义工具 Schema
为每个外部 API 定义清晰的工具 Schema,包括名称、描述、参数。
第二步:实现工具执行引擎
封装每个 API 调用,处理认证、错误、重试。
第三步:实现编排逻辑
使用条件分支 + 动态选择的混合编排:
- 先查询天气(串行)
- 根据天气决定景点类型(条件分支)
- 并行查询航班和酒店(并行)
- 由 LLM 根据结果生成最终推荐(动态选择)
第四步:实现错误处理
为每个工具添加重试、降级、错误隔离。
第五步:集成测试
模拟各种场景:正常流程、工具失败、超时、权限错误。
关键代码实现:
下面的代码展示了一个完整的多工具 Agent 实现,包括工具定义、编排逻辑、错误处理。
import Anthropic from '@anthropic-ai/sdk';
import { z } from 'zod';
const anthropic = new Anthropic();
// 1. 定义工具 Schema
const tools = [
{
name: "get_weather",
description: "查询指定城市的天气信息,包括温度、天气状况、未来 3 天预报。",
input_schema: {
type: "object",
properties: {
city: { type: "string", description: "城市名称" },
date: { type: "string", description: "日期 YYYY-MM-DD,默认为今天" },
},
required: ["city"],
},
},
{
name: "search_flights",
description: "搜索航班信息,返回价格和时刻表。",
input_schema: {
type: "object",
properties: {
from: { type: "string", description: "出发城市" },
to: { type: "string", description: "到达城市" },
date: { type: "string", description: "出发日期 YYYY-MM-DD" },
budget: { type: "number", description: "预算上限(元)" },
},
required: ["from", "to", "date"],
},
},
{
name: "search_hotels",
description: "搜索酒店信息,返回价格、评分、设施。",
input_schema: {
type: "object",
properties: {
city: { type: "string", description: "城市名称" },
checkin: { type: "string", description: "入住日期 YYYY-MM-DD" },
checkout: { type: "string", description: "退房日期 YYYY-MM-DD" },
budget_per_night: { type: "number", description: "每晚预算上限(元)" },
},
required: ["city", "checkin", "checkout"],
},
},
{
name: "recommend_attractions",
description: "推荐景点,支持按类型筛选(户外/室内/文化/美食)。",
input_schema: {
type: "object",
properties: {
city: { type: "string", description: "城市名称" },
type: {
type: "string",
enum: ["outdoor", "indoor", "culture", "food"],
description: "景点类型",
},
count: {
type: "integer",
description: "推荐数量,默认 5",
default: 5,
},
},
required: ["city"],
},
},
];
// 2. 工具执行引擎(带错误处理和重试)
async function executeTool(
name: string,
args: any,
maxRetries = 3
): Promise<{ success: boolean; data?: any; error?: string }> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
// 根据工具名调用对应的 API
switch (name) {
case "get_weather":
return await executeWeatherAPI(args);
case "search_flights":
return await executeFlightAPI(args);
case "search_hotels":
return await executeHotelAPI(args);
case "recommend_attractions":
return await executeAttractionAPI(args);
default:
return { success: false, error: `Unknown tool: ${name}` };
}
} catch (error: any) {
console.error(`Tool ${name} failed (attempt ${attempt}): ${error.message}`);
if (attempt === maxRetries) {
return { success: false, error: `Tool ${name} failed after ${maxRetries} attempts: ${error.message}` };
}
// 指数退避重试
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt - 1)));
}
}
return { success: false, error: "Unexpected error" };
}
// 3. 主循环:Agent 推理与工具调用
async function travelAgent(userRequest: string): Promise<string> {
const messages: Anthropic.MessageParam[] = [
{
role: "user",
content: userRequest,
},
];
const maxIterations = 10; // 防止无限循环
let iteration = 0;
while (iteration < maxIterations) {
iteration++;
// 调用 Claude
const response = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 4096,
tools: tools,
messages: messages,
});
// 检查是否需要调用工具
const toolUses = response.content.filter(
(block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
);
if (toolUses.length === 0) {
// 没有工具调用,返回最终回复
const textBlock = response.content.find(
(block): block is Anthropic.TextBlock => block.type === "text"
);
return textBlock?.text || "Sorry, I couldn't generate a response.";
}
// 执行所有工具调用
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const toolUse of toolUses) {
console.log(`Calling tool: ${toolUse.name} with args:`, toolUse.input);
const result = await executeTool(toolUse.name, toolUse.input);
toolResults.push({
type: "tool_result",
tool_use_id: toolUse.id,
content: JSON.stringify(result),
});
}
// 更新消息历史
messages.push({
role: "assistant",
content: response.content,
});
messages.push({
role: "user",
content: toolResults,
});
}
return "Sorry, I couldn't complete the task after multiple attempts.";
}
// 使用示例
async function main() {
const userRequest = `
我计划下周一从上海去北京出差 3 天。
预算:机票 2000 元以内,酒店每晚 800 元以内。
请帮我查一下北京天气,搜索航班和酒店,推荐一些适合的餐厅。
`;
const response = await travelAgent(userRequest);
console.log(response);
}
main().catch(console.error);💡 一句话理解
在开发阶段,为每个工具添加详细的日志输出(工具名、参数、结果、耗时),便于调试和优化。
⚠️ 常见踩坑
生产环境必须设置最大迭代次数(maxIterations)和超时机制,防止 Agent 陷入无限循环或长时间运行。
八、2026 年最新进展与未来方向
2026 年工具调用领域的关键趋势:
1. 自主工具发现与加载(Autonomous Tool Discovery)
2026 年的 Agent 不再局限于预定义的工具集,而是能够根据任务需求自主搜索和加载合适的工具。
实现方式:
- Agent 连接到工具注册中心(Tool Registry)
- 根据任务描述,语义搜索匹配的工具
- 动态加载工具 Schema 和使用文档
- 评估工具的可信度和质量
示例:用户说"帮我分析一下这个网站的 SEO",Agent 自主搜索并加载 SEO 分析工具、网站爬虫工具、性能测试工具。
2. 工具组合与链式调用(Tool Composition)
Agent 能够将多个简单工具组合成复杂的工作流。
实现方式:
- 工具之间通过标准化的数据格式传递
- Agent 理解工具的输入输出,自动构建调用链
- 支持条件分支、循环、并行执行
示例:网站监控 Agent = 网站爬虫 + 性能测试 + SEO 分析 + 报告生成
3. 工具学习与优化(Tool Learning)
Agent 能够从历史工具调用中学习,优化未来的调用策略。
实现方式:
示例:Agent 发现"先查天气再查航班"的成功率高于"同时查询",自动调整编排策略。
4. 跨 Agent 工具共享(Tool Sharing)
多个 Agent 之间可以共享工具和工具调用经验。
实现方式:
示例:旅行规划 Agent 发现了一个好用的汇率转换工具,推荐给其他 Agent。
5. 安全与隐私保护(Security & Privacy)
随着工具调用能力的增强,安全问题也日益突出。
关键挑战:
解决方案:
- 工具调用沙箱化
- 细粒度的权限控制
- 操作审计和回滚机制
- 用户确认机制(对于敏感操作)
未来方向:
1. 通用工具智能(General Tool Intelligence)
未来的 Agent 将具备通用的工具使用能力,能够:
- 理解任何工具的 Schema 和文档
- 自主探索工具的功能和限制
- 创造性地组合工具解决新问题
2. 工具生态标准化
MCP 等标准协议的普及将带来:
- 工具的可移植性(一次开发,到处使用)
- 工具市场的繁荣(类似 App Store)
- 工具质量的提升(社区评审和评级)
3. 人机协作工具调用
Agent 与人类协作完成复杂任务:
- Agent 负责工具调用和数据收集
- 人类负责决策和审核
- 双向反馈优化
总结: 工具调用是 AI Agent 从"能说"到"能做"的关键能力。从 2023 年 OpenAI 的 Function Calling 到 2026 年的 MCP 生态和自主工具编排,这个领域正在快速发展。掌握工具调用的核心架构、编排模式、错误处理,是构建生产级 Agent 的必备技能。