部署DeepSeek模型,进群交流最in玩法!
立即加群
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >借助CodeBuddy对MCP从理解到实践

借助CodeBuddy对MCP从理解到实践

原创
作者头像
languageX
修改于 2025-05-18 04:55:37
修改于 2025-05-18 04:55:37
34800
代码可运行
举报
文章被收录于专栏:大语言模型大语言模型
运行总次数:0
代码可运行

本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴

先说结论,使用CodeBuddy接入MCP,只需要十行配置代码。但是在使用之前,我们借助CodeBuddy先理解MCP的概念以及他能解决的问题,再基于CodeBuddy实践接入一个充电站信息查询MCP服务。

CodeBuddy

CodeBuddy是腾讯云代码助手,通过 Craft 智能体、代码补全等能力,在编码的各个阶段给予可靠支持。

CodeBuddy下载地址:https://copilot.tencent.com/setup/vscode/

CodeBuddy是国内首个支持 MCP 的代码助手,本文就利用CodyBuddy的智能对话和craft智能体模式对MCP从理论到实践全面理解。

descript
descript

MCP

通常大家都不太理解function call和MCP的关系和区别,提到function call就不得不提LLMAgent了,所以本文还是想将这些概念串起来进行简单介绍。

LLM

LLM就不介绍了,人尽皆知...GPT,Gemini,Claude,deepseek,混元,通义, 豆包, kimi等等。这些底座模型会较长时间进行一次迭代更新,所以在一段时间内模型具有的知识是固定的,实时性知识他们是无法回答的。

RAG

RAG就是来解决LLM的实时性和幻觉问题,我们可以通过检索将大模型不了解的知识以prompt的形式让他具有短期记忆,来回答用户问题。

Prompt

刚提到RAG是我们通过检索的形式将实时信息获取,然后以prompt的形式给大模型。Prompt大家也非常熟悉,用LLM就要写Prompt。在AI产品中比如腾讯混元大家通常就是一个指令让大模型进行回答,但是如果是构建智能体,通常会写一个系统提示词。

system Prompt

用来确定大模型的角色以及回复风格等,通常system Prompt是不变的。可以让CodeBuddy帮我们写一个system_prompt。

如下图,文件都帮生成好了:

descript
descript

user Prompt

用来确定你的需求,也就是希望希望大模型回复你的问题,利用RAG检索的内容就可以附加在User Prompt里面,user Prompt是变化的。

这块大家熟悉的东西我们再次强调,主要是后续function call会使用到。

Agent

其实在1986年Agent概念就被人工智能先驱 马文·明斯基(Marvin Minsky) 在其著作《思维的社会》(The Society of Mind)中首次系统性地提出。他定义 Agent 为能够感知环境、自主决策并执行行动的实体,并强调其社会交互性和智能性。

2023年ChatGPT的出现为 Agent 赋予了更强的能力,推动Agent从理论走向实际应用。AIAgen被定义为:以大语言模型为大脑驱动,具有自主理解感知、规划、记忆和使用工具的能力,能自动化执行完成复杂任务的系统。

我们重点看看对于Agent,LLM在规划子任务后在决策阶段对工具的选择和执行这个重要环节。

如何选择和执行工具呢?

function call

1. 使用Prompt

前面提到LLM可以使用Prompt的形式灌入知识,所以我们可以把我们工具(API接口)的描述,调用API的输入输出参数格式以Prompt形式告诉LLM不就好了?去年做过一个Agent项目,当时的langchain,dify等Agent框架就是这么做的。

首先需要基于Tool类构建自己的工具,之前人工写的代码。

我们可以让CodeBuddy进行一下CodeRewiew

descript
descript

也可以让CodeBuddy帮忙优化下代码:

descript
descript
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
'''
@Time    :   2024/01/24 15:18:43
@Author  :   zoyxiong 
@File    :   rag_tool.py
@Desc    :   调用RAG,获取内部数据库用户问题相关内容
'''
from langchain.tools.base import ToolException
from langchain.agents.tools import Tool
from functools import lru_cache

class RAGTool:
    name = "RAGTool"
    description = """知识库工具:此工具可以从本地知识库中检索用户问题相关内容。"""

    def __init__(self, query):
        self.query = query
    
    @lru_cache(maxsize=128)
    def get_rag_content(self, info):
        # 调用RAG接口,这里需要替换为实际的API调用
        content = your_rag_api(info)
        return content
        
    def get_tool(self):
        return Tool(
            name=self.name,
            func=self._run,
            description=self.description,
        )
    
    def _run(self, query) -> str:
        # 修正参数,应该使用self.query而不是query
        result = self.get_rag_content(query) 
        return result

然后在Agent中添加工具:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
def test_agent(query):
    rag_tool = RAGTool(query)
    web_tool = WebTool(query)
    tools = [rag_tool.get_tool(), web_tool.get_tool()]
    planner = load_chat_planner(llm, system_prompt=PLAN_PROMPT)
    executor = load_agent_executor(llm, tools, verbose=True)
    agent = PlanAndExecute(planner=planner, executor=executor, verbose=True)
    result = agent.run(query)
    return result

