我将在本文教你如何使用 LangGraph、MCP 和 Ollama 打造一个多智能体(Multi-Agent)聊天机器人。
MCP 是 Model Context Protocol(模型上下文协议)的简称。一些开发者将其比作“为 AI 打造的 USB-C 接口”。
尽管 MCP 去年才发布,但最近它突然流行起来,这也引发了关于它的“花期”能持续多久的讨论。LangChain 还在 X 上发起了一项投票:

结果显示,40.8% 的人认为 MCP 是未来的标准,25.8% 的人觉得 MCP 只是昙花一现,其余 33.4% 的人选择观望。
虽然 MCP 在 2024 年 11 月才发布,但它已经支持了如 GitHub、Slack 和 PostgreSQL在内的许多服务。
作为一个开放标准,令人惊讶的是它可以与任何大语言模型(LLM,例如 Claude、OpenAI、Gemini 等)一起使用。

接下来,我将为你展示如何使用 LangGraph、MCP 和 Ollama 打造一个多智能体(Multi-Agent)聊天机器人。
我将向聊天机器人提出两个不同的问题:第一个问题是,“你能写一份关于最新 LLM 的报告吗?”

如果你观察聊天机器人生成输出的过程,你会发现这个 Agent 使用其结构化的流程(通过 create_chatbot 函数驱动)来处理输入。这个函数将系统提示、用户消息和工具执行整合成一个流畅的交互过程,然后根据查询决定使用哪个工具。它会调用 Google 搜索工具来查找最新信息并生成报告。
对于第二个问题,“编写一个使用 Seaborn 创建带回归线的散点图的 Python 脚本”,聊天机器人会处理请求并将其路由到合适的工具,比如 python_repl 或 data_visualization,具体取决于查询的结构。async_tool_executor 会动态处理工具调用,确保同步和异步函数(比如生成代码或可视化内容)都能正确执行。

在这个过程中,我们使用 StateGraph 管理聊天机器人的对话状态,因此它能够对后续问题提供准确且具有上下文感知的回答。
get_tools 函数确保只提供可用的工具,维持系统稳定性。
主函数让一切顺利运行,实时处理用户输入,调用正确的工具并处理输出。
因此,在这个本文结束时,你将明白 MCP 和函数调用(Function Call)的区别,什么时候使用函数调用,什么时候使用 MCP,以及我们如何利用 LangGraph、MCP 和 Ollama 打造一个强大的智能体聊天机器人。
MCP 和函数调用有什么区别?
在函数调用中,AI 就像一个技术娴熟的工人,严格按照脚本操作——它可以填写表格并调用预定义的工具,但只能使用它已有的工具,并且一次调用一个。而在 MCP 中,AI 更像是一个拥有工具箱的智能体:它可以在工具箱中翻找(发现新工具),组合使用它们,处理更多任务,并拥有更大的自主性。
-
函数调用与模型的提示紧密耦合,开发者需要管理调用顺序,这使得它非常可控,但某种程度上缺乏灵活性。
-
MCP 通过开放协议实现松耦合,这让它具有高度的灵活性和扩展性,但需要强大的设计来管理复杂性(并确保安全性)。
下一部分将深入探讨如何使用 MCP 构建智能体,以及如何应对这种灵活性带来的挑战。
什么时候使用函数调用和 MCP?
选择函数调用还是 MCP 取决于使用场景:
-
当你有一组明确定义的少量动作或查询时,特别是在单步操作且需要高度结构化的输出时,使用函数调用。它非常适合可预测的任务和轻量级集成,此时 MCP 的额外开销可能显得多余。因此,当需要结构化、狭窄的任务以及与应用轻松集成时,选择函数调用。
-
当你需要更大的灵活性、多功能工具或跨交互演变的上下文时,使用 MCP。MCP 更适合复杂、多步骤的工作流程,或者当 AI 需要维持长期上下文并与各种系统交互时。如果你的 AI Agent 是一个跨内部系统的通用助手,可以从多个数据源获取信息,MCP 是更好的选择。
值得注意的是,这两种方法并非互斥——它们可以互补。例如,可以在 MCP 客户端内部使用函数调用来处理模型的结构化输出。
从概念上讲,函数调用旨在以受控方式将自然语言翻译为函数执行,而 MCP 则旨在为 AI 提供更广泛的接口,让它在环境中探索和操作。
开始编码吧
接下来,我将介绍本次项目的重点。
首先,本项目所需的主要技术栈:
-
langchain_mcp_adapters:将 MCP 工具转换为 LangChain 工具,与 LangGraph Agent 一起使用,并提供客户端实现,允许用户连接并从多个 MCP 服务器加载工具。 -
MCP:MCP 是一个开放协议,标准化了应用程序如何为大语言模型提供上下文。 -
Googlesearch-python:一个便于 Google 搜索的包。
以下是代码的主要部分(因篇幅限制,仅讲述核心内容):
agent.py
我将 create_agent 函数设计为一个异步过程,以构建 AI Agent。我设置了一个异步函数,该函数接受 docs_info 这个可选参数,以向聊天机器人提供相关数据。
我将 MultiServerMCPClient 集成到异步上下文管理器中,确保使用服务器发送事件 (SSE) 与 MCP 服务器 http://localhost:8000/sse 无缝通信,超时时间为 30 秒。
我实现了对 client.get_tools() 的调用,以检索必要的 MCP 工具,从而启用高级功能。为了管理对话状态,我使用 MessagesState 构建了一个 StateGraph。
然后,我使用 create_chatbot(docs_info) 创建了一个聊天机器人节点,使其能够处理和与提供的文档进行交互。

