第3章 MCP与LLM的协同

72 阅读7分钟

第3章 MCP与LLM的协同

前言

MCP的真正价值在于如何与LLM形成完美的协同。本章将深入探讨LLM如何理解和使用MCP提供的工具,以及如何形成自主决策和循环推理的能力。


3.1 MCP如何扩展LLM的能力

3.1.1 LLM的核心能力和局限

LLM的五大核心能力
graph TB
    A["LLM核心能力"] --> B["理解"]
    A --> C["推理"]
    A --> D["生成"]
    A --> E["学习"]
    
    B --> B1["自然语言理解"]
    B --> B2["上下文推断"]
    B --> B3["信息抽取"]
    
    C --> C1["逻辑推导"]
    C --> C2["问题分解"]
    C --> C3["多步推理"]
    
    D --> D1["自然文本生成"]
    D --> D2["代码生成"]
    D --> D3["创意输出"]
    
    E --> E1["in-context学习"]
    E --> E2["提示优化"]
    E --> E3["模式识别"]
LLM的三大根本局限
局限具体表现例子
知识断点训练数据有截止日期不知道最新的股票价格
计算能力不善于精确计算无法准确计算大数乘法
执行能力不能主动修改外部系统无法真正发送邮件或转账

3.1.2 MCP补充的三大维度

graph LR
    A["LLM"] -->|局限| B["MCP拓展"]
    
    B --> B1["知识补充"]
    B --> B2["计算能力"]
    B --> B3["执行能力"]
    
    B1 --> B1A["实时数据"]
    B1A --> B1A1["最新市场数据"]
    B1A --> B1A2["企业内部信息"]
    
    B2 --> B2A["精确计算"]
    B2A --> B2A1["数据分析"]
    B2A --> B2A2["统计运算"]
    
    B3 --> B3A["真实操作"]
    B3A --> B3A1["修改数据库"]
    B3A --> B3A2["调用外部API"]

1. 知识补充

LLM + MCP资源 = 实时知识系统

场景:用户问"今年Q3的销售额是多少?"

LLM的困境:
- 训练数据中没有2025年的数据
- 即使知道之前的数据,也不知道Q3结束后的最新情况

MCP的解决:
1. MCP服务器暴露 resources://finance/sales/2025_q3.xlsx
2. LLM识别需要这个资源
3. MCP客户端读取资源内容
4. LLM基于实时数据回答

2. 计算能力

LLM + MCP工具 = 可靠计算引擎

场景:对1000个客户的消费数据进行统计分析

LLM的困难:
- 容易出错(特别是大数据)
- 计算步骤容易混乱

MCP的解决:
1. LLM调用 calculate_average(dataset) 工具
2. MCP服务器精确计算
3. 返回可靠的结果

3. 执行能力

LLM + MCP工具 = 自主代理系统

场景:用户说"如果销售额低于100万,自动发送预警邮件"

LLM的困难:
- 无法真正修改外部系统
- 无法发送真实的邮件

MCP的解决:
1. LLM理解业务逻辑
2. LLM调用 check_sales() 获取数据
3. LLM调用 send_alert_email() 真实发送
4. 形成完整的自动化流程

3.2 工具调用流程与循环推理

3.2.1 工具调用的完整流程

sequenceDiagram
    participant User
    participant LLM as Claude LLM
    participant Client as MCP客户端
    participant Server as MCP服务器
    participant System as 业务系统
    
    User->>LLM: 1.用户请求
    Note over LLM: 分析请求,确定是否需要工具
    
    LLM->>Client: 2.工具调用请求<br/>(需要的工具名和参数)
    
    Client->>Server: 3.转发工具请求<br/>(MCP协议)
    
    Server->>System: 4.执行具体操作<br/>(查询/修改数据)
    System-->>Server: 5.返回结果
    
    Server-->>Client: 6.返回工具结果<br/>(MCP响应)
    
    Client-->>LLM: 7.展示工具结果
    Note over LLM: 基于工具结果继续推理
    
    LLM-->>User: 8.最终回复

3.2.2 循环推理(Agentic Loop)

工具调用的真正威力在于循环推理,即LLM可以多次调用工具,基于结果再决定下一步。

graph TB
    A["用户请求"] --> B["LLM分析"]
    B --> C{是否需要<br/>工具调用?}
    
    C -->|否| D["直接回答"]
    D --> E["输出结果"]
    
    C -->|是| F["调用工具"]
    F --> G["获得结果"]
    G --> H{结果是否<br/>充分?}
    
    H -->|是| D
    H -->|否| I{是否需要<br/>其他工具?}
    
    I -->|是| F
    I -->|否| J["分析并调整"]
    J --> F
    
    style A fill:#e3f2fd
    style E fill:#c8e6c9

