LangChain核心概念一文全解析:从Prompt到Agent

在这篇博客中,我们将学习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,然后拿到回复。但真实世界中的应用并没有这么简单。让我们看看为什么。

假设我们希望应用完成以下事情:

  1. 接收用户提出的问题。

  2. 从我们自己的文档中查找答案。

  3. 记住对话中的历史消息。

  4. 必要时调用计算器或者搜索引擎。

  5. 将最终答案格式化成干净的形式。

如果我们手动实现所有这些事情,代码会变得非常混乱。我们需要写大量代码,把每一个组件粘合在一起。我们还必须管理:

  • 各个步骤的执行顺序

  • 数据如何从一个步骤传递到另一个步骤

这不仅难以构建,而且更难维护。于是,LangChain 就派上用场了。

LangChain 为我们提供了许多现成的构建模块。我们只需要像拼乐高积木一样把这些模块连接起来。每一个模块只负责一件事情,而 LangChain 负责把它们连接起来。

这样,我们就可以利用 LangChain,以一种非常简单的方式构建复杂的 LLM 应用。现在我们已经了解为什么需要 LangChain,接下来看看它背后的核心思想。

LangChain 背后的核心思想

LangChain 的核心思想非常简单:使用一些小型构建模块,并把它们连接起来,从而构建完整的流程。我们通过一个类比来理解,想象一条汽车工厂的装配线。一辆汽车是一步一步制造出来的:

  1. 首先制造车身。

  2. 然后安装发动机。

  3. 接着安装车轮。

  4. 最后进行喷漆。

每一个工位只完成一项工作,然后将汽车交给下一个工位。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 会:

  1. 从 Memory 中获取旧消息。

  2. 把这些历史消息添加到新的 Prompt 中。

  3. 再把整个 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 步:搜索相关内容

当用户提出问题后,我们同样会:

  1. 将用户的问题转换成 Embedding。

  2. 使用这个 Embedding 在 Vector Store 中搜索。

  3. 找到最接近、最相关的 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 只负责:

  1. 推荐应该使用哪个 Tool。

  2. 推荐应该给这个 Tool 传什么参数。

真正调用 Tool 的,是我们的代码。可以把它理解成:

复制代码
LLM = 顾问Code = 执行者

于是,下一个关键问题来了:

谁负责接收 LLM 的建议,然后真正执行 Tool?

答案就是:Agent。 Agent 是一个智能控制器。

它使用 LLM 来决定:

  • 应该使用哪个 Tool

  • Tool 应该按照什么顺序执行

然后 Agent:

  1. 执行 Tool。

  2. 获取 Tool 返回的结果。

  3. 把结果重新发送给 LLM。

  4. 再让 LLM 判断下一步应该做什么。

  5. 不断重复,直到任务完成。

简单来说:

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 的工作方式。

相关推荐
johnsong1 小时前
AI实验室人才战争:DeepMind流失117人、Anthropic反向净流入,一组数据揭示了什么?
人工智能
麻雀飞吧1 小时前
学量化:看到“近期工具推荐”时,先问工具要解决什么问题
人工智能·python
梦想出海-Phoebe1 小时前
ChatGPT 被欧盟纳入大型搜索服务监管:AI 正在变成新的信息入口
人工智能·chatgpt
中科同志科技1 小时前
真空回流炉高温合金元器件焊接炉实操教程:从参数设定到良率提升
大数据·人工智能·机器人·业界资讯
桃西西呀2 小时前
《牛来》票房涨 1000 倍是真的吗?——2026暑期档 124 亿里的数学
人工智能·数据分析·llm
小小龙学IT2 小时前
ONNX Runtime 开源 AI 推理引擎深度解析:从模型部署到边缘 AI 加速的全栈实战
c++·人工智能·开源
Leslie1652 小时前
流式对话接口怎么选:SSE 与 WebSocket 的原理、实现和工程边界
人工智能
QXWZ_IA2 小时前
如何防止第三方施工对油气管道的破坏?千寻智慧桩+北斗定位预警方案
人工智能·科技·智能硬件