
先聊点实在的。现在只要一搜 LangChain铺天盖地的都是“Agent 实战”“智能体开发教程”好像你不会写 Agent 就不配说自己搞大模型应用。但以我带团队做生产级 LLM 应用这一年多的经验来看大部分被 Agent 折磨得死去活来的人问题根本不是出在 Agent 本身而是链Chain那一层就没吃透。LangChain 这个生态看着乱其实有一条非常清晰的演进线索从最初的 Chain 串联到工具调用Tool Calling再到以图为基础的 Agent 编排。你只有把这条线索上的核心概念理顺了看 LangChain 的源码也好、看 LangGraph 的文档也罢才会有那种“原来如此”的通透感。这篇东西我不打算给你罗列 API 文档那玩意儿官方写得比我清楚。我想从一个开发者的实操视角把 LangChain 生态里从链到代理这条路径上的三大核心拆开揉碎声明式链LCEL、工具调用、图状态编排。搞懂这三个你基本就掌握了这个生态的命脉。1. 先理清 LangChain 的定位它到底替你解决了什么问题很多人学 LangChain 学得一头雾水是因为他们根本不知道这个框架存在的意义。用大白话说LangChain 解决的是LLM 应用开发中的“胶水”问题。1.1 没有 LangChain 之前你在写什么代码假设你现在要做一个最简单的“翻译机器人”调用 OpenAI 的 API。没有框架你怎么写大概是这样拼接 Prompt 模板把用户输入塞进去。调用client.chat.completions.create()。从返回的 JSON 里把content字段抠出来。处理报错。把这个过程封装成一个函数。这看起来不难对吧可一旦你的业务变复杂比如老板说“不仅要翻译还要先判断语言类型再决定是否调用外部术语库翻译完还得自动检查有没有敏感词”。你那个简单的函数就会膨胀成一坨充满 if-else 的意大利面条。LangChain 的核心价值就是把这坨面条重新规划成一条条标准化的流水线Pipeline。每一个环节是一个组件组件之间通过标准接口传递数据你可以随意插拔、组合、替换。1.2 理解两个基础抽象Model 与 Prompt在深入链和代理之前你脑子里必须建立两个最基本的抽象Model模型在 LangChain 里无论是 OpenAI、Anthropic 还是本地跑的开源模型都被封装成统一的接口。你今天用ChatOpenAI明天想换成ChatOllama只需要改一行实例化代码后面所有的逻辑都不用动。这个设计在前期看没什么了不起但一旦你进入生产环境要搞模型灾备、成本控制的时候你就知道这层抽象有多值钱了。Prompt提示词LangChain 里的PromptTemplate绝不只是一个简单的字符串替换工具。它提供的是结构化的模板管理方式支持变量校验、部分变量注入、甚至可以从对话历史里自动提取上下文。我见过很多刚上手的人喜欢把 Prompt 直接硬编码在业务代码里。等到 Prompt 迭代了三版之后代码被改得面目全非不得不重构。用PromptTemplate把这些提示词全部外置管理你会发现迭代成本瞬间降下来了。记住LangChain 不管你是哪家模型也不管你写什么提示词它只管让这些零件能像一个整体那样协同工作。2. 核心一LCEL 声明式链—— LangChain 立身之本聊完了定位我们进入正题。LangChain 生态里第一个你必须吃透的核心就是LCELLangChain Expression LanguageLangChain 表达式语言。如果你现在看的是老教程里面还在教你用LLMChain这个类那我建议你赶紧关掉换一篇。LLMChain是上一代的产物现在的 LangChain 官方已经把 LCEL 定为标准方式甚至可以说LCEL 是整个 LangChain 未来的地基。2.1 为什么说是“声明式”它和你平时写的代码有何不同传统的命令式编程是你一步步告诉计算机“怎么做”。LCEL 声明式编程是你告诉系统“我要什么”系统自己决定怎么把步骤串起来。直接看代码感受一下 LCEL 的丝滑from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # 初始化模型注意这里我们设置了 temperature 低一些翻译任务需要更高的确定性 model ChatOpenAI(modelgpt-4o-mini, temperature0) # 定义提示词模板{input} 是待填充的变量 prompt ChatPromptTemplate.from_messages([ (system, 你是一位专业的科技领域英文翻译专家请将用户输入翻译为地道的英文。), (user, {input}) ]) # 用管道符 | 把 Prompt 和 Model 串成一条链 translate_chain prompt | model # 调用链输入一个 dict返回一个 AIMessage result translate_chain.invoke({input: 我爱写代码}) print(result.content) # I love writing code.你看核心就一个管道符|。它的语义非常直观prompt的输出作为model的输入。prompt | model就是一条最简单的链。这条链的执行流程是你传入一个包含input字段的字典 →prompt根据模板渲染出完整的消息列表 → 传给model→model返回消息对象。整个过程你只表达了“组装”的意图至于数据是怎么流转的LangChain 帮你搞定了。2.2 Runnable 协议与管道符背后的设计智慧那管道符两边要满足什么条件才能拼起来这就引出了 LCEL 最核心的设计——Runnable 协议。在 LangChain 的世界里任何实现了Runnable接口的对象都可以用|连接。Runnable 协议的标准方法就三个invoke(input): 同步调用输入一个值输出一个值。stream(input): 流式调用返回一个迭代器逐块产出输出。这个对提升用户体验非常重要你的应用可以实现“打字机”效果。batch(inputs): 批量调用传入一个输入列表返回一个输出列表。这意味着什么意味着Prompt、Model、还有我们后面要讲的各种 Tool、Retriever检索器本质上都是 Runnable。只要遵循这个接口你怎么拼都行。刚才那行代码prompt | model在实际执行时LangChain 会构建一个RunnableSequence对象。你可以把它理解成一条流水线数据从一端进去经过每个工位加工最后从另一端出来。整个流水线自己也实现了 Runnable 接口所以它还能继续被|接到别的东西后面。这就给了你极大的组合自由度。比如你想在输出之后加一个字典解析的步骤你可以写from langchain_core.output_parsers import StrOutputParser chain prompt | model | StrOutputParser() result chain.invoke({input: 我爱写代码}) print(result) # 直接输出字符串: I love writing code.加了StrOutputParser之后输出从AIMessage对象变成了纯字符串。你如果了解过 Java 里的 Stream 流或者 Linux 里的管道命令你一定能 get 到这种设计的优雅之处——把大问题拆成一个个小问题然后用一根管道串起来。这比传统那种层层嵌套调用函数不知道清爽了多少倍。2.3 并联与分支RunnableParallel 的妙用你用管道把组件串起来这只是流水线的“串联”。真实业务里还有大量需要“并联”的场景。举个例子。你想让模型写一篇关于苹果公司Apple Inc.的介绍为了内容全面你需要同时查三个信息源官网的最新新闻、某百科的基础信息、某股票论坛的股民讨论。这三个查询是相互独立的完全可以并行执行。如果不用框架你要写asyncio.gather或者ThreadPoolExecutor再去手动管理多个协程的协作那代码写起来就非常繁琐。在 LCEL 里这个过程被简化成了RunnableParallelfrom langchain_core.runnables import RunnableParallel def search_official(query): # 模拟官网搜索 return f官网结果: ...关于 {query} 的最新新闻... def search_wiki(query): # 模拟百科搜索 return f百科结果: ...关于 {query} 的历史... # 这样可以并行执行3个不同的任务 parallel_chain RunnableParallel( officialsearch_official, wikisearch_wiki, stocksearch_stock ) result parallel_chain.invoke(苹果公司) # 结果: {official: 官网结果..., wiki: 百科结果..., stock: 股民讨论...}RunnableParallel允许你传入多个 Runnable函数、链、模型调用均可它会并发执行这些子任务最终返回一个包含所有结果的字典。你的链就可以在一个节点同时开启多个执行分支最后汇总结果交给下一步处理。在 LangChain 的世界里这是实现并行化和信息聚合的基础手段也是后面进阶玩法的垫脚石。实用建议在构建较复杂的链时建议优先用具名的 RunnableParallel 分支来组织中间结果而不是手动写字典合并。可读性和可维护性都会好很多。3. 核心二Agent 与工具调用 —— 让模型从“会说话”变成“会做事”讲完了链我们终于可以谈代理了。这是目前整个生态里最热闹、也最容易翻车的领域。3.1 Agent 和执行链的本质区别链Chain是一套预先定义好的、固定的执行路线。但真实业务中很多时候你是无法预先定死路线的。比如你让 Agent “查一下本周公司的服务器有没有异常”它是先查日志还是先看告警平台还是直接问运维知识库这完全取决于它从工具里拿到的结果。这就是 Agent 存在的意义模型自己是判断者由它来决定“下一步该调哪个工具、该不该结束”而不是人类提前设定好。这是一次智能控制权的转移——从“开发者”转移到了“模型”。3.2 Tool CallingAgent 的一双手如果说模型是 Agent 的大脑那么工具Tools就是 Agent 的手。所以 Tool Calling函数调用就成了 Agent 最关键的基础能力。现在的主流模型如 GPT-4 系列、Claude 3 系列、开源界的 Qwen都原生支持 function calling。它的逻辑是这样的你把你定义的函数比如get_weather(city)的 JSON Schema 描述包括函数名、参数名、参数类型、函数功能描述传给模型。模型看完你的指令后不会直接调用这个函数而是会输出一段结构化的 JSON里面写明“我决定要调用 get_weather参数为 {city: 北京}”。然后由你的业务代码来真正执行这个函数把结果回传给模型模型再根据结果生成最终给用户的回复。在 LangChain 里把普通 Python 函数变成工具只需要一个装饰器from langchain_core.tools import tool tool def get_weather(location: str, unit: str 摄氏度) - str: 获取指定地点的当前天气。对这个函数的描述要写的足够详细且语义清晰这对模型是否调用它至关重要。 # 这里应该是真实的天气 API 调用我们假装返回固定数据 if location 北京: return f北京当前 25 度{unit}晴。 return f{location}天气数据暂不可获取。 # 检查工具对应的 JSON Schema看看模型眼里你的函数长什么样 print(get_weather.args_schema.schema())tool装饰器会自动读取你函数的签名和类型注解结合 docstring 生成一份 OpenAPI 格式的 JSON Schema。模型就靠这个 Schema 来理解你提供了什么能力。这里有一个非常重要的经验写工具的 docstring比写函数体内的代码还重要。因为模型只通过 docstring 来理解这个工具是干嘛用的、什么时候该用它。你要是随便写一句“获取天气”模型很可能在用户问“明天需要穿什么衣服”时不调用你的天气工具。但如果你写“当用户询问任何与天气、温度、降水、穿衣指数相关的信息时调用此工具”模型调用的成功率会直线上升。3.3 AgentExecutor 的运行机制以 Tool Calling 为例有了模型大脑和工具双手接下来就是组装 Agent。在 LangChain 生态的早期和中期大家最常用的就是AgentExecutor。它的循环逻辑非常经典我把核心步骤拆出来接收用户输入连同系统提示词说明当前身份与任务、可用工具的 Schema 列表、以及 Agent 上次生成的中间步骤Thought/Action/Observation一起发给模型。模型判断是应该输出“最终答案”还是输出“下一步要调用的工具名和参数”。如果模型决定调用工具LangChain 就在你的本地环境执行这个工具函数拿到 Observation观察结果。把这一步的思考和观察结果追加到消息列表里继续发回给模型。重复步骤 2-4直到模型认为任务已结束输出最终答案。这就是经典的 ReAct 模式的工程实现。模型在循环里不断地“思考 - 行动 - 观察”。你甚至可以在控制台里打印出这个过程你会看到模型像个人一样在思考Thought: 用户想知道北京天气我需要调用 get_weather 工具。Action: get_weatherAction Input: {location: 北京}Observation: 北京当前 25 度摄氏度晴。Thought: 我已经拿到了天气信息可以回答用户了。Final Answer: 北京现在晴25 度体感挺舒服的。我们在改造客服机器人的时候就发现一个很有意思的规律任务越垂直、工具越精简Agent 发挥越稳定任务越开放、工具给得越多Agent 就越容易自己把自己绕晕。所以别迷信“Agent 万能论”。3.4 从 AgentExecutor 到 LangGraph 的必然性AgentExecutor好用吗对于简单场景很好用。但作为早起从 Chain 切换到 Agent 的团队我们很快撞上了两堵墙缺乏可控性AgentExecutor内部的循环是一个黑盒。开发者很难在中间插入一个人工审批节点或者规定“最多只能调用三次工具否则强制结束”。缺乏状态管理Agent 执行过程中的上下文Context管理很粗糙。当你需要让它操作 Excel 并生成图表这种多步骤任务时中间状态很容易丢失或者让模型产生幻觉。这时候LangChain 生态里那个“隐藏的第三个核心”就该上场了。4. 核心三LangGraph 图编排 —— 重新定义复杂 Agent 的可能如果说 LCEL 是 LangChain 的“过去式”Agent 是“现在式”那LangGraph 就是 LangChain 生态当之无愧的“未来式”。这也是判断一个开发者是否资深的隐性分水岭——你是在用AgentExecutor硬扛还是已经切换到图状态编排了。用一句话概括 LangGraph 的本质它把 Agent 的执行流程从“一个隐式的循环”升级成了“一张可控的图”。你可能在热搜词里看到了“langgraph和langchain的区别”这个问题我在这里给你讲透。4.1 StateGraph把流程画成图AgentExecutor的问题在于循环是硬编码的LangGraph 则允许你用节点Node和边Edge来显式定义流程。在 LangGraph 里有这几个你需要记住的概念State状态一个全局的数据对象通常是一个 TypedDict在整个图的执行过程中不断被更新。每个节点都能读取它并返回一个包含部分修改的字典来更新它。这就像是图里的“共享记忆库”。Node节点就是一个函数或一个 Runnable。它接收当前 State 作为输入执行一些逻辑比如“调用模型”或“调用工具”然后返回一个字典里面是它想更新进 State 的字段。Edge边连接节点的路径决定了执行的走向。条件边Conditional Edge这是图的灵魂。它的存在让流程可以在运行时动态改变走向——比如模型判断“还需要再调一次工具”就走“继续”的边判断“已有足够信息”就走“结束”的边。做个对比你就明白了LCEL 里的|是静态编写流水线LangGraph 里的节点和条件边是动态决策状态机。AgentExecutor 是 LangGraph 的一个特殊化封装实例而非最佳形态。4.2 一个最小可用的 LangGraph Agent 示例这一步可能会颠覆你过去写 Agent 的方式我们实际写一个带有“人工确认审核”环节的 Agent 节点图from typing import TypedDict, Literal from langgraph.graph import StateGraph, START, END from langchain_openai import ChatOpenAI from langchain_core.tools import tool from langgraph.prebuilt import ToolNode # 1. 定义 Agent 的全局状态 class AgentState(TypedDict): user_query: str intermediate_response: str final_answer: str # 2. 定义工具节点要执行的东西 tool def search_product(name: str) - str: 在内部商品库检索商品名称返回商品编号和价格。 return f商品 {name} 的编号是 P10086价格是 3999 元。 # 3. 定义两个节点函数 def agent_node(state: AgentState) - dict: 核心决策节点模型决定要不要调用工具还是直接回答。 model ChatOpenAI(modelgpt-4o, temperature0).bind_tools([search_product]) prompt f用户的诉求是{state[user_query]}。如果你觉得有必要查询商品库请调用工具。 response model.invoke(prompt) return {intermediate_response: response} def human_approval_node(state: AgentState) - dict: 模拟人工审核实际应用中可对接邮件、企微通知等审批流。 print(f【人工审核】AI 中间结果{state[intermediate_response]}) print(是否批准放行Y/N) user_input input().strip().upper() # 生产环境中应替换为异步审批 API return {should_continue: execute_tool if user_input Y else stop} # 4. 构建图 graph StateGraph(AgentState) # 添加节点 graph.add_node(agent, agent_node) graph.add_node(human_approval, human_approval_node) graph.add_node(tools, ToolNode([search_product])) # 添加边 graph.add_edge(START, agent) graph.add_edge(agent, human_approval) # 条件边根据人工审核结果决定下一步走工具还是直接结束 def route_after_approval(state: AgentState) - Literal[tools, final]: return tools if state.get(should_continue) execute_tool else final graph.add_conditional_edges(human_approval, route_after_approval) graph.add_edge(tools, agent) # 工具执行完回到 agent 节点继续决策 graph.add_edge(final, END) app graph.compile()看到没有在这个图里我们做到了过去AgentExecutor完全做不到的事情——在模型决定调用工具后插入了一个必须由真人确认的节点。模型说它要查商品库可以但得老板点头。这在涉及金钱交易、内容发布、代码部署等高风险场景里是刚需中的刚需。LangGraph 的价值不止于此。它还内置了持久化Checkpoint机制支持人机交互任务的暂停与恢复它的节点天然支持流式输出它甚至能处理循环图这在 LangChain 原生的 LCEL 里是没法做到的。4.3 双 Agent 协作从单点流程走向团队协作LangGraph 真正让我觉得“这个框架能干活”的是你可以在一个图里跑多个模型节点每个模型节点扮演不同角色这就是业界说的 Multi-Agent多代理协作。我在前公司做过一个合同审查应用就是用 LangGraph 搭的。图里有三个模型节点风险识别模型负责扫描合同正文提取可能存在的法律风险点。财务评估模型负责审阅付款条件、赔偿条款等涉及钱的部分。汇总仲裁模型把前两个模型的意见吸收进来解决它们之间的冲突并生成给用户的最终风险报告。这三个模型节点各自拿着不同的 Prompt 和 Tool比如风险识别模型能调法条数据库财务评估模型能调内部费率系统它们通过共享的 State 来传递信息。这种架构下你不会得到一个“万能 Agent”但你会得到一个配合默契的“专业团队”。可控性、专业性、可解释性都远胜于单体 Agent。这也是为什么 CrewAI 今年会那么火因为它把“多个各司其职的角色组队干活”这个概念推向了大众。但 LangGraph 作为底层编排工具其表达能力和灵活度是更高的。5. 开发者必须理清的三大核心关系与选型经验最后我们做一个横向对比总结。我知道很多人看教程最痛苦的点就是不知道什么场景用什么方案。我把自己的选型经验分享出来希望能帮你少走一些弯路。5.1 LangChain、LangGraph、CrewAI它们之间到底是什么关系这是一个高频困惑点。“langgraph和langchain的区别”这个热搜词下回答基本千篇一律。我用自己的话说LangChain是一个工具链生态提供模型接入、Prompt 管理、文档加载、输出解析等基础服务。你可以把它当做一个大工具箱LCEL 就是装这个工具箱的底板。LangGraph是基于 LangChain 的底层编排引擎。如果你的应用流程是一张有分支、有循环、有状态流转的图用它。它管的是“流程的骨架”。CrewAI是更上层的、面向角色协作的封装。如果你希望快速实现“一个研究分析师 一个文案撰写人”这种多角色协作用 CrewAI 上手会快一些。但在高度定制和低层控制上它不如 LangGraph 灵活。用盖楼来类比LangChain 是建材市场买水泥、钢筋、砖头LangGraph 是施工图纸和脚手架决定楼怎么盖CrewAI 是精装修团队专门负责把人住的体验感做出来。5.2 实际项目里的选型建议那实际工作里到底怎么选这里给出我自己的判断框架场景特征推荐方案理由流程固定输入输出明确例如“查天气”、“翻译”LCEL 链简单、高效、易维护不需要引入复杂的状态管理需要模型自主决定调用多个工具且流程线性原生AgentExecutor快速实现内置了 ReAct 循环逻辑流程需要分支、人工介入核对、多步骤循环操作LangGraph可控性最强、状态可追踪、可插桩需要多个智能体分工扮演不同角色相互协作产出LangGraph/CrewAI落地优先可用 CrewAI深度定制选 LangGraph5.3 重要提醒最后再分享一个贯穿始终的心态准备。LangChain 生态目前仍处于快速迭代期。你看到这篇博文的时候AgentExecutor或许已经被官网标注为了“旧版”取而代之的是create_tool_calling_agent等新方法。框架版本 API 变更的速度远比你学得快。所以我建议你学 LangChain 生态时可以带一些“历史视角”——去看 Chain 是怎么被设计出来的为什么后来被 LCEL 替代AgentExecutor有什么缺陷为什么官方用 LangGraph 重写了所有 Agent 构造器。你才能以不变应万变。工具会过时API 会变更但这套“基础工具 → 固定流水线 → 动态决策图”的设计思想会一直在。把它装进脑子里比记住任何具体函数签名都值钱。