ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LangChain集成MCP:构建生产级Agent工具编排体系

LangChain集成MCP:构建生产级Agent工具编排体系 开发 Agent 应用时真正棘手的问题往往不是模型能不能“聪明地”调用工具而是工具如何定义、如何注册、如何跨进程连接、如何调试、如何从小 demo 平滑部署到生产环境。传统的 Function Calling 只解决“模型输出一段带参数的结构化调用意图”但当我们面对多个系统、多个团队、多种工具协议时缺少统一连接层会非常痛苦。本文围绕 LangChain MCP 这条主线路从背景概念、环境准备、核心机制拆解到完整可运行案例、调试技巧、生产部署建议和常见面试题逐一展开。无论你是刚接触 LangChain 的新手还是正在团队内落地多智能体系统的开发者都可以按这篇内容把关键链路跑通。整篇文章的重点不是堆概念而是让你能照着一套代码把 MCP Server 搭起来让 LangChain Agent 动态调用工具并知道线上出问题时应该从哪些层面排查。1. 背景与核心概念1.1 为什么 Agent 需要“工具编排”大模型本身擅长文本生成、推理和归纳但它不具备读取实时数据、操作业务系统、调用外部 API 的能力。Agent 的核心价值在于让模型在推理循环中根据任务需要主动挑选工具、传入参数并处理返回值。举个例子用户问“帮我看看这个仓库今天的提交情况然后总结一份英文日报”如果只靠底层模型它无法连接 Git 系统如果把它接成一个死板的“固定调用链”当输入任务稍有变化整个流程就失效了。Agent 的典型执行链路大致是接收用户消息。模型判断是否需要工具。如果需要则输出工具名与参数。运行时解析并执行工具。将结果返回给模型。模型根据结果继续推理或结束任务。当工具数量少、开发者自己维护时这个流程可以实现。但一旦涉及数据库、企业内网 API、设计稿平台、开发工具链等异构系统就会出现一个很现实的问题每个系统都有自己的 SDK 和鉴权方式Agent 代码会被各种客户端的初始化逻辑塞满。1.2 LangChain、LangGraph、MCP 三者是什么关系很多初学者会把 LangChain 和 LangGraph 混在一起。简单地说LangChain 是一个包含模型封装、Prompt 模板、输出解析、文档加载、向量存储、Tool 抽象等组件的 LLM 应用开发框架LangGraph 则是基于图状态机思想的编排引擎适合构建带循环、条件分支、人工审批、长时间运行等特性的 Agent。LangChain 并不等于 Agent。过去 LangChain 有 AgentExecutor后来随着 LangGraph 的成熟新的 Agent 编排逻辑更多迁移到 LangGraph 中。社区里经常出现的create_agent、create_react_agent本质上都是基于 LangGraph 构建的 Agent 封装。LangChain 的组件体系负责工具封装和模型接入LangGraph 负责编排和控制循环这样分工比较清晰。MCP 则是一个更底层的开放协议全称 Model Context Protocol中文通常叫“模型上下文协议”。它由 Anthropic 提出并开源目标是让 AI 应用通过一套标准协议连接“外部工具和数据源”。它不绑定具体大模型也不绑定具体 Agent 框架。你可以先理解成“AI 世界的 USB-C 接口”Host 是 AI 应用Server 是被接入的业务能力。一条最容易混淆的边界是MCP 并不替代模型的 Function CallingMCP 解决的是“工具如何被发现、如何连接、如何调用、如何返回”Function Calling 解决的是“模型如何按照结构化 schema 生成调用意图”。两者可以组合使用LangChain 内部仍然需要模型支持工具调用能力。1.3 MCP 解决的真实问题在实际项目中MCP 带来的收益可以归纳成四点第一连接方式标准化。无论工具背后的系统是 Jira、GitHub、Figma、蓝湖还是内部工单系统只要实现了 MCP ServerAgent 都使用同一套交互协议不需要为每个系统封装一套独立插件。第二进程边界更清晰。工具能力可以独立部署升级工具系统时不需要重新发版整个 Agent。尤其是中大型团队MCP Server 可以由对应业务团队维护Agent 团队只关心工具名、入参、出参和稳定性。第三上下文与工具能力动态加载。MCP 协议中 Server 可以暴露三类能力tools、resources、prompts。其中resources类似给模型提供可读取的数据资源prompts类似服务端维护的提示词模板但被引用最多的还是tools。第四生态复用。比如社区已经有 Figma MCP、Unity MCP、Notion MCP、设计协作平台 MCP 等服务相当于别人已经把某个系统的 Agent 接入能力封装好你只需要通过 MCP Client 连接即可。从这个角度看MCP 不改变 Agent 的推理方式但改变了工具能力的分发和接入方式。这正好和 LangChain 组合成一套比较理想的生产架构LangChain/LangGraph 负责 Agent 编排MCP Server 负责业务工具接入。2. 环境准备与版本说明2.1 环境清单在开始前先明确示例运行环境。以下依赖版本不需要严格照抄但建议 Python 使用 3.10 及以上版本。新版 LangChain 中大量 Agent API 已经依赖异步能力和类型新语法Python 版本太低会出现很多兼容性问题。推荐环境如下依赖版本建议Python3.10 或更高langchain最新稳定版示例面向 0.3 APIlanggraph新版使用langgraph.prebuilt.create_agentlangchain-openai兼容 OpenAI 接口的模型接入包langchain-mcp-adaptersMCP Tools 到 LangChain Tools 的适配包mcpMCP Python SDK用于编写 MCP Server说明一点大模型 API 不一定是 OpenAI 官方接口。国内很多云厂商、开源推理框架以及 DeepSeek、Ollama 本地服务都提供 OpenAI 兼容接口。只要你的模型服务商提供base_url、api_key、model三个参数示例中的ChatOpenAI通常都可以替换使用。2.2 创建一个最小项目结构建议先建立一个独立目录目录结构比较简单langchain-mcp-demo/ ├── mcp_server.py # MCP Server对外暴露工具 ├── agent_demo.py # LangChain Agent连接 MCP 并执行任务 └── requirements.txt # Python 依赖不要把所有代码都堆在一个文件里MCP Server 和 Agent Client 分开会让调试更清晰。后面上线时MCP Server 很可能独立运行在另一台机器或容器中。2.3 安装依赖执行下面命令安装依赖pip install -U langchain langgraph langchain-openai langchain-mcp-adapters mcp python-dotenv如果下载速度较慢可以使用国内 PyPI 镜像pip install -U langchain langgraph langchain-openai langchain-mcp-adapters mcp python-dotenv -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后可以先确认关键包能否正常导入import langchain import langgraph import mcp import langchain_mcp_adapters print(dependencies ok)如果某个包因为版本原因无法导入优先升级到最新版本不要在旧版本 API 上修改样例代码。过去 LangChain Agent 曾使用langchain.agents.initialize_agent现在新项目更推荐基于 LangGraph 的create_agent这也是许多教程看起来“对不上”的主要原因。3. 核心机制拆解3.1 一次 Agent 调用到底发生了什么以 LangGraph 的create_agent为例它在底层构建了包含“Agent 节点”和“Tools 节点”的图。当模型觉得需要调用工具时输出结果会被图路由到 Tools 节点Tools 节点拿到结果后再把工具输出放回消息流继续触发 Agent 节点推理。这个循环会一直持续直到模型认为已生成最终答案。这个机制带来的一个直接结果是Agent 的每一轮工具调用其实都是模型与运行时状态的交互。开发者可以在这个流程中插入人工审批、权限校验、结果改写等逻辑这就是 LangGraph 可控性的价值。如果工具数量变得很多还需要考虑工具描述的质量。模型的参数选择依赖工具名称与描述描述写得太模糊模型可能误调用描述写得太啰嗦则浪费上下文长度。工具设计要像 API 文档一样保持精确和简洁。3.2 MCP 协议的核心设计MCP 协议基于 JSON-RPC 2.0。MCP Client 与 MCP Server 之间通过消息交换完成初始化、工具列表获取、工具调用等动作。一次典型的 MCP 工具调用流程可以简化成客户端发送initialize请求协商协议版本。服务端返回支持能力和服务信息。客户端发送tools/list获取工具列表。Agent 根据工具列表决定是否调用。客户端发送tools/call传入工具名和参数。服务端执行工具并返回结果。在传输方式上本地开发最常见的是stdio传输即 Agent 主进程通过标准输入输出与子进程里的 MCP Server 通信。这也是本文案例选用的方式。远程部署时MCP Server 可以基于 HTTP 的 Streamable HTTP 或 SSE 传输由 Agent 服务通过 URL 访问。理解 stdio 模式时有一个重要坑点主进程的 stdout 用于与子进程通信所以 MCP Server 内部不要打印日志到标准输出否则会破坏通信协议。后面调试部分会再强调这一点。3.3 从 MCP Server 到 LangChain Tools 的桥接LangChain 原生有自己的tool装饰器可以将一个普通 Python 函数转换成 Tool。但如果我们想接入一个已经实现好的 MCP Server不需要自己实现 MCP Client 调用细节使用langchain-mcp-adapters会更方便。MultiServerMCPClient是其中一个非常重要的类。它允许你同时连接多个 MCP Server把每个 Server 暴露的tools统一收集为 LangChain Tools最后传给 Agent。这里的关键理解是MCP Server 不关心你的 Agent 使用什么语言和框架它只遵循协议接收请求并返回结果LangChain 也不关心工具背后是本地函数还是远程服务它只管拿到 Tool 后用统一方式触发。适配层解决的是不同抽象之间的转换。4. 完整实战MCP Server LangChain Agent4.1 编写 MCP Server我们先用 MCP Python SDK 的高层 API 写一个演示 Server。它暴露两个工具一个返回当前时间一个返回模拟天气数据。天气工具如果接真实数据源直接在里面调用 HTTP API 即可这里为了保持环境纯净用固定模拟值。文件路径mcp_server.pyfrom datetime import datetime from mcp.server.fastmcp import FastMCP mcp FastMCP(demo-server) mcp.tool() def get_current_time(timezone: str Asia/Shanghai) - str: 返回指定时区的当前时间。 注意这是一个演示工具。真实生产环境建议使用 zoneinfo 等库 处理时区转换避免只返回服务器本地时间。 now datetime.now() return ( f当前服务器时间为 {now.isoformat()} f你请求的时区是 {timezone}。 ) mcp.tool() def get_city_weather(city: str) - str: 查询指定城市当前天气概况。 这是演示工具返回模拟数据。生产环境应替换为真实天气服务调用 并处理外部 API 超时、限流、鉴权等逻辑。 return f{city} 当前天气晴气温 22 摄氏度空气质量良。 if __name__ __main__: mcp.run(transportstdio)这个文件里需要注意几点FastMCP(demo-server)中的名称会出现在客户端工具前缀中能帮助区分不同 MCP Server 的来源。每个函数一定要写清楚中文或英文描述因为描述会作为模型判断是否调用该工具的重要信息。mcp.run(transportstdio)表示通过标准输入输出通信这是本地进程连接最简单的方式。4.2 编写 LangChain Agent接下来新建agent_demo.py。这个文件要做三件事建立 MCP Client 连接、使用create_agent构建 Agent、执行用户请求。文件路径agent_demo.pyimport asyncio import os from dotenv import load_dotenv from langchain_mcp_adapters.client import MultiServerMCPClient from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_agent load_dotenv() async def main(): # 1. 通过 stdio 方式连接本地 MCP Server async with MultiServerMCPClient( { demo: { command: python, args: [mcp_server.py], transport: stdio, } } ) as client: # 2. 获取 MCP Server 暴露的所有工具 tools client.get_tools() # 3. 初始化模型。 # 如果你使用国内模型服务或本地推理服务请替换 base_url 和 model。 model ChatOpenAI( modelos.getenv(OPENAI_MODEL, gpt-4o-mini), api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv( OPENAI_BASE_URL, https://api.openai.com/v1 ), ) # 4. 基于 LangGraph 创建 Agent agent create_agent( model, tools, prompt( 你是一个智能助手。如果需要查询时间或天气 请主动调用工具获取信息不要凭空编造。 ), ) # 5. 执行一次对话 result await agent.ainvoke( { messages: [ { role: user, content: 现在几点了顺便看看北京天气怎么样, } ] } ) # 6. 输出最终回答 print(result[messages][-1].content) if __name__ __main__: asyncio.run(main())运行前创建环境变量文件cp .env.example .env如果你的项目没有.env.example也可以直接在.env中维护以下内容OPENAI_API_KEYsk-xxx OPENAI_MODELgpt-4o-mini OPENAI_BASE_URLhttps://api.openai.com/v1如果不使用官方 OpenAI可以把OPENAI_API_KEY和OPENAI_BASE_URL换成模型服务商提供的值。4.3 运行与验证执行下面的命令python agent_demo.py正常情况下Agent 会先路由到get_current_time和get_city_weather工具拿到结果后生成最终回答。你会看到类似输出当前服务器时间为 2025-06-01T10:30:00.123456 你请求的时区是 Asia/Shanghai。 北京 当前天气晴气温 22 摄氏度空气质量良。注意不同模型的最终回答风格会不同但只要它没有直接编造而是把工具结果转成自然语言就说明 Agent 链路已经跑通。4.4 扩展同时连接多个 MCP Server生产环境通常不会只有一个 MCP Server。例如你可能既要连接企业内部的 Git 工具又要连接研发效能平台还要连接数据库代理服务。此时可以在MultiServerMCPClient配置中增加多个 server。async with MultiServerMCPClient( { demo: { command: python, args: [mcp_server.py], transport: stdio, }, business: { url: https://mcp.internal.example.com/mcp, transport: http, headers: {Authorization: Bearer your-token}, }, } ) as client: tools client.get_tools() ...不同 MCP Server 返回的 tools 会自动带上前缀或者由适配层做去重处理具体行为以你安装的langchain-mcp-adapters版本为准。多 Server 情况下建议在工具描述中明确标注归属系统减少模型误选工具的几率。5. 调试技巧与高频问题排查5.1 Agent 调试的三个层次Agent 项目排查时最忌讳一上来就怀疑模型能力差。建议按下面三个层次排查第一层是“工具本身是否可用”。可以先不经过 Agent直接用 Python 脚本调用 MCP Server 工具方法确认返回结果是否符合预期。若工具本身报错再强大的 Agent 也无法完成。第二层是“Agent 是否正确选择了工具”。如果工具可用但结果不对重点看中间消息流。模型可能没有意识到需要工具也可能选择了错误的工具也可能传入参数格式不对。第三层是“模型是否合理利用工具结果”。有些时候工具被调用了结果也正确但模型最终的总结内容与事实不一致这种情况通常需要调整 prompt 或模型参数。5.2 查看 Agent 中间状态LangGraph 的stream_modeupdates可以帮助我们看到每一步是哪个节点在执行、工具返回了什么。代码片段可以参考inputs { messages: [ { role: user, content: 上海天气怎么样现在几点, } ] } async for update in agent.astream(inputs, stream_modeupdates): print(update)输出结果会是一个字典key 通常是节点名比如agent或tools。看到tools节点输出后就可以确认工具确实执行了。如果你发现 Agent 一直在重复调用同一个工具需要考虑设置最大递归次数避免循环跑死。5.3 MCP stdio 模式下最常见的坑MCP 本地调试中有一个很典型的错误是 MCP Server 内部使用print输出日志。stdio 模式下stdout 通道承载的是 MCP 协议消息任何额外的print都可能让客户端解析失败表现为“连接关闭”“响应格式错误”“工具列表为空”。正确的做法是日志输出到 stderr或者统一收集到文件中。Python 的logging模块默认输出到 stderr所以比较安全。如果使用 FastMCP它自身也有日志体系需要单独配置。第二个高频问题是“子进程启动失败”。MCP Server 的command通常是python但如果你的电脑有多个 Python 环境python实际指向的环境和安装mcp包的环境不一致就会找不到模块。建议在配置中写绝对路径或者用虚拟环境中的 Python 路径。第三个问题是“MCP Server 阻塞”。手动启动 MCP Server 时它会在 stdout 上等待协议消息所以看起来像“卡住”。这不是程序 bug是它正在等待客户端连接。调试时可以直接使用 MCP 调试工具连接它而不是手动敲命令。5.4 常见问题速查表问题现象常见原因解决思路Agent 不调用工具工具描述不清晰或模型不支持工具调用检查模型参数与工具描述换更强模型工具列表为空MCP Server 启动失败或通信协议被破坏单独运行 Server 观察 stderr检查 stdout 是否污染工具调用一次后流程结束Agent 循环配置错误或模型提前终止打印中间状态检查工具返回是否加入消息流模型输出的参数与工具 schema 不匹配Schema 定义不准确精简工具参数增加类型说明和枚举约束Agent 反复调用同一工具缺少终止条件或结果不够明确设置recursion_limit在 prompt 中提示“结果不可用时可换工具不要重复调用”MCP Server 数据更新Agent 拿不到服务未重启或缓存检查服务生命周期与日志6. 生产级部署建议6.1 stdio 与 HTTP 如何选择开发环境通常用 stdio 方式因为它不需要网络监听启动和调试都简单。但到生产环境后如果 Agent 和 MCP Server 部署在不同机器或者需要支持多个 Agent 实例连接同一个 MCP Serverstdio 并不合适。这时更推荐让 MCP Server 以 HTTP 或 SSE 方式独立部署。Agent 服务通过 URL 远程连接Server 可以单独扩缩容、加权限控制、做日志采集。不过要注意远程 MCP 一旦变成网络服务“安全”就成为一个不可绕过的主题。MCP 本身是协议不是完整的安全方案部署时必须在外层加上认证鉴权、流量限制和网络隔离。6.2 推荐的部署拆分方式如果项目规模不大可以把 Agent 服务和 MCP Server 放在同一台机器上用 systemd 或 Docker Compose 管理。MCP Server 以 HTTP transport 启动Agent 服务作为另一个进程调用它。一个简化的 systemd 服务模板如下具体 ExecStart 和 transport 参数需要根据自己的 MCP Server 启动方式调整[Unit] DescriptionDemo MCP Server Afternetwork.target [Service] Useragentuser Groupagentuser WorkingDirectory/opt/mcp-demo ExecStart/usr/bin/python /opt/mcp-demo/mcp_server.py Restartalways RestartSec5 EnvironmentFile/etc/mcp-demo.env StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target如果希望更好隔离环境也可以把 MCP Server 打成 Docker 镜像然后通过 Docker Compose 和 Agent 服务一起启动。FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD [python, server_main.py]在业务日志逻辑上要让 Agent 的每次工具调用都能跟踪到会话 ID、工具名、入参、出参、耗时和错误码。没有可观测性Agent 一旦出现“自动连续调用多个工具并且结果错误”的故障定位成本会非常高。6.3 连接生命周期与进程管理如果使用MultiServerMCPClient的async with方式连接作用是每次请求都建立和关闭连接。本地开发没问题但生产环境如果每个请求都拉起一个 MCP Server 子进程资源开销会很大。更合理的做法是Agent 启动时建立好与 MCP Server 的连接在应用退出时统一关闭。也就是把 MCP Client 的生命周期放到服务进程的 start/shutdown 钩子中。LangChain 官方适配层提供了异步上下文管理实际生产编码时可以根据 FastAPI 的lifespan或普通后台任务的启动关闭逻辑去封装。6.4 安全基线与性能优化可以从下面几个方向来构建安全基线最小权限MCP Server 进程不要使用 root 账号运行数据库账号只授权所需库表的只读或最小写权限。模型提示词注入Agent 在调用网页抓取或读取外部文档后要警惕返回内容里包含恶意指令。不要无条件信任工具结果。人工审批对删除、转账、对外发送消息等敏感操作应先返回待审批状态由人工确认后再执行。超时控制每个工具调用都应有超时时间。外部 API 故障时不能让 Agent 无限等待。敏感信息脱敏日志中不要完整记录模型输入输出中可能包含的密钥和用户隐私数据。性能方面推荐的优化路径是减少不必要的工具调用、精简上下文、避免把大文件全部塞进模型输入。如果工具返回结果很大可以通过分页或摘要机制把关键信息传给模型而不是一次性灌入。7. 面试真题与答题思路7.1 概念理解类题目面试官经常问MCP 和 Function Calling 有什么区别这是一个很好的区分题。Function Calling 是模型服务商提供的结构化输出能力它让模型可以返回工具调用指令。MCP 是一个外部工具接入的开放协议它定义的是客户端、服务端、工具发现和调用流程。MCP 服务器往往通过 Function Calling 上游能力与模型协作但 MCP 本身并不替代模型的工具调用生成能力。答题时如果能说出“标准化的工具分发层”和“模型能力层”这两个不同维度会显得理解更深。第二个高频题是LangChain 和 LangGraph 有什么区别可以按组件和编排的定位回答。LangChain 更像组件库封装了模型、提示词、向量库、文档加载器、Tool 等LangGraph 则是面向状态和循环的图编排引擎适合构建智能体工作流。现在很多 Agent 应用本质上是 LangChain 的组件和 LangGraph 的控制流组合出来的。7.2 工程实践类题目如果面试官问“Agent 如何避免无限循环”可以从三个层面回答第一是设置最大递归次数如 LangGraph 的recursion_limit第二是审查工具返回结果如果某个工具持续返回错误应当触发回退策略第三是设计停机条件模型只有在确认任务完成且没有新工具计划时才输出最终答案。如果被问到“MCP Server 如何做安全管控”可以围绕认证、授权、请求限流、工具白名单、敏感操作审批链路来回答。注意阐述时要强调 Agent 不是完全自治的尤其在生产环境里必要的人工审批或权限系统是必须的。还会有一个常被追问的问题如何设计 Agent 使用的工具工具不是越细越好。例如“获取天气”和“获取降雨概率”可以分成两个独立工具但如果一个场景中两个数据总是被同时使用则合并成一个工具反而能降低模型调用的复杂度。工具描述应当由实际使用者进行回归测试而不是写完一个描述就不管。7.3 答题时容易踩的坑很多人在面试中会陷入“背概念”的误区忽略了工程表达。面试官更想听你如何判断“什么时候用 LangChain、什么时候直接写逻辑、什么时候引入 MCP”。如果能把方案演进路径讲出来比如初期只有三五个工具时不需要 MCP工具增多、团队协作变复杂后引入 MCP 能带来什么收益会比单纯解释协议细节更有说服力。另外不要在描述中夸大数据能力。MCP 不能解决“模型每次都准确调用工具”的问题它解决的是“工具可以稳定地被发现和连接”的问题。准确回答这一点既能体现认知边界也能避免过度拔高方案效果。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进