万字长文:说清MCP的前世今生+RAGFlow整合应用示例

人工智能
本文从复杂提示词引导模型调用工具开始,到 MCP 作为统一协议标准的变化过程以及小试牛刀的演示下在传统 RAG 基础上,针对机械加工场景结合 MCP 的一些功能延展示例。

上篇文章给大家预告了我在研究些 RAG+MCP(大模型上下文协议)的事,前后断断续续写了四天,终于完成了这篇稿子,这篇试图说清楚两个事情:

1、从复杂提示词引导模型调用工具开始,到 MCP 作为统一协议标准的变化过程;

2、小试牛刀的演示下在传统 RAG 基础上,针对机械加工场景结合 MCP 的一些功能延展示例。

以下,enjoy:

1、先说说大模型 API 调用

先简单回顾下最简单的大模型基础聊天应用开发,也就是直接按照目标 LLM 的官方 API 文档进行请求的做法。例如,如果我们要通过 Python 调用 DeepSeek-R1 模型进行问答,按照官方文档说明示例如下:

from openai import OpenAI


client = OpenAI(api_key="<DeepSeek API Key>", base_url="https://api.deepseek.com")


response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "Hello"},
    ],
    stream=False
)


print(response.choices[0].message.content)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

图片

因为大多数模型厂商都是兼容 OpenAI 规范的,也就是说在使用 OpenAI SDK 请求方式下,直接替换上述的 base_url 换成其他模型地址,都是可以实现请求响应的。比如如果要请求Qwen 系列模型,那base_url 就替换成: https://dashscope.aliyuncs.com/compatible-mode/v1 。进一步说,如果要想实现多轮对话,让大模型“拥有记忆”满足追问,以阿里的 QWQ 模型为例,可以把content字段通过{'role': 'assistant', 'content':拼接后的流式输出 content}添加到上下文。(注:无需添加reasoning_content字段)

2、复杂提示词工程的缘起

上面提到的聊天应用,只是基于 LLM 的已有知识,回答效果在有些场景下不符合预期。毕竟,LLM 在训练完成的那一刻,它所掌握的知识就冻结了。这显然是回答不了具有时效性或者准确来说是超出 LLM 训练截止完成以前时间的问题,当然还包括私有化的信息等。

简而言之,通过引入外部工具,可以让 LLM 和外部世界进行交互。OpenAI 在 23年6月正式推出了 Function Calling 功能,最初在 GPT-3.5和 GPT-4 模型上实现。不过,在正式介绍这个 Fucntion Calling 功能之前,先来聊下在此之前通过复杂提示词引导模型调用工具的尝试。

以 get_current_weather 和 get_current_weather 两个 tool 为例,下文进行相关实现方式的对比说明。

# 系统提示词设计
SYSTEM_PROMPT = """
你是一个智能助手,具有以下工具:


1. 时间工具 (TIME)
   - 格式:TIME: 获取当前时间
   - 功能:返回当前的完整日期和时间


2. 天气工具 (WEATHER)
   - 格式:WEATHER: 城市名称
   - 功能:获取指定城市的当前天气情况


3. 计算工具 (CALCULATE)
   - 格式:CALCULATE: 数学表达式
   - 功能:执行数学计算


重要规则:
- 必须严格遵循上述格式
- 只有在确实需要使用工具时才使用
- 工具调用应该是输出的唯一内容
- 使用工具后,还需要对结果进行自然语言解释


示例:
用户: 北京今天几点了?
助手: TIME: 获取当前时间


用户: 我想知道北京的天气
助手: WEATHER: 北京


用户: 帮我计算15乘以23
助手: CALCULATE: 15 * 23
"""


# 模拟工具实现
def mock_tool_execution(tool_call):
    import datetime
    
    if tool_call.startswith("TIME:"):
        return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    elif tool_call.startswith("WEATHER:"):
        city = tool_call.split("WEATHER:")[1].strip()
        # 模拟天气API
        return f"{city}:晴,温度22°C,湿度45%"
    
    elif tool_call.startswith("CALCULATE:"):
        expression = tool_call.split("CALCULATE:")[1].strip()
        try:
            return str(eval(expression))
        except Exception as e:
            return f"计算错误:{str(e)}"
    
    return "未识别的工具调用"


