吴恩达MCP课程(3):mcp_chatbot

article/2025/6/16 19:47:51

原课程代码是用Anthropic写的,下面代码是用OpenAI改写的,模型则用阿里巴巴的模型做测试
.env 文件为:

OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
OPENAI_API_BASE=https://dashscope.aliyuncs.com/compatible-mode/v1

目录

    • 代码
    • 代码解释
      • 1. 导入和初始化
      • 2. MCP_ChatBot类初始化
      • 3. 查询处理核心方法
        • 3.1 消息处理循环
        • 3.2 工具调用处理
      • 4. 聊天循环
      • 5. 服务器连接和工具初始化
      • 6. 程序入口
      • 核心特性
    • 示例

代码

from dotenv import load_dotenv
import openai
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
from typing import List
import asyncio
import json
import osload_dotenv()class MCP_ChatBot:def __init__(self):# Initialize session and client objectsself.session: ClientSession = Noneself.client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"),base_url=os.getenv("OPENAI_API_BASE"))self.available_tools: List[dict] = []async def process_query(self, query):messages = [{'role':'user', 'content':query}]response = self.client.chat.completions.create(model='qwen-turbo',max_tokens=2024,tools=self.available_tools,messages=messages)process_query = Truewhile process_query:# 获取助手的回复message = response.choices[0].message# 检查是否有普通文本内容if message.content:print(message.content)process_query = False# 检查是否有工具调用elif message.tool_calls:# 添加助手消息到历史messages.append({"role": "assistant", "content": None,"tool_calls": message.tool_calls})# 处理每个工具调用for tool_call in message.tool_calls:tool_id = tool_call.idtool_name = tool_call.function.nametool_args = json.loads(tool_call.function.arguments)print(f"Calling tool {tool_name} with args {tool_args}")# 执行工具调用result = await self.session.call_tool(tool_name, arguments=tool_args)# 添加工具结果到消息历史messages.append({"role": "tool","tool_call_id": tool_id,"content": result.content})# 获取下一个回复response = self.client.chat.completions.create(model='qwen-turbo',max_tokens=2024,tools=self.available_tools,messages=messages)# 如果只有文本回复,则结束处理if response.choices[0].message.content and not response.choices[0].message.tool_calls:print(response.choices[0].message.content)process_query = Falseasync def chat_loop(self):"""Run an interactive chat loop"""print("\nMCP Chatbot Started!")print("Type your queries or 'quit' to exit.")while True:try:query = input("\nQuery: ").strip()if query.lower() == 'quit':breakawait self.process_query(query)print("\n")except Exception as e:print(f"\nError: {str(e)}")async def connect_to_server_and_run(self):# Create server parameters for stdio connectionserver_params = StdioServerParameters(command="uv",  # Executableargs=["run", "research_server.py"],  # Optional command line argumentsenv=None,  # Optional environment variables)async with stdio_client(server_params) as (read, write):async with ClientSession(read, write) as session:self.session = session# Initialize the connectionawait session.initialize()# List available toolsresponse = await session.list_tools()tools = response.toolsprint("\nConnected to server with tools:", [tool.name for tool in tools])self.available_tools = [{"type": "function","function": {"name": tool.name,"description": tool.description,"parameters": tool.inputSchema}} for tool in response.tools]await self.chat_loop()async def main():chatbot = MCP_ChatBot()await chatbot.connect_to_server_and_run()if __name__ == "__main__":asyncio.run(main())

代码解释

1. 导入和初始化

from dotenv import load_dotenv
import openai
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
from typing import List
import asyncio
import json
import osload_dotenv()
  • load_dotenv(): 加载环境变量文件(.env)中的配置
  • openai: OpenAI API客户端库
  • mcp: Model Context Protocol相关模块,用于与MCP服务器通信
  • asyncio: 异步编程支持
  • json: JSON数据处理

2. MCP_ChatBot类初始化

class MCP_ChatBot:def __init__(self):self.session: ClientSession = Noneself.client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"),base_url=os.getenv("OPENAI_API_BASE"))self.available_tools: List[dict] = []
  • session: MCP客户端会话,用于与MCP服务器通信
  • client: OpenAI客户端,配置API密钥和基础URL
  • available_tools: 存储从MCP服务器获取的可用工具列表

3. 查询处理核心方法

async def process_query(self, query):messages = [{'role':'user', 'content':query}]response = self.client.chat.completions.create(model='qwen-turbo',max_tokens=2024,tools=self.available_tools,messages=messages)

这个方法是整个系统的核心,处理用户查询的完整流程:

3.1 消息处理循环
process_query = True
while process_query:message = response.choices[0].messageif message.content:print(message.content)process_query = False
  • 检查AI回复是否包含文本内容
  • 如果有文本内容,直接输出并结束处理
