LangChain+MCP构建Agent工具:DeepSeek接入与Claude Code实战
之前在业务迭代中做 Agent 工具接入时,我反复卡在同几个问题上:模型能理解工具描述,但真正对接内部系统时,每个工具都要手写一套解析逻辑;换一个模型厂商,参数格式又要重新适配;想把工具开放给 Claude Code 这类外部助手使用,还得再搭一套服务。网上资料虽然不少,但大多只讲 LangChain 基础,或者只讲 MCP 协议概念,能把两者串起来跑通一个完整 Agent 的教程很少。本文就整理一条从原理到代码的闭环路径,基于 LangChain 和 MCP 构建 Agent 工具,并演示如何接入 DeepSeek,同时聊聊 Claude Code 和 LangGraph 的使用边界。无论你是刚入门 Agent 开发的新手,还是已经在做企业级 AI 应用落地的后端工程师,这篇文章都可以当作一份可直接复用的实操手册。
1. 背景与核心概念
1.1 为什么 Agent 工具开发需要 MCP
先看一个很常见的场景。你想让大模型能够查询订单状态,传统做法是这样:调用一次模型接口,把用户问题“我的订单 10086 现在什么状态”发给模型,模型返回一段话,你通过正则或 NER 抽取出订单号,再调用自己的订单服务接口。这套逻辑在单个场景下没问题,但一旦工具数量多起来,问题就暴露了:每个工具的入参、出参、鉴权方式都不一致,调用层代码会越来越臃肿;模型本身并不知道有哪些工具可用、参数怎么填;每个 AI 应用都要为同样的工具写一遍对接代码,重复造轮子。
MCP 要解决的正是这一类“模型应用与外部工具/数据源对接”的重复劳动。MCP 全称 Model Context Protocol(模型上下文协议),是由 Anthropic 提出并开放的标准化协议。它定义了一套统一的规则,让 AI 应用(MCP Client)能够以标准方式发现、调用外部能力(MCP Server)。你可以把 MCP 理解为 AI 世界的 USB-C 接口:只要设备都遵守同一套协议,插上就能用。对于 Agent 开发来说,MCP 的价值在于隔离了“工具提供方”和“模型应用方”,工具实现一次,LangChain 应用、Claude Code、其他支持 MCP 的客户端都能复用。
1.2 MCP 协议的核心组成
MCP 协议在架构上分为两侧。一侧是 MCP Server,负责把某个能力封装成标准接口,比如订单查询、天气查询、数据库读取;另一侧是 MCP Client,运行在 AI 应用内部,负责与 Server 建立连接,并把这些能力暴露给大模型。两者之间通过 JSON-RPC 2.0 格式的消息通信,传输层可以基于标准输入输出(stdio),也可以基于 HTTP 或 SSE。对本地开发来说,stdio 模式最简单,服务端作为一个子进程启动,通过进程间管道通信;对生产环境来说,更推荐 HTTP 模式,把 MCP Server 部署成独立服务,多个客户端共享访问。
在 MCP Server 内部,主要暴露三类能力。Tool 是最常用的,对应一个可执行动作,比如查询天气、创建工单,大模型会根据用户需求决定要不要调用、何时调用。Resource 对应可读取的数据,比如一份配置文件、一张表数据,相当于给模型提供上下文材料。Prompt 则是预定义的提示词模板,方便复用固定的任务指令。初学者不需要一次掌握全部,从 Tool 开始理解和编写就足够覆盖大部分 Agent 场景。
1.3 LangChain、LangGraph、MCP、Agent 之间的关系
这几个概念在热词里经常被放在一起,但它们解决的是不同层面的问题,容易混淆。LangChain 是一个用于构建大模型应用的开发框架,提供模型封装、提示词管理、输出解析、文档加载、向量检索等通用组件,同时 agent 的周边能力也都内置好了。LangGraph 是 LangChain 生态中的编排框架,用图结构来描述 Agent 的状态流转,你可以在节点之间定义条件和循环,实现比早期 AgentExecutor 更精细的执行流程。MCP 则是一条“总线”,负责连接模型应用和外部工具,它不关心你用的是 LangChain 还是 LangGraph,也不关心底层模型是谁。Agent 是一种应用范式,核心是让模型在“推理-行动-观察”的循环里自主完成任务,LangChain 和 LangGraph 是它的实现载体,MCP 是它获取工具能力的通道。
用一个例子串起来:你用一个 ChatOpenAI 实例接入 DeepSeek 模型,这个模型就是 Agent 的“大脑”;通过 MCP Client 连接一个订单查询 Server,这个工具就是 Agent 的“手脚”;LangChain 的 Agent 执行器或 LangGraph 的状态图负责编排“大脑”和“手脚”之间的协作顺序。看到这里,你应该明白了一件事:MCP 不是要替代 LangChain,而是补齐了 LangChain 在外部工具标准化接入上的短板,两者是配合关系。
2. 环境准备与版本说明
2.1 运行环境与依赖安装
本文示例基于 Python 3.10+ 环境,操作系统使用 Linux 或 macOS 都可以,Windows 用户建议使用 WSL2,因为部分 MCP 相关依赖在原生 Windows 下的进程管理和信号处理会有些兼容性问题。框架版本迭代非常快,以下安装命令以本文写作时的常见版本为例,你执行时大概率会拉到更新的版本,这不影响配置思路,但如果出现 API 变更,请以你实际安装版本的官方文档为准。
先创建虚拟环境并安装依赖:
如果你在安装时遇到某个包版本冲突,建议先只安装核心依赖,再按报错信息逐个补装。langchain-mcp-adapters 是 LangChain 官方提供的 MCP 适配层,用于把 MCP Server 暴露的工具转换为 LangChain 的 Tool 对象;mcp 是 MCP 官方 Python SDK,用于编写 MCP Server 和 Client。这两个包是本文示例的关键依赖。
2.2 API Key 与模型配置
本文会演示接入 DeepSeek 模型。DeepSeek 的接口兼容 OpenAI 格式,所以在 LangChain 中不需要引入专门的 SDK,直接用 langchain-openai 包即可,只需要修改模型名和 base_url。你需要提前准备一个 DeepSeek 的 API Key,并保证账户内有可用余额。建议把密钥写入 .env 文件,而不是直接硬编码在代码里:
后面所有示例都会通过 dotenv 加载这些环境变量。如果你使用的是其他兼容 OpenAI 协议的大模型服务,只需要替换 base_url 和 model 名称即可,这也是目前多模型切换成本最低的一种做法。
2.3 示例项目结构
为了让你能跟着操作,我把示例项目组织成下面这个结构:
3. 核心原理拆解
3.1 大模型 Function Calling 是什么
在进入 MCP 代码之前,有必要先理解底层的大模型工具调用机制,也就是 Function Calling。当你把一组工具的描述以 JSON Schema 形式传给模型时,模型不会直接执行工具,而是根据对话内容输出一个结构化的“调用意图”,比如“需要调用 get_order_status 工具,参数 order_id 为 10086”。你的程序拿到这段结构化输出后,自己去执行真正的业务逻辑,再把结果以消息形式回传给模型,模型最终生成面向用户的回答。
早期实现 Agent 需要手工解析模型输出的 JSON,现在主流模型都原生支持工具调用格式。DeepSeek 的 deepseek-chat 和 deepseek-reasoner 都支持工具调用,且参数格式与 OpenAI 兼容。对 LLM 应用框架来说,Function Calling 是 Agent 的“信号通道”:模型输出结构化调用指令,框架负责执行和回填结果。MCP 恰好把“定义工具、描述参数、传递给模型”这一整条链路标准化了,所以两者是天然互补的。
3.2 MCP 协议拆解:Client、Server、Tool
用一句话概括 MCP 的运行机制:MCP Client 启动一个 MCP Server 进程,通过协议标准接口发现 Server 暴露的 Tool 列表,把 Tool 转换为模型可理解的 JSON Schema,在模型决定调用时把参数转发给 Server 执行,再把执行结果交回模型。
这里有几个核心概念需要强调。MCP Server 的 Tool 定义和实际执行逻辑是分离的:在 FastMCP 中,函数签名就是 Tool 的参数定义,函数的 docstring 会被作为 Tool 描述发给模型。正因为 Tool 描述的质量直接影响模型是否正确地选择工具,你写函数时的 docstring 必须清晰说明用途和参数含义。另外,MCP Client 与 Server 之间是长生命周期连接,一个 Client 可以同时连接多个 Server,而一个 Server 理论上也可以被多个 Client 共享,只要传输层允许。
3.3 LangChain Agent 的工作方式
LangChain 的 Agent 默认采用 ReAct 模式,即 Reasoning + Acting。整个流程是一个循环:模型先根据用户问题推理(Thought),决定调用哪个工具(Action),传入参数,你这一侧执行工具后得到观察结果(Observation),把结果回传给模型,模型继续推理,直到它能直接给出最终答案。在 LangChain 中,这个循环由 AgentExecutor 或 LangGraph 的图结构驱动。
早期 LangChain 的 Agent 使用字符串提示词模板来引导模型输出 ReAct 格式,比如让模型输出“Thought: ... Action: ... Action Input: ...”。后来模型普遍支持原生 Function Calling 之后,官网推荐改为 create_tool_calling_agent,这种方式不再需要手工解析文本格式,鲁棒性高很多。理解这一点对你排错很重要:遇到工具调用失败时,先分清是“模型没输出正确调用指令”,还是“框架没正确执行工具”,还是“工具执行结果没回传成功”,排查路径完全不同。
3.4 LangGraph 和 LangChain 的区别
热词里 LangGraph 和 LangChain 的区别被频繁搜索,这里明确说一下。LangChain 是一个涵盖模型接入、提示词、输出解析、向量库、Agent 的综合性框架;LangGraph 则是更底层的编排框架,核心概念是图:节点表示一步处理,边表示状态流转,所有节点共享一个状态对象,节点之间通过条件边实现分支和循环。你可以把 LangGraph 理解为“用代码画流程图”的框架,它适合需要精确控制 Agent 流程的场景,比如必须要求先检索后生成、多步骤审批、用户人工介入确认等。
那什么时候用 LangChain 的 AgentExecutor,什么时候用 LangGraph?AgentExecutor 封装程度高,几行代码就能跑通,适合快速验证原型;LangGraph 灵活度高,状态可中断、可恢复,适合生产级复杂流程。本文第 4 节会分别给出两种实现,你可以直观对比二者差异。
4. 手把手实战:LangChain + MCP 构建 Agent
4.1 编写一个 MCP Server
我们从一个最简单的业务场景开始:让 Agent 能查询订单状态。用 MCP 官方 Python SDK 里的 FastMCP 框架编写 Server 非常直观,server/order_server.py 内容如下:
这段代码定义了一个名为 get_order_status 的工具。docstring 里写明工具用途和参数含义,大模型在调用时就会参考这段描述来决定是否调用。在本地验证时,我们可以用 MCP 官方提供的调试客户端工具来测试,也可以直接配合 LangChain 集成测试。需要注意的是,工具函数内部不应包含敏感的业务逻辑,它只负责“接收参数、返回结果”,真正的权限校验和业务校验应该在更内层完成。
4.2 在 LangChain 中连接 MCP 工具
接下来把上面这个 MCP Server 接入 LangChain。这里使用 langchain_mcp_adapters 提供的 MultiServerMCPClient,它可以同时连接多个 MCP Server,并把工具合并为一个列表。我们创建一个 agent/connect_mcp.py 文件:
这里配置了一个名为 order 的 MCP Server,command 指定启动命令,args 指定要运行的脚本,transport 指定为 stdio。get_tools() 返回的是 LangChain 的 BaseTool 列表,后面可以直接传给 Agent。如果你实际运行时发现 MultiServerMCPClient 的 API 有变化(这类适配包更新比较频繁),可以退回到更底层的写法:先用 MCP SDK 创建 ClientSession,再通过 langchain_mcp_adapters.tools.load_mcp_tools 加载工具。两种方式本质相同,都是把 MCP Tool 转换成 LangChain Tool。
4.3 创建 Agent 并绑定工具:LangChain 版本
工具连接工作完成后,下一步就是创建 Agent。先看 LangChain 经典写法。我们创建 agent/langchain_agent.py:
注意这里 ChatOpenAI 的 base_url 被设置为 DeepSeek 的地址,所以本质上是用 LangChain 的 OpenAI 客户端去连接一个兼容 OpenAI 协议的服务。DeepSeek 官方也在文档中明确建议这种方式接入。提示词模板中的 {agent_scratchpad} 是 Agent 中间过程的占位符,框架会在循环中把模型历史推理和调用结果回填到这里,不要删掉。
运行上面的脚本,预期输出类似:
通过 verbose=True,你还能在控制台看到完整的 ReAct 过程:模型如何决定调用工具、传入了什么参数、工具返回了什么结果。这一步能帮你直观理解 Agent 的工作机制。
4.4 创建 Agent:LangGraph 版本
如果你后续要对流程做更精细控制,建议改用 LangGraph。LangGraph 提供了预构建的 create_react_agent,一行代码即可创建 Agent,同时保留了后续扩展图结构的可能性。agent/langgraph_agent.py 代码如下:
create_react_agent 会自动完成 ReAct 循环的状态管理,你只需要传入模型和工具列表,之后把用户消息作为 messages 传入即可。执行后它会把整个过程的所有消息打印出来,包括模型的思考结果、工具调用结果和最终回答。相比 AgentExecutor,LangGraph 版本的优势在于这些消息都存储在状态对象里,你可以随时检查、分支或者持久化。
4.5 运行与验证
在项目根目录执行:
如果一切正常,你会看到 Agent 自动完成“识别参数 → 调用工具 → 生成回答”的过程。如果环境变量没有正确加载,脚本会因为缺少 API Key 报错,建议先执行 python -c "from dotenv import load_dotenv; load_dotenv(); import os; print(os.getenv('DEEPSEEK_API_KEY'))" 确认变量是否读入。这里有两个值得单独说明的实验细节。第一,当你把 order_id 换成不在状态表里的值时,模型会返回“未查到该订单”,这说明工具执行结果被正确回传给了模型。第二,当你问一个与工具无关的问题,比如“今天天气怎么样”,模型应该会明确回答无法获取天气信息,而不会强行调用订单工具,这说明工具描述质量是合格的。
5. 接入 Claude Code 与多模型切换
5.1 Claude Code 是什么
Claude Code 是 Anthropic 提供的命令行编程助手,它可以在终端里理解项目代码、执行命令、修改文件。很多开发者关心它是因为它天然支持 MCP,也就是说,你在第 4 节写的 MCP Server 可以直接被 Claude Code 使用,不需要再为它单独写一套工具适配层。Claude Code 的安装和配置方式在不同版本之间变化较快,所以这里只介绍通用的 MCP 配置思路,具体命令请以官方文档为准。
5.2 把 MCP Server 配置给 Claude Code
在项目目录下创建 .mcp.json,内容是:
启动 Claude Code 后,它会自动读取项目下的 .mcp.json 并启动对应的 MCP Server。之后你可以在对话中直接问“帮我查一下订单 10086”,Claude Code 会通过 MCP 调用到我们的订单查询工具。这里和 LangChain 示例的核心区别是:LangChain 通过代码显式管理 MCP Client 生命周期,而 Claude Code 自己实现了 MCP Client,你只负责提供 Server 配置。如果你在配置多个 MCP Server 时提示连接失败,优先检查 command 是否在 PATH 中、args 路径是否相对于项目根目录正确。
5.3 多模型切换与 DeepSeek 接入
在 LangChain 侧,多模型切换非常简单,因为 ChatOpenAI 本身就是协议兼容层的体现。如果你想从 DeepSeek 切到其他兼容 OpenAI 接口的模型,只需要修改 base_url 和 model 两个参数。这也引出一个工程经验:在企业内部,建议把模型接入层再封装一层,通过配置中心动态控制模型名称、温度、最大 token 等参数,不要让模型信息散落在业务代码里。
如果不想用 LangChain,直接用 OpenAI SDK 调用 DeepSeek 工具调用接口也可以,核心代码如下:
这个示例展示了 MCP 背后“工具定义”的本质:无论你用哪种框架,最终都要把工具描述转换成模型能识别的 JSON Schema。MCP 的价值就是帮你自动生成并维护这一层定义,避免手工维护导致的不一致。
6. 常见问题与排查思路
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| MCP 客户端启动 Server 时报 command not found | 启动命令不在 PATH 中,或使用了虚拟环境但没有指定完整路径 | 将 command 改为虚拟环境中 python 的绝对路径,例如 .venv/bin/python |
| Agent 一直不调用工具,直接编造答案 | 模型不支持工具调用,或工具描述不清晰 | 确认模型是否支持 Function Calling;检查工具 docstring 是否明确说明用途和参数 |
| 调用工具后报参数格式错误 | MCP Server 函数签名与模型生成的参数不匹配 | 在函数中增加参数类型校验;使用 pydantic 模型约束参数结构 |
| Claude Code 提示 the agent execution provider did not respond in time | MCP Server 启动超时或进程阻塞 | 检查 Server 是否有死循环、是否等待 stdin 输入;尝试用 HTTP transport 部署独立服务 |
| 模型名错误报错,例如 deepseek-v4-pro is not a model this version recognizes | 配置的模型名在当前版本中不存在 | 在对应平台文档中确认可用模型名,或通过接口列表动态获取 |
| API 返回 401/403 | API Key 错误或账户没有权限 | 检查 .env 是否加载、key 是否过期、账户余额是否充足 |
| 异步代码报 RuntimeError: asyncio 相关异常 | 在同步函数中混用了 async/await | 确保使用 asyncio.run 或维护统一的事件循环 |
以上常见问题里,最需要重视的是“工具调用格式不匹配”这一类。很多初学者看到工具报错就怀疑模型能力,但实际上根源往往在参数描述不精确。建议先打印模型返回的 tool_calls 原始结构,再和工具函数签名逐一比对,通常能快速定位问题。
7. 最佳实践与工程建议
7.1 工具描述与参数设计
工具描述是 Agent 效果的最大变量。docstring 要写清楚三件事:工具是干什么的、什么时候该调用、参数怎么填。例如“根据订单号查询订单状态”比“订单查询”信息量高一个数量级。参数命名也尽量使用领域通用名称,避免让模型猜测。对可选参数,必须设置默认值,并明确说明默认行为。实际项目中,建议由业务方和 AI 工程方共同评审工具描述,业务方负责语义准确性,工程方负责参数格式约束。
7.2 MCP Server 的安全边界
MCP Server 本质上是一个可被模型自主调用的“命令执行入口”,安全边界要格外重视。首先,工具函数内部必须做参数校验和幂等设计,不能被模型幻觉出的错误参数影响业务数据。其次,涉及删除、更新类操作时,MCP Server 应该要求二次确认参数,并且遵循最小权限原则,只暴露当前场景需要的能力。再次,stdio 模式下 MCP Server 与 Client 在同一进程内,工具产生的输出不要打印敏感信息,避免日志泄露。生产环境建议使用 HTTP transport,把 MCP Server 独立部署,通过鉴权网关控制访问。
7.3 状态管理与可观测性
Agent 的开发调试比普通接口复杂,因为结果依赖模型推理路径。建议从第一天就建立可观测性意识:在 AgentExecutor 或 LangGraph 节点中记录每次工具调用的输入输出、耗时、模型 token 消耗。LangGraph 的状态对象天然适合做这类追踪,每个节点的输入输出都会记录在 messages 里。对于生产环境,建议接入 LangSmith 或自建日志系统,至少把 model、prompt、tool_calls、tool_result 这几项结构化输出,便于事后复现。
7.4 超时、重试与降级
工具调用过程中可能发生外部服务慢、网络抖动、模型限流等问题。MCP Client 侧要配置合理的超时时间,避免 Agent 一直卡在等待工具返回;对可重试的瞬时错误,比如 429、5xx,要设置指数退避重试;对不可恢复的错误,要让 Agent 能优雅地告诉用户“暂时无法查询,请稍后再试”,而不是让整条链路崩溃。这一点在生产环境尤其重要,大模型应用的用户体验很大程度取决于异常降级策略。
8. 总结与下一步学习路线
这篇文章从一个实际痛点出发,带你完整走通了“MCP Server 编写 → LangChain 工具加载 → Agent 创建 → DeepSeek 接入 → Claude Code 复用”的闭环。你现在应该能理解 MCP 协议在 Agent 工具调用中的定位,能自己用 FastMCP 编写一个工具,也知道 LangGraph 和 LangChain 原生 AgentExecutor 在编排能力上的差异。对于刚接触 Agent 的读者,建议先在本地跑通第 4 节的示例,再尝试修改 MCP Server 增加一个新工具,观察 Agent 是否能自动识别。
如果你的下一步是深入生产环境,优先学习三个方向:LangGraph 的状态流转与中断恢复机制、MCP 的 HTTP transport 部署方式、以及一套完整的 Agent 评测体系。评测往往是最容易被忽视的环节,工具描述改一个词、模型版本升一次,Agent 的实际表现都可能变化,没有评测集就无法量化反馈。一个小技巧是,把你最容易失败的业务场景做成回归用例,每次改动后自动跑一遍,能省下大量线上排错时间。最后给你一个动手练习:尝试把第 4 节的订单查询 Server 扩展为同时提供“查询物流轨迹”和“发起退货申请”两个工具,并思考如何在 MCP Server 中校验“只有已发货的订单才能申请退货”,这会让你对 Agent 工具设计的边界有更深的理解。