# 对话交互模拟
def chat_interaction():
    print("智能助手已启动。输入'退出'结束对话。")
    
    while True:
        user_input = input("用户: ")
        
        if user_input == '退出':
            break
        
        # 模拟模型处理
        # 实际场景中这里会是大语言模型的处理
        tool_match = None
        
        # 简单的规则匹配
        if "时间" in user_input:
            tool_match = "TIME: 获取当前时间"
        elif "天气" in user_input:
            city_match = user_input.replace("天气", "").strip()
            tool_match = f"WEATHER: {city_match}" if city_match else None
        elif "计算" in user_input or "*" in user_input or "+" in user_input:
            # 尝试提取计算表达式
            import re
            match = re.search(r'(\d+\s*[\+\-\*\/]\s*\d+)', user_input)
            if match:
                tool_match = f"CALCULATE: {match.group(1)}"
        
        if tool_match:
            print("助手:", tool_match)
            result = mock_tool_execution(tool_match)
            print(f"工具执行结果: {result}")
        else:
            print("助手: 很抱歉,我没有找到合适的工具来处理您的请求。")


# 运行交互
if __name__ == "__main__":
    chat_interaction()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.

示例运行展示效果如下:

智能助手已启动。输入'退出'结束对话。
用户: 现在几点了
助手: TIME: 获取当前时间
工具执行结果: 2024-03-18 16:45:30
用户: 北京天气怎么样
助手: WEATHER: 北京
工具执行结果: 北京:晴,温度22°C,湿度45%
用户: 计算15乘以23
助手: CALCULATE: 15 * 23
工具执行结果: 345
用户: 退出
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

总结来说,这种复杂提示词的做法,主要包括以下四个特征:

  • 在系统提示中详细说明输出格式
  • 使用特定的分隔符和标记(如 XML 标签)
  • 通过正则表达式解析模型输出提取"函数调用"
  • 在对话历史中包含工具使用示例

这种做法的局限性首先就是表现为格式不可靠,大模型可能不一致地遵循指令。毕竟 Transformer 的底层逻辑还是 Next token prediction。其次,对于复杂参数结构就更加不靠谱。当然还有例如参数验证困难、占用大量提示词空间等问题,就不一一赘述了。

不过,需要给这种做法正名的是,对于简单场景,可以考虑使用此类提示词方法,实现成本低,也不依赖特定模型能力,但同时需要始终警惕模型输出的不确定性。

3、Function Calling 初露锋芒

上述提到的通过提示词来引导模型调用工具的尝试,OpenAI 将其标准化并作为 API 的一部分提供,也就有了现在大家所说的 Function Calling。

3.1创新之处

相比于提示词引导模型调用工具的方法,主要创新之处体现在以下几点:

结构化输出:

确保模型能以预定义的 JSON 格式输出函数调用参数,提高了可解析性和可靠性

函数定义明确:

通过函数模式(schema)清晰定义名称、描述、参数类型等

降低解析复杂度:

开发者不需要编写复杂的文本解析逻辑

提高准确性:

减少了模型在生成函数调用时的"幻觉"问题

简化开发流程:

标准化了大模型与外部工具的交互方式

BTW,并不是所有的 LLM 都支持 Function Calling,因为模型要支持 Function Calling 通常需要专门的训练或微调。具体来说,需要在预训练或者微调阶段引入函数调用的示例,训练模型理解函数模式(schema),学习如何生成符合预期格式的 json 输出,以及理解参数类型和约束条件等。

3.2实现机制

那大模型的工具选择和调用具体关键机制是什么样的呢,这里提供一个 Qwen 模型的简单示例,具体实现上大致分为两步:

1、意图推理与工具匹配

  • 大模型会基于用户输入,对可用工具的描述和参数进行语义理解
  • 模型会通过自然语言理解和推理,判断是否需要调用工具,以及调用哪个具体的工具

这个过程是自动的,不需要开发者手动硬编码每一个判断逻辑

2、智能参数填充

  • 模型能够从对话上下文中提取必要的参数信息
  • 对于需要特定参数的函数,模型可以智能地填充这些参数值