3.2 工具调用处理
elif message.tool_calls:messages.append({"role": "assistant", "content": None,"tool_calls": message.tool_calls})for tool_call in message.tool_calls:tool_id = tool_call.idtool_name = tool_call.function.nametool_args = json.loads(tool_call.function.arguments)result = await self.session.call_tool(tool_name, arguments=tool_args)messages.append({"role": "tool","tool_call_id": tool_id,"content": result.content})

工具调用处理流程:

  1. 将助手的工具调用请求添加到消息历史
  2. 遍历每个工具调用请求
  3. 提取工具名称、参数和调用ID
  4. 通过MCP会话执行实际的工具调用
  5. 将工具执行结果添加到消息历史
  6. 继续与AI对话,获取基于工具结果的最终回复

4. 聊天循环

async def chat_loop(self):print("\nMCP Chatbot Started!")print("Type your queries or 'quit' to exit.")while True:try:query = input("\nQuery: ").strip()if query.lower() == 'quit':breakawait self.process_query(query)print("\n")except Exception as e:print(f"\nError: {str(e)}")
  • 提供交互式命令行界面
  • 持续接收用户输入
  • 调用process_query处理每个查询
  • 包含异常处理机制

5. 服务器连接和工具初始化

async def connect_to_server_and_run(self):server_params = StdioServerParameters(command="uv",args=["run", "research_server.py"],env=None,)async with stdio_client(server_params) as (read, write):async with ClientSession(read, write) as session:self.session = sessionawait session.initialize()response = await session.list_tools()tools = response.toolsself.available_tools = [{"type": "function","function": {"name": tool.name,"description": tool.description,"parameters": tool.inputSchema}} for tool in response.tools]await self.chat_loop()

服务器连接流程:

  1. 配置MCP服务器参数(使用uv运行research_server.py)
  2. 建立stdio通信连接
  3. 创建客户端会话并初始化
  4. 获取服务器提供的工具列表
  5. 将工具格式转换为OpenAI兼容格式
  6. 启动聊天循环

6. 程序入口

async def main():chatbot = MCP_ChatBot()await chatbot.connect_to_server_and_run()if __name__ == "__main__":asyncio.run(main())
  • 创建聊天机器人实例
  • 启动异步主程序

核心特性

  1. 异步处理: 全程使用async/await,支持高并发
  2. 工具集成: 通过MCP协议动态获取和调用外部工具
  3. 对话连续性: 维护完整的对话历史,支持多轮对话
  4. 错误处理: 包含异常捕获和错误提示
  5. 灵活配置: 通过环境变量配置API密钥和服务器地址

示例

uv run mcp_chatbot.py

请添加图片描述
其他相关链接:
吴恩达MCP课程(1):chat_bot
吴恩达MCP课程(2):research_server


http://www.hkcw.cn/article/fCiJEfnSjT.shtml

相关文章

新视角!经济学顶刊QJE用文本分析探究新技术扩散

美国圣路易斯联邦储备银行Aakash Kalyani、美国斯坦福大学与国家经济研究局Nicholas Bloom、英国伦敦商学院Marcela Carvalho和其合作者们共同研究的“The Diffusion of New Technologies(新技术的扩散)”在顶刊The Quarterly Journal of Economics中发表…

动态规划-376.摆动序列-力扣(LeetCode)

一、题目解析 看着题目上的解释或许有点难以理解,这里一图流 只要形似上图的都可以是摆动序列,如左图,且仅含一个元素和两个元素的也算摆动序列,如右图 二、算法原理 1、状态表示 根据经验我们都是以i位置为结尾时&#xff0c…

【机器学习基础】机器学习入门核心算法:XGBoost 和 LightGBM

机器学习入门核心算法:XGBoost 和 LightGBM 一、算法逻辑XGBoost (eXtreme Gradient Boosting)LightGBM (Light Gradient Boosting Machine) 二、算法原理与数学推导目标函数(二者通用)二阶泰勒展开:XGBoost 分裂点增益计算&#…

《STL--stack 和 queue 的使用及其底层实现》