3.2.3 循环推理的实际例子

场景:销售分析代理

用户:分析我们今年的销售表现,给出改进建议

第1轮:
LLM思考:需要获取销售数据
LLM调用:query_sales(year=2025)
结果:销售额$5M,同比增长15%

第2轮:
LLM思考:需要按产品类别分析
LLM调用:get_sales_by_category(year=2025)
结果:[电子产品$2.5M, 服装$1.5M, 食品$1M]

第3轮:
LLM思考:需要对比行业平均
LLM调用:get_industry_benchmark(industry="retail")
结果:行业平均$4.2M,我们超出19%

第4轮:
LLM思考:需要了解增长驱动因素
LLM调用:analyze_growth_factors(year=2025)
结果:新产品线贡献50%,地区扩展贡献30%

最终:
LLM综合分析4个工具的结果,生成综合建议:
"我们的销售表现超越行业平均19%,主要得益于新产品线和地区扩展..."

这展示了一个完整的多步代理循环


3.3 上下文注入机制

3.3.1 什么是上下文注入

定义:上下文注入是将外部信息、资源、提示等注入到LLM的上下文窗口中,帮助LLM做出更准确的决策。

graph TB
    A["LLM上下文"] --> B["系统提示"]
    A --> C["用户输入"]
    A --> D["工具定义"]
    A --> E["外部资源"]
    A --> F["历史对话"]
    
    B --> B1["角色设定"]
    B --> B2["行为规范"]
    B --> B3["输出格式"]
    
    D --> D1["可用工具列表"]
    D --> D2["工具参数定义"]
    D --> D3["工具使用场景"]
    
    E --> E1["实时数据"]
    E --> E2["知识库文档"]
    E --> E3["业务规则"]
    
    style A fill:#fff9c4

3.3.2 上下文优化策略

1. 工具描述优化

不好的描述

{
  "name": "query_db",
  "description": "Query the database"
}

好的描述

{
  "name": "query_sales",
  "description": "查询销售数据库中的订单和销售额信息。支持按时间范围、产品类别、地区等条件过滤。返回总销售额、订单数量、平均订单价格等指标。",
  "inputSchema": {
    "type": "object",
    "properties": {
      "start_date": {
        "type": "string",
        "description": "查询开始日期,格式YYYY-MM-DD。例如2025-01-01"
      },
      "end_date": {
        "type": "string",
        "description": "查询结束日期,格式YYYY-MM-DD。例如2025-12-31"
      },
      "category": {
        "type": "string",
        "enum": ["electronics", "clothing", "food", "all"],
        "description": "产品类别过滤。不指定则返回所有类别"
      }
    },
    "required": ["start_date", "end_date"]
  }
}

关键改进

  • 详细的功能说明
  • 返回值的具体描述
  • 参数的格式要求
  • 具体示例
2. 资源文档注入

某些情况下,应该把重要的参考文档注入上下文

系统提示词:
你是一个销售分析专家。以下是我们公司的销售政策文档:

【销售折扣政策】
- 订单金额>$10k: 5%折扣
- 订单金额>$50k: 10%折扣
- VIP客户额外5%折扣

【销售目标】
- 本季度目标:$5M
- 增长率目标:15%

基于上述政策,分析用户的销售数据...

3.3.3 上下文窗口的管理

graph TB
    A["上下文窗口"] -->|固定部分| B["系统提示"]
    A -->|固定部分| C["工具定义"]
    A -->|动态部分| D["对话历史"]
    A -->|动态部分| E["相关资源"]
    
    B --> B1["大小:500-1000字"]
    B --> B1A["通常不变"]
    
    C --> C1["大小:2000-5000字"]
    C --> C1A["根据用户需求调整"]
    
    D --> D1["大小:动态"]
    D --> D1A["需要定期修剪"]
    
    E --> E1["大小:动态"]
    E --> E1A["基于当前任务选择"]

上下文管理最佳实践

class ContextManager:
    def __init__(self, max_context_tokens=4000):
        self.max_tokens = max_context_tokens
        self.system_prompt = ""  # 固定
        self.tool_definitions = {}  # 固定
        self.conversation_history = []  # 动态
        self.injected_resources = []  # 动态
    
    def calculate_total_tokens(self):
        """计算当前上下文的总token数"""
        total = (
            self.count_tokens(self.system_prompt) +
            self.count_tokens(self.tool_definitions) +
            sum(self.count_tokens(msg) for msg in self.conversation_history) +
            sum(self.count_tokens(res) for res in self.injected_resources)
        )
        return total
    
    def ensure_within_limit(self):
        """确保上下文在限制内"""
        while self.calculate_total_tokens() > self.max_tokens:
            # 优先删除最早的对话记录
            if self.conversation_history:
                self.conversation_history.pop(0)
            # 然后删除最不相关的资源
            elif self.injected_resources:
                self.injected_resources.pop(0)
            else:
                break

