Function CAll和MCP

Function CAll和MCP

1 Function Call

1.1 基础概念

  早期的LLMs工作流程基本上是用户通过输入文本与模型进行交互,模型根据输入文本生成响应文本。但是这样的模型有个问题,模型根据用户输入生成对应的响应输出文本,只能利用模型本身的能力。为了突破这层壁垒,将现有大量的软件生态能力接入到LLMs中,让LLMs更具生命力,能够与外部软件生态进行交互。

  GPT提供了根据用户输入文本解析用户意图,生成对应函数调用响应的能力。这种能够根据用户输入生成对应函数调用信息的能力,就是Function Call。需要明确的是,Function Call是建立在模型推理能力和外部软件能力的基础上的,是二者共同交互协作的产物。LLMs本身只能进行推理,无法完成具体的任务,Function Call就是将传统文本推理能力进一步细化,调整成推理函数调用信息。因此,可以看到LLMs在任务中的角色从来没有改变,一直是扮演任务推理的角色只是任务本身变化了。

  这也是大模型对Agent相关的价值所在,其打破了用户和代码直接的界限,可以让用户直接和底层能力交互,让生产环境某些步骤更加简单高效。

1.2 工作流程

  Function Calling最基本的工作流程是:用户提出请求,LLM 理解意图并选择合适的函数,生成参数并调用该函数,接收函数执行结果后整合到最终回复中呈现给用户,从而实现 LLM 与外部工具的交互,扩展其能力并完成更复杂的任务。

  其中LLMs主要参与用户的意图理解,输入是用户期望的promot,输出是相关函数的调用信息。而具体的函数调用是由外部软件完成的。

  最基本的工作流程就是:输入——推理——调用——返回结果。但是通常情况下为了处理更加复杂的任务流程会更加复杂,推理流程也会更加复杂。比如需要区分用户的诉求是咨询诉求还是执行诉求,根据不同的诉求执行不同的单元等等。

1.3 示例

  简单的描述比较干燥,下面用一个大模型Function Call的例子来说明LLMs Function Call是如何工作的。首先,我们需要实现期望运行的函数,这里实现了两个含简单的函数,一个是显示图片,一个是图片重设大小。

需要注意的是这里展示的只是最基本的原理,而实际上很多开元的function call会对工具进行二次封装,比如openai的示例。但是大体流程是一致的。

response = client.responses.create(
    model="gpt-4.1",
    input=[{"role": "user", "content": "What is the weather like in Paris today?"}],
    tools=tools
)
from PIL import Image
import ollama
import json
import re  # Import the regular expression module

def display_image(image_path):
    """Displays an image from the given path."""
    try:
        img = Image.open(image_path)
        img.show()  # This will open the image using the default image viewer
        return f"Image displayed successfully from {image_path}"
    except FileNotFoundError:
        return f"Error: Image not found at {image_path}"
    except Exception as e:
        return f"Error displaying image: {e}"


def resize_image(image_path, scale=0.5):
    """Resizes an image to half its original size and saves it with '_resized' suffix."""
    try:
        img = Image.open(image_path)
        width, height = img.size
        new_width = int(width * scale)
        new_height = int(height * scale)
        resized_img = img.resize((new_width, new_height))
        new_image_path = image_path.replace(".", "_resized.")  # Add '_resized' before the extension
        resized_img.save(new_image_path)
        return f"Image resized successfully and saved to {new_image_path}"
    except FileNotFoundError:
        return f"Error: Image not found at {image_path}"
    except Exception as e:
        return f"Error resizing image: {e}"

  然后我们需要告诉大模型,这些函数能干什么,参数是什么,返回值是什么。

