在这篇博客中,我们将学习LangChain 是如何工作的。我们还会了解为什么需要 LangChain、Chain、Prompt、Memory 和 Output Parser 分别是什么,以及 Retrieval、Agent 如何融入其中,最后看看整个流程在真实场景中是如何协同工作的。
我们将介绍以下内容:
-
什么是 LangChain?
-
为什么需要 LangChain?
-
LangChain 背后的核心思想
-
LLM 和 Prompt Template
-
什么是 Chain?
-
Output Parser
-
Memory
-
Retrieval 和 RAG
-
Tools 和 Agents
-
LangChain 完整的工作流程
让我们开始吧。
什么是 LangChain?
LangChain 是一个帮助我们构建由大型语言模型(Large Language Model,LLM)驱动的应用程序的框架。在继续之前,我们先理解一个术语。
大型语言模型,也叫 LLM,是一种能够理解并生成类似人类文本的模型。ChatGPT 就是基于 LLM 构建的。我们给它一些文本,它会返回一些文本。
LangChain 是位于我们和 LLM 之间的一个工具。它帮助我们将 LLM 与其他东西连接起来,例如:
-
我们自己的数据
-
我们的工具
-
我们的业务逻辑
简单来说,LangChain 帮助我们构建智能应用,让这些应用可以与 LLM 对话,并替我们完成有用的工作。为了更好地理解它,我们可以拆解一下这个名字:LangChain = Lang + Chain
这里:
-
Lang 代表 Language,即语言,指语言模型。
-
Chain 代表把许多步骤一个接一个地连接起来。
所以,LangChain 的核心就是:将多个步骤连接成一个顺畅的流程。
这种逐步连接 Prompt 的方式,也就是将一个 Prompt 的输出作为下一个 Prompt 的输入,被称为Prompt Chaining(提示词链)。
现在,我们已经理解了 LangChain 是什么。接下来,让我们看看为什么需要它。
为什么需要 LangChain?
假设我们想构建一个非常简单的应用。我们给它一个问题,它使用 LLM 返回答案。这非常简单:我们把文本发送给 LLM,然后拿到回复。但真实世界中的应用并没有这么简单。让我们看看为什么。
假设我们希望应用完成以下事情:
-
接收用户提出的问题。
-
从我们自己的文档中查找答案。
-
记住对话中的历史消息。
-
必要时调用计算器或者搜索引擎。
-
将最终答案格式化成干净的形式。
如果我们手动实现所有这些事情,代码会变得非常混乱。我们需要写大量代码,把每一个组件粘合在一起。我们还必须管理:
-
各个步骤的执行顺序
-
数据如何从一个步骤传递到另一个步骤
这不仅难以构建,而且更难维护。于是,LangChain 就派上用场了。
LangChain 为我们提供了许多现成的构建模块。我们只需要像拼乐高积木一样把这些模块连接起来。每一个模块只负责一件事情,而 LangChain 负责把它们连接起来。
这样,我们就可以利用 LangChain,以一种非常简单的方式构建复杂的 LLM 应用。现在我们已经了解为什么需要 LangChain,接下来看看它背后的核心思想。
LangChain 背后的核心思想
LangChain 的核心思想非常简单:使用一些小型构建模块,并把它们连接起来,从而构建完整的流程。我们通过一个类比来理解,想象一条汽车工厂的装配线。一辆汽车是一步一步制造出来的:
-
首先制造车身。
-
然后安装发动机。
-
接着安装车轮。
-
最后进行喷漆。
每一个工位只完成一项工作,然后将汽车交给下一个工位。LangChain 的工作方式完全一样。每一个模块都负责一个小任务。一个模块的输出,会成为下一个模块的输入。这就是Chain。
我们把工厂装配线与 LangChain 对应起来:
| 装配线 | LangChain |
|---|---|
| 进入工厂的原材料 | 用户输入 |
| 一个工作站 | 一个构建模块 |
| 汽车继续向前移动 | 数据传递到下一个步骤 |
| 完成的汽车 | 最终答案 |
现在,我们已经看到了整体结构。接下来,我们逐个学习这些构建模块。不用担心,我们会详细介绍每一个模块。
LLM 和 Prompt Template
第一个模块就是LLM。LLM 是我们应用的大脑。我们已经知道:
LLM 接收文本,并返回文本。
但是,在把文本发送给 LLM 之前,我们必须认真准备这些文本。发送给 LLM 的文本叫作Prompt(提示词)。简单来说:
Prompt 就是我们给 LLM 的指令。
大多数情况下,我们使用的 Prompt 并不是完全固定的。Prompt 中的一部分内容会根据用户输入发生变化。于是,Prompt Template(提示词模板)就出现了。Prompt Template 是一个预先准备好的 Prompt,其中包含一些空白位置,这些位置会在运行时动态填充。下面来看一个 Prompt Template 的代码:
from langchain_core.prompts import PromptTemplate template = PromptTemplate.from_template( "Explain {topic} in simple words for a beginner.") prompt = template.format(topic="LangChain")
这里,我们创建了一个模板,其中包含一个名为:topic 的空白位置。当我们调用:format(topic="LangChain") 时,这个空白位置就会被填充。
最终的 Prompt 变成:
Explain LangChain in simple words for a beginner.
也就是:用简单易懂的语言向初学者解释 LangChain。这就是 Prompt Template 的作用。它帮助我们使用不同的参数值重复使用同一个 Prompt,让我们的工作变得更加简单。现在,我们已经准备好了 Prompt。接下来,我们要学习如何将 Prompt Template 与 LLM 连接起来。这就是Chain发挥作用的地方。
什么是 Chain?
Chain 是将多个模块连接在一起,使得一个模块的输出能够流入下一个模块。简单来说:Chain 就是一条由多个步骤组成的流水线。假设我们想创建一个简单的 Chain。
第一步:
Prompt Template 根据用户输入的 topic 填充 Prompt。
第二步:
LLM 读取这个 Prompt,然后生成答案。这就是一个包含两个步骤的 Chain。
代码如下:
from langchain_openai import ChatOpenAIfrom langchain_core.prompts import PromptTemplate llm = ChatOpenAI(model="gpt-4o-mini") template = PromptTemplate.from_template( "Explain {topic} in simple words for a beginner.") chain = template | llm result = chain.invoke({"topic": "LangChain"})
这里有几个重要的地方。我们创建了:
-
llm模块
-
template模块
然后使用:" | " 把它们连接起来。这个 | 符号叫作pipe(管道)。它的含义是:
将左边的输出发送给右边。
因此:template | llm
意味着:Prompt Template 填充完成后的 Prompt,会直接发送给 LLM。当我们通过:invoke。传入 topic 后,数据会沿着整个 Chain 流动,然后得到结果。这就是 LangChain 的核心。我们构建很多小模块,然后通过 Pipe 把它们连接起来。
我们可以把这个 Chain 可视化为:

可以看到,数据从左向右流动。上面一行表示每一段管道中传递的数据。下面一行表示每个模块所完成的工作。
Template:
-
填充 Prompt 中的空白位置。
-
将填充完成的 Prompt 发送给 LLM。
LLM:
-
充当应用的大脑。
-
读取 Prompt。
-
生成回答。
-
将答案继续向后传递。
Parser:
- 将答案整理成干净的结果。
模块之间的:" | "。Pipe,就是负责把前一个模块的输出发送给后一个模块。这就是 Chain 的含义。现在,我们已经理解了 Chain。但是 LLM 返回的是普通文本。很多时候,我们需要将回答转换成更加干净、结构化的数据。
于是,我们需要学习Output Parser。
Output Parser
Output Parser 会接收 LLM 输出的原始文本,并将它转换成更加干净、结构化的形式。简单来说:
LLM 使用普通文本进行回答,而 Output Parser 会把文本转换成程序更加容易使用的形式。
例如,我们让 LLM 返回三个水果:
apple, banana, mango
LLM 返回的是普通字符串。但是在我们的代码中,我们可能需要真正的列表:
["apple", "banana", "mango"]
Output Parser 就可以帮助我们完成这样的转换。
来看代码:
from langchain_core.output_parsers import StrOutputParser parser = StrOutputParser() chain = template | llm | parser result = chain.invoke({"topic": "LangChain"})
这里,我们在 Chain 中新增了一个模块:parser
现在,数据会经过三个模块:
Template ↓LLM ↓Parser
Template 负责填充 Prompt。LLM 负责生成答案。Parser 负责把答案整理成简单的字符串。StrOutputParser 会直接返回干净的文本,而不是完整的 Message 对象。这就是 Output Parser 如何让最终结果变得整洁并且可以直接使用。
现在,我们的 Chain 已经能够:
-
接收输入
-
与 LLM 交互
-
清理输出
但是还有一个问题。我们的应用在每次消息处理完成后都会忘记之前发生过什么。接下来,我们使用Memory来解决这个问题。
Memory
假设我们正在和自己的应用聊天。我们问: Who is 牧码人工智能?
也就是:牧码人工智能是谁?
应用正确回答了这个问题。然后我们继续问:Where was he born?也就是:他出生在哪里?这时候问题出现了。应用不知道这里的:he指的是谁。
因为它已经忘记了上一条消息。每一次调用 LLM 都是一次新的调用,LLM 本身并不会自动记住之前的内容。
于是,我们就需要Memory。
Memory 是 LangChain 中负责保存历史对话消息的部分,从而让应用能够记住上下文。
简单来说:
Memory 让我们的应用拥有回忆之前对话内容的能力。
它是如何工作的呢?每当用户发送一条新的消息时,LangChain 会:
-
从 Memory 中获取旧消息。
-
把这些历史消息添加到新的 Prompt 中。
-
再把整个 Prompt 发送给 LLM。
这样,LLM 看到的就不只是最新的一条消息,而是完整的对话上下文。
下面来看 Memory 的一个简单流程:
# 第 1 轮 # 存储到 Memory:# "User: Who is 牧码人工智能?"
第二轮:
# 第 2 轮 # Memory + 新消息会一起发送: # "User: Who is 牧码人工智能?# AI: 牧码人工智能 was a famous physicist.# User: Where was he born?"
我们可以看到,在第二轮对话中,旧的对话内容会被添加到新问题之前。
因此,LLM 现在就知道:he 指的是: 牧码人工智能
Memory 让上下文能够在多轮对话之间持续传递。这就是 Memory 如何让我们的应用拥有类似真实对话的体验。问题解决了。现在,我们的应用已经可以记住聊天内容了。
但是如果我们希望应用使用自己的文档来回答问题呢?
LLM 并不知道我们的私有数据。接下来,我们使用Retrieval来解决这个问题。
Retrieval 和 RAG
LLM 是基于互联网上的大量通用数据训练的。它并不知道:
-
我们公司的内部文档
-
我们的个人笔记
-
我们最新生成的文件
假设我们有一本:200 页的公司员工手册
我们希望应用能够根据这本员工手册回答问题。但是 LLM 从来没有见过这个文档。那么,我们怎么让应用知道里面的内容?这时候就需要Retrieval(检索)。
Retrieval 的意思是:
从我们自己的数据中找出与用户问题最相关的内容,并将这些内容与问题一起发送给 LLM。
这种完整的模式有一个名字:RAG 全称:Retrieval-Augmented Generation 即: 检索增强生成。
简单来说:
我们首先检索正确的信息,然后让 LLM 基于这些信息生成答案。
让我们看看 Retrieval 的具体工作步骤。
第 1 步:切分文档
我们首先把一个大文档切分成许多小片段。这些小片段叫作:Chunks
第 2 步:生成 Embedding
然后,我们将每个 Chunk 转换成一组数字。这组数字叫:Embedding
Embedding 本质上是一种:
将文本表示成数字的方法,从而让计算机能够比较不同文本之间的语义。
第 3 步:存储到 Vector Store
然后,我们将所有 Embedding 存储到一个特殊的数据库中。这个数据库叫:Vector Store 也就是:向量存储 / 向量数据库。
Vector Store 与普通数据库的不同点在于,它主要用于:
根据"语义"搜索内容,而不是只按照完全相同的关键词搜索。
第 4 步:搜索相关内容
当用户提出问题后,我们同样会:
-
将用户的问题转换成 Embedding。
-
使用这个 Embedding 在 Vector Store 中搜索。
-
找到最接近、最相关的 Chunks。
第 5 步:交给 LLM
最后,我们将:用户问题 + 匹配到的 Chunks
一起发送给 LLM。LLM 根据这些内容生成答案。
整个 RAG 流程可以表示为:

这里可以看到,最上面这一条流程是数据的预处理过程。
通常只需要准备一次:
文档 ↓Chunks ↓Embeddings ↓Vector Store
然后,当用户提出问题时:
User Question ↓Embedding ↓在 Vector Store 中进行语义搜索 ↓找到匹配的 Chunks
然后:
用户问题 + Chunks ↓ Prompt ↓ LLM ↓ Answer
这样,LLM 就可以根据我们自己的数据生成最终答案。
下面来看一个简化的 Retrieval 代码:
# 找到与用户问题匹配的 Chunksrelevant_chunks = vector_store.similarity_search( "What is the leave policy?") # 将 Chunks 和问题发送给 LLMchain = prompt_with_context | llm | parser result = chain.invoke({ "context": relevant_chunks, "question": "What is the leave policy?"})
这里首先搜索 Vector Store,找到和: leave policy 也就是: 请假制度
相关的 Chunks。然后,我们把:
-
Chunks
-
用户问题
一起传入 Chain。现在,LLM 就可以读取我们自己的数据,并根据这些数据生成答案。这就是 Retrieval 和 RAG 如何让 LLM 使用我们的私有数据进行问答。这正是 LangChain 的魅力所在。
现在,我们的应用已经能够:
-
使用 Memory
-
使用自己的文档
但是有时候,LLM 需要在真实世界中执行某些操作,例如:
-
搜索互联网
-
做数学计算
于是,我们需要了解Tools 和 Agents。
Tools 和 Agents
LLM 非常擅长语言处理,但它并不擅长所有事情。
例如:
-
LLM 并不擅长精确数学计算。
-
LLM 不知道今天的实时信息。
假设我们问:What is the weather in hangzhou right now?
也就是:杭州现在的天气怎么样?LLM 无法直接知道这个问题的答案。
因为它并没有与实时天气数据建立连接。于是,就有了Tool(工具)。
Tool 是一个外部函数,例如:
-
计算器
-
搜索引擎
-
天气服务
它们可以完成 LLM 自己无法完成的事情。简单来说:
Tool 就像一个助手,当 LLM 自己无法完成任务时,可以运行 Tool 来完成任务。
这里有一个非常重要的点,很多人经常理解错误:
LLM 本身并不会执行 Tool。
LLM 只负责:
-
推荐应该使用哪个 Tool。
-
推荐应该给这个 Tool 传什么参数。
真正调用 Tool 的,是我们的代码。可以把它理解成:
LLM = 顾问Code = 执行者
于是,下一个关键问题来了:
谁负责接收 LLM 的建议,然后真正执行 Tool?
答案就是:Agent。 Agent 是一个智能控制器。
它使用 LLM 来决定:
-
应该使用哪个 Tool
-
Tool 应该按照什么顺序执行
然后 Agent:
-
执行 Tool。
-
获取 Tool 返回的结果。
-
把结果重新发送给 LLM。
-
再让 LLM 判断下一步应该做什么。
-
不断重复,直到任务完成。
简单来说:
Agent 工作在一个循环中。
流程类似:
Agent ↓询问 LLM:下一步做什么? ↓LLM 推荐 Tool + Tool 参数 ↓Agent 执行 Tool ↓获得 Tool Result ↓把 Result 发送给 LLM ↓LLM 判断下一步 ↓...直到任务完成
我们通过一个具体的数字例子理解 Agent 的工作方式。
假设用户问:What is 25 times 18, and is that more than 400?
也就是:25 × 18 等于多少?结果是否大于 400?
第 1 步
Agent 把这个问题发送给 LLM。
LLM 推荐使用:Calculator Tool
并给出输入:25 * 18
第 2 步
Agent 真正执行 Calculator Tool:25 * 18
Tool 返回:450
第 3 步
Agent 把:450 重新发送给 LLM。 LLM 比较:450 和:400
然后判断:450 > 400
第 4 步
LLM 生成最终答案: 25 times 18 is 450, which is more than 400.
也就是:25 × 18 = 450,450 大于 400。
这里可以看到,数学计算并不是 LLM 猜出来的。Agent 实际调用了真正的计算工具。然后 LLM 再对工具返回的结果进行推理。这样可以让答案更加可靠。
当 Agent 的:
-
步骤
-
决策
-
循环
越来越复杂时,我们可以把这些流程组织成一个Graph(图),然后让框架帮助我们运行整个流程。
注意:
Agent 使用 LLM 作为自己的大脑进行决策,使用 Tools 作为自己的双手执行操作。
也就是:
LLM = BrainTools = HandsAgent = Controller
这就是 Tools 和 Agents 如何赋予应用真正执行工作的能力。现在,我们已经了解了所有构建模块。接下来,我们把它们连接起来,看看完整的 LangChain 工作流程。
LangChain 完整的工作流程
让我们把前面学习到的所有内容连接成一个完整的故事。
假设用户打开我们的应用,并针对公司员工手册提出了一个问题。
第 1 步:用户提出问题
用户在应用中输入问题。User Question
第 2 步:读取 Memory
LangChain 从 Memory 中获取之前的历史消息,并将这些消息作为上下文。
Memory ↓Conversation Context
第 3 步:执行 Retrieval
LangChain 使用 Retrieval,从 Vector Store 中找出与用户问题最相关的 Chunks。
Question ↓Retrieval ↓Vector Store ↓Relevant Chunks
第 4 步:构建 Prompt
Prompt Template 将:
-
用户问题
-
Memory 中的历史消息
-
Retrieval 找到的 Chunks
组合成一个最终 Prompt。
Question+Memory+Retrieved Chunks ↓Prompt Template ↓Final Prompt
第 5 步:调用 LLM
最终 Prompt 通过 Chain 传递给 LLM。
Prompt ↓LLM
第 6 步:必要时调用 Tool
如果任务需要执行某种实际操作:
LLM 会推荐:
-
使用哪个 Tool
-
Tool 的输入参数
然后:
Agent 执行 Tool,并把 Tool 的执行结果重新发送给 LLM。
LLM ↓Tool Recommendation ↓Agent ↓Tool ↓Tool Result ↓LLM
第 7 步:LLM 生成答案
LLM 根据:
-
Prompt
-
Retrieved Context
-
Tool Result
生成最终答案。
第 8 步:Output Parser 处理输出
LLM 的答案会经过 Output Parser。
Parser 会把答案转换成更加干净、规整的形式。
LLM Output ↓Parser ↓Clean Output
第 9 步:返回答案并更新 Memory
最终的干净答案会显示给用户。
与此同时:
用户的新消息和 AI 的回答会被重新保存到 Memory 中。
这样下一轮对话就可以继续使用这些上下文。
整个流程如下:

这里可以看到所有模块是如何协同工作的。
首先:User Question 从两个地方获得额外上下文:Memory以及:Retrieval。Memory 提供历史对话上下文。
Retrieval 从 Vector Store 中找到与当前问题匹配的 Chunks。
然后:Prompt Template
把所有内容组合成一个 Prompt。接下来,这个 Prompt 被发送给:LLM
如果需要执行某个操作:LLM 会推荐 Tool。Agent 真正调用 Tool,并将 Tool 的执行结果重新交给 LLM。然后 LLM 生成答案。答案继续经过:Parser 被整理成干净的结果。 最终答案返回给用户。与此同时,新产生的对话消息又会保存进: Memory供下一轮对话继续使用。
我们可以看到,每个模块只负责一项工作,然后把结果传递给下一个模块。输入从一边进入,沿着 Chain 向前流动,最终答案从另一边输出。
这正是文章最开始提到的: 工厂装配线模型。
总结
这就是 LangChain 从头到尾的工作原理。LangChain 是一个帮助我们构建 LLM 应用的框架。它为我们提供了许多小型构建模块,然后允许我们把这些模块连接起来。我们学习了:Prompt Template
用于准备发送给 LLM 的文本。
Variables ↓Prompt Template ↓Final Prompt
Chain
用于将多个模块连接起来,让数据可以在不同模块之间流动。
Block A ↓Block B ↓Block C
Output Parser
用于整理 LLM 的输出结果。
LLM Raw Output ↓Output Parser ↓Structured / Clean Output
Memory
用于记住历史对话,让应用拥有上下文。
Conversation History ↓ Memory ↓ Current Prompt
Retrieval 和 RAG
用于将我们自己的数据提供给 LLM。
Documents ↓Chunks ↓Embeddings ↓Vector Store ↓Retrieval ↓LLM
Tools 和 Agents
用于让应用能够执行真实操作。
Agent ↓LLM 决策 ↓Tool 调用 ↓Tool Result ↓LLM
最终,整个 LangChain 可以概括为:
User Question ↓Memory + Retrieval ↓Prompt Template ↓LLM ↕Agent + Tools ↓Output Parser ↓Final Answer ↓Memory
这就是LangChain 的工作方式。