import os
from openai import OpenAI


# 初始化OpenAI客户端,配置阿里云DashScope服务
client = OpenAI(
    # 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",
    api_key=os.getenv("DASHSCOPE_API_KEY"),  # 从环境变量读取API密钥
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)


# 定义可用工具列表
tools = [
    # 工具1 获取当前时刻的时间
    {
        "type": "function",
        "function": {
            "name": "get_current_time",
            "description": "当你想知道现在的时间时非常有用。",
            "parameters": {}  # 无需参数
        }
    },  
    # 工具2 获取指定城市的天气
    {
        "type": "function",
        "function": {
            "name": "get_current_weather",
            "description": "当你想查询指定城市的天气时非常有用。",
            "parameters": {  
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "城市或县区,比如北京市、杭州市、余杭区等。"
                    }
                },
                "required": ["location"]  # 必填参数
            }
        }
    }
]


# 节省篇幅,此处省略后续代码
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.

例如,如果用户问:

"现在几点了?" → 模型可能调用 get_current_time"

北京今天天气怎么样?" → 模型可能调用 get_current_weather,并自动填充 locatinotallow="北京"

总结来说,关键实现包括:

  • 工具描述(description)提供语义线索
  • 参数定义(parameters)指导参数填充
  • 模型的上下文理解和推理能力

尽管看起来很强大,但 Function Calling 会比较依赖模型的理解能力,而且工具描述的质量直接影响调用准确性,所以也存在误解或错误调用的可能性。

3.3Function Calling vs 传统硬编码

看到这里,可能会有盆友会疑惑 Function Calling 和传统手动函数调用外部工具实现逻辑的差别是啥。同样参照上述提到的两个 tool,附上一个传统硬编码的做法示例:

import datetime
import requests


def get_current_time():
    """manually retrieve current time"""
    return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")


def get_current_weather(location):
    """manually fetch weather for a specific location"""
    # 模拟天气API调用
    try:
        # 假设这里是一个真实的天气API调用
        # 实际场景中,你需要替换为真实的API端点和处理逻辑
        response = requests.get(f"https://weather-api.example.com/current?city={location}")
        weather_data = response.json()
        return f"{location}的当前天气:{weather_data['temperature']}°C,{weather_data['condition']}"
    except Exception as e:
        return f"获取{location}天气失败:{str(e)}"


def process_user_query(query):
    """手动线性触发函数"""
    # 使用硬编码的条件判断
    if "时间" in query:
        return get_current_time()
    elif "天气" in query:
        # 需要额外的参数提取逻辑
        import re
        location_match = re.search(r'([\u4e00-\u9fff]+)天气', query)
        if location_match:
            location = location_match.group(1)
            return get_current_weather(location)
        else:
            return "请提供具体城市名称"
    else:
        return "无法理解您的请求"


# 模拟用户交互
def main():
    while True:
        user_input = input("请输入您的问题(输入'退出'结束):")
        if user_input == '退出':
            break
        
        response = process_user_query(user_input)
        print("系统回复:", response)


if __name__ == "__main__":
    main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.

示例运行结果:

# 可能的交互示例
请输入您的问题(输入'退出'结束):现在几点了
系统回复:2024-03-18 15:30:45


请输入您的问题(输入'退出'结束):北京天气怎么样
系统回复:北京的当前天气:15°C,晴朗


请输入您的问题(输入'退出'结束):退出
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

这个示例清晰地展示了传统手动触发方法的局限性:代码逻辑复杂、扩展性差、对用户输入的理解能力有限。相比之下,Function Calling 提供了一种更智能、更灵活的工具调用范式。

4、GPTs 的试图”大一统“

在正式说到 MCP 之前,还需要再聊下 GPTs 的故事。上述提到的 Function Calling 固然有很多好处,但是全部自己手动写似乎有点太麻烦,于是大聪明 OpenAI 就在 23 年 11 月初的开发者大会上,首次介绍了 GPTs 的概念,用户不需要任何编程知识,只需要通过自然语言指令和上传知识库,就能够轻松的定制自己的个性化 GPT。p.s.此举还有个实际效果是让全球开发者主动的为 ChatGPT 开发 Funtion Calling 工具。