在planner中就是告知模型我们有哪些工具,让LLM根据已有工具规划和编排执行流程,在executor就是告知LLM指令遵循按照输入输出格式来调用工具。

选择工具后进行执行也是基于Prompt来定义工具输入格式:

代码语言:txt
AI代码解释
复制
PREFIX = """Respond to the human as helpfully and accurately as possible. You have access to the following tools:"""
FORMAT_INSTRUCTIONS = """Use a json blob to specify a tool by providing an action key (tool name) and an action_input key (tool input).

Valid "action" values: "Final Answer" or {tool_names}
Provide only ONE action per $JSON_BLOB, as shown:

```
{{{{
  "action": $TOOL_NAME,
  "action_input": $INPUT
}}}}
```

Follow this format:

Question: input question to answer
Thought: consider previous and subsequent steps
Action:
```
$JSON_BLOB
```
Observation: action result
... (repeat Thought/Action/Observation N times)
Thought: I know what to respond
Action:
```
{{{{
  "action": "Final Answer",
  "action_input": "Final response to human"
}}}}
```"""
SUFFIX = """Begin! Reminder to ALWAYS respond with a valid json blob of a single action. Use tools if necessary. Respond directly if appropriate. Format is Action:```$JSON_BLOB```then Observation:.
Thought:"""

整个流程可以看出非常依赖大模型的指令遵循能力,去年年初的代码,我记得当时运行一个任务想得到好的效果非常艰难,主要问题:

  1. 私有化部署的开源模型的指令遵循能力很差,需要不断调整Prompt
  2. 不同大模型指令遵循能力不一样,如果要进行对比,需要对每个模型进行针对性的Prompt配置。即使是闭源ChatGPT
  3. 在Agent项目中,需要的工具都需要继承Tool基类实现一个工具类,不同项目都需要实现一遍,很多重复工作

2. 使用function_call

openAI在2年6月提出了function_call。在调用openAI的ChatGPT接口时可以打开function_call功能。那ChatGPT的function_call如何实现的呢?

让codeBuddy实现:使用python实现一个ChatGPT使用function_call的示例,可以看出直接生成了一个非常完整的工程。

descript
descript

看下具体实现的核心代码:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
# 定义函数的结构和参数
functions = [
    {
        "name": "get_current_weather",
        "description": "获取指定位置的当前天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "城市名称,如'北京'、'上海'等"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "温度单位"
                }
            },
            "required": ["location"]
        }
    }
]
def chat_with_function_call(user_message: str) -> None:
    """
    Chat with ChatGPT and handle potential function calls.
    
    Args:
        user_message (str): The user's input message to send to ChatGPT.
    
    Returns:
        None: Prints ChatGPT's response or function call results directly.
    
    Process:
        1. Sends user message to ChatGPT API with function definitions
        2. Checks if response requires function call
        3. If function call needed:
            - Executes the requested function
            - Sends function result back to ChatGPT
            - Prints final response
        4. If no function call needed, prints direct response
        5. Handles and reports any errors during the process
    
    Note:
        Requires properly configured 'client' and 'functions' to be available.
        Uses 'gpt-3.5-turbo-1106' model which supports function calling.
    """
    """
    与ChatGPT进行对话,并处理可能的函数调用
    """
    # 创建对话消息
    messages = [{"role": "user", "content": user_message}]
    
    try:
        # 调用ChatGPT API
        response = client.chat.completions.create(
            model="gpt-3.5-turbo-1106",  # 使用支持函数调用的模型
            messages=messages,
            functions=functions,
            function_call="auto"
        )
        
        # 获取助手的回应
        assistant_message = response.choices[0].message
        
        # 检查是否需要调用函数
        if assistant_message.function_call:
            # 获取函数调用信息
            function_name = assistant_message.function_call.name
            function_args = eval(assistant_message.function_call.arguments)
            
            # 调用相应的函数
            if function_name == "get_current_weather":
                function_response = get_current_weather(**function_args)
                
                # 将函数调用结果添加到消息历史
                messages.append({
                    "role": "function",
                    "name": function_name,
                    "content": str(function_response)
                })
                
                # 再次调用API让模型处理函数返回的结果
                second_response = client.chat.completions.create(
                    model="gpt-3.5-turbo-1106",
                    messages=messages
                )
                
                # 打印最终响应
                print("ChatGPT的回答:", second_response.choices[0].message.content)
        else:
            # 如果不需要调用函数,直接打印回答
            print("ChatGPT的回答:", assistant_message.content)
            
    except Exception as e:
        print(f"发生错误: {str(e)}")

在工具调用上不是添加到prompt,而是单独的一个functions字段,对函数名,描述,参数等进行标准化。

我们用下图来总结上面提到的概念,然后再来看MCP的提出能解决哪些问题。

descript
descript

MCP

不知道MCP的定义也可以问问CodeBuddy~

记得把CodeBase开关关掉,不然回答不出来(我猜测这里是切换了底座模型以及增加了联网功能)

descript
descript

