)
上一篇我们讲了 RAG——让大模型「知道知识」。这一篇讲 Tool Use——让大模型「做事情」。如果 LLM 只是个会聊天的嘴巴价值有限。真正的革命发生在它能主动调用工具——查天气、订机票、写代码、跑 SQL、控制设备、操作浏览器……这就是Function Calling / Tool Use的能力。2024 年下半年开始几乎所有主流大模型都把 Tool Use 作为核心能力。2025-2026 的杀手应用——Cursor、Claude Code、Devin、Manus……全都建立在这个基础上。如果你做过相关工作下面这些问题应该不陌生OpenAI 的tools字段和 Anthropic 的tool_use怎么对接模型经常调错工具 / 参数错乱怎么治让模型一次调多个工具parallel calling怎么实现MCPModel Context Protocol和 Function Calling 是同一个东西吗自部署开源模型支持 Function Calling 吗读完本文你将能设计标准的 Tool Use 协议用 vLLM / Claude / GPT 实现工具调用理解 MCP 协议在 2026 年的地位用 ReAct 模式做多步推理工具调用跑通一个端到端 Tool Use Agent我们开始。一、Tool Use 在 LLM 时代的位置1.1 从会答到会做LLM 应用的演进2022ChatGPT ──────────── 会答问题 2023RAG 应用 ──────────── 会查私有知识 2024Function Calling ─── 会调外部接口 2025Agent 时代 ───────── 会自主完成任务 2026MCP / Computer Use ── 会操作 GUI / 系统Tool Use 是 Agent 的核心能力——没有它LLM 只能说不能动。1.2 三类典型 Tool类型例子难度查询类查天气、查股价、查文档⭐执行类发邮件、下订单、调 API⭐⭐⭐计算类跑 SQL、写代码、做表格⭐⭐⭐⭐GUI 操作类浏览器自动化、桌面操作⭐⭐⭐⭐⭐1.3 工程师为什么必须懂如果你做以下任何工作必须懂 Tool UseAgent 应用自动化任务流AI 客服能查订单、发工单AI Coding调用 Linter / Test / BuildAI 分析师跑 SQL、画图、生成报告AI 助理日历、邮件、文档二、Function Calling 协议详解2.1 OpenAI 标准事实主流OpenAI 在 2023.06 推出 Function Calling后来扩展成 Tools已经成为事实标准。2.1.1 工具定义tools [{ type: function, function: { name: get_weather, description: 查询指定城市的天气, parameters: { type: object, properties: { city: { type: string, description: 城市名如「上海」 }, unit: { type: string, enum: [celsius, fahrenheit], default: celsius } }, required: [city] } } }]关键点description 极其重要——模型只通过 description 理解工具parameters 用 JSON Schemarequired 字段强制约束2.1.2 调用流程完整调用是多轮的from openai import OpenAI client OpenAI() # 第 1 轮用户问题 工具列表 response client.chat.completions.create( modelgpt-5, messages[ {role: user, content: 上海明天天气怎么样} ], toolstools, tool_choiceauto, # auto / none / required / 指定工具 ) # 模型返回工具调用请求 assistant_msg response.choices[0].message # assistant_msg.tool_calls [{ # id: call_abc123, # function: { # name: get_weather, # arguments: {city: 上海} # } # }] # 第 2 轮执行工具 把结果送回 tool_result call_real_weather_api(上海) # 你的真实实现 response client.chat.completions.create( modelgpt-5, messages[ {role: user, content: 上海明天天气怎么样}, assistant_msg, { role: tool, tool_call_id: call_abc123, content: json.dumps(tool_result) } ], toolstools, ) # 模型基于工具结果生成最终回答 print(response.choices[0].message.content) # 上海明天晴最高 28°C最低 18°C2.1.3 Parallel Function CallingOpenAI / Claude 都支持一次调用多个工具# 用户问上海和北京天气怎么样 # 模型可能返回 { tool_calls: [ {id: call_1, function: {name: get_weather, arguments: {city: 上海}}}, {id: call_2, function: {name: get_weather, arguments: {city: 北京}}} ] } # 客户端并行执行两个工具结果一起送回并行调用大幅减少多步延迟是 2026 年 Agent 的核心优化。2.2 AnthropicClaude的差异Claude 的协议略有不同import anthropic client anthropic.Anthropic() tools [{ name: get_weather, description: 查询天气, input_schema: { # 不是 parameters type: object, properties: {...}, required: [city] } }] response client.messages.create( modelclaude-sonnet-4-6, max_tokens1024, toolstools, messages[{role: user, content: 上海天气}] ) # response.content 包含混合内容 # [ # {type: text, text: 我帮你查询...}, # {type: tool_use, id: ..., name: get_weather, input: {city: 上海}} # ]主要差异维度OpenAIAnthropic字段名parametersinput_schema返回格式tool_calls数组content混合块强制调用tool_choice: requiredtool_choice: {type: tool, name: ...}并行默认支持默认支持描述单独字段单独字段LiteLLM、LangChain 等工具会自动转换两种格式。2.3 各家模型的 Tool Use 能力实测对比2026.05 主流模型模型单工具准确率多工具准确率参数准确率Claude Opus 4.799%97%⭐99%GPT-598%95%98%Gemini 2.5 Pro97%93%97%Qwen3-32B95%88%94%Llama-3-70B91%80%91%DeepSeek V396%92%95%关键观察闭源 Top 3 都 95%开源 Qwen / DeepSeek 接近闭源多工具并行调用是当下分水岭三、自部署模型的 Tool Use3.1 vLLM 中启用 Tool UsevLLM 0.6 全面支持 Function Callingvllm serve Qwen/Qwen3-32B-Instruct \ --enable-auto-tool-choice \ --tool-call-parser hermes \ # 解析器按模型选 --chat-template /path/to/template.jinja \ --port 8000关键参数--enable-auto-tool-choice自动模式推荐--tool-call-parser每个模型有自己的格式主流模型的 parser 选择模型parserQwen3hermesLlama 3llama3_jsonMistralmistralInternLMinternlm3.2 SGLang 中启用python -m sglang.launch_server \ --model-path Qwen/Qwen3-32B-Instruct \ --tool-call-parser qwen25 \ --port 30000SGLang 对结构化输出 / 工具调用支持更原生第 17 篇讲过。3.3 Ollama 中启用import ollama response ollama.chat( modelqwen3:32b-instruct, messages[{role: user, content: 上海天气}], tools[{ type: function, function: { name: get_weather, description: 查询天气, parameters: {...} } }] )Ollama 内置 Tool Use 解析开箱即用。四、ReAct 模式多步推理 工具调用简单的用户问→工具调用→回答是基础。真正强大的应用需要多步推理——这就是 ReAct 模式。4.1 ReAct 的思想ReAct Reasoning ActingThought我需要先查上海天气再查北京天气最后对比 Action调用 get_weather(上海) Observation上海 28°C晴 Thought现在查北京 Action调用 get_weather(北京) Observation北京 25°C多云 Thought可以回答了 Final Answer上海比北京暖 3°C且更晴朗模型在思考和行动之间循环直到能给出最终答案。4.2 实现 ReAct 循环def react_agent(question, max_iter10): messages [{role: user, content: question}] for iteration inrange(max_iter): # 让 LLM 决定下一步 response client.chat.completions.create( modelqwen3-32b, messagesmessages, toolsavailable_tools, ) assistant_msg response.choices[0].message messages.append(assistant_msg) # 如果没有工具调用说明 LLM 已经给出最终答案 ifnot assistant_msg.tool_calls: return assistant_msg.content # 并行执行所有工具调用 for tool_call in assistant_msg.tool_calls: tool_name tool_call.function.name args json.loads(tool_call.function.arguments) try: result TOOLS[tool_name](**args) except Exception as e: result fError: {e} messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result), }) return 达到最大迭代次数4.3 工具调用的思考链带 thinking 的模型如 Claude 4.7、o3、DeepSeek R1让 ReAct 进入新阶段模型内部 thinking用户不可见 分析用户问的是天气对比 规划分两步先查上海再查北京 考虑可以并行查吗可以 决策发起 parallel tool calls 可见输出[tool_use × 2 并行]Thinking 模型的工具使用更智能——会主动规划避免无效调用。五、MCP协议化的工具生态5.1 MCP 是什么MCPModel Context Protocol是 Anthropic 在 2024.11 推出的开放协议目标是把 AI 与各种数据源 / 工具的接入标准化。类比理解USB-C 之于硬件接口 MCP 之于 AI 工具接入之前每个工具都要自己设计接口给每个模型用——M 个模型 × N 个工具 M×N 个适配。MCP 把这变成 MN。5.2 MCP 架构┌──────────────────────────────────────┐ │ AI HostClaude Desktop / Cursor │ └──────────────────────────────────────┘ ↓ MCP Client ┌──────────────────────────────────────┐ │ MCP Server │ │ ├─ filesystem 工具 │ │ ├─ database 工具 │ │ ├─ web search 工具 │ │ └─ ... 你想要的任何工具 │ └──────────────────────────────────────┘5.3 2026 年 MCP 生态经过 1 年多发展MCP 已经成为 Agent 时代的事实标准之一MCP Server功能GitHub代码、PR、issue 操作Slack消息、频道管理Notion数据库、文档PostgreSQLSQL 查询Filesystem文件读写Browser网页操作Memory持久化记忆你自研任何业务主流支持Claude Desktop / Claude Code原生Cursor / Windsurf2025 集成各类 Agent 框架LangChain、CrewAI 等国内Cherry Studio、ChatBox5.4 写一个 MCP Server 简单的 MCP Server 示例 依赖pip install mcp from mcp.server import Server from mcp.types import Tool, TextContent server Server(my-server) server.list_tools() asyncdeflist_tools() - list[Tool]: return [ Tool( nameget_weather, description查询天气, inputSchema{ type: object, properties: { city: {type: string} }, required: [city], }, ) ] server.call_tool() asyncdefcall_tool(name: str, arguments: dict) - list[TextContent]: if name get_weather: city arguments[city] # 实际逻辑 result await fetch_weather(city) return [TextContent(typetext, textjson.dumps(result))] if __name__ __main__: import asyncio from mcp.server.stdio import stdio_server asyncdefmain(): asyncwith stdio_server() as (read, write): await server.run(read, write, ...) asyncio.run(main())任何 MCP 兼容的客户端都能用这个 Server。5.5 MCP vs 传统 Function Calling维度Function CallingMCP协议每个 API 自己定标准化工具描述写在每次请求Server 注册动态加载难容易即插即用跨模型复用难容易跨应用复用难容易生态各家分散统一未来趋势MCP 将逐渐替代各家私有的 Function Calling 协议——但目前两者并存。六、生产实战完整 Tool Use Agent下面是一个生产可用的 Tool Use Agent 完整实现。6.1 工具定义层from typing importCallable from dataclasses import dataclass dataclass classTool: name: str description: str parameters: dict handler: Callable # 注册工具 TOOLS: dict[str, Tool] {} defregister_tool(name: str, description: str, parameters: dict): defdecorator(func: Callable): TOOLS[name] Tool(name, description, parameters, func) return func return decorator register_tool( namesearch_kb, description在知识库中搜索相关文档, parameters{ type: object, properties: { query: {type: string}, top_k: {type: integer, default: 5} }, required: [query] } ) asyncdefsearch_kb(query: str, top_k: int 5): results await rag_engine.search(query, top_ktop_k) return [{text: r.text, source: r.source} for r in results] register_tool( namerun_sql, description执行 SQL 查询并返回结果, parameters{ type: object, properties: {sql: {type: string}}, required: [sql] } ) asyncdefrun_sql(sql: str): # 加白名单防 SQL 注入 ifnot is_safe_sql(sql): return {error: Unsafe SQL} returnawait db.execute(sql)6.2 Agent 核心循环import json from openai import AsyncOpenAI client AsyncOpenAI( base_urlhttp://vllm:8000/v1, api_keydummy ) asyncdefagent_loop(question: str, max_iter: int 15): messages [ {role: system, content: 你是一个专业助手可以调用工具完成任务}, {role: user, content: question} ] tool_schemas [ {type: function, function: { name: t.name, description: t.description, parameters: t.parameters, }} for t in TOOLS.values() ] for it inrange(max_iter): response await client.chat.completions.create( modelqwen3-32b, messagesmessages, toolstool_schemas, tool_choiceauto, ) msg response.choices[0].message messages.append(msg.model_dump()) ifnot msg.tool_calls: return msg.content # 并行执行所有工具 tasks [] for tc in msg.tool_calls: tool TOOLS.get(tc.function.name) if tool isNone: tasks.append((tc.id, {error: Unknown tool})) continue args json.loads(tc.function.arguments) tasks.append((tc.id, tool.handler(**args))) # 等所有工具 results await asyncio.gather(*[t[1] for t in tasks], return_exceptionsTrue) for (call_id, _), result inzip(tasks, results): messages.append({ role: tool, tool_call_id: call_id, content: json.dumps(result, ensure_asciiFalse) }) return 已达最大迭代次数6.3 流式输出 工具调用生产环境通常要流式输出async defagent_loop_stream(question: str): messages [...] whileTrue: stream await client.chat.completions.create( modelqwen3-32b, messagesmessages, toolstool_schemas, streamTrue, ) # 收集 stream区分文本 chunk 和 tool_call chunk text_buf, tool_calls , [] asyncfor chunk in stream: delta chunk.choices[0].delta if delta.content: yield {type: text, content: delta.content} text_buf delta.content if delta.tool_calls: # 增量构建 tool_calls ... ifnot tool_calls: return # 执行工具 for tc in tool_calls: yield {type: tool_start, tool: tc.function.name} result await TOOLS[tc.function.name].handler(...) yield {type: tool_end, tool: tc.function.name, result: result} messages.append({role: tool, ...})6.4 错误处理与重试async defsafe_call_tool(tool, args, retries2): for i inrange(retries 1): try: returnawait tool.handler(**args) except ValidationError as e: # 参数错误立即返回让 LLM 修 return {error: fInvalid args: {e}} except TimeoutError: if i retries: return {error: Tool timeout} await asyncio.sleep(2 ** i) except Exception as e: return {error: str(e)}让 LLM 看到错误信息可以自我纠错——下一轮它会改用更合适的参数。七、避坑清单7.1 坑 1工具 description 模糊症状模型频繁选错工具。对策description 要写什么时候用、返回什么加 examples部分模型支持7.2 坑 2参数 JSON Schema 不严格症状模型乱传参数。对策用enum限制可选值加pattern正则约束强制required字段7.3 坑 3工具太多症状30 个工具同时给模型 → 选不对。对策工具不要超过 20 个大量工具用两级路由先选工具组再选具体工具或用 RAG 动态召回相关工具7.4 坑 4陷入循环症状模型连续 10 次调用同一个工具。对策设max_iter检测同样工具调用 3 次相同参数 → 终止LLM 提示中加「不要重复调用相同工具」7.5 坑 5工具结果太长症状单个工具返回 50K tokens → 上下文爆炸。对策工具自身做摘要 / 分页引入 view next page 子工具长结果存到 KV store返回 ID7.6 坑 6并行工具的依赖关系症状A 工具依赖 B 工具的结果但模型试图并行。对策设计工具时让输入和输出清晰description 里说这个工具的输入需要...用 thinking 模型规划更稳八、结语Tool Use 是 Agent 时代的「关键开关」读完本文你应该明白Function Calling 是 OpenAI 定义的事实标准——其他都向它兼容闭源 Top 3Claude/GPT/Gemini多工具调用 95%开源 Qwen / DeepSeek 接近闭源——自部署可用ReAct 模式是多步推理的基础MCP 是 2026 年的协议级革命——统一工具生态生产 Tool Use 要做好错误处理 流式输出参考文献Function Calling 与 Tool Use让大模型「动」起来