# Function descriptions (adapt to the model's expected format)
function_descriptions = [
    {
        "name": "display_image",
        "description": "Displays an image from a given file path.",
        "parameters": {
            "type": "object",
            "properties": {
                "image_path": {
                    "type": "string",
                    "description": "The path to the image file.  Must be a valid path to an image file (e.g., PNG, JPG, JPEG).",
                },
            },
            "required": ["image_path"],
        },
    },
    {
        "name": "resize_image",
        "description": "Resizes an image to half its original size and saves the resized image with a suffix.",
        "parameters": {
            "type": "object",
            "properties": {
                "image_path": {
                    "type": "string",
                    "description": "The path to the image file to resize.",
                },
                "scale": {
                    "type": "number",
                    "description": "The scale factor to resize the image. Default is 0.5 for half the size.",
                    "default": 0.5,
                },
            },
            "required": ["image_path"],
        },
    },
]

  有了上面的函数描述,我们就可以将其告诉大模型我们的意图和相关的函数描述,大模型会根据输入来判断我们期望调用的参数。需要注意的是,在prompt中尽量标准化输出方便后续解析输出。

def run_conversation_ollama(user_prompt, model="deepseek-r1:1.5b-qwen-distill-fp16"):
    """
    Interacts with the local LLM via the ollama API, attempts to identify function calls, and executes them.
    """
    messages = [{"role": "user", "content": user_prompt}]

    # Include function descriptions in the prompt (you might need to adapt this based on the model)
    system_prompt = f"""你是一个图像处理专家,根据给定的函数列表分析出用户期望调用的函数名和对应的参数,返回的格式为:
    ```json
    {{
        "function": "function_name",
        "args": {{
            "image_path": "1.jpg",
            "scale": "0.1"
        }}
    }}
    ```
    可用的函数列表如下:\n{json.dumps(function_descriptions)}
    """
    messages.insert(0, {"role": "system", "content": system_prompt}) # Add system prompt

    try:
        response = ollama.chat(model=model, messages=messages)
        llm_response = response['message']['content']

        print(f"LLM Response: {llm_response}")

        # Attempt to parse the response to identify a function call
        function_name, arguments = extract_function_call(llm_response)  # Implement this function!

        if function_name:
            print(f"Identified function call: {function_name} with arguments: {arguments}")

            # Execute the function
            function_response = execute_function(function_name, arguments)  # Implement this function!

            print(f"Function response: {function_response}")

            # Integrate the function response into a final response
            messages.append({"role": "assistant", "content": llm_response}) # Add assistant response
            messages.append({"role": "function", "name": function_name, "content": function_response}) # Add function response

            # Get a new response from the model with the function result
            second_response = ollama.chat(model=model, messages=messages)
            final_response = second_response['message']['content']
            return final_response
        else:
            return llm_response

    except Exception as e:
        return f"Error during ollama interaction: {e}"

  拿到输出后就是从输出中解析出我们需要的参数,比如我本地返回的输出为如下,后续解析参数和调用比较简单就不说了。

<think>
好的,我现在要分析用户提供的信息,并根据给定的函数列表来确定应该调用哪个函数以及对应的参数。
首先,用户提供了一个示例:显示图片,图片路径是1.jpeg。看起来这是一个简单的请求,要求将指定的图像显示出来。根据可用的函数列表,有两个可能相关的函数:display_image 和 resize_image。  
我需要判断用户的需求属于哪种情况。用户明确提到“显示图片”,而不是“ resized image”。因此,应该使用 display_image 函数来完成操作。
接下来,我查看函数的参数。对于 display_image 函数,主要参数是 image_path,这是一个字符串,表示要显示的图像文件路径。用户提供的例子中,image_path 是1.jpeg,所以参数应该是 { "image_path": "1.jpg" }。
不需要使用 resize_image 的函数,因为用户没有提到需要调整大小或缩放。因此,在 args 中不包括 scale 参数。
总结一下,应该调用 display_image 函数,参数是 image_path,“1.jpg”。
</think>

```json
{
    "function": "display_image",
    "args": {
        "image_path": "1.jpg"
    }
}
```json

2 MCP

