LangChain是一个专门开发大语言模型应用的框架。它主要解决三个问题:
第一,标准化封装。LLM应用开发涉及模型调用、向量库、工具集成等多个环节,每个环节都有不同的提供商和API。LangChain把这些都封装成统一的接口,开发者不用关心底层差异。
第二,快速组装。LangChain把常见功能抽象成独立组件,比如模型接口、Prompt模板、文档加载器、文本分割器、向量存储等。开发者可以像搭积木一样组合这些组件,几行代码就能搭出一个RAG应用或Agent。
第三,复杂流程编排。除了基础组件,LangChain还提供了Chain链式调用、Memory记忆管理、Agent自主决策等高级能力,让复杂任务的实现变得简单。
LangChain降低了LLM应用开发的门槛,是目前最流行的LLM开发框架之一。
LangChain的五大核心组件分别是:
Models(模型):封装各类LLM和Embedding模型,支持OpenAI、Anthropic、本地模型等多种提供商,可以无缝切换。
Prompts(提示词):提供PromptTemplate模板管理,支持变量插值、FewShot示例、ChatMessage消息模板等,让Prompt管理更规范。
Chains(链):把多个组件串联起来形成执行流程,前一个组件的输出作为后一个组件的输入。LangChain预置了很多常用Chain,比如LLMChain、RetrievalQA、SQLDatabaseChain等。
Memory(记忆):在对话中保持上下文,支持BufferMemory完整保存、SummaryMemory自动总结、VectorStoreMemory向量检索等多种实现。
Tools & Agents(工具与智能体):Tools封装外部功能供Agent调用,Agent则根据用户输入自主决策是否调用工具、调用哪个工具、传什么参数。
这五个组件覆盖了LLM应用开发的核心环节。
LangChain中区分LLM和ChatModel主要是适配不同类型的模型接口:
LLM是传统的文本补全模型,输入输出都是纯字符串。比如早期的GPT-3,你给它一段文本,它继续生成后面的内容。
ChatModel是对话模型,基于消息结构交互。输入是HumanMessage、SystemMessage、AIMessage等角色消息组成的列表,输出也是消息对象。ChatGPT、通义千问、文心一言都属于这类。
实际开发中ChatModel是主流用法,因为它支持角色区分,可以用SystemMessage设定模型行为,用HumanMessage传递用户输入,对话管理更清晰。
LangChain对两者做了统一封装,但内部处理逻辑不同。选型时要看模型提供商的API类型,选择对应的封装类。
LangChain实现RAG的流程分为两个阶段:
索引阶段(离线):
第一步,文档加载。用Document Loader加载各种格式的文档,比如PDF、Word、网页等。
第二步,文本分割。用TextSplitter把长文档切分成小块Chunk,适配模型上下文限制。
第三步,向量化。用Embedding模型把文本Chunk转换成向量。
第四步,存储索引。把向量存入VectorStore向量数据库,同时保存原始文本作为元数据。
查询阶段(在线):
第一步,问题向量化。把用户问题用同样的Embedding模型转成向量。
第二步,相似度检索。在向量库中搜索最相似的几个文档片段。
第三步,上下文拼接。把检索到的片段和用户问题一起拼成Prompt。
第四步,生成答案。调用LLM基于上下文生成回答。
LangChain的RetrievalQA链把查询阶段的后三步封装在一起,几行代码就能实现RAG问答。
LangChain提供了多种Memory实现来应对不同场景:
ConversationBufferMemory是最简单的方式,完整保存全部对话历史,直接拼接到Prompt中。适合对话轮数少的场景,缺点是历史太长会超出模型上下文限制。
ConversationBufferWindowMemory只保留最近K轮对话,通过滑动窗口控制长度。解决了超长问题,但可能丢失早期的重要信息。
ConversationSummaryMemory用LLM定期总结对话历史,把长篇对话压缩成简短摘要。既保留了关键信息又控制了长度,但增加了调用成本。
VectorStoreRetrieverMemory把对话历史存到向量数据库,检索时根据问题召回相关的历史片段。适合需要长期记忆的场景。
实际使用中要根据对话长度、成本预算、记忆需求来选择合适的Memory类型,也可以组合使用。
LCEL是LangChain Expression Language的缩写,是LangChain推出的声明式链式语法。它用管道符|来组合组件,写法类似Unix管道。
举个例子,一个完整的RAG链用LCEL写大概是这样:retriever | format_docs | prompt | llm | output_parser
LCEL的优势有几个:
语法简洁。几行代码就能表达复杂的链式流程,比传统的类继承方式清晰很多。
支持流式输出。LCEL链天然支持流式响应,不用额外配置。
支持异步执行。组件可以异步调用,提高整体性能。
可观测性好。每个步骤的输入输出都能方便地查看和调试。
易于组合复用。定义好的LCEL片段可以像函数一样在其他地方复用。
LCEL是LangChain推荐的新式写法,新项目中建议优先使用。
这三种都是LangChain处理长文档的文档链策略,区别主要在于怎么处理多个文档片段:
Stuff是最简单的方式,把所有检索到的文档片段一次性塞进Prompt,然后调用LLM生成答案。优点是简单高效,只调用一次模型。缺点是受限于模型上下文长度,片段太多会超限制。适合文档较短或检索结果少的场景。
MapReduce是分而治之的思路。先把每个文档片段分别传给模型处理(Map阶段),得到中间结果,然后再把这些中间结果汇总生成最终答案(Reduce阶段)。适合超长文档,但会调用多次模型,成本较高。
Refine是迭代优化的思路。先基于第一个片段生成初始答案,然后逐个把后续片段和当前答案一起传给模型进行优化,不断refine直到处理完所有片段。上下文连贯性好,但耗时最长,适合需要深度整合多个文档内容的场景。
选型时要权衡文档长度、成本预算、答案质量要求。
LangChain Agent的核心是让LLM自主决策。
Agent的工作流程是这样的:
第一步,接收用户输入,结合对话历史和可用工具描述,生成Prompt传给LLM。
第二步,LLM判断是直接回答还是调用工具。如果需要调用工具,输出遵循ReAct格式,包含Thought(思考过程)和Action(工具调用指令)。
第三步,框架解析Action,提取工具名和参数,执行对应的工具函数,获取Observation(观察结果)。
第四步,把Observation追加到上下文,再次传给LLM,让模型基于工具返回的结果继续决策。
第五步,循环执行直到LLM决定输出最终答案。
整个过程的关键是模型拥有自主决策权,自己判断什么时候调用工具、调用哪个、传什么参数。LangChain预置了多种Agent类型,比如zero-shot-react-description适合通用任务,structured-chat-zero-shot支持多参数工具调用。
LangChain定义工具有两种方式:
第一种是用@tool装饰器,这是最简洁的推荐方式。把一个普通函数用@tool装饰,LangChain会自动从函数名和docstring生成工具描述。
第二种是继承BaseTool类,适合需要更精细控制的场景。需要定义name、description、args_schema等属性,重写_run方法实现工具逻辑。
工具定义好后,把工具列表传给Agent,Agent就能在运行时调用它们。工具的描述要写清楚功能、参数含义、返回值格式,让模型能正确选择和使用。
LangGraph和LangChain Chain的最大区别在于架构范式。
LangChain Chain是基于链式结构的,数据线性流动,从A到B到C,或者简单的分支。适合顺序执行、流程固定的场景。Chain一旦定义好,执行路径就确定了。
LangGraph是基于图结构的,支持复杂的分支、循环、并行。节点之间通过边连接,可以有条件边根据状态动态决定下一步去哪。适合多步骤复杂任务、需要循环迭代的场景、多Agent协作。
打个比方,Chain像是一条流水线,物料按固定顺序经过各个工位。LangGraph像是一张交通网,车辆可以根据路况选择不同路线,可以绕圈,可以并行多条路。
LangGraph专为复杂Agent设计,可以建模反思优化、审批流程、多角色协作等复杂场景。两者可以无缝集成,LangGraph的节点里可以使用LangChain的Chain和Agent。
LangGraph的三大核心概念是State、Node、Edge。
State(状态)是全局共享的数据结构,贯穿整个图流程。所有节点都可以读写State,用来保存对话历史、工具执行结果、中间变量等。State用TypedDict定义,类型安全且支持自动合并。
Node(节点)是最小执行单元,代表一个具体的处理步骤。Node可以是函数调用、LLM调用、工具执行等。Node接收State作为输入,返回对State的更新。LangGraph中一切操作都在Node里完成。
Edge(边)定义节点之间的流转规则。普通Edge是无条件跳转,从一个节点固定到下一个节点。条件Edge根据State的值动态决定下一个节点去哪,实现分支逻辑。
这三个概念配合起来,State负责数据共享,Node负责逻辑执行,Edge负责流程控制,构成了LangGraph完整的工作流编排能力。
StateGraph是LangGraph的核心构图类,相当于整个图的"画布"。
StateGraph的主要作用有四个:
第一,定义状态结构。初始化StateGraph时要传入State的TypedDict定义,确定整个图共享的数据结构。
第二,添加节点。用add_node方法注册各个业务节点,每个节点绑定一个处理函数。
第三,配置边。用add_edge添加普通边,用add_conditional_edges添加条件边,定义节点之间的流转规则。
第四,编译运行。调用compile方法把图定义编译成可运行的实例,然后传入初始State触发执行。
StateGraph是声明式的,先定义好图的结构,再一次性编译执行。这种设计让复杂工作流的定义变得清晰,也便于可视化理解和调试。
条件边Conditional Edge是LangGraph实现动态分支的核心机制。
普通边是固定的,A节点执行完一定到B节点。条件边则根据当前State的值动态决定下一步去哪。
使用条件边需要三个要素:
源节点:条件边从哪个节点出发。
条件函数:接收State作为参数,返回一个字符串标识。
映射字典:把字符串标识映射到目标节点。
举个例子,一个审批流程中,条件函数检查State中的审批结果字段,如果通过返回"approved",映射到结束节点;如果拒绝返回"rejected",映射到修改节点。
条件边让图具备了运行时决策能力,是实现循环、分支、多路径的关键。条件函数要保持纯函数特性,只依赖State不依赖外部状态,确保可预测性。
LangGraph通过边的循环引用实现循环执行。
具体做法是在add_edge时,把目标节点设为之前执行过的节点,形成闭环。比如graph.add_edge("generate", "evaluate"),然后graph.add_edge("evaluate", "generate"),评估后回到生成,形成循环。
实际使用中循环要有终止条件,否则会变成死循环。通常的做法是:
在State中设置计数器或标志位,比如retry_count记录迭代次数,is_complete标记是否完成。
条件函数检查这些字段,如果达到最大迭代次数或任务已完成,返回结束标识跳出循环;否则返回继续标识保持循环。
这种循环机制让LangGraph可以处理需要多轮迭代的任务,比如代码生成中的生成-测试-修复循环,内容创作中的生成-评估-优化循环。
LangGraph构建多Agent系统的典型模式是:每个Agent作为一个Node,通过State共享信息,通过Edge协调执行。
具体实现步骤:
第一步,定义Agent Node。每个Node内部封装一个Agent,可以是LangChain的Agent,也可以是自定义逻辑。
第二步,设计State结构。包含messages消息列表、任务分配字段、各Agent的中间结果等,确保Agent之间能交换信息。
第三步,编排执行流程。用条件边实现任务分配,比如根据问题类型路由到不同Agent;用普通边定义Agent之间的执行顺序。
常见的协作模式有:
监督者模式:一个Supervisor Agent负责协调多个Worker Agent,决定任务分配给哪个Worker,汇总Worker的结果。
流水线模式:多个Agent按顺序处理,前一个Agent的输出作为后一个的输入,像流水线一样传递。
多轮协商模式:多个Agent反复讨论,通过State交换意见,直到达成共识。
LangGraph的持久化机制用于保存图执行的State和会话记录,支持断点续传和历史会话恢复。
持久化的核心概念是检查点Checkpoint。在图执行的关键节点,框架会自动把当前State保存到存储中。如果执行中断,下次可以从检查点恢复继续执行。
LangGraph支持多种存储后端:
内存存储:数据存在内存中,重启丢失,适合开发调试。
SQLite:本地文件存储,轻量便捷,适合小规模应用。
PostgreSQL/Redis:生产级存储,支持分布式部署,数据可靠性高。
持久化的价值在于:第一,容错恢复。长时间运行的任务如果中断,可以从检查点恢复而不是从头开始。第二,历史回溯。可以查看任意时刻的State状态,方便调试和审计。第三,会话保持。用户的对话历史可以持久化,下次访问时恢复上下文。
LangGraph的完整执行流程分为六个步骤:
第一步,定义State。用TypedDict定义全局状态的数据结构,包含消息列表、中间变量、控制标志等字段。
第二步,初始化StateGraph。创建StateGraph实例,绑定State类型。
第三步,注册Node。用add_node添加各个业务节点,配置每个节点的处理函数。节点可以是LLM调用、工具执行、自定义函数等。
第四步,配置边。设置入口节点,用add_edge添加普通流转边,用add_conditional_edges添加条件分支边,定义完整的流程图。
第五步,编译图。调用compile方法把图定义编译成可运行的实例。
第六步,触发执行。传入初始State,调用invoke或stream方法启动执行。节点按边的规则流转,直到到达结束节点,返回最终的State。
整个流程是声明式的,先定义图的结构,再执行。这种设计让复杂工作流的逻辑清晰可控。
LangChain和LlamaIndex都是LLM应用开发框架,但侧重点不同:
LangChain更通用,提供完整的组件体系,覆盖模型调用、Prompt管理、Chain编排、Agent实现、工具集成等全流程。设计理念是灵活组合,开发者可以自由搭建各种架构。生态更丰富,社区更活跃。
LlamaIndex更专注,聚焦于RAG和知识检索场景。提供数据加载、索引构建、查询引擎等专业化组件。设计理念是开箱即用,针对检索场景做了深度优化。索引类型更丰富,支持向量索引、树形索引、列表索引、关键词索引等。
具体选择建议:
如果你的项目是做通用LLM应用,涉及多种功能组合,选LangChain。
如果你的项目专注做RAG知识库,对检索质量要求高,选LlamaIndex。
两者也可以组合使用,比如用LlamaIndex做文档索引和检索,用LangChain做Chain编排和Agent实现,各取所长。
总结
本文整理了18道LangChain和LangGraph的核心面试题,覆盖了框架的基础概念、核心组件、Chain与Agent、LCEL表达式、LangGraph状态流、节点编排、条件分支、持久化等高频考点。
LangChain是LLM应用开发的"瑞士军刀",提供了丰富的组件和灵活的组装能力。LangGraph则是在复杂工作流场景的增强,用图结构建模让多Agent协作和复杂流程变得清晰可控。掌握这两个框架,是成为AI应用开发工程师的必备技能。