3.4 Agent系统设计

3.4.1 什么是MCP Agent

定义:MCP Agent是一个自主决策系统,可以:

  1. 理解用户目标
  2. 规划执行步骤
  3. 自主调用MCP工具
  4. 基于结果反复调整
  5. 最终达成目标
graph TB
    A["Agent架构"] --> B["感知层"]
    A --> C["决策层"]
    A --> D["执行层"]
    A --> E["反馈层"]
    
    B --> B1["理解用户需求"]
    B --> B2["获取环境信息"]
    B --> B3["检查工具可用性"]
    
    C --> C1["规划执行步骤"]
    C --> C2["选择合适工具"]
    C --> C3["生成工具参数"]
    
    D --> D1["调用MCP工具"]
    D --> D2["处理返回结果"]
    D --> D3["更新内部状态"]
    
    E --> E1["评估是否达成目标"]
    E --> E2["决定是否继续"]
    E --> E3["学习和优化"]

3.4.2 Agent的状态机

stateDiagram-v2
    [*] --> 初始化
    
    初始化 --> 分析请求
    
    分析请求 --> 是否理解?
    是否理解? -->|否| 请求澄清
    请求澄清 --> 分析请求
    
    是否理解? -->|是| 规划
    
    规划 --> 是否需要工具?
    是否需要工具? -->|否| 直接回答
    是否需要工具? -->|是| 选择工具
    
    选择工具 --> 调用工具
    调用工具 --> 获得结果
    
    获得结果 --> 目标完成?
    目标完成? -->|是| 总结结果
    目标完成? -->|否| 还有资源?
    
    还有资源? -->|是| 规划
    还有资源? -->|否| 总结结果
    
    总结结果 --> 直接回答
    直接回答 --> [*]

3.4.3 Agent实现示例(Python伪代码)

class MCPAgent:
    def __init__(self, llm, mcp_client):
        self.llm = llm
        self.mcp = mcp_client
        self.max_iterations = 10
        self.conversation_history = []
    
    async def run(self, user_request):
        """运行Agent解决用户问题"""
        self.conversation_history = []
        
        for iteration in range(self.max_iterations):
            # 1. 让LLM分析当前状态并决定下一步
            response = await self.llm.complete(
                messages=self.conversation_history + [
                    {"role": "user", "content": user_request}
                ],
                tools=self.mcp.list_tools()
            )
            
            # 2. 检查LLM是否想调用工具
            if response.stop_reason == "tool_use":
                tool_use = response.tool_use[0]
                tool_name = tool_use["name"]
                tool_args = tool_use["input"]
                
                # 3. 调用MCP工具
                tool_result = await self.mcp.call_tool(
                    tool_name, 
                    tool_args
                )
                
                # 4. 将结果添加到对话历史
                self.conversation_history.append({
                    "role": "assistant",
                    "content": response.text,
                    "tool_use": tool_use
                })
                self.conversation_history.append({
                    "role": "user",
                    "content": f"工具 {tool_name} 的结果: {tool_result}"
                })
                
            else:
                # LLM已经得出最终答案
                return response.text
        
        return "达到最大迭代次数,无法完成任务"

3.5 提示工程与MCP的结合

3.5.1 为MCP优化提示词

关键原则
graph TB
    A["MCP提示词设计"] --> B["清晰"]
    A --> C["具体"]
    A --> D["上下文"]
    A --> E["约束"]
    
    B --> B1["明确工具的目的"]
    B --> B2["明确何时调用"]
    
    C --> C1["具体示例"]
    C --> C2["参数要求"]
    
    D --> D1["业务背景"]
    D --> D2["相关规则"]
    
    E --> E1["调用限制"]
    E --> E2["安全边界"]
提示词模板
你是一个{角色}。你可以访问以下工具来{任务}。

## 可用工具
{工具列表和描述}

## 业务规则
- {规则1}
- {规则2}
- {规则3}

## 用户请求处理流程
1. 理解用户的具体需求
2. 分析是否需要调用工具
3. 如果需要,按照以下优先级调用:
   a. 首先查询必要数据(使用query工具)
   b. 然后进行分析(使用analysis工具)
   c. 最后生成报告(使用reporting工具)
4. 基于工具结果给出专业建议