2.1 简介

  模型上下文协议 (MCP) 是一种旨在标准化和管理大语言模型 (LLM) 上下文信息的协议。它定义了 LLM 如何接收、处理和利用上下文信息,以提高生成结果的相关性、准确性和一致性。MCP 的目标是解决 LLM 在处理长文本、多轮对话和复杂任务时遇到的上下文理解和利用问题。

  所以总体上MCP只是一套协议,相比这就意味着可以通过这个协议调用网络上的LLM能力。Function Call是用来和LLM交互的,用来表示如何通过LLMs实现某些功能,更加和native贴近,相比之下MCP则是将这些能力通过协议开放到网络上让用户或者其他C端使用。这里只描述了MCP是什么,具体MCP细节不赘述了。
在这里插入图片描述

2.2 简单实现一个MCP

  简单实现一个MCP,首先是服务器,服务器是用来处理具体事务的。下面的代码比较简单就是接受客户端的请求然后通过llm解析然后执行具体的调用(这里也用到了function call解析,只不过没有那么标准,没有写function描述)。

from flask import Flask, request, jsonify
from PIL import Image
import io
import base64
import os
import threading
import time
import ollama
import json

app = Flask(__name__)

# 身份验证 (简单示例)
API_KEY = "your_secret_api_key"

# Ollama 模型名称
OLLAMA_MODEL = "llama2"  # 替换为你实际使用的 Ollama 模型

def authenticate(request):
    api_key = request.headers.get('X-API-Key')
    if api_key == API_KEY:
        return True
    else:
        return False

# 健康检查
@app.route('/health', methods=['GET'])
def health_check():
    return jsonify({"status": "ok"}), 200

@app.route('/process_image', methods=['POST'])
def process_image():
    print("processing request...")
    if not authenticate(request):
        return jsonify({"error": "Unauthorized"}), 401

    if 'image' not in request.files:
        return jsonify({"error": "No image provided"}), 400

    image_file = request.files['image']
    instruction = request.form.get('instruction', 'Resize the image to 200x200')  # 默认指令

    try:
        img = Image.open(io.BytesIO(image_file.read()))

        # 调用 Ollama 模型
        prompt = f"""你是一个图像处理专家,能够对图像进行缩放(scale),灰度化(grayscale),裁剪处理(crop)。分析输入的指令返回执行的结果格式为(输出结果除了这个json多余的内容不要加)
        ```json
        {{
            "function": "function_name",
            "args": {{
                "width": "200",
                "height": "200"
            }}
        }}
        ```
        "用户的输入为: {instruction}
        """
        response = ollama.generate(model=OLLAMA_MODEL, prompt=prompt, stream=False)
        res = response['response']
        i = res.find("{")
        re = res[i:]
        j = re.rfind("}")
        re = re[:j + 1]
        operation_data = json.loads(re)
        # 根据 Ollama 模型的输出进行图像处理
        if operation_data:
            operation = operation_data.get('function')
            if operation == 'scale':
                width = operation_data.get('width', 200)
                height = operation_data.get('height', 200)
                img = img.resize((width, height))
            elif operation == 'grayscale':
                img = img.convert('L')
            elif operation == 'rotate':
                angle = operation_data.get('angle', 90)
                img = img.rotate(angle)
            elif operation == 'crop':
                left = operation_data.get('left', 0)
                top = operation_data.get('top', 0)
                right = operation_data.get('right', 100)
                bottom = operation_data.get('bottom', 100)
                img = img.crop((left, top, right, bottom))
            else:
                return jsonify({"error": "Invalid operation from LLM"}), 400
        else:
            print("No operation needed based on the instruction.")

        # 将处理后的图像转换为 base64 编码
        buffered = io.BytesIO()
        img.save(buffered, format="JPEG")
        img_str = base64.b64encode(buffered.getvalue()).decode('utf-8')

        return jsonify({"image": img_str}), 200

    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True, port=5001)

  然后是客户端,客户端比较简单就是请求-响应。

import requests
import base64
from PIL import Image
import io

