ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LangChain与LangGraph实战:Agent、RAG、MCP全链路解析

2026/9/9 10:55:07 拓冰建站 浏览量
LangChain与LangGraph实战:Agent、RAG、MCP全链路解析 很多开发者学 LangChain 的时候都会遇到一种奇怪的拧巴感查 RAG 教程能看到一堆langchain_community拼接代码查 Agent 教程又有人告诉你“LangChain 做复杂 Agent 容易乱要上 LangGraph”再往后MCP 这个概念又冒出来了什么“AI 万能插头”“工具调用新标准”。一套技术栈里塞了五个热门词LangChain、LangGraph、Agent、RAG、MCP。每个单拎出来都有人讲但连在一起是什么关系从哪开始学先学哪个很多人其实没理清楚。更麻烦的是网上很多教程只讲“怎么调 API”不解释“为什么要这么设计”。于是你抄完代码能跑换一个业务场景就不知道怎么改了。这篇教程想解决的就是这个问题。先说结论LangChain 负责把大模型和外部数据、模型、输出解析这些“部件”标准化LangGraph 负责把复杂流程变成有状态、可控制、可回退的图RAG 解决知识不足问题Agent 解决任务自动拆解问题MCP 解决工具和数据接入标准问题。它们不是替代关系而是不同层级的分工。读完这篇文章你可以亲手搭出一个带私有知识库、能调用外部工具、用 LangGraph 控制状态的 Agent 应用。整个过程中我会把每个概念放到实际场景里讲并给出完整的可运行代码和排查思路。1. 2026 年为什么还要重新学一遍 LangChain 和 LangGraph先回应一个常见的疑问。最近两年经常能看到这样的说法“LangChain 太抽象了写复杂业务不如直接调 OpenAI SDK”“LangGraph 不就是一个状态机包装吗自己写也不难”。这两个观点都有道理但都不全面。2026 年看 LangChain 和 LangGraph重点不是它们能做到单次调用 API 做不到的事而是它们在工程化上帮你省了三类成本一是组件标准化成本你可以无缝切换不同的向量库、模型供应商和文档加载器二是流程可观测成本LangGraph 的图结构天然暴露了每个节点的输入输出方便调试和监控三是工具接入成本配合 MCP 之后Agent 不再需要为每个内部系统单独写一套函数封装。说句更直白的话如果你只是做一个“后端调 GPT 的小工具”确实不需要 LangChain但如果你要做“一个能回答公司内部问题、能查请假余额、能订会议室、还能在答错时回溯流程”的业务系统靠硬编码维护成本会非常高。LangGraph 这种有状态编排层的意义就在这里。本文定位是零基础到实战。所谓的“零基础”不是说你完全不懂 Python而是指你对 LangChain、LangGraph、Agent、RAG、MCP 这些术语没有体系化认识。你需要具备最基本的 Python 能力然后跟着一步步走。2. Agent、RAG、LangChain、LangGraph、MCP 到底是什么关系很多教程会把这几件事混在一起讲这是新手最大的认知负担来源。先把它们拆开。2.1 用一句话区分五个概念概念一句话解释解决的问题LangChain一套大模型应用开发的组件标准把模型、提示词、文档加载、向量库等抽象成可组合的模块RAG检索增强生成让模型回答私域知识问题而不是全靠训练记忆Agent能自主决策和调用工具的智能体把一个复杂任务拆成多步并调用外部能力完成LangGraph用图结构编排有状态流程解决 Agent 多步执行中的状态维护、分支、回退、循环问题MCP模型上下文协议统一外部工具和数据源接入方式避免每个系统一套接入协议2.2 LangChain 和 LangGraph 的分工很多人问“LangGraph 和 LangChain 的区别是什么”。这两者最关键的差异在于编程模型。LangChain 的核心抽象是 Chain也就是“输入经过一系列模块得到一个输出”。它适合流程相对固定、分支比较少的场景比如“先检索再拼提示词再调模型再解析输出”。对这种 pipelineLangChain 的 LCEL 表达式使用起来非常简洁。LangGraph 的核心抽象是图也就是“由节点和边组成的有状态工作流”。每个节点是一个函数每个边决定下一步走向节点之间通过共享的 State 传递数据。这个模型适合流程中有条件分支、循环、人工审批、需要记录多轮步骤状态的场景。Agent 本质上就是一个循环模型决定调用什么工具工具返回结果模型再决定下一步直到认为任务完成。所以更准确的判断是LangGraph 在解决 LangChain 不适合处理的那部分复杂流程问题。2026 年的实际项目中LangChain 组件依然负责底层拼接LangGraph 负责上层控制流。两者互补而非互斥。2.3 Agent 和 RAG 的关系RAG 是一种具体的检索增强生成技术而 Agent 是一种任务执行范式。Agent 内部完全可以复用 RAG 能力比如 Agent 发现用户问题涉及私域文档就调用一个“文档检索工具”去查资料查完之后再用查到的内容生成答案。用行业术语说这种形态就是Agentic RAGAgent 不再只做一次检索而是根据对话状态动态决定是否需要检索、查几次、是否追问。2.4 MCP 在什么时候有用MCP 要解决的是“每个 AI 应用都要重新连接一遍公司系统”的问题。没有 MCP 的时候Agent 要接数据库、企业内部 API、文件系统通常要写大量自定义函数且每个函数只对当前 Agent 项目生效。有了 MCP 后数据提供方实现一个标准 MCP ServerAgent 通过 MCP 协议加载同一个 Server 提供的工具这叫“一次接入多处复用”。整条技术链路可以这样理解RAG 提供知识LangChain 提供组件LangGraph 提供控制流MCP 提供工具接入标准Agent 把这些组合成最终的应用形态。3. 环境准备与项目初始化下面进入实操。本文采用 Python 编写目标环境以你当前项目为准。由于 LangChain、LangGraph 和 MCP 的工具更新速度都比较快我不会写死某个固定版本而是给出通用的依赖安装方式。如果你在安装时遇到版本冲突建议优先参考官方文档中的版本匹配说明。3.1 创建虚拟环境建议使用venv或conda创建独立环境避免污染全局 Python。python -m venv .venv source .venv/bin/activate # Windows 下执行 .venv\Scripts\activate3.2 安装依赖pip install --upgrade langchain langchain-openai langchain-community langchain-text-splitters langgraph langchain-mcp-adapters mcp faiss-cpu pypdf python-dotenv这里简单说明一下每个包的用途包名用途langchain框架核心提供 LCEL、链式组合、通用接口langchain-openaiOpenAI 模型的 LangChain 接入类langchain-community社区贡献的文档加载器、向量库适配器等langchain-text-splitters文本分割器langgraph状态图编排框架langchain-mcp-adapters把 MCP Server 暴露的工具封装成 LangChain 工具mcpMCP 官方 Python SDKfaiss-cpu本地向量检索库pypdf读取 PDF 文档python-dotenv读取 .env 环境变量文件3.3 配置模型访问在项目根目录新建.env文件# 文件路径.env OPENAI_API_KEYsk-xxxxx OPENAI_API_BASEhttps://api.openai.com/v1 # 如果使用国内兼容 OpenAI 协议的模型服务可以修改上面的地址如果你的场景不允许调用外部模型服务可以改用本地模型。LangChain 通过ChatOpenAI兼容 OpenAI 协议很多本地推理框架也支持该协议只需要修改base_url指向本地服务地址即可。后面的代码我会统一用环境变量读取的方式便于切换。3.4 项目目录规划langchain-rag-agent/ ├── .env ├── requirements.txt ├── docs/ # 放私有知识文档 ├── rag_demo.py # 第 4 节的 RAG 示例 ├── graph_demo.py # 第 5 节的 LangGraph 示例 ├── agent_demo.py # 第 6 节的 Agent 示例 ├── mcp_server.py # 第 7 节的 MCP Server └── mcp_client_demo.py # 第 7 节的 MCP 接入示例4. RAG 第一阶段从普通问答到文档知识库先不要急着写 Agent。把 RAG 跑通是后续所有复杂功能的基础。4.1 准备一份私有文档在docs目录下放一个文本文件比如company_manual.txt内容写一段公司内部的请假制度。这里注意文档内容必须是你能合法授权用于检索的资料。在公司真实场景中文档的访问权限管理要和 RAG 系统同步考虑这我放到后面最佳实践里再展开。4.2 文档加载与分割# 文件路径rag_demo.py import os from dotenv import load_dotenv load_dotenv() from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import FAISS from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough loader TextLoader(./docs/company_manual.txt) documents loader.load() text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, ) chunks text_splitter.split_documents(documents) print(f文档被切割为 {len(chunks)} 个片段)为什么要切分文档两个原因。一是大模型输入有 token 上限整份文档放不进提示词二是“检索相关性”需要有粒度概念越长的文档命中后带进来的噪声越多。chunk_size500表示每个片段大约 500 个字符chunk_overlap50表示相邻片段有 50 个字符重叠避免关键词正好落在切割边缘导致检索丢失。4.3 向量化与构建检索器embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore FAISS.from_documents(chunks, embeddingembeddings) retriever vectorstore.as_retriever(search_kwargs{k: 4})这一段做的事情是把每个文本片段通过 Embedding 模型转成向量存入向量库查询时用户问题也被转成向量然后通过向量相似度召回最相关的 4 个片段。4.4 拼接提示词并生成回答prompt ChatPromptTemplate.from_messages([ ( system, 你是一个企业内部知识库助手请根据提供的资料回答用户问题。 如果资料中没有答案请直接说明不知道不要编造。, ), ( human, 资料\n{context}\n\n问题{question}, ), ]) llm ChatOpenAI(modelgpt-4o-mini, temperature0) def format_docs(docs): return \n\n.join([doc.page_content for doc in docs]) rag_chain ( { context: retriever | format_docs, question: RunnablePassthrough(), } | prompt | llm | StrOutputParser() ) if __name__ __main__: answer rag_chain.invoke(新员工请假的流程是什么) print(answer)这是 LangChain 最核心的 LCEL 写法左边的字典定义了依赖关系context由 retriever 计算得到并交给format_docs格式化question直接透传然后经过prompt格式化经过llm生成最后经过StrOutputParser输出字符串。运行方式python rag_demo.py如果输出中能看到根据文档内容整理出的请假流程而不是模型“自由发挥”说明 RAG 链路已经通了。4.5 RAG 阶段的常见认知坑这个阶段有几点需要提前说明。第一RAG 的检索质量不等于模型生成质量很多回答不准确的问题根源是“没召回正确内容”而不是“模型不行”第二k4只是一个起点具体 k 值要根据文档粒度调整第三向量检索依赖 Embedding 模型不同 Embedding 模型对中文、代码、表格的支持差异很大必要时可以做检索评测。5. LangGraph 入门用状态图改写普通问答流程RAG 跑通后你会发现它有一个明显局限流程固定没有分支。用户问的问题可能根本不需要检索也可能需要连续检索两次。这时候就轮到 LangGraph 上场。5.1 最小 LangGraph 应用LangGraph 的抽象可以浓缩为三个概念State、Node、Edge。State全局共享的数据结构所有节点都能读取和写入。Node一个普通 Python 函数接收 State返回一个新 State 字段。Edge从一个节点到另一个节点的连接可以带条件。下面先把第 4 节的 RAG 流程改造成图结构# 文件路径graph_demo.py from typing import TypedDict, List from langgraph.graph import StateGraph, END from langchain_core.output_parsers import StrOutputParser class AgentState(TypedDict): question: str context: List[str] answer: str def retrieve_node(state: AgentState): # 这里简化处理实际复用上面 RAG 示例中的 retriever docs retriever.invoke(state[question]) return {context: [d.page_content for d in docs]} def generate_node(state: AgentState): context \n\n.join(state[context]) prompt_formatted prompt.invoke({context: context, question: state[question]}) response llm.invoke(prompt_formatted) return {answer: StrOutputParser().invoke(response)} graph StateGraph(AgentState) graph.add_node(retrieve, retrieve_node) graph.add_node(generate, generate_node) graph.set_entry_point(retrieve) graph.add_edge(retrieve, generate) graph.add_edge(generate, END) app graph.compile() if __name__ __main__: result app.invoke({question: 公司的请假流程是什么}) print(result[answer])运行后效果和之前 RAG 示例一样但流程被显式地拆成节点了。不要小看这一步变化把流程变成图之后你可以在任意节点之间插入“判断逻辑”可以被外部系统触发也可以记录每一步的耗时、token 消耗、检索命中情况。5.2 为什么需要状态你可能想问普通链式调用也能传数据为什么 LangGraph 强调 State区别在于普通链式调用是线性的A 的输出只能传给 B而图结构中的每个节点都只与 State 交互。比如有一个节点负责“判断用户问题是否需要检索”它改写question字段后后面的检索节点和生成节点都能感知。再比如你希望支持“知识库检索不到时换一个检索器再搜一次”这在普通链式流程里要写大量 if-else而在 LangGraph 里只需要加一个条件边。LangGraph 的 State 还继承了 LangChain 的管道协议支持流式输出、状态持久化和断点恢复。对生产环境来说这意味着你的 Agent 执行到一半挂了可以从最近一次持久化状态恢复而不是从头重跑。6. Agent 实战让模型学会调用外部工具接下来做真正意义上的 Agent。这里的核心变化是模型不再只是“生成文字”而是可以决定“调用工具”。6.1 什么是工具调用工具调用Tool Calling是模型输出的一种结构化消息。它不是让模型真的去执行代码而是让模型从预设工具列表中选择一个并生成调用参数。真正的执行由你的程序完成执行结果再交回给模型。比如用户问“我剩余年假还有几天”模型没有能力查数据库但它可以决定调用get_user_leave_balance工具参数是user_id。你的程序执行这段逻辑返回后模型根据工具结果生成最终回答。6.2 用 LangGraph 快速构建 AgentLangGraph 提供了create_react_agent这个预置入口适合大部分入门场景。它实现了 ReAct 循环模型思考 - 调用工具 - 观察结果 - 再思考。# 文件路径agent_demo.py from dotenv import load_dotenv load_dotenv() from langchain_openai import ChatOpenAI from langchain_core.tools import tool from langgraph.prebuilt import create_react_agent tool def get_user_leave_balance(user_id: str) - str: 查询员工剩余年假天数参数为员工工号。 # 实际项目中这里应该访问权限可控的业务系统或数据库 leave_data { 1001: 剩余 6 天, 1002: 剩余 3 天, } return leave_data.get(user_id, 查无此员工) tools [get_user_leave_balance] llm ChatOpenAI(modelgpt-4o-mini, temperature0) agent create_react_agent(llm, tools) if __name__ __main__: result agent.invoke({messages: [{role: user, content: 工号1001的员工还剩几天年假}]}) print(result[messages][-1].content)这段代码里的tool装饰器是关键。它把普通函数变成了符合 LangChain 工具规范的对象函数名、docstring、参数签名会被自动传给模型作为模型选择工具的参考信息。6.3 给 Agent 接上 RAG 工具刚才的 Agent 只能调用一个模拟函数还不能查询文档。把 RAG 检索封装成工具后Agent 就同时具备“查文档”和“查内部系统”的能力from langchain.tools.retriever import create_retriever_tool retriever_tool create_retriever_tool( retriever, namecompany_manual_search, description搜索公司内部制度文档。当问题涉及请假制度、报销规范、考勤规则时请先调用此工具。, ) tools [get_user_leave_balance, retriever_tool]这样用户问“请假流程是什么”Agent 会调用company_manual_search检索文档后回答用户问“我年假剩几天”Agent 会调用get_user_leave_balance。这已经是一个有实际业务价值的 Agentic RAG 形态。6.4 LangGraph 还可以做什么create_react_agent虽然方便但它是“约定好的通用 Agent”。当你的流程需要更精细控制时就需要自定义图了。例如一个典型的“先判断后执行”的流程可以这样设计def should_use_search(state): if state.get(need_search): return search return direct_answer graph.add_conditional_edges( router, should_use_search, {search: search_node, direct_answer: answer_node}, )这种条件边让流程可视化程度更高也更容易加人工审核节点。比如模型搜索结果置信度低时节点可以转给人工处理而不是继续自动回答。7. MCP 接入打通企业数据和权限边界现在到了很多人最感兴趣的 MCP 部分。前面已经说过MCP 是一套标准协议。下面实际演示怎么做一个最简单的 MCP Server再把它接入 LangChain Agent。7.1 从例子看 MCP 解决的问题假设你们公司有一个人力资源系统提供“查询请假余额”接口。没有 MCP 时你在每个 Agent 项目里都要写一遍def query_leave(user_id): resp requests.post(http://hr.internal/leave, json{user_id: user_id}) return resp.json()如果再接财务系统、会议系统、项目管理系统每个都要写一套。有 MCP 后这些系统各自实现一个标准化的 MCP Server任何支持 MCP 的 Agent 都能发现并调用它们的工具。7.2 编写一个最小 MCP Server# 文件路径mcp_server.py from mcp.server.fastmcp import FastMCP # 创建 MCP Server名称会在连接时展示给客户端 mcp FastMCP(hr-service) mcp.tool() def get_leave_balance(user_id: str) - str: 查询员工剩余年假参数 user_id 为员工工号。 # 生产环境必须通过内部权限系统鉴权 balances {1001: 6, 1002: 3} return balances.get(user_id, 查无此员工) if __name__ __main__: mcp.run()这段代码的核心是mcp.tool()装饰器。函数被注册为 MCP Server 的一个工具客户端可以通过 MCP 协议发现它、读取它的描述、调用它。7.3 在 LangChain Agent 中接入 MCP 工具LangChain 社区提供了langchain-mcp-adapters可以把 MCP Server 的工具加载成 LangChain Agent 可用的工具列表。下面是基于该适配器的典型写法# 文件路径mcp_client_demo.py import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client from langchain_mcp_adapters.tools import load_mcp_tools from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent server_params StdioServerParameters( commandpython, args[mcp_server.py], ) async def main(): async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools await load_mcp_tools(session) llm ChatOpenAI(modelgpt-4o-mini, temperature0) agent create_react_agent(llm, tools) result await agent.ainvoke( {messages: [{role: user, content: 工号1002的员工还剩几天年假}]} ) print(result[messages][-1].content) if __name__ __main__: asyncio.run(main())注意MCP 客户端会有多种传输方式这里用的是stdio也就是 Agent 启动 MCP Server 子进程通过标准输入输出通信。另一种常见方式是streamable-http适合 MCP Server 部署在远程服务器上的场景。运行方式python mcp_client_demo.py如果正常运行Agent 会通过 MCP 协议调用mcp_server.py中暴露的get_leave_balance工具得到结果后生成回答。7.4 MCP 接入的安全边界MCP 非常像“给 AI 开了一堆系统接口”。接口越多潜在风险越大。尤其是企业场景中MCP Server 后面连着数据库和内部系统不能默认 Agent 有调用一切权限。至少要做到MCP Server 必须做身份认证工具级做最小权限授权敏感操作单独加审批节点所有调用留日志方便审计。不要觉得“只是查个余额”就不重视工具一旦可以被任意提示词触发就有越权风险。8. 组合案例知识库 工具调用 状态控制的完整 Agent到这里我们已经分别演示了 RAG、LangGraph、工具调用和 MCP。把它们放在一起就是一个接近生产形态的 Agent。下面的示例演示这样一个场景用户询问“我请假还剩几天同时告诉我请假制度里对提前几天申请的要求”。这个任务需要 Agent 先后完成查询 HR 系统、检索知识库文档、将两段信息拼接成最终回答。# 文件路径full_agent_demo.py from dotenv import load_dotenv load_dotenv() from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import FAISS from langchain.tools.retriever import create_retriever_tool from langchain_core.tools import tool from langgraph.prebuilt import create_react_agent # 1. 构造知识库检索工具 loader TextLoader(./docs/company_manual.txt) documents loader.load() splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) chunks splitter.split_documents(documents) embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore FAISS.from_documents(chunks, embeddingembeddings) retriever vectorstore.as_retriever(search_kwargs{k: 4}) retriever_tool create_retriever_tool( retriever, namecompany_manual_search, description搜索公司内部制度文档。当问题涉及请假制度、报销规范、考勤规则时请先调用此工具。, ) # 2. 构造内部系统查询工具 tool def get_user_leave_balance(user_id: str) - str: 查询员工剩余年假天数参数为员工工号。 leave_data { 1001: 剩余 6 天, 1002: 剩余 3 天, } return leave_data.get(user_id, 查无此员工) tools [retriever_tool, get_user_leave_balance] # 3. 构造 Agent llm ChatOpenAI(modelgpt-4o-mini, temperature0) agent create_react_agent(llm, tools) if __name__ __main__: result agent.invoke( { messages: [ { role: user, content: 工号1001的员工请假还剩几天 另外公司制度里对提前几天申请病假有规定吗, } ] } ) print(result[messages][-1].content)把这个示例跑起来你会看到输出里包含两轮信息既回答了剩余天数又引用了手册中的病假申请要求。这就是 Agent 自行拆解任务的结果。如果你希望整个流程更可控比如先查 HR 系统再查文档或者要求“必须得到 HR 系统结果才能生成回答”那就可以用第 5 节的自定义StateGraph替代create_react_agent。这也是 LangGraph 价值最明显的场景——把业务规则固化在流程里而不是靠提示词约束模型。9. 常见问题与排查思路下面整理这套技术栈里最容易踩的坑。问题现象可能原因排查方式解决方案运行时报依赖版本冲突langchain 各子包版本不匹配pip list查看版本检查官方文档版本对应表统一升级到同一版本族避免混用旧包模型 API 调用 401OPENAI_API_KEY未加载或无效检查.env是否放在项目根目录打印os.getenv结果确认 key 有效用load_dotenv()加载检索结果与问题明显无关文档切分不合理或 Embedding 模型不适配打印召回片段观察内容是否完整调整 chunk_size更换 Embedding 模型Agent 不调用工具直接编答案工具描述不清楚或模型版本不支持 tool calling打印模型回包查看 tool_calls 字段重写工具描述换支持工具调用的模型MCP 连接报错“Session not initialized”客户端与服务端握手未完成检查调用顺序确认await session.initialize()已执行按官方示例补齐初始化步骤LangGraph 节点返回字段不在 State 中State 定义与实际返回不一致查看对应报错堆栈中的 key 名称在TypedDict中补全字段定义Agent 执行中途报AgentExecutionError某个工具抛异常或模型输出格式不符合预期查看工具函数日志是否捕获了所有异常给工具函数加 try/except返回结构化错误信息本地向量检索速度慢文本片段过多或向量维度高统计 chunk 数量和向量库规模使用批量检索、缩减文档量或迁移专业向量数据库再补充一个通用排查建议任何一步失败了第一件事是看原始输入和输出。不要只看最终结果。LangChain 的chain.invoke()可以替换成chain.batch()或者逐步调用节点LangGraph 可以打开调试日志观察每个节点的前后状态。定位问题永远是从“哪一步和预期的数据变化不一致”开始的。10. 工程化建议与最佳实践学完入门示例后如果你要把它用到真实项目里下面这些经验比较重要。10.1 先小后大不要把五个概念一次性引入很多团队一开始就想做一个“RAG Agent MCP LangGraph”的全功能平台结果项目前四周全在联调依赖。更务实的路径是先只做 RAG跑通知识库问答再单独引入 Agent最后接入 MCP。每一步都能独立上线风险小反馈快。10.2 密钥管理和权限控制代码示例中用了python-dotenv读取环境变量这在本地没问题但生产环境建议使用密钥管理服务不要把密钥写进镜像或代码仓库。同时RAG 检索的文档要提前做权限分级。如果所有人共用同一个向量库低权限用户在检索时极可能把高权限文档内容作为上下文交给大模型这是一种隐蔽的数据泄露。10.3 检索质量要在生成之前评估很多项目“回答质量差”的表象其实是检索环节召回不准确。建议在项目初期就把检索评估做起来构造一批“问题-预期文档/预期答案”测试集用命中率评估检索器。没有评测体系的 RAG 项目后期优化会非常被动。常见做法是选择多种 Embedding 模型做对比测试再针对召回结果调整切分策略。10.4 LangGraph 的状态设计要有边界意识不要把所有临时变量都塞进同一个 State。State 是流程共享内存字段越多越难维护。建议把一次性使用的变量放在节点内部只把跨节点传递的必要字段放到 State 里。长对话场景中还要考虑消息列表的截断策略避免状态无限膨胀。10.5 MCP 是接入层标准不是业务层架构MCP 解决的是“客户端如何发现和调用工具”的问题它不替你解决“这个工具该不该被调用”“并发怎么控制”“失败怎么重试”这类问题。所以不要把 MCP Server 写成包含复杂业务逻辑的巨型服务。MCP Server 越薄越好后面的业务逻辑仍然应该走你已有的后端服务权限体系。10.6 日志与监控Agent 应用比普通接口复杂得多用户一次提问可能触发多次工具调用、多次模型生成。建议给每次会话生成 trace id记录每个节点的输入输出、每次 LLM 调用的 token 数、每个工具的调用参数和耗时、最终答案来源是否包含检索片段。没有 trace线上问题基本没法排查。10.7 流式输出与交互体验真实业务中用户不喜欢长时间等待。LangChain 和 LangGraph 都支持流式输出。实现流式的思路是在图编译后调用.astream()把每个节点的输出按事件流发送给前端。如果你做的产品对交互要求高建议尽早把流式接入方案引入不然后期加入会涉及整个链路改造。11. 写在最后把这篇教程的核心脉络再串一遍。先跑通 RAG解决“知识从哪来”的问题再引入 LangGraph解决“流程怎么控制”的问题再让 Agent 学会调用工具解决“模型怎么行动”的问题最后用 MCP 标准化工具接入解决“系统之间怎么连通”的问题。五件事层层递进每一件都落在具体的代码和业务场景上。学完这篇内容你可以继续深入的方向有三个一是 LangGraph 的高级能力比如状态持久化、多 Agent 协作、人工审批中断与恢复二是检索质量优化包括多路召回、重排序、混合检索三是 MCP 的生产级应用比如认证鉴权、Server 注册与发现机制。建议你把这篇文章里最后一个组合案例替换成自己手头真实的数据和工具从一个小场景开始让流程真正跑起来。跑通第一条链路之后再逐步加复杂度。2026 年LangChain 和 LangGraph 已经不算新技术但把它们用对、用好的人依然稀缺。