## 重要限制
- 不要调用tools/transfer_funds超过3次
- 所有金额操作需要经过审批
- 不要修改生产数据,仅供测试使用

## 输出格式
提供结构化的分析,包括:
1. 数据摘要
2. 关键发现
3. 建议

现在,用户的请求是:{用户请求}

3.5.2 思维链(Chain of Thought)与MCP

让LLM逐步思考,而不是直接调用工具:

用户请求:分析我们的销售数据,给出增长建议

改进的提示:
请按照以下步骤分析:

**第一步:理解问题**
- 用户想了解什么方面的销售数据?
- 需要什么时间范围的数据?

**第二步:收集信息**
使用以下工具按顺序调用:
1. query_sales(时间范围) - 获取总体销售额
2. get_sales_by_product(时间范围) - 了解产品结构
3. get_regional_performance(时间范围) - 了解地区表现

**第三步:分析数据**
基于收集的数据:
- 对比同期表现
- 找出最强和最弱的产品/地区
- 识别增长驱动因素

**第四步:生成建议**
基于分析,提出可行的改进建议

---

请开始分析:

3.6 MCP vs 函数调用 vs 原生集成

3.6.1 三种方案对比

graph TB
    A["LLM能力扩展方案"] --> B["OpenAI Function Calling"]
    A --> C["原生SDK集成"]
    A --> D["MCP方案"]
    
    B --> B1["优点"]
    B --> B2["缺点"]
    
    B1 --> B1A["简单易用"]
    B1 --> B1B["开发快"]
    
    B2 --> B2A["仅支持OpenAI"]
    B2A --> B2A1["ChatGPT、GPT-4"]
    B2A --> B2A2["格式不统一"]
    B2 --> B2B["难以维护"]
    B2 --> B2C["每个应用独立"]
    
    C --> C1["优点"]
    C --> C2["缺点"]
    
    C1 --> C1A["高度集成"]
    C1 --> C1B["性能优"]
    
    C2 --> C2A["厂商锁定"]
    C2 --> C2B["维护成本高"]
    C2 --> C2C["难以跨项目"]
    
    D --> D1["优点"]
    D --> D2["缺点"]
    
    D1 --> D1A["模型无关"]
    D1 --> D1B["标准统一"]
    D1 --> D1C["易于维护"]
    D1 --> D1D["可复用性强"]
    
    D2 --> D2A["相对复杂"]
    D2 --> D2B["生态还在成长"]

3.6.2 选择矩阵

因素Function Calling原生SDKMCP
模型兼容性仅OpenAI单一厂商所有模型
学习曲线陡峭中等平缓
开发速度快(初始)中等中等偏快
长期维护困难困难容易
复用性
企业适用小项目中等大型
未来扩展受限受限灵活

本章总结

核心概念关键点
能力补充知识、计算、执行三个维度
工具调用完整的请求-响应流程
循环推理多轮迭代,逐步完成复杂任务
上下文注入为LLM提供必要的背景信息
Agent系统自主决策和规划能力
提示工程与MCP结合的最佳实践
方案对比MCP在标准化和可维护性上优势明显

常见问题

Q1: LLM什么时候应该调用工具? A: 当LLM判断基于自身知识无法准确回答时。关键指标包括:需要最新数据、需要精确计算、需要修改外部系统。

Q2: 如何判断一个Agent是否陷入死循环? A: 设置最大迭代次数(如10次),监控是否重复调用同样的工具组合,追踪相同的对话内容。

Q3: 上下文窗口满了怎么办? A: 优先保留系统提示和工具定义,删除最早的对话记录,根据相关度删除资源。或使用更长的上下文窗口模型。

Q4: 如何确保Agent的输出安全? A: 在调用修改性操作的工具前必须人工确认,记录所有工具调用的审计日志,限制敏感工具的调用频率。

Q5: MCP Agent相比传统编程有什么优势? A: MCP Agent更灵活、更易理解、更容易适应变化。但需要额外的监控和验证来确保可靠性。


实战要点

✅ 做好的做法

  • 充分测试工具的正确性,因为Agent会依赖它们
  • 为工具提供详细清晰的描述
  • 设置合理的迭代限制
  • 对关键操作进行人工验证
  • 监控和记录所有的Agent执行过程

❌ 避免的做法

  • 不要让Agent直接调用不可逆的操作(如永久删除)
  • 不要给Agent不必要的工具访问权限
  • 不要依赖LLM的准确性而忽视验证
  • 不要在生产环境直接部署未充分测试的Agent
  • 不要忽视审计和监控

延伸阅读


下一章预告:第4章将介绍MCP生态现状,包括官方实现、社区方案、开源服务器、开发者工具等,帮助您快速找到合适的工具。