首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >deepseek+MCP简单实践

deepseek+MCP简单实践

原创
作者头像
用户9546848
发布2025-10-12 21:44:11
发布2025-10-12 21:44:11
910
举报

1. 背景介绍

目前市场上的各种LLM模型已经十分丰富,一直在考虑如何在本地搭建数据库和训练一个自己的专属模型。在探索过程中发现了一个比较有趣的方向,就是Model Context Protocol(MCP),即模型上下文协议。按照当下很多人的看法,MCP类似于LLM的USB接口,通过MCP协议LLM可以方便的调用各种丰富的外部工具,只要工具是支持MCP协议的。

2. MCP协议

2.1 简介

MCP(模型上下文协议,Model Context Protocol)是由Anthropic提出的一种用于LLM与各种数据源和工具进行交互的接口协议规范。其消息传输格式遵循JSON-RPC2.0标准,共包含

2. 简单代码示例

MCP协议遵循服务器-客户端的通信模式(client-server),因此在一个MCP项目中需要包含mcp_client和mcp_server两个组件。在mcp_server中用户可以定义自己的方法库,即工具库。mcp_client负责和mcp服务器和LLM进行交互。案例参考了文档:MCP 系列六:FastMCP,构建 MCP 的 python 框架,比官方 SDK 更好用!前文我们基于官方的 pyt - 掘金

2.1 mcp_server.py

代码语言:txt
复制
from fastmcp import FastMCP

mcp = FastMCP(name="math")

@mcp.tool()
def add(a: float, b: float) -> float:
    """加法运算

    参数:
    a: 第一个数字
    b: 第二个数字

    返回:
    两数之和
    """
    return a + b


@mcp.tool()
def subtract(a: float, b: float) -> float:
    """减法运算

    参数:
    a: 第一个数字
    b: 第二个数字

    返回:
    两数之差 (a - b)
    """
    return a - b


@mcp.tool()
def multiply(a: float, b: float) -> float:
    """乘法运算

    参数:
    a: 第一个数字
    b: 第二个数字

    返回:
    两数之积
    """
    return a * b


@mcp.tool()
def divide(a: float, b: float) -> float:
    """除法运算

    参数:
    a: 被除数
    b: 除数

    返回:
    两数之商 (a / b)

    异常:
    ValueError: 当除数为零时
    """
    if b == 0:
        raise ValueError("除数不能为零")
    return a / b

if __name__ == "__main__":
    mcp.run(transport='sse', host="127.0.0.1", port=8001)

2.2 llm_client.py

在llm_client.py中主要实现LLM模型的调用。

代码语言:txt
复制
import json
from typing import List, Dict
import asyncio

from fastmcp import Client
from openai import OpenAI

class LLMClient:

    """LLM客户端,负责与大语言模型API通信"""

    def __init__(self, model_name: str, url: str, api_key: str) -> None:
        self.model_name: str = model_name
        self.url: str = url
        self.client = OpenAI(api_key=api_key, base_url=url)

    def get_response(self, messages: list[dict[str, str]]) -> str:
        """发送消息给LLM并获取响应"""
        response = self.client.chat.completions.create(
            model=self.model_name,
            messages=messages,
            stream=False
        )
        return response.choices[0].message.content

2.3 user_client.py

user_client.py中主要负责实现用户和mcp_client和llm_client的交互。

代码语言:txt
复制
import json
from typing import List, Dict
import asyncio
from llm_client import LLMClient
from fastmcp import Client
from openai import OpenAI