MCP 是标准化执行这些请求的协议框架

MCP(即模型上下文协议)试图标准化function call的过程。 MCP (Model Context Protocol):是一个开放协议和标准,旨在标准化AI 应用(MCP 客户端)如何发现、连接和与外部工具/数据源(实现为 MCP 服务器)进行交互。它关注的是系统间的通信和集成,解决 Function Calling 指令生成后,如何高效、安全、可扩展地执行这些调用。

Function Calling 帮助 LLM 决定它想要做什么。

MCP 确保工具可靠可用、可发现和可执行,而无需自定义集成所有内容。

descript
descript

上图很好的解释了function call和MCP的区别。

MCP解决了大模型的function call的什么问题呢?

我的观点:他是个协议,虽然名字是模型上下文协议,用于大模型与外部工具的标准化通信,他解决不了任何大模型本身对工具选择和调用的问题。

也就是说你精心调整Prompt后大模型解决不了的问题,你把工具封装成MCP服务,然仍然解决不了问题。

那要和他何用!

他是个协议,所以做的事情是统一,减少重复性工作而已。统一了协议(JSON-RPC 2.0),在工程上一次开发多模型适配。

比如你是个全栈工程师,开发了很多工具。同时还承担了5个业务需求,要开发5个Agent,每个业务给你不同的底座。有的业务提供的LLM支持function call,有的不支持function call。

你得怎么做?你要写5套代码,每个项目接入工具类们,然后不支持function call的LLM们你要调整不同的Prompt来实现function call,支持function call的LLM你根据tool字段去编写工具参数。

这种情况,MCP就是你的救星。

MCP client将MCP Server提供的工具进行了注册,然后客户端把这些获取的工具交给大模型进行工具的选择和参数的提取,MCPServer负责执行模型选择的工具。其中不同的MCP client实现方式也不一样,Cline客户端是将获取的工具列表以system_prompt形式提供。 如果你使用的大模型支持function call,那我按你格式适配;如果你的大模型不支持function call,那我把工具的描述,输入输出参数的标准格式都写好Prompt,这两种方式就是我们上面介绍的如何进行工具调用的方式。而MCP把这个统一实现了,是不是省去很多事情~

MCP当然做了非常多工程事情,以我浅薄的认知,MCP的贡献有:

  1. 工具服务化:你不用在每个Agent添加工具接口,提供MCP服务,每个客户端复用。
  2. 模型调用开发成本降低:你不用每个Agent去适配function call能力。MCP client做为中间商,完成了获取工具详细信息,按照规范格式整理为Prompt,提供给大模型。你不用去适配大模型的functioncall能力。
  3. 生态发展:随着MCP的火热,市场上越来越多MCP服务提供大家使用,所以大模型的可选工具越来越多。

当然其中也会有些误区和问题:

  1. MCP是不会对大模型能力有任何提升,甚至如何客户端对Prompt的滥用,可能会导致Prompt爆炸,反而影响大模型的效果。
  2. MCP 的质量和安全性。目前MCP市场服务越来越多是一件好事,但是目前并没有对MCP的质量和安全进行测评的好的工作,在接入过程中并不知道服务的风险,所以使用需谨慎。

个人观点:不用盲目追求MCP化:如果业务很垂域,如果你目前的业务Agent都是内部的API工具,模型底座也是固定的,其实也不用跟风非要将服务MCP化,已经精心调整过的prompt就继续使用吧~

从真实的业务场景落地来看,大模型能力还是更核心的,prompt遵循和function_call能力强,工具能够选对,工具参数能够提取对,才能保障Agent的稳定性和正确性。MCP协议是为了大模型的工具服务化和工具调用的标准化。

CodeBuddy x MCP

现在我们对MCP的概念和协议有了了解~再来看在CodeBuddy如何接入~

我们接入的是朗新集团新电途充电站信息查询MCP服务,在CodeBuddy的MCP广场也有很多优秀的MCP服务可以选择~

还是在Craft智能体功能,我们点击MCP:

descript
descript
descript
descript

添加如下配置:

代码语言:json
AI代码解释
复制
{
  "mcpServers": {
    "xdt-charge-station": {     
       "command":"npx",     
         "args": [       
           "-y",        
           "@longshine-ai/xdt"      
          ]
    }
  }
}

配置完后就可以看到如下界面:

descript
descript

我们点击运行:

descript
descript

最后我们来测试下使用大模型调用服务解决我们的任务。

任务:我要从武汉到无锡,路上有哪些充电桩

descript
descript
descript
descript

可以看出在CodeBuddy上接入MCP非常的方便。

参考:

https://zhuanlan.zhihu.com/p/656031413

https://zhuanlan.zhihu.com/p/1898326676087223572

https://mp.weixin.qq.com/s/36oE36DQXXscnkBrZQhv6g

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CodeBuddy
  • MCP
    • LLM
    • RAG
    • Prompt
      • system Prompt
      • user Prompt
    • Agent
    • function call
      • 1. 使用Prompt
      • 2. 使用function_call
    • MCP
  • CodeBuddy x MCP
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档