发布时间:2026/7/23 11:56:49
LLM 工具调用与 MCP 机制 主题LLM 如何被提供可用工具、工具调用协议、MCP 工具发现机制、以及多模型参数差异的抹平方式。一、工具调用整体流程工具调用Function Calling / Tool Use本质是一套「声明 → 决策 → 执行 → 回填」的循环在请求里声明「有哪些工具可用」(tools 定义)LLM 根据用户问题决定「是否调用 / 调用哪个 / 传什么参数」应用程序真正执行工具拿到结果把结果回填给 LLMLLM 生成最终自然语言回答关键认知LLM 本身不执行工具它只输出「我想调用某工具 参数」的结构化意图真正的执行由应用代码负责。二、如何提供可用工具工具声明主流做法在 API 请求中传入一个tools数组每个工具用 JSON Schema 描述。OpenAI 格式{model:gpt-4,messages:[],tools:[{type:function,function:{name:get_weather,description:查询指定城市的实时天气,parameters:{type:object,properties:{city:{type:string,description:城市名如 杭州},unit:{type:string,enum:[celsius,fahrenheit]}},required:[city]}}}],tool_choice:auto}Anthropic (Claude) 格式{model:claude-sonnet-4,messages:[],tools:[{name:get_weather,description:查询指定城市的实时天气,input_schema:{type:object,properties:{city:{type:string}},required:[city]}}]}关键点name工具唯一标识description最重要模型靠它判断何时调用要写清楚用途/触发条件parameters/input_schema用 JSON Schema 约束参数类型、枚举、必填项三、工具调用协议关键要素1. 调用控制字段 tool_choiceauto模型自行决定是否调用none禁止调用required/any强制必须调用某工具指定具体工具名强制调用该工具2. 模型返回工具调用意图OpenAI{role:assistant,tool_calls:[{id:call_abc123,type:function,function:{name:get_weather,arguments:{\city\: \杭州\}}}]}Anthropic{role:assistant,content:[{type:tool_use,id:toolu_abc123,name:get_weather,input:{city:杭州}}],stop_reason:tool_use}3. 回填执行结果协议核心执行完工具后必须用特定角色/类型把结果塞回对话历史并通过 id 关联OpenAI —— 用role: tooltool_call_id{role:tool,tool_call_id:call_abc123,content:{\temp\: 28, \desc\: \晴\}}Anthropic —— 用role: user里的tool_resulttool_use_id{role:user,content:[{type:tool_result,tool_use_id:toolu_abc123,content:{\temp\: 28, \desc\: \晴\}}]}4. 多轮循环回填后再次请求模型模型可能继续调用下一个工具多步/链式调用或生成最终回答stop_reason: end_turn/finish_reason: stop。5. 并行工具调用现代模型支持一次返回多个 tool_call。协议要求每个 tool_call 有独立 id回填时每个结果按 id 一一对应返回缺一不可应用可并行执行这些工具以提速6. 常见协议注意事项事项说明arguments 是字符串OpenAI 的 arguments 是 JSON 字符串需二次解析Anthropic 的 input 已是对象id 必须匹配回填结果 id 与调用 id 不匹配会报错完整对话历史每轮请求需带上包含 tool_call tool_result 的完整 messagesschema 越清晰越准description 和 enum 约束能显著降低幻觉/传错参错误也要回填工具执行失败时把错误信息作为 tool_result 返回让模型决定重试或换方案四、MCP支持哪些工具是怎么告诉 LLM 的核心结论LLM 本身并不直接知道有哪些 MCP它只认标准的 tools 定义。中间的 MCP Client宿主程序负责去各 MCP Server 发现工具再翻译成 LLM 的工具协议喂给它。整体链路MCP Server提供工具 ↑ MCP 协议 (tools/list, tools/call) MCP Client / Host如 Claude Desktop、IDE、Agent 框架 ↑ 把 MCP 工具翻译成 LLM 的 tools 定义 LLM API 请求 (tools: [...])第一步宿主如何知道支持哪些 MCP—— 靠配置{mcpServers:{filesystem:{command:npx,args:[-y,modelcontextprotocol/server-filesystem,/path]},github:{command:npx,args:[-y,modelcontextprotocol/server-github],env:{GITHUB_TOKEN:xxx}},my-remote:{url:https://example.com/mcp,transport:sse}}}宿主启动时按配置逐个连接本地用 stdio 启子进程远程用 SSE / HTTP。第二步MCP 协议的工具发现底层 JSON-RPC 2.0握手初始化{jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2024-11-05,capabilities:{}}}列出工具 tools/list// Client → Server{jsonrpc:2.0,id:2,method:tools/list}// Server → Client{jsonrpc:2.0,id:2,result:{tools:[{name:read_file,description:读取指定路径的文件内容,inputSchema:{type:object,properties:{path:{type:string}},required:[path]}}]}}MCP Server 除了 tools还能暴露 resourcesresources/list和 promptsprompts/list发现机制类似。第三步翻译成 LLM 的 tools 定义宿主把所有 MCP Server 返回的工具聚合转换成 LLM 工具格式注入 API 请求。MCP 的 inputSchema 与 LLM 的 input_schema/parameters 几乎同构都是 JSON Schema。命名冲突处理多 Server 可能有同名工具宿主通常加前缀区分例如filesystem__read_file、github__create_issue。第四步调用回路1. LLM 返回 tool_use: { name: filesystem__read_file, input: {...} } 2. 宿主识别前缀路由到对应 MCP Server 3. 宿主向该 Server 发 tools/call 4. Server 执行返回 result 5. 宿主把 result 作为 tool_result 回填给 LLMtools/call 示例// Client → Server{jsonrpc:2.0,id:3,method:tools/call,params:{name:read_file,arguments:{path:/a.txt}}}// Server → Client{jsonrpc:2.0,id:3,result:{content:[{type:text,text:文件内容...}]}}动态更新工具列表变化通知{jsonrpc:2.0,method:notifications/tools/list_changed}宿主收到后重新 tools/list并在下一轮请求里更新给 LLM 的 tools 定义。完整图景配置文件 → 宿主知道「连哪些 MCP Server」 tools/list → 宿主知道「每个 Server 有哪些工具」 Schema 翻译聚合 → 拼成 LLM 的 tools 定义 API 请求 → 这一刻 LLM 才「知道」有哪些工具可用 tool_use → LLM 决定调用 tools/call → 宿主路由回对应 Server 执行 tool_result 回填 → LLM 生成最终回答一句话总结支持哪些 MCP 由宿主的配置决定宿主通过 MCP 的 tools/list 发现工具再翻译聚合成标准 tools 定义在每次 API 请求里告诉 LLM。LLM 全程只跟标准工具协议打交道对 MCP 本身无感知。五、不同模型参数格式差异的抹平核心结论差异主要在「客户端 / Agent 框架层」通过适配器Adapter / Provider 抽象抹平。抹平的是「协议格式」抹不平的是「模型能力和行为」。抹平发生在哪一层业务代码 ↓ 统一接口抹平层 ┌─────────────────────────────┐ │ Provider / Adapter 抽象层 │ │ OpenAIAdapter / ClaudeAdapter / GeminiAdapter │ └─────────────────────────────┘ ↓ 各自原生 API 格式 OpenAI API Claude API Gemini API两种常见实现方式Agent / SDK 框架内置适配LangChain、LlamaIndex、Vercel AI SDK、Spring AI 等定义统一的 Tool / Message 抽象内部为每个厂商写 adapter。网关 / 代理服务如 LiteLLM、OneAPI对外统一暴露 OpenAI 格式内部转译成各厂商格式。具体抹平了哪些差异以工具调用为例差异点OpenAIAnthropicGemini抹平方式工具定义键名function.parametersinput_schemafunctionDeclarations.parametersadapter 改字段名schema 本体同构调用意图tool_calls[]content[].tool_usefunctionCall统一解析成内部 ToolCall参数载荷argumentsJSON 字符串input对象args对象adapter 统一 parse 成对象结果回填role:“tool” tool_call_idrole:“user” 里 tool_result tool_use_idfunctionResponse统一封装成 ToolResult 按厂商拼回system 提示messages 里 role:“system”顶层独立 system 字段systemInstructionadapter 搬运到对应位置强制调用tool_choicetool_choicetoolConfig.mode统一枚举映射本质一套内部中间表示IR业务定义统一 Tool │ ▼ 内部 IR中立表示Message / Tool / ToolCall / ToolResult │ serialize按 provider 出站翻译 ▼ 各厂商原生请求格式 │ 调用 API ▼ 各厂商原生响应 │ parse入站翻译回 IR ▼ 内部 IR → 业务统一处理伪代码classToolCall:# 中立表示id:strname:strargs:dict# 统一是对象不管厂商用字符串还是对象classOpenAIAdapter:defto_request(self,tools,messages):...defparse_response(self,resp)-list[ToolCall]:# OpenAI 的 arguments 是字符串这里 json.loads 抹平成 dict...classClaudeAdapter:defto_request(self,tools,messages):...defparse_response(self,resp)-list[ToolCall]:...能抹平 vs 抹不平能抹平格式/协议层字段名、消息结构、system 位置参数是字符串还是对象工具定义、调用、回填的封装形式流式事件格式抹不平能力/行为层是否支持并行工具调用是否支持工具调用本身老模型/小模型可能不支持只能降级为提示词模拟 ReActJSON Schema 支持程度enum、嵌套对象、$ref 遵守度不同指令遵循度 / 幻觉率上下文窗口、token 计费、stop_reason 语义差异多模态、思维链thinking等特有能力对能力差异框架只能做「能力探测 降级策略」而非真正抹平。结论格式差异在 Agent / 框架 / 网关的适配层根据 provider 自动抹平业务代码通常无感。能力差异抹不平只能靠能力标记 降级 / 兼容策略处理。这也是很多框架有「provider」或「model capability」概念的原因——既做格式翻译也记录每个模型支持什么运行时决定走原生工具协议还是模拟方案。

相关新闻

2026/7/23 11:56:49

手把手教你用PDFTranslator处理多语言技术文档

做技术文档翻译的同学应该都遇到过这个问题:一份英文技术白皮书或API文档,翻译后表格错位、代码块丢失、图片和文字混成一团,最后还不如直接看原文。 今天分享一个实测好用的在线PDF翻译工具 PDFTranslator,它能比较好地保留原始排…

2026/7/23 11:56:49

嵌入式事件驱动架构:硬件事件管理器原理与实战应用

1. 事件驱动架构:嵌入式系统高效协同的基石在嵌入式开发领域,尤其是资源受限的微控制器应用中,如何高效、实时地处理来自传感器、通信接口和定时器的各种信号,一直是开发者面临的核心挑战。传统轮询方式不仅浪费宝贵的CPU周期&…

2026/7/23 11:56:49

MSPM0 ADC FIFO模式与DMA触发机制深度解析与实战配置

1. MSPM0 ADC FIFO模式与DMA触发机制深度解析在嵌入式系统开发中,尤其是涉及模拟信号采集的应用,ADC的性能和效率往往是决定系统实时性与可靠性的关键。传统的CPU轮询读取ADC结果的方式,不仅会占用大量处理器时间,在高采样率下还极…

2026/7/23 13:31:58

123、OIS光学防抖:陀螺仪标定、音圈马达控制与滚珠式vs悬丝式的机械特性对比

123、OIS光学防抖:陀螺仪标定、音圈马达控制与滚珠式vs悬丝式的机械特性对比 去年在调试某旗舰机型的OIS时,遇到一个让人抓狂的问题:预览画面在低频抖动下防抖效果很好,但一旦用户走路或者坐车,画面边缘就开始出现诡异的“呼吸效应”——像是有只无形的手在反复拉扯画面。…

2026/7/23 13:31:58

B-树原理与数据库索引优化实战

1. B-树:数据库与文件系统的幕后英雄第一次接触B-树是在大学数据库课程上,教授讲到"索引"时轻描淡写地提了一句"底层用的是B-树",当时只觉得是个普通的数据结构。直到后来自己开发一个文件管理系统时,面对百万…

2026/7/23 13:31:58

认知蒸馏技术:将人类思维转化为AI技能模块

1. 项目背景与核心概念"把自己蒸馏成Skill"这个看似科幻的概念,实际上是一种前沿的认知提取技术。它的核心思想是将一个人的思维方式、决策模式和知识体系转化为可执行的AI技能模块。这种技术源于知识蒸馏(Knowledge Distillation)…

2026/7/23 13:31:58

MoveIt Setup Assistant配置

文章目录Ubuntu 24.04 ROS 2 Jazzy 下使用 MoveIt Setup Assistant 配置机械臂1. MSA 是什么2. 前置环境3. Ubuntu 24.04 注意点:Wayland 问题4. MSA 配置整体流程5. Start:加载机器人模型6. Self-Collisions:生成自碰撞矩阵7. Virtual Join…

2026/7/23 13:31:58

分库分表架构下数据库连接数优化实战

1. 分库分表架构下的连接数爆炸问题 去年双十一大促前,我们的订单系统突然出现数据库连接耗尽告警。当时系统采用Sharding-JDBC进行分库,共部署了8个MySQL实例,每个实例16个库。随着机器扩容到200台,单个MySQL实例的连接数直接突破…

2026/7/23 13:26:56

Day30-MCP项目解析:模块化开发与时间管理实践

1. 项目概述:Day30-MCP 是什么?Day30-MCP 是一个典型的项目里程碑命名方式,常见于技术挑战、学习计划或产品迭代场景。从命名结构来看,"Day30"明确指向一个持续30天的周期节点,而"MCP"作为缩写可能…

2026/7/23 12:54:51

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/23 0:01:10

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/22 21:00:12

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…