解密prompt系列58. MCP - 工具演变 & MCP基础
<p>作为<code>结构化推理</code>的坚定支持者,我一度对MCP感到困惑:Agent和工具调用的概念早已普及,为何还需要MCP这样的额外设计呢?本文就来深入探讨MCP,看看它究竟解决了什么问题。<br>我们将分几章解析MCP:本章理清基础概念和逻辑,后面我们直接以一个Agent为例演示全MCP接入的实现方案。</p>
<h2 id="工具调用方式的演进">工具调用方式的演进</h2>
<p>大模型调用工具的概念从ChatGPT亮相后就被提出,其表达形式经历了三个阶段演变:</p>
<p><strong>1. 函数表达阶段</strong><br>
早期的工具描述多采用简单的函数形式,通常通过提示词(Prompt)要求模型输出包含工具名称和参数的JSON对象。例如下面的System Prompt期望模型输出JSON结构来调用天气查询工具:</p>
<pre><code>system_prompt = """你是一个智能助手,可以帮助用户查询天气。
如果你需要查询天气,请调用一个名为 'get_current_weather' 的工具。
这个工具需要一个 'location' (字符串,必填) 参数,表示要查询天气的城市。
请以 JSON 格式输出工具调用,例如:
{"tool_name": "get_current_weather", "parameters": {"location": "上海"}}
"""
</code></pre>
<p>模型可能输出</p>
<pre><code class="language-json">{
"tool_name": "get_current_weather",
"parameters": {
"location": "北京"
}
}
</code></pre>
<p>这种方式存在明显痛点:</p>
<ul>
<li><strong>缺乏统一标准</strong>:工具描述格式五花八门</li>
<li><strong>推理脆弱</strong>:JSON缺乏强约束,易出现格式错误</li>
<li><strong>解析繁琐</strong>:需额外编写解析代码</li>
</ul>
<p><strong>2. 标准化工具定义</strong></p>
<p>2023年6月,OpenAI推出的Function Calling功能是一个重要转折点。它引入JSON Schema标准化工具描述,明确定义:</p>
<ul>
<li>工具名称(name)</li>
<li>功能描述(description)</li>
<li>参数列表(parameters),包含类型、描述、是否必填等</li>
</ul>
<pre><code class="language-json">{
"name": "get_current_weather",
"description": "获取指定地点的当前天气信息",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,例如:旧金山、上海"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位,摄氏度或华氏度"
}
},
"required": ["location"]
}
}
</code></pre>
<p><strong>3. 引入结构化推理</strong></p>
<p>虽然OpenAI,Anthropic等闭源模型先后推出了Function Calling的接口能力,但是众多开源模型仍无法使用类似的能力,并且手工编写工具的JSON Schema也较为复杂。</p>
<p>而转折点则是24年结构化推理的普及,基于掩码的结构化推理能力(不熟悉的朋友看这里LLM结构化输出)不仅显著提升了模型生成工具JSON Schema的准确性,同时还让Pydantic这个数据验证和解析库进入了大家的视野中。</p>
<p>像Langchain、LlamaIndex、DSPY等开源框架都开始引入Pydantic来自动生成工具的JSON Schema。这样不仅解析部分能自动化标准化,生成工具描述的部分同样也被标准化。还是上面的查天气,可以使用Pydantic来标准化入参</p>
<pre><code class="language-python">from langchain_core.tools import tool
class WeatherInput(BaseModel):
location: str = Field(description="需要查询天气的城市名称")
unit: str = Field(description="温度单位,可以是 'celsius' 或 'fahrenheit'", default="celsius")
@tool("get_current_weather", args_schema=WeatherInput, return_direct=True)
def get_current_weather(location: str, unit: str):
"获取指定地点的当前天气信息"
return ''
</code></pre>
<h2 id="mcp基础概念">MCP基础概念</h2>
<blockquote>
<ul>
<li>Anthropic: Model Context Protocol</li>
</ul>
</blockquote>
<p>既然前三阶段解决了工具描述标准化、推理准确性和解析自动化,为什么还需要MCP?</p>
<p>后来我思考良久才意识到<strong>MCP解决的不是Agent算法问题,而是工程问题,可以类比设计模式中的Adapter接口转换思想,MCP推出的是工具的标准化协议</strong>。与其说是搭建新的MCP工具服务,不如说是把已有的服务通过MCP的链接中枢转接成统一协议的AI工具服务。</p>
<h3 id="理解mcp从完整工具调用流程说起">理解MCP:从完整工具调用流程说起</h3>
<p>要理解MCP的作用,需先看LLM调用工具的完整流程:</p>
<ol>
<li>构建上下文:Agent获取可用工具列表及其描述(JSON Schema/Prompt)</li>
<li>模型推理:LLM结合用户Query和工具上下文生成工具调用指令</li>
<li>执行调用:Client解析指令并调用对应服务(本地函数/进程/远程API)获取</li>
<li>处理结果:Client获取工具结果并反馈给LLM进行后续处理</li>
</ol>
<p>工具发展的前三个阶段主要解决步骤2的准确性和接口标准化,而步骤1(获取工具列表)和步骤3(调用异构服务),步骤4(处理服务结果) 的工程化集成缺乏统一方案,这也是MCP的价值所在</p>
<h3 id="mcp的核心价值统一协议降低复杂度">MCP的核心价值:统一协议,降低复杂度</h3>
<p>在没有MCP时,每个Agent需为每个工具服务定制开发连接逻辑,这里包括接口定义,错误处理,鉴权等等。**当存在M个Agent和N个工具服务时,复杂度是O(M×N)(接近平方级)。<br>
<img src="https://img2024.cnblogs.com/blog/1326688/202508/1326688-20250806072722737-1599333680.png"></p>
<p>而引入MCP后,<strong>MCP通过标准协议解决这个问题把复杂度降低到M+N</strong></p>
<p><img src="https://img2024.cnblogs.com/blog/1326688/202508/1326688-20250806072722750-116269500.png"></p>
<ul>
<li>Client侧:Agent只需集成通用MCP客户端,将请求编码为标准MCP消息(JSON-RPC 2.0格式)</li>
<li>Server侧:每个工具服务部署MCP服务端适配器,转换请求并返回标准化响应</li>
</ul>
<p>MCP除核心连接简化外,还提供:</p>
<ul>
<li><strong>动态上下文构建</strong>:工具列表通过标准list_tools方法动态获取,无需在Agent内部硬编码工具描述</li>
<li><strong>协议标准化</strong>:明确定义工具发现、调用、返回结构、错误处理等标准操作,无需每个Agent独立处理</li>
<li><strong>传输无关性</strong>:支持HTTP、Stdio等多种传输层,统一了Agent进程内本地工具和远程API调用</li>
</ul>
<h3 id="mcp协议">MCP协议</h3>
<p>说到这里MCP相关的核心架构已经比较清晰了,就是按照JSON-RPC 2.0标准协议通信(使用JSON作为消息格式)的Server-Client服务架构,其中client和Server各自提供以下核心能力</p>
<ol>
<li>Client:在智能体启动时会初始化客户端,每个对应的MCP Server都初始化一个对应的客户端</li>
</ol>
<ul>
<li><strong>初始化</strong>:根据Server类型(Stdio/HTTP)建立连接</li>
<li><strong>发现工具</strong>:通过统一的<code>list_tools</code>获取可用工具及描述</li>
<li><strong>调用工具</strong>:将模型输出封装为统一的工具标准请求call_tool请求服务端,同时服务端也会返回标准化的工具调用结果</li>
</ul>
<ol start="2">
<li>Server:每个(一组)工具都设计启动一个对应的服务端</li>
</ol>
<ul>
<li><strong>提供工具描述</strong>:实现<code>list_tools</code>返回工具定义</li>
<li><strong>执行工具调用</strong>:通过<code>call_tool</code>转换并执行实际工具</li>
<li><strong>传输层适配</strong>:
<ul>
<li><code>Stdio</code>:用于本机进程间通信</li>
<li><code>Http</code>:用于跨网络调用</li>
</ul>
</li>
<li><strong>提供交互提示</strong>:可选提供推荐Prompt模板(工具说明/结果解释)</li>
</ul>
<p>对于MCP中的高级概念如<code>Resource</code>、<code>Roots</code>、<code>Sampling</code>、<code>Elicitation</code>,仅靠定义难以理解。在接下来的章节中,我们将通过具体案例探讨这些概念。</p>
<p>当然其实还有一层概念也就是在client的外层,也就是智能体层或应用层,例如cursor, windsurf, claude desktop等等,在MCP中称之为Host层,这一层也更多是和Resource订阅、Prompt使用这些高级概念相关,我们放在后面的章节再说了。</p>
<p>想看更全的大模型论文·微调预训练数据·开源框架·AIGC应用 >> DecryPrompt</p><br><br>
来源:https://www.cnblogs.com/gogoSandy/p/19024358
頁:
[1]