class MCPClient:
    def __init__(self, base_url, api_key):
        self.base_url = base_url
        self.api_key = api_key
        self.headers = {'X-API-Key': self.api_key}

    def process_image(self, image_path, instruction="Resize the image to 200x200"):
        url = f"{self.base_url}/process_image"
        try:
            with open(image_path, 'rb') as image_file:
                files = {'image': (image_path, image_file, 'image/jpeg')}
                data = {'instruction': instruction}
                print("sending request...")
                response = requests.post(url, files=files, data=data, headers=self.headers)
                response.raise_for_status()
                return response.json()
        except requests.exceptions.RequestException as e:
            print(f"Error processing image: {e}")
            return None

def display_image_from_base64(base64_image):
    try:
        image_data = base64.b64decode(base64_image)
        image = Image.open(io.BytesIO(image_data))
        image.show()  # 使用默认图像查看器显示图像
    except Exception as e:
        print(f"Error displaying image: {e}")

# 示例用法
if __name__ == '__main__':
    # 替换为你的 MCP 服务器地址和 API 密钥
    mcp_client = MCPClient("http://localhost:5001", "your_secret_api_key")

    image_path = "1.jpg"
    instruction = "Enter the image processing instruction: 缩放图片到200x200"

    result = mcp_client.process_image(image_path, instruction=instruction)
    if result:
        processed_image = result['image']
        display_image_from_base64(processed_image)
    else:
        print("Image processing failed.")

3 总结

  Function Calling 是一种 LLM 的能力,用于生成调用外部函数的指令,而 MCP 是一种自定义的消息传递协议,用于在客户端和服务器之间传递消息。 Function Calling 侧重于利用 LLM 的推理能力来驱动外部系统的执行,而 MCP 侧重于建立可靠的通信通道,以便客户端和服务器能够协同工作。 在你的图像处理应用中,你可以同时使用 Function Calling 和 MCP: 使用 Function Calling 来让 LLM 决定如何处理图像 (例如,选择合适的滤镜或调整参数),然后使用 MCP 将图像数据和 LLM 生成的指令传递给服务器进行处理。

特性Function Calling (LLM)MCP (自定义消息传递协议)
核心功能LLM 生成函数调用指令客户端和服务器之间的消息传递
执行函数LLM 执行函数,而是将指令返回给应用程序服务器执行函数 (例如图像处理)
控制权应用程序控制函数的执行客户端和服务器共同控制协议的实现
通用性可以与各种外部工具和服务集成通常用于特定的应用程序场景
自定义程度函数的定义和实现由开发者控制,但 LLM 的行为受到预训练模型的限制协议的各个方面 (消息格式、状态码、错误处理等) 都可以自定义
应用场景扩展 LLM 的能力,使其能够完成更复杂的任务在客户端和服务器之间建立可靠的通信通道,用于特定的应用程序需求 (例如图像处理)

4 参考文献