class UserClient:
    """聊天会话,处理用户输入和LLM响应,并与MCP工具交互"""

    def __init__(self, llm_client: LLMClient, mcp_client: Client, ) -> None:
        self.mcp_client: Client = mcp_client
        self.llm_client: LLMClient = llm_client

    async def process_llm_response(self, llm_response: str) -> str:
        """处理LLM响应,解析工具调用并执行"""
        try:
            # 尝试移除可能的markdown格式
            if llm_response.startswith('```json'):
                llm_response = llm_response.strip('```json').strip('```').strip()
            tool_call = json.loads(llm_response)
            if"tool"in tool_call and"arguments"in tool_call:
                # 检查工具是否可用
                tools = await self.mcp_client.list_tools()
                if any(tool.name == tool_call["tool"] for tool in tools):
                    try:
                        # 执行工具调用
                        result = await self.mcp_client.call_tool(
                            tool_call["tool"], tool_call["arguments"]
                        )

                        return f"Tool execution result: {result}"
                    except Exception as e:
                        error_msg = f"Error executing tool: {str(e)}"
                        logging.error(error_msg)
                        return error_msg
                return f"No server found with tool: {tool_call['tool']}"
            return llm_response
        except json.JSONDecodeError:
            # 如果不是JSON格式,直接返回原始响应
            return llm_response

    async def start(self, system_message) -> None:
        """启动聊天会话的主循环"""
        messages = [{"role": "system", "content": system_message}]
        while True:
            try:
                # 获取用户输入
                user_input = input("用户: ").strip().lower()
                if user_input in ["quit", "exit", "退出"]:
                    print('AI助手退出')
                    break
                messages.append({"role": "user", "content": user_input})

                # 获取LLM的初始响应
                llm_response = self.llm_client.get_response(messages)
                print("助手: ", llm_response)

                # 处理可能的工具调用
                result = await self.process_llm_response(llm_response)

                # 如果处理结果与原始响应不同,说明执行了工具调用,需要进一步处理
                while result != llm_response:
                    messages.append({"role": "assistant", "content": llm_response})
                    messages.append({"role": "system", "content": result})

                    # 将工具执行结果发送回LLM获取新响应
                    llm_response = self.llm_client.get_response(messages)
                    result = await self.process_llm_response(llm_response)
                    print("助手: ", llm_response)

                messages.append({"role": "assistant", "content": llm_response})

            except KeyboardInterrupt:
                print('AI助手退出')
                break

2.4 main.py

main.py作为项目的执行入口程序

代码语言:txt
复制
import json
from typing import List, Dict
import asyncio
from llm_client import LLMClient
from math_client import MathClient
from fastmcp import Client
from openai import OpenAI

async def main():
    async with Client("http://127.0.0.1:8001/sse") as mcp_client:
        # 初始化LLM客户端,使用deepseek
        llm_client = LLMClient(model_name='deepseek-chat', api_key="xxxxxx",
                               url='https://api.deepseek.com')

        # 获取可用工具列表并格式化为系统提示的一部分
        tools = await mcp_client.list_tools()
        dict_list = [tool.__dict__ for tool in tools]
        tools_description = json.dumps(dict_list, ensure_ascii=False)

        # 系统提示,指导LLM如何使用工具和返回响应
        system_message = f'''
                你是一个智能助手,严格遵循以下协议返回响应:

                可用工具:{tools_description}

                响应规则:
                1、当需要计算时,返回严格符合以下格式的纯净JSON:
                {{
                    "tool": "tool-name",
                    "arguments": {{
                        "argument-name": "value"
                    }}
                }}
                2、禁止包含以下内容:
                 - Markdown标记(如```json)
                 - 自然语言解释(如"结果:")
                 - 格式化数值(必须保持原始精度)
                 - 单位符号(如元、kg)

                校验流程:
                ✓ 参数数量与工具定义一致
                ✓ 数值类型为number
                ✓ JSON格式有效性检查

                正确示例:
                用户:单价88.5买235个多少钱?
                响应:{{"tool":"multiply","arguments":{{"a":88.5,"b":235}}}}

                错误示例:
                用户:总金额是多少?
                错误响应:总价500元 → 含自然语言
                错误响应:```json{{...}}``` → 含Markdown

                3、在收到工具的响应后:
                 - 将原始数据转化为自然、对话式的回应
                 - 保持回复简洁但信息丰富
                 - 聚焦于最相关的信息
                 - 使用用户问题中的适当上下文
                 - 避免简单重复使用原始数据
                '''
        # 启动聊天会话
        chat_session = UserClient(llm_client=llm_client, mcp_client=mcp_client)
        await chat_session.start(system_message=system_message)

if __name__ == "__main__":
    asyncio.run(main())

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 背景介绍
  • 2. MCP协议
  • 2. 简单代码示例
    • 2.1 mcp_server.py
    • 2.2 llm_client.py
    • 2.3 user_client.py
    • 2.4 main.py
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档