我还设计了 async_tool_executor 函数来动态处理工具调用。它以 state 作为输入,包含对话中交换的消息列表。我提取最后一条消息(messages[-1])来检查是否有工具调用。如果没有工具调用,直接返回消息不变。如果有,我会遍历每个工具调用,提取工具名称、参数和 ID,并根据工具名查找匹配的工具。如果工具不存在,则返回错误信息;如果存在,则根据工具是异步还是同步函数来执行,并处理可能的异常。

我通过添加异步工具执行节点和路由函数,设计了一个结构化的对话流程。路由函数根据最后一条消息是否包含工具调用,决定下一步是转到工具节点还是结束对话。

nodes.py
我设计了 get_system_prompt 函数来动态生成系统提示,确保 AI 助手在清晰的指导和上下文感知下运行。我使用当前日期并定义了助手角色及其可用工具:
-
generate_image(DALL-E 生成图像)
-
data_visualization(matplotlib 创建图表)
-
python_repl(执行 Python 代码)。

我开发的 create_chatbot 函数处理用户输入并生成 AI 响应。它使用 ChatPromptTemplate 将系统指令与用户消息结合,通过管道操作(|)连接到 LLM,确保消息格式一致并维持结构化的对话历史。

server.py
我开发了一组工具,包括图像生成、数据可视化和 Python 代码执行。
-
generate_image 使用 DALL-E 根据提示生成图像并返回 URL;
-
data_visualization 执行 matplotlib 代码并返回 base64 编码的 PNG 图像;
-
python_repl 在 REPL 环境中运行 Python 代码。

main.py
我设计了 main 函数来运行异步代理,处理用户输入并动态与工具交互。它通过命令行获取输入,异步调用 Agent 并处理响应,特别处理工具结果(如图像 URL)。

结论
MCP 不仅仅是一个简单的工具调用协议升级,而是一个重大的范式升级。
MCP 提供了一个通用的开放标准,使 AI 系统能够以标准化方式连接到各种数据源、工具和服务,减少了为每个数据源构建单独连接器的需求,简化了 AI 集成过程。
当前的非智能服务可以通过 MCP 将自身功能暴露为“工具”,供 LLM 调用,这使得 LLM 能够与现有系统交互并执行任务,而无需对现有系统进行重大修改。
(文:PyTorch研习社)