<think>嗯,用户问的是“functioncallmcp”的区别。首先,我需要明确这两个术语的具体含义,因为不同的领域可能有不同的解释。根据常见的计算机科学编程上下文,可能的解释方向有两个:操作系统中的系统调用(system call)与进程间通信(IPC)中的消息传递机制,或者是在某些特定框架或库中的概念,比如函数调用(function call)与某种消息传递协议(MCP)。 首先,考虑“function call”通常指的是程序中的函数调用,即一个函数执行时调用另一个函数的过程,涉及栈帧、参数传递、返回地址等。这是编程中的基础概念。而“MCP”可能有多种含义,比如“Message Channel Protocol”、“Microprocessor Control Protocol”,或者是某些系统中的专有术语。如果用户指的是操作系统中的机制,可能需要考虑“Message Passing”相关的概念,比如在进程间通信中的消息传递(Message Passing)与函数调用的对比。 需要进一步验证可能的领域。例如,在分布式系统中,消息传递(Message Passing)是进程间通信的一种方式,而本地函数调用则是同步的、直接的调用。另一个可能性是,在某些框架或库中,比如gRPC或某些RPC框架,可能会有远程函数调用(类似RPC)特定的消息传递协议(如MCP)的区别。 如果用户指的是系统级的概念,比如系统调用(syscall)中的“function call”与“MCP”,这里可能存在混淆。系统调用是用户空间程序请求内核服务的接口,而MCP可能是指某种消息传递机制,如Mach内核中的消息传递。此时,两者的区别在于系统调用的方式:系统调用通常通过软中断或专用指令触发,而消息传递可能通过共享内存、消息队列等方式实现。 另外,也可能用户提到的“mcp”是指“Message Channel Protocol”或其他特定协议,需要具体分析。例如,在微服务架构中,服务间通信可能通过HTTP/RPC(类似函数调用)或消息队列(如AMQP、Kafka)来实现,后者属于消息传递模式。 综合来看,可能的对比方向是:函数调用(Function Call)作为直接的、同步的调用方式,而消息传递(Message Passing)作为间接的、异步的通信机制。两者的主要区别在于调用方式、通信模型(同步/异步)、耦合度、错误处理机制等。 需要进一步确认用户的具体上下文,但由于无法询问,只能基于常见情况解释。因此,在回答中需要明确假设可能的定义,并对比两者的区别,包括执行方式、通信机制、适用场景等,同时指出可能的歧义,建议用户提供更多上下文以便更准确的解答。</think>### Function CallMCP 的区别分析 需要明确的是,**“Function Call”** **“MCP”** 的具体含义可能因上下文不同而变化。以下是两种常见场景下的解释: --- #### **1. 编程与系统设计中的对比** 假设 **Function Call** 指常规函数调用,**MCP** 指消息传递协议(Message Passing Protocol)或类似机制: | **特性** | **Function Call** | **MCP(消息传递)** | |------------------|-------------------------------------|----------------------------------| | **执行方式** | 同步调用,直接控制权转移 | 异步通信,通过发送/接收消息完成 | | **通信范围** | 同一进程内(或线程内) | 跨进程、跨机器、分布式系统 | | **耦合性** | 高(需明确调用目标) | 低(通过消息队列/主题解耦) | | **错误处理** | 通过异常或返回值直接处理 | 需监听反馈或超时机制 | | **典型应用** | 函数库、本地逻辑执行 | 微服务通信、事件驱动架构 | **示例** - **Function Call**(函数调用): ```python def add(a, b): return a + b result = add(3, 5) # 同步调用,直接返回结果 ``` - **MCP**(消息传递): 生产者发送消息到 Kafka 主题,消费者异步订阅处理。 --- #### **2. 操作系统中的对比** 若 **Function Call** 指系统调用(System Call),**MCP** 指消息控制协议(Message Control Protocol): | **特性** | **System Call** | **MCP(消息控制协议)** | |------------------|-------------------------------------|----------------------------------| | **目的** | 用户程序请求内核服务(如文件操作) | 管理进程间通信或硬件消息传递 | | **触发方式** | 软中断(如 `int 0x80`) | 通过特定硬件/协议通道 | | **性能开销** | 较高(需上下文切换) | 依赖实现(可能优化为低延迟) | | **典型场景** | 打开文件、网络通信 | 驱动层通信、实时系统消息传递 | **示例** - **System Call**: ```c int fd = open("file.txt", O_RDONLY); // 调用内核打开文件 ``` - **MCP**: 嵌入式系统中,通过 CAN 总线协议传递控制消息。 --- ### 关键区别总结 1. **执行模型** - Function Call:同步、直接、紧耦合。 - MCP:异步、间接、松耦合。 2. **适用场景** - Function Call:单机程序逻辑、快速本地操作。 - MCP:分布式系统、解耦组件、高容错需求。 3. **技术实现** - Function Call 依赖栈寄存器传递参数。 - MCP 依赖队列、网络协议或专用硬件通道。 --- ### 注意事项 - **术语歧义**:若 MCP 指代其他特定协议(如 **Multicast Communication Protocol**),需结合具体领域重新分析。 - **建议**:提供更多上下文(如操作系统、框架名称),可进一步明确差异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值