此处忽略后来的狗血宫斗插曲,GPT Store 在 24 年 1 月对外正式发布,我查到的数据是,截止到 24 年1月份,用户自主创建的 GPTs 据说就超过了 300 万个。

图片

想起我 23 年 11 月 11 号发布第一个自己的 GPTs 的时候,当时看到 GPTs 导航站的统计有 4000+个,当时感慨发布一周就这么快上新,不曾想后来会如此井喷。

下面展示一个获取当前时间的 GPTs 示例,并解释其工作机制。

# 1. manifest.json
{
    "schema_version": "v1",
    "name_for_human": "Time Assistant",
    "name_for_model": "time_tool_gpt",
    "description_for_human": "A GPT that can retrieve current time information across different time zones.",
    "description_for_model": "You are a helpful time assistant capable of retrieving current time information precisely and efficiently.",
    "auth": {
        "type": "none"
    },
    "api": {
        "type": "openapi",
        "url": "https://your-domain.com/openapi.yaml"
    },
    "logo_url": "https://example.com/time-assistant-logo.png",
    "contact_email": "support@example.com",
    "privacy_policy_url": "https://example.com/privacy"
}


# 2. openapi.yaml
openapi: 3.0.0
info:
  title: Time Assistant API
  version: 1.0.0
  description: API for retrieving current time information
servers:
  - url: https://your-domain.com/api/v1


paths:
  /current-time:
    get:
      summary: Get current time
      operationId: getCurrentTime
      parameters:
        - name: timezone
          in: query
          required: false
          schema:
            type: string
            default: "UTC"
          description: Timezone to retrieve current time (e.g., 'UTC', 'America/New_York', 'Asia/Shanghai')
      responses:
        '200':
          description: Successful time retrieval
          content:
            application/json:
              schema:
                type: object
                properties:
                  current_time:
                    type: string
                    example: "2024-03-18T15:30:45Z"
                  timezone:
                    type: string
                    example: "UTC"
                  timestamp:
                    type: integer
                    example: 1710770445
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.

4.1核心文件解析

1、manifest.json

定义 GPT 的基本元数据

指定 API 交互方式

提供人类和模型可读的描述

配置身份验证和 API 接入点

2、 openapi.yaml

定义具体的 API 接口规范

描述可用的端点、参数和响应结构

提供工具调用的接口约定

4.2使用场景示例

"现在几点了?"、"北京现在是什么时间?"、"告诉我纽约当前时间"

GPT 会根据这些问题:

识别时间查询意图

选择/current-time接口

传入相应的 timezone 参数

4.3局限性

GPTs 完全绑定 OpenAI 生态系统,不兼容其他大模型平台(Anthropic、Google 等),无法跨平台移植和使用。在功能实现方面,工具调用方式高度标准化,缺乏灵活的参数传递机制,不支持复杂的状态管理,也无法实现复杂的工作流编排。另外从托管方式上看,完全依赖 OpenAI 云平台,不支持私有化部署,无法进行深度定制和二次开发等。

总结来说,GPTs 本质上是一个封闭、受限的生态系统,适合快速构建简单的交互工具,但对于需要高度定制和灵活性的场景,其局限性非常明显。对于追求技术自主可控的企业和开发者,GPTs 并不是一个好的选择。

5、MCP 推出的偶然和必然

模型上下文协议 (MCP) 24 年 11 月由 Anthropic 发布,总结来说就是两个要点,首先是一个协议兼容所有的 AI 应用,另外在 Function Calling 基础上增加了资源和提示词的功能。

5.1工具调用示例

先看下 MCP 实现工具调用示例, 这里以 get_current_time 的工具为例:

用户提问:现在几点了?

MCP 执行流程:

1、请求阶段:

{
  "messages": [
    {"role": "user", "content": "现在几点了?"}
  ],
  "context": {
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_current_time",
          "description": "当你想知道现在的时间时非常有用。",
          "parameters": {}
        }
      },
      {...}  // 另一个工具定义
    ]
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

2、模型响应阶段