引言: 上次我们学习了容器list的使用及其底层实现,相对来说是比较复杂的,今天我们要学习的适配器stack和queue与list相比就简单很多了,下面我们就开始今天的学习: 一:stack(后进先出&#xff…

Redis缓存问题重点详解

前言:本节包含常见redis缓存问题,包含缓存一致性问题,缓存雪崩,缓存穿透,缓存击穿问题及其解决方案 1. 缓存一致性 我们先看下目前企业用的最多的缓存模型。缓存的通用模型有三种: 缓存模型解释Cache Asi…

Redis最佳实践——安全与稳定性保障之访问控制详解

Redis 在电商应用的安全与稳定性保障之访问控制全面详解 一、安全访问控制体系架构 1. 多层级防护体系 #mermaid-svg-jpkDj2nKxCq9AXIW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jpkDj2nKxCq9AXIW .error-ico…

矩阵快速幂算法快速上手

矩阵快速幂算法快速上手 一、基础知识回顾1.1 矩阵乘法1.2 单位矩阵 二、快速幂算法思想2.1 整数快速幂2.2 矩阵快速幂 三、矩阵快速幂的代码实现3.1 Python实现3.2 C实现3.3 Java实现 四、矩阵快速幂的应用场景4.1 斐波那契数列4.2 线性递推数列4.3 图论中的路径计数4.4 动态规…

外国人眼中的端午赛龙舟 文化共鸣与体验

当地人教恩佐包香囊,黄春隆体验划龙舟,罗珃身着汉服,沉浸式体验端午文化后拍照留念。吃粽子、赛龙舟、做香囊……外国友人对端午文化有多少了解?哪些端午习俗令他们印象深刻?恩佐来自法国中部卢瓦雷省的小城蒙塔日,他的家乡与中国渊源已久,是邓小平年轻时曾经勤工俭学的…

博主:登贝莱预定金球奖 欧冠决赛闪耀

巴黎圣日耳曼在欧冠决赛中以5-0大胜国米,首次夺得冠军。奥斯曼-登贝莱为队友送出了两次助攻。《队报》认为,他比以往任何时候都更有希望角逐2025年金球奖。作为俱乐部主席,纳赛尔-阿尔赫莱菲按惯例出现在颁奖台上,紧紧拥抱了奥斯曼-登贝莱,并在他耳边低语。这位卡塔尔人脸…

uniapp调试,设置默认展示的toolbar内容

uniapp调试,设置默认展示的toolbar内容 设置pages.json中 pages数组中 json的顺序就可以只需要调整顺序,不会影响该bar在页面中的显示默认展示第一条page

设计模式——适配器设计模式(结构型)

摘要 本文详细介绍了适配器设计模式,包括其定义、核心思想、角色、结构、实现方式、适用场景及实战示例。适配器模式是一种结构型设计模式,通过将一个类的接口转换成客户端期望的另一个接口,解决接口不兼容问题,提高系统灵活性和…

元胞自动机(Cellular Automata, CA)

一、什么是元胞自动机(Cellular Automata, CA) 元胞自动机(CA) 是一种基于离散时间、离散空间与规则驱动演化的动力系统,由 冯诺依曼(John von Neumann) 于1940年代首次提出,用于模…

华为OD机试真题——模拟消息队列(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《模拟消息队列》: 目录 题…

Nacos 配置文件总结

Nacos 配置文件总结 文章目录 Nacos 配置文件总结1 、在 Nacos 服务端添加配置文件1. 启动Nacos Server。2. 新建配置文件。3. 发布配置集后,我们便可以在配置列表中查看相应的配置文件。4. 配置nacos数据库5. 运行 Nacos 容器6. 验证安装结果7. 配置验证 2 、在 Na…

一文读懂MCP模型上下文协议

前言:MCP(Model Context Protocol,模型上下文协议)作为一个全新的开源协议框架被提出,它试图重塑模型开发、集成与协作的方式。MCP让只能人机交互的大模型转化为了能够快速对接各类业务系统的生产力大脑。传统做法通常…

C#数字图像处理(一)

文章目录 1.C#图像处理基础1.1 Bitmap类1.2 Bitmapdata类1.3 Graphics类1.4 Image类 2.彩色图像灰度化1.提取像素法2.内存法3.指针法三种方法的比较4.灰度图像二值化: 3.相关链接 Bitmap类、 Bitmapdata类和 Graphics类是C#图像处理中最重要的3个类,如果要用C# 进行…

各种数据库,行式、列式、文档型、KV、时序、向量、图究竟怎么选?

慕然回首,发现这些年来涌现出了许多类型的数据库,今天抽空简单回顾一下,以便于后面用到时能快速选择。 1. 关系型数据库(行式) 关系型数据库(RDBMS),我们常说的数据库就是指的关系型数据库。 它的全称是关…

uView UI的使用

1. uView UI 封装了request.get登方法请求,异步调用。 故需可以使用then, catch, finally uView UI. 是一个专为UniApp设计的跨平台UI框架, 注意这里是跨平台,也就是可以再IOS, ANDROID 机器上运行的框架 2. easycom 词面意思容易使用的组件 在使用…

win32相关(临界区)

临界区 每个线程都有自己的栈,而局部变量是存在在栈中的,这就意味着每个线程都有一份自己的”局部变量“,如果线程仅仅只是使用自己的”局部变量“那么就不会有线程安全问题,那如果多个线程使用一个全局变量呢? 我们用…

UE5蓝图暴露变量,在游戏运行时修改变量实时变化、看向目标跟随目标Find Look at Rotation、修改玩家自身弹簧臂

UE5蓝图中暴露变量,类似Unity中public一个变量,在游戏运行时修改变量实时变化 1,添加变量 2,设置变量的值 3,点开小眼睛,此变量显示在编辑器中,可以运行时修改 看向目标跟随目标Find Look at R…