简介
本文提供一个简短教程,展示如何使用 LangGraph、MCP(模型上下文协议) 和 Ollama 创建多代理聊天机器人,构建适用于商业或个人使用的强大智能代理聊天机器人。
不久前,我制作了一段关于模型上下文协议(MCP)的视频。一些开发者将其比喻为“为AI打造的Zapier”,认为它仅为API使用增加了额外步骤。
“在MCP出现之前,开发者需要编写代码并通过API将AI工具连接到外部系统,这意味着每个集成都需要提前编码。” —— John Rush
尽管MCP于2024年11月发布,但近期突然流行,引发了关于其“繁荣期”持续时间的讨论。LangChain 在 X 平台上发起投票,结果显示:
•40.8% 认为 MCP 是未来标准;•25.8% 认为 MCP 只是昙花一现;•33.4% 选择观望。
MCP 虽新,但已支持 GitHub、Slack 和 PostgreSQL 等服务。作为开放标准,它可与任何大语言模型(LLM,如 Claude、OpenAI、Gemini 等)配合使用,令人惊讶。
接下来,我将通过实时聊天机器人演示展示其效果。
演示
我将向聊天机器人提出两个问题:
1.“你能写一份关于最新大语言模型的报告吗?”
您也可自由提问。
观察聊天机器人输出,代理通过 create_chatbot
函数使用结构化流程处理输入。该函数整合系统指令、用户消息和工具执行,形成流畅交互,并根据查询选择工具。
对于第一个问题,聊天机器人调用 Google 搜索工具获取最新信息并生成报告。对于第二个问题,“编写一个使用 Seaborn 创建带回归线的散点图的 Python 脚本”,聊天机器人处理请求并路由到适当工具(如 python_repl
或 data_visualization
),具体取决于查询结构。async_tool_executor
动态处理工具调用,确保同步和异步功能(如生成代码或可视化)正确执行。
StateGraph
管理对话状态,确保后续问题响应准确且具上下文相关性。get_tools
函数确保仅使用可用工具,维护系统稳定性。main
函数确保顺畅运行,实时处理用户输入、调用工具并处理输出。
通过本文,您将了解 MCP 与函数调用(Function Call)的区别、何时使用两者,以及如何使用 LangGraph、MCP 和开源工具创建强大的智能代理聊天机器人。
开始之前!🦸🏻♀️
如果您喜欢此主题并想支持我:
•为文章鼓掌50次,助力我前行!👏•在 Medium 上关注我并订阅,免费获取最新文章🫶•订阅我的 YouTube 频道,加入大家庭!
MCP 与函数调用的区别
在函数调用中,AI 像遵循严格脚本的工人,仅能调用预定义工具,逐一执行,限制于已获取工具。而在 MCP 中,AI 像拥有工具箱的代理,可探索新工具、组合使用,处理更多任务,拥有更大自主性。
函数调用与模型提示紧密耦合,开发者需管理调用顺序,控制性强但灵活性有限。MCP 通过开放协议实现松耦合,灵活可扩展,但需精心设计以管理复杂性和确保安全性。下一节将探讨如何使用 MCP 构建代理并应对其灵活性挑战。
何时使用函数调用和 MCP
选择函数调用或 MCP 取决于用例:
•函数调用:适用于明确定义的简单动作或单步查询,需高度结构化输出。适合可预测任务和轻量集成,MCP 的额外开销可能过重。若需结构化、狭窄任务和简单应用集成,选择函数调用。•MCP:适用于需灵活性、多功能工具或跨交互演变上下文的场景。适合复杂、多步骤工作流程,或 AI 需维护长期上下文并与多种系统交互(如跨内部系统的通用助手,调用多数据源)。
两者不互斥,可互补。例如,函数调用可在 MCP 客户端内处理模型结构化输出。概念上,函数调用将自然语言转化为可控的函数执行,而 MCP 为 AI 提供更广接口以探索和操作环境。
开始编码
让我们逐步探索如何创建 MCP 应用程序。首先安装支持模型的库:
pip install -r requirements.txt
接下来导入相关库,其重要性将在后续显现:
•langchain_mcp_adapters:将 MCP 工具转为 LangChain 工具,供 LangGraph 代理使用,提供客户端实现,连接多个 MCP 服务器加载工具。•MCP:开放协议,标准化应用程序为大语言模型提供上下文。•googlesearch-python:便于 Google 搜索的包。
代码文件概览
agent.py
我设计了 create_agent
函数作为异步过程构建 AI 代理,接受可选参数 docs_info
提供聊天机器人数据。MultiServerMCPClient
集成到异步上下文管理器,确保与 MCP 服务器(http://localhost:8000/sse
)通过服务器发送事件(SSE)无缝通信,超时30秒。
调用 client.get_tools()
获取 MCP 工具,启用高级功能。使用 MessagesState
构建 StateGraph
管理对话状态,通过 create_chatbot(docs_info)
创建聊天机器人节点,处理和交互文档。
from langchain_core.messages importAIMessage,ToolMessage,HumanMessage
from langgraph.graph importStateGraph, START,END,MessagesState
from nodes import create_chatbot
import asyncio
import os
import dotenv
from langchain_mcp_adapters.client importMultiServerMCPClient
async def create_agent(docs_info=None):
async withMultiServerMCPClient(
{
"server":{
"url":"http://localhost:8000/sse",
"transport":"sse",
"timeout":30
}
}
)as client:
tools = client.get_tools()
graph_builder =StateGraph(MessagesState)
chatbot_node = create_chatbot(docs_info)
graph_builder.add_node("chatbot", chatbot_node)
async_tool_executor
动态处理工具调用,输入为包含对话消息列表的 state
。提取最后消息(messages[-1]
)检查工具调用,从 tool_calls
或 additional_kwargs
获取。若无工具调用,返回未更改消息。
为处理工具调用,复制消息到 new_messages
,遍历每个工具调用,提取 tool_name
、tool_args
和 tool_id
,支持字典和对象格式。匹配 tool_name
查找工具;若未找到,生成错误消息列出有效工具。
若工具存在,使用 asyncio.iscoroutinefunction()
判断是否异步函数——若异步,执行 await tool.coroutine(**tool_args)
;否则,调用 tool.func(**tool_args)
或 tool(**tool_args)
。通过捕获异常处理错误,附加详细错误消息到 new_messages
。
async def async_tool_executor(state):
messages = state["messages"]
last_message = messages[-1]
tool_calls =None
if hasattr(last_message,"tool_calls"):
tool_calls = last_message.tool_calls
elif hasattr(last_message,"additional_kwargs")and"tool_calls"in last_message.additional_kwargs:
tool_calls = last_message.additional_kwargs["tool_calls"]
ifnot tool_calls:
return{"messages": messages}
new_messages = messages.copy()
for tool_call in tool_calls:
if isinstance(tool_call, dict):
tool_name = tool_call.get("name")
tool_args = tool_call.get("args",{})
tool_id = tool_call.get("id","tool-call-id")
else:
tool_name = tool_call.name
tool_args = tool_call.args if hasattr(tool_call,"args")else{}
tool_id = getattr(tool_call,"id","tool-call-id")
print(f"执行工具:{tool_name}")
print(f"工具参数:{tool_args}")
tool =next((t for t in tools if t.name == tool_name),None)
ifnot tool:
tool_error = f"错误:{tool_name} 不是有效工具,请尝试以下工具之一:{[t.name for t in tools]}。"
new_messages.append(AIMessage(content=tool_error))
else:
try:
if asyncio.iscoroutinefunction(tool.coroutine):
result = await tool.coroutine(**tool_args)
else:
result = tool.func(**tool_args)if hasattr(tool,'func')else tool(**tool_args)
print(f"工具结果:{result}")
new_messages.append(ToolMessage(
content=str(result),
tool_call_id=tool_id,
name=tool_name
))
exceptExceptionas e:
error_msg = f"错误:{str(e)}\n 请修复您的错误。"
print(f"工具错误:{error_msg}")
new_messages.append(AIMessage(content=error_msg))
return{"messages": new_messages}
通过集成异步工具执行节点和路由函数,设计了结构化对话流程。添加 async_tool_executor
作为“tools”节点,动态处理工具调用。创建路由函数,根据最后消息决定下一步:若 AI 消息含工具调用,路由到“tools”;否则,结束对话。
为图添加边:从“chatbot”开始,条件路由到“tools”或“end”,并将“tools”循环回“chatbot”,支持多次工具交互。
graph_builder.add_node("tools", async_tool_executor)
def router(state):
messages = state["messages"]
last_message = messages[-1]
has_tool_calls =False
if isinstance(last_message,AIMessage):
if hasattr(last_message,"tool_calls")and last_message.tool_calls:
has_tool_calls =True
elif hasattr(last_message,"additional_kwargs")and last_message.additional_kwargs.get("tool_calls"):
has_tool_calls =True
return"tools"if has_tool_calls else"end"
graph_builder.add_edge(START,"chatbot")
graph_builder.add_conditional_edges(
"chatbot",
router,
{
"tools":"tools",
"end":END
}
)
graph_builder.add_edge("tools","chatbot")
graph = graph_builder.compile()
return graph, client
nodes.py
get_system_prompt
函数动态生成 AI 助手系统提示,确保明确指导和上下文感知。使用 datetime.now().strftime("%Y-%m-%d")
格式化当前日期嵌入提示,提供实时参考。
定义助手角色和能力,列出三个工具:generate_image
(DALL-E 生成图像)、data_visualization
(matplotlib 生成图表)、python_repl
(Python 执行环境)。
from server import get_tools
from langgraph.graph importMessagesState
from langchain_openai importChatOpenAI
from langchain_ollama importChatOllama
from langchain_core.prompts importChatPromptTemplate,SystemMessagePromptTemplate,HumanMessagePromptTemplate
from datetime import datetime
import os
def get_system_prompt(docs_info=None):
system_prompt = f"""
今天是{datetime.now().strftime("%Y-%m-%d")}
你是一个有用的 AI 助手,可使用以下工具:
- generate_image:根据提示使用 DALL-E 生成图像
- data_visualization:使用Python和 matplotlib 创建图表
- python_repl:执行Python代码
调用图像生成或数据可视化工具时,仅回答生成事实,不返回 base64 代码或 URL。
一旦通过工具生成图像,在一个回答中不再重复调用。
"""
if docs_info:
docs_context ="\n\n你可以访问以下文档:\n"
for doc in docs_info:
docs_context += f"- {doc['name']}:{doc['type']}\n"
system_prompt += docs_context
system_prompt +="\n你应始终使用与用户提问相同的语言回答。"
return system_prompt
create_chatbot
函数处理用户输入并生成 AI 响应,使用 ChatPromptTemplate
结合系统指令(来自 get_system_prompt
)和用户消息。通过管道(|
)将提示传递到 LLM,创建无缝处理链。
函数将字符串转为 HumanMessage
对象,确保消息格式一致。聊天机器人调用 LLM 处理用户消息并附加响应,维护结构化对话历史。助手遵循规则,适应查询,保持工具无关性,提供灵活响应,确保互动动态体验。🚀
def create_chatbot(docs_info=None):
prompt =ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template(get_system_prompt(docs_info)),
HumanMessagePromptTemplate.from_template("{input}")
])
chain = prompt | llm
def chatbot(state:MessagesState):
if isinstance(state["messages"], str):
from langchain_core.messages importHumanMessage
messages =[HumanMessage(content=state["messages"])]
else:
messages = state["messages"]
response = chain.invoke(messages)
return{"messages": messages +[response]}
return chatbot
server.py
开发了一套工具,用于生成图像、可视化数据和执行 Python 代码。generate_image
工具使用 DALL-E 根据提示生成图像,验证提示有效后,异步调用 OpenAI API,成功返回图像 URL,失败返回错误消息。
data_visualization
工具使用 matplotlib 执行 Python 代码创建图表,保存为 base64 编码的 PNG 图像。python_repl
工具在 REPL 环境运行 Python 代码,提供动态执行。工具均设计为处理错误并返回有意义响应。
from mcp.server.fastmcp importFastMCP
from langchain_experimental.utilities importPythonREPL
import io
import base64
import matplotlib.pyplot as plt
from openai importOpenAI
from pydantic importBaseModel,Field
import os
from dotenv import load_dotenv
import asyncio
from googlesearch import search
@mcp.tool()
async def generate_image(prompt: str)-> str:
"""
根据给定的提示使用 DALL-E 生成图像。
"""
ifnot isinstance(prompt, str)ornot prompt.strip():
raiseValueError("无效提示")
try:
loop = asyncio.get_event_loop()
response = await loop.run_in_executor(
None,
lambda: client.images.generate(
model="dall-e-3",
prompt=prompt,
size="1024x1024",
quality="standard",
n=1
)
)
return f"成功生成 {prompt} 的图像!URL:{response.data[0].url}"
exceptExceptionas e:
return f"生成图像错误:{str(e)}"
repl =PythonREPL()
@mcp.tool()
def data_visualization(code: str):
"""执行 Python 代码,使用 matplotlib 进行可视化。"""
try:
repl.run(code)
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
img_str = base64.b64encode(buf.getvalue()).decode()
return f"data:image/png;base64,{img_str}"
exceptExceptionas e:
return f"创建图表错误:{str(e)}"
@mcp.tool()
def python_repl(code: str):
"""执行 Python 代码。"""
return repl.run(code)
get_tools
函数返回可用工具列表,确保仅包含功能性工具,包括 generate_image
、python_repl
和 data_visualization
。若提供 retriever_tool
,则加入列表。脚本通过 mcp.run(transport="sse")
运行 MCP 服务器,确保工具可用。
def get_tools(retriever_tool=None):
base_tools =[generate_image, python_repl, data_visualization]
if retriever_tool:
base_tools.append(retriever_tool)
return base_tools
if __name__ =="__main__":
mcp.run(transport="sse")
main.py
main
函数运行异步代理,动态处理用户输入和工具交互。通过 await create_agent()
创建代理和客户端,通过命令行获取用户输入,构造 HumanMessage
。
通过 agent.ainvoke()
异步调用代理处理请求,打印用户输入或工具结果(若为图像生成,提取 URL)。捕获异常并打印。客户端保持活跃,脚本通过 asyncio.run(main())
异步执行。
import streamlit as st
import asyncio
from agent import create_agent
from langchain_core.messages importHumanMessage
async def main():
agent, client = await create_agent()
user_input = input("您想问什么? ")
initial_message =HumanMessage(content=user_input)
try:
print("正在处理您的请求...")
result = await agent.ainvoke({"messages":[initial_message]})
for message in result["messages"]:
if hasattr(message,"type")and message.type =="human":
print(f"用户:{message.content}")
elif hasattr(message,"type")and message.type =="tool":
print(f"工具结果:{message.content}")
if"image"in message.content.lower()and"url"in message.content.lower():
print("图像生成成功!")
else:
print(f"AI:{message.content}")
exceptExceptionas e:
print(f"错误:{str(e)}")
if __name__ =="__main__":
asyncio.run(main())
结论
MCP 不仅是工具调用协议的升级,而是范式变革。它提供通用开放标准,使 AI 系统以标准化方式连接数据源、工具和服务,减少单独连接器需求,简化集成。
非智能服务可通过 MCP 暴露功能为“工具”,供大语言模型调用,无需大幅修改现有系统即可交互和执行任务。
学习是持续的过程,充满挑战。天道酬勤,愈努力愈优秀。
如何系统的去学习大模型LLM ?
大模型时代,火爆出圈的LLM大模型让程序员们开始重新评估自己的本领。 “AI会取代那些行业
?”“谁的饭碗又将不保了?
”等问题热议不断。
事实上,抢你饭碗的不是AI,而是会利用AI的人。
继科大讯飞、阿里、华为
等巨头公司发布AI产品后,很多中小企业也陆续进场!超高年薪,挖掘AI大模型人才! 如今大厂老板们,也更倾向于会AI的人,普通程序员,还有应对的机会吗?
与其焦虑……
不如成为「掌握AI工具的技术人
」,毕竟AI时代,谁先尝试,谁就能占得先机!
但是LLM相关的内容很多,现在网上的老课程老教材关于LLM又太少。所以现在小白入门就只能靠自学,学习成本和门槛很高。
基于此,我用做产品的心态来打磨这份大模型教程,深挖痛点并持续修改了近70次后,终于把整个AI大模型的学习门槛,降到了最低!
在这个版本当中:
第一您不需要具备任何算法和数学的基础
第二不要求准备高配置的电脑
第三不必懂Python等任何编程语言
您只需要听我讲,跟着我做即可,为了让学习的道路变得更简单,这份大模型教程已经给大家整理并打包,现在将这份 LLM大模型资料
分享出来:包括LLM大模型书籍、640套大模型行业报告、LLM大模型学习视频、LLM大模型学习路线、开源大模型学习教程
等, 😝有需要的小伙伴,可以 扫描下方二维码领取🆓↓↓↓
一、LLM大模型经典书籍
AI大模型已经成为了当今科技领域的一大热点,那以下这些大模型书籍就是非常不错的学习资源。
二、640套LLM大模型报告合集
这套包含640份报告的合集,涵盖了大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。(几乎涵盖所有行业)
三、LLM大模型系列视频教程
四、LLM大模型开源教程(LLaLA/Meta/chatglm/chatgpt)
五、AI产品经理大模型教程
LLM大模型学习路线 ↓
阶段1:AI大模型时代的基础理解
-
目标:了解AI大模型的基本概念、发展历程和核心原理。
-
内容:
- L1.1 人工智能简述与大模型起源
- L1.2 大模型与通用人工智能
- L1.3 GPT模型的发展历程
- L1.4 模型工程
- L1.4.1 知识大模型
- L1.4.2 生产大模型
- L1.4.3 模型工程方法论
- L1.4.4 模型工程实践
- L1.5 GPT应用案例
阶段2:AI大模型API应用开发工程
-
目标:掌握AI大模型API的使用和开发,以及相关的编程技能。
-
内容:
- L2.1 API接口
- L2.1.1 OpenAI API接口
- L2.1.2 Python接口接入
- L2.1.3 BOT工具类框架
- L2.1.4 代码示例
- L2.2 Prompt框架
- L2.3 流水线工程
- L2.4 总结与展望
阶段3:AI大模型应用架构实践
-
目标:深入理解AI大模型的应用架构,并能够进行私有化部署。
-
内容:
- L3.1 Agent模型框架
- L3.2 MetaGPT
- L3.3 ChatGLM
- L3.4 LLAMA
- L3.5 其他大模型介绍
阶段4:AI大模型私有化部署
-
目标:掌握多种AI大模型的私有化部署,包括多模态和特定领域模型。
-
内容:
- L4.1 模型私有化部署概述
- L4.2 模型私有化部署的关键技术
- L4.3 模型私有化部署的实施步骤
- L4.4 模型私有化部署的应用场景
这份 LLM大模型资料
包括LLM大模型书籍、640套大模型行业报告、LLM大模型学习视频、LLM大模型学习路线、开源大模型学习教程
等, 😝有需要的小伙伴,可以 扫描下方二维码领取🆓↓↓↓