{
  "response": {
    "model": "DeepSeek-R1:32b",
    "content": [
      {
        "type": "tool_use",
        "id": "call_1",
        "tool_use": {
          "name": "get_current_time",
          "parameters": {}
        }
      }
    ]
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

3、工具执行阶段:系统执行get_current_time函数,返回结果

{
  "messages": [
    {"role": "user", "content": "现在几点了?"},
    {
      "role": "assistant",
      "content": [
        {
          "type": "tool_use",
          "id": "call_1",
          "tool_use": {
            "name": "get_current_time",
            "parameters": {}
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_use_id": "call_1",
      "content": {"time": "2025-03-18T14:30:00Z"}
    }
  ]
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

4、最终响应

{
  "response": {
    "model": "DeepSeek-R1:32b",
    "content": [
      {
        "type": "text",
        "text": "现在的时间是北京时间2025年3月18日22:30(世界协调时间14:30)。"
      }
    ]
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

5.2执行步骤拆解

用户查询解析:

模型分析用户问题,确定需要调用哪个工具

对于需要参数的工具,提取必要参数(如城市名称)

工具调用请求生成:

模型生成标准化的工具调用请求,包含工具名称和参数

每个工具调用都有唯一 ID,方便后续追踪

工具执行:

系统接收工具调用请求

执行相应函数并获取结果

将结果以标准格式返回,关联到对应的工具调用 ID
  • 1.

结果整合与回复生成:

模型接收工具调用结果

将结果整合到上下文中

生成自然语言回复给用户

5.3MCP 资源访问控制

MCP 的资源访问控制功能可以精确定义大模型如何安全地访问企业内部资源。以机械加工企业部署 RAG 系统访问 MySQL 数据库为例做个效果演示:

{
  "messages": [
    {"role": "user", "content": "查询公司圆钢硬度标准"}
  ],
  "context": {
    "resources": [
      {
        "type": "database",
        "id": "materials_db",
        "config": {
          "engine": "mysql",
          "connection": {
            "host": "192.168.1.100",
            "database": "materials_specs",
            "schema": "standards"
          },
          "permissions": ["read"],
          "tables": ["material_standards", "quality_tests"],
          "access_level": "restricted"
        }
      }
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "query_database",
          "description": "查询企业材料标准数据库",
          "parameters": {
            "type": "object",
            "properties": {
              "resource_id": {"type": "string"},
              "query_type": {"type": "string", "enum": ["standard", "test", "material"]},
              "material_category": {"type": "string"},
              "standard_type": {"type": "string"}
            },
            "required": ["resource_id", "query_type"]
          }
        }
      }
    ]
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.

执行过程

权限验证层:系统首先验证当前用户对材料数据库的访问权限

资源边界定义:MCP 限制只能访问特定表(材料标准和质量测试)

查询限制:只允许读取操作,禁止写入或修改

数据筛选:可设置只返回非机密等级的标准数据

5.4实际应用优势

数据隔离:确保 LLM 只能访问授权表,无法看到客户数据、财务信息等敏感数据

审计追踪:记录所有数据库查询,便于合规审计

精细控制:可针对不同部门用户设置不同的数据访问范围

防止 SQL 注入:MCP 可以验证和清理查询请求,增强安全性

5.5提示词增强功能

MCP 的提示词增强功能可以为 LLM 提供额外上下文和专业指导,使其更好地处理专业领域问题,此处同样以机械加工企业为例:

{
  "messages": [
    {"role": "user", "content": "CNC加工中心出现S-02错误代码,如何排查?"}
  ],
  "context": {
    "prompts": [
      {
        "id": "mechanical_expertise",
        "content": "你是一名专业的机械加工技术顾问,熟悉CNC设备操作和故障排除。总是优先考虑安全因素,并遵循ISO 9001质量标准流程。在回答前,先确认错误的严重程度,然后按照'初步检查→可能原因→解决步骤→预防措施'的顺序组织回答。"
      },
      {
        "id": "company_terminology",
        "content": "使用公司标准术语:'加工中心'指HAAS VF-2SS设备,'S系列错误'表示主轴系统故障,'技术处理单'指企业内部ERP系统中的故障报告表单。参考设备代号时使用'HC-'前缀。"
      },
      {
        "id": "safety_guidelines",
        "content": "任何设备维修建议必须包含以下安全提醒:'维修前确保设备完全断电并上锁挂牌,穿戴适当的PPE装备,遵循公司MP-S-001安全手册规定的维修流程。'"
      }
    ],
    "resources": [
      {
        "type": "vector_database",
        "id": "equipment_manual_db",
        "config": {
          "collection": "equipment_manuals",
          "filters": {"equipment_type": "CNC"}
        }
      }
    ]
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

5.6应用场景与优势

专业术语统一

系统能理解并使用企业内部特定术语(如"HC-1500"指特定型号的加工中心)

确保回答符合企业标准规范和命名习惯

流程标准化

强制模型按照企业工艺流程标准回答问题

例如:CNC 故障诊断必须先检查安全状态,再进行电气和机械系统排查

知识融合

结合行业通用知识与企业特定知识
  • 1.

例如:将 ISO 标准与企业内部工艺规范结合

安全与合规保障

针对高风险操作自动添加安全警告

例如:加工特殊材料时提示需要特定防护措施和环保要求

5.7具体应用实例

机械设备故障诊断

提示词增强:设备故障回答必须包含:故障代码解释、可能原因(按概率排序)、诊断步骤(从简单到复杂)、维修所需工具清单、预计维修时间
  • 1.

工艺参数推荐

提示词增强:回答材料加工参数问题时,必须考虑企业现有设备能力限制,并参考企业工艺数据库中的历史成功案例
  • 1.

质量辅助控制

提示词增强:分析质量问题时,自动关联企业SPC数据,引用相关ISO标准条款,并建议适用的企业标准检测方法
  • 1.

6、RAGFlow 与 MCP 整合方案示例

为了实现企业多源数据的接入,这里演示下最近项目中初步实践通过 MCP 将 MySQL、EMS 等系统数据整合到 RAGFlow 框架中做法,供参考。

6.1架构设计

┌─────────────────────────────────────────────────┐
│               RAGFlow + MCP 集成架构             │
├─────────────────┬───────────────────────────────┤
│                 │        LLM调用层              │
│                 ├───────────────────────────────┤
│  原有RAGFlow    │        向量检索层             │
│                 ├───────────────────────────────┤
│                 │        文档处理层             │
├─────────────────┼───────────────────────────────┤
│                 │        MCP适配器层 ◄──────────┼──► MCP协议定义
│                 ├───────────────────────────────┤
│  MCP扩展部分    │        资源访问控制层         │
│                 ├───────────────────────────────┤
│                 │        多源数据连接层         │
└─────────────────┴───────────────────────────────┘
                           ▲   ▲   ▲
                           │   │   │
                  ┌────────┘   │   └────────┐
                  │            │            │
             ┌────────┐   ┌────────┐   ┌────────┐
             │ MySQL  │   │  EMS   │   │ 其他系统│
             └────────┘   └────────┘   └────────┘
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

6.2参考案例

场景:工程师查询设备故障和相关维修历史

(此处打个广告,相关示例源码请移步我的知识星球)

图片

1、用户查询

"数控车床HC-2000最近频繁报E-35错误,是否有相关的维修记录?"
  • 1.

2、系统处理流程

MCP 请求生成

{
  "response": {
    "model": "DeepSeek-R1:32b",
    "content": [
      {
        "type": "tool_use",
        "id": "call_1",
        "tool_use": {
          "name": "query_equipment_status",
          "parameters": {
            "resource_id": "production_db",
            "equipment_id": "HC-2000",
            "query_type": "maintenance_history"
          }
        }
      }
    ]
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

数据库查询执行:系统从 MySQL 数据库中查询 HC-2000 的维修记录工具执行结果

{
  "data": [
    {
      "date": "2025-02-15",
      "issue": "E-35错误:主轴编码器信号异常",
      "solution": "更换主轴编码器,调整编码器间隙"
    },
    {
      "date": "2025-01-20",
      "issue": "E-35错误:断续出现",
      "solution": "清洁线缆接头,重新固定连接器"
    }
  ]
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

向量检索补充:同时系统从向量数据库检索与"E-35 错误"相关的设备手册和技术文档

最终回复生成:系统综合数据库查询结果和向量检索结果,生成完整回答

用户获得回答

根据维修记录,HC-2000数控车床近期两次出现E-35错误(主轴编码器信号异常):


1. 2025年2月15日:更换了主轴编码器并调整了编码器间隙
2. 2025年1月20日:清洁了线缆接头并重新固定连接器


从设备手册分析,E-35错误通常由以下原因导致:
- 编码器线缆损坏或接触不良(占70%的案例)
- 编码器本身故障(约20%的案例)
- 主轴驱动电路问题(约10%的案例)


建议采取以下步骤:
1. 检查编码器线缆是否有磨损或松动
2. 测量线缆连接器与编码器接口电阻值(应<0.2Ω)
3. 使用示波器检查编码器信号质量


根据企业SOP-M1001标准,此类问题需填写《设备异常跟踪表》并由维修部门评估是否需要调整预防性维护计划。
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

7、整合技术要点

保持模块化设计

将 MCP 适配器作为独立模块添加,不破坏现有 RAGFlow 核心功能

使用适配器模式连接 RAGFlow 和企业数据源

统一资源访问接口

为所有数据源(向量库、MySQL、EMS 等)创建统一的资源访问接口

确保权限控制一致性

查询路由机制

开发智能查询路由,自动决定是使用向量检索还是结构化数据查询

支持混合查询模式,综合多种数据源结果

缓存与性能优化

对频繁查询的数据库结果进行缓存

使用批处理减少数据库连接开销

部署考虑

确保数据库连接器在企业内网环境正确配置

处理网络隔离环境下的连接问题

8、LLM 工具调用技术演进的一点思考

从复杂提示词→Function Calling→GPTs 插件→MCP 协议的技术演进路径,非常类似于几个经典技术标准化的发展历程,特别是 Web 技术、互联网协议和 API 标准化的过程。以 Web API 的标准化进程类比,

Web API 演进

AI 工具调用演进

早期:RPC(远程过程调用)各自实现

早期:提示词工程中的工具调用

发展期:SOAP 和 XML-RPC 等框架

发展期:Function Calling 的 JSON 结构化调用

成熟期:REST API 成为主流

成熟期:GPTs 等平台专属实现

统一期:GraphQL 等新一代标准

统一期:MCP 作为统一协议

观察 LLM 工具调用和相关技术标准的发展,似乎可以归纳出技术标准化的普遍规律:

探索期:

各方以自己的方式解决问题(提示词工程)

初步标准化:

出现基础结构化方案(Function Calling)

平台主导期:

主要平台推出自己的解决方案(GPTs 插件)

开放标准期:

形成统一开放标准(MCP 协议)

从历史经验看,统一标准的出现通常会带来技术领域的爆发式增长,如 Web 标准统一后的互联网繁荣。MCP 协议的出现,很可能标志着 LLM 工具生态即将进入一个快速发展、广泛应用的新阶段。

图片

25 年由此说来,值得期待更多垂直场景的最佳实践了。

责任编辑:庞桂玉 来源: 韦东东
相关推荐

2023-06-08 09:37:44

模型自动驾驶

2020-11-16 10:47:14

FreeRTOS应用嵌入式

2021-10-18 11:58:56

负载均衡虚拟机

2022-09-06 08:02:40

死锁顺序锁轮询锁

2021-01-19 05:49:44

DNS协议

2022-09-14 09:01:55

shell可视化

2024-03-07 18:11:39

Golang采集链接

2020-07-15 08:57:40

HTTPSTCP协议

2023-06-12 08:49:12

RocketMQ消费逻辑

2020-07-09 07:54:35

ThreadPoolE线程池

2022-10-10 08:35:17

kafka工作机制消息发送

2022-07-19 16:03:14

KubernetesLinux

2024-05-10 12:59:58

PyTorch人工智能

2021-08-26 05:02:50

分布式设计

2024-01-11 09:53:31

面试C++

2022-07-15 16:31:49

Postman测试

2024-01-05 08:30:26

自动驾驶算法

2022-09-08 10:14:29

人脸识别算法

2022-04-25 10:56:33

前端优化性能

2022-02-15 18:45:35

Linux进程调度器
点赞
收藏

51CTO技术栈公众号