最近,模型上下文协议 (Model Context Protocol, MCP) 在 AI 开发圈引起了不小的关注。这个由 Anthropic 推出的开放标准,被一些开发者称为"专为 AI 打造的 Zapier",也有人质疑它只是给 API 调用增加了不必要的复杂性。
实际上,MCP 解决了一个很实际的问题:在 MCP 出现之前,每当我们想让 AI 工具连接外部系统,都需要单独编写集成代码,每个 API 都要重新适配一遍。而 MCP 提供了标准化的接口,让这个过程变得简单很多。
虽然 MCP 相对较新,但发展势头很猛。LangChain 最近的一次社区投票显示:40.8% 的开发者认为 MCP 会成为未来标准,25.8% 认为它只是昙花一现,33.4% 还在观望。
目前 MCP 已经支持 GitHub、Slack、PostgreSQL 等众多主流服务,而且作为开放标准,它能与任何大语言模型 (Claude、OpenAI、Gemini 等) 配合使用。
本教程将手把手教你如何结合 LangGraph、MCP 和 Ollama,构建一个功能强大的多智能体聊天机器人。我们会通过实际案例展示这套技术栈的威力------比如让 AI 自动搜索最新信息生成报告,或者根据需求编写数据可视化代码。
学完这个教程,你将理解 MCP 和函数调用 (Function Call) 的区别、何时使用哪种方案,以及如何用 LangGraph、MCP 和开源工具创建强大的智能体聊天机器人。
MCP 和函数调用有什么区别?
在函数调用模式中,AI 就像一个按照严格脚本工作的熟练工人------它能填写表格、调用预定义工具,但只能使用已获得的工具,而且只能逐个调用。
而在 MCP 模式中,AI 更像一个拥有完整工具箱的智能体:它能在工具箱里翻找 (发现新工具)、组合使用不同工具、处理更复杂的任务,拥有更大的自主权。
函数调用与模型提示紧密绑定,需要开发者管理执行顺序,这让它很好控制但灵活性有限。
MCP 通过开放协议实现松散耦合,具有高度的灵活性和可扩展性,但需要精心设计来管理复杂性和确保安全性。接下来我们会深入介绍如何用 MCP 构建智能体,以及如何应对这种灵活性带来的挑战。
何时选择函数调用,何时选择 MCP?
选择哪种方案主要看具体用例:
选择函数调用的情况:
- 有一小组定义明确的操作或查询
- 主要是单步操作,需要高度结构化的输出
- 适合可预测的任务和轻量级集成
- 当结构化、专一的任务和集成简便性是关键需求时
选择 MCP 的情况:
- 需要更大的灵活性和多功能工具
- 需要跨交互演进的上下文
- 适合复杂的多步工作流程
- AI 需要维护长期上下文并与多种系统交互
- 你的 AI 智能体是跨内部系统的通用助手,需要利用多个数据源
需要注意的是,这两种方法并不互斥------它们可以相互补充。比如,在 MCP 客户端内部可以使用函数调用来处理模型的结构化输出。
从概念上讲,函数调用专注于以可控方式将自然语言转换为函数执行,而 MCP 旨在为 AI 提供更广泛的接口来探索和操作环境。
开始编程实现
现在让我们逐步探索 MCP 应用的创建过程。首先安装必要的依赖库:
bash
pip install -r requirements.txt
接下来导入相关库,这些库的重要性会在后续实现中逐渐体现:
langchain_mcp_adapters 负责将 MCP 工具转换为 LangChain 工具,提供客户端实现,让用户能连接多个 MCP 服务器并加载工具。
MCP 是标准化应用程序为大语言模型提供上下文的开放协议。
Googlesearch-python 是便于进行 Google 搜索的工具包。
python
# agent.py
from langchain_core.messages import AIMessage, ToolMessage, HumanMessage
from langgraph.graph import StateGraph, START, END, MessagesState
from nodes import create_chatbot
import asyncio
import os
import dotenv
from langchain_mcp_adapters.client import MultiServerMCPClient
# main.py
import streamlit as st
import asyncio
from agent import create_agent
from langchain_core.messages import HumanMessage
# nodes.py
from server import get_tools
from langgraph.graph import MessagesState
from langchain_openai import ChatOpenAI
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
from datetime import datetime
import os
# server.py
from mcp.server.fastmcp import FastMCP
from langchain_experimental.utilities import PythonREPL
import io
import base64
import matplotlib.pyplot as plt
from openai import OpenAI
from pydantic import BaseModel, Field
import os
from dotenv import load_dotenv
import asyncio
from googlesearch import search
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) 创建聊天机器人节点。
async_tool_executor 负责动态处理工具调用。它接收包含对话消息列表的状态,提取最后一条消息检查工具调用。如果没有工具调用则直接返回,否则处理每个工具调用,提取工具名称、参数和 ID。
系统会搜索对应的工具,如果找不到就生成错误信息。找到工具后,判断是否为异步函数,相应地使用 await 或直接调用执行。所有错误都会被捕获并生成详细的错误信息。
python
async def create_agent(docs_info=None):
async with MultiServerMCPClient({
"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 def async_tool_executor(state):
# 工具调用处理逻辑
pass
# 添加工具节点和路由逻辑
graph_builder.add_node("tools", async_tool_executor)
# 路由器函数和边的添加
graph = graph_builder.compile()
return graph, client
Nodes.py 模块详解
这个模块包含聊天机器人的核心节点逻辑。get_system_prompt 函数动态生成系统提示,确保 AI 助手有清晰的工作指南和上下文感知能力。
函数首先格式化当前日期,然后定义助手的角色和能力。系统支持三个主要工具:generate_image (使用 DALL-E 生成图像)、data_visualization (用 matplotlib 创建图表) 和 python_repl (Python 代码执行环境)。
create_chatbot 函数处理用户输入并生成 AI 回应。它使用 ChatPromptTemplate 将系统指令与用户消息结合,创建无缝的处理链。函数确保消息格式一致性,维护结构化的对话历史。
python
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 代码
"""
return system_prompt
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):
messages = [HumanMessage(content=state["messages"])]
else:
messages = state["messages"]
response = chain.invoke(messages)
return {"messages": messages + [response]}
return chatbot
Server.py 工具服务器实现
这个模块实现了多功能工具服务器。generate_image 工具使用 DALL-E 根据提示生成图像,确保提示有效后异步调用 OpenAI API。成功时返回图像 URL,失败时提供错误信息。
data_visualization 工具执行包含 matplotlib 的 Python 代码创建图表,将结果保存为 base64 编码的 PNG 图像。python_repl 工具提供 Python 代码的动态执行环境。
每个工具都设计了错误处理机制,向用户返回有意义的响应。get_tools 函数返回可用工具列表,确保只包含功能正常的工具。
python
@mcp.tool()
async def generate_image(prompt: str) -> str:
"""使用 DALL-E 根据提示生成图像"""
if not isinstance(prompt, str) or not prompt.strip():
raise ValueError("无效的提示")
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}"
except Exception as e:
return f"图像生成错误:{str(e)}"
@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}"
except Exception as e:
return f"图表创建错误:{str(e)}"
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 主程序入口
主程序实现异步智能体,处理用户输入并与工具动态交互。函数首先创建智能体和客户端,然后通过命令行获取用户输入,构造初始消息。
使用 agent.ainvoke() 异步调用智能体,处理请求和响应。根据消息类型打印不同内容,对图像生成结果进行特殊处理。所有异常都会被捕获并显示详细信息。
python
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}")
except Exception as e:
print(f"错误:{str(e)}")
if __name__ == "__main__":
asyncio.run(main())
系统架构和工作原理
核心组件说明
LangGraph 负责管理智能体的状态和工作流程,通过 StateGraph 定义节点和边来构建复杂的对话逻辑。每个节点代表一个处理步骤,边定义了节点间的转换条件。
MCP 作为开放协议,标准化了 AI 系统与外部工具的交互方式。它提供了发现、调用和管理工具的统一接口,让智能体能够动态使用各种功能。
异步处理机制确保系统能同时处理多个请求,提升响应速度和用户体验。工具执行器支持同步和异步工具,保证系统的兼容性和稳定性。
消息流处理
系统使用 MessagesState 管理对话状态,包含用户输入、AI 回复、工具调用和工具结果等各类消息。每条消息都有明确的类型和结构,便于系统识别和处理。
路由器根据最后一条消息的内容决定下一步操作。如果包含工具调用,就转到工具执行节点;否则结束对话或继续生成回复。这种设计让系统能灵活处理各种对话场景。
错误处理和容错机制
系统在多个层面实现了错误处理。工具执行时的异常会被捕获并转换为用户友好的错误信息。网络连接问题、API 调用失败等都有相应的处理逻辑。
超时机制防止系统无限等待外部服务响应。客户端连接管理确保资源的正确释放。这些措施保证了系统的稳定性和可靠性。
总结
通过本教程,我们深入探索了如何使用 LangGraph、MCP 和 Ollama 构建强大的多智能体聊天机器人。这套方案结合了最新的 AI 技术和开放标准,为构建智能应用提供了强大的基础。
MCP 作为新兴的开放协议,不仅仅是工具调用的升级版,更是 AI 系统架构的重大革新。它提供了标准化的接口,让 AI 系统能够灵活地连接各种数据源、工具和服务,大大简化了集成过程。
这种标准化的方法让现有的服务能够轻松地将自己的功能暴露给大语言模型使用,实现了 AI 与传统系统的无缝对接,无需对现有系统进行大幅修改。
随着 MCP 生态的不断发展,我们可以期待看到更多创新的应用和服务。对于开发者而言,掌握这些前沿技术将为在 AI 时代创造更大价值提供强有力的支撑。