LangChain是用来做什么的
一言以蔽之,LangChain是用于构建大语言模型应用的工程化解决方案。
LangChain的结构是什么样的
既然是工程化的解决方案,LangChain符合一般软件的基本结构。
一般软件分层结构
- Runtime(运行时):技术基座
- 内存+持久化:软件必要的部分
- 逻辑层:逻辑控制的部分
- 方案设计:软件开发前的技术设计
- 可观测:系统在线上运行时,对系统运作状态(Metrics)、问题排查(Log, Trace)的观测
LangChain的对标工程结构
LangChain符合一般软件分层结构的对标工程结构。
- Module I/O 对标 Runtime
- 持久化 对标 DataConnection
- Chain 对标 逻辑层
- Agents 对标 方案设计
- LangSmith 对标 可观测
(LangServe是LangChain中为了方便部署而设计的工具,暂时可忽略)
通过这样的对比,你能够快速了解LangChain有哪些模块以及模块的作用吗?
LangChain各个模块的具体细节
了解各个模块的细节,从底层到上层,是一个比较快速的方式。
Runtime模块 -> Model I/O
任何语言模型应用的核心元素是模型的输入和输出。LangChain提供了与任何语言模型进行接口交互的基本组件。
- 提示 prompts:将模型输入模板化、动态选择和管理
- 语言模型 models:通过常见接口调用语言模型
- 输出解析器 output_parsers:从模型输出中提取信息
Memory模块
大多数LLM应用都有对话接口。对话的一个重要组成部分是能够引用对话中先前介绍的信息。至少,对话系统应该能够直接访问过去消息的某些窗口。更复杂的系统需要有一个不断更新的世界模型,这使得它能够执行诸如维护有关实体及其关系的信息之类的事情。
我们将这种存储过去交互信息的能力称为"记忆"。 LangChain提供了许多用于向系统添加内存的实用工具。这些实用程序可以单独使用,也可以无缝地合并到Chain中。
内存系统需要支持两个基本操作:读和写。回想一下,每个链都定义了一些需要某些输入的核心执行逻辑。其中一些输入直接来自用户,但其中一些输入可以来自内存。在给定的运行中,一条链将与其内存系统交互两次。
- 在收到初始用户输入之后但在执行核心逻辑之前,链将从其内存系统中读取并增加用户输入。
- 在执行核心逻辑之后但在返回答案之前,链会将当前运行的输入和输出写入内存,以便在将来的运行中引用它们。
持久化 -> Data Connection
许多LLM应用程序需要用户特定数据,这些数据不是模型的训练集的一部分。完成这一任务的主要方法是通过检索增强生成(RAG)。在此过程中,检索外部数据,然后在生成步骤中将其传递给LLM。
LangChain为RAG应用程序提供了所有的构建模块-从简单到复杂。本文档部分涵盖了与检索步骤相关的所有内容,例如数据的获取。虽然听起来很简单,但可能有微妙的复杂性。这涵盖了几个关键模块。
逻辑层 -> Chain
在简单应用中,单独使用LLM是可以的,但更复杂的应用需要将LLM进行链接 - 要么相互链接,要么与其他组件链接。
LangChain为这种"链接"应用提供了Chain接口。LangChain将链定义得非常通用,它是对组件调用的序列,可以包含其他链。基本接口很简单:
python
from langchain.chat_models import ChatAnthropic
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser
model = ChatAnthropic()
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You're a very knowledgeable historian who provides accurate and eloquent answers to historical questions.",
),
("human", "{question}"),
]
)
runnable = prompt | model | StrOutputParser()
为什么需要链? 链允许我们将多个组件组合在一起创建一个单一的、连贯的应用。例如,我们可以创建一个链,该链接收用户输入,使用PromptTemplate对其进行格式化,然后将格式化后的响应传递给LLM。我们可以通过将多个链组合在一起或将链与其他组件组合来构建更复杂的链。
技术方案 -> 智能体(Agents)
智能体的核心思想是使用LLM来选择要采取的一系列动作。在链式结构中,一系列动作是硬编码的(在代码中)。在代理中,使用语言模型作为推理引擎来确定要采取的动作及其顺序。
代理 Agent
这是负责决定下一步采取什么动作的类。这是由语言模型和提示词驱动的。该输入可以包括以下内容:
- Tools: 可用工具的描述.
- 用户输入: 高级别的目标
- 中间步骤: 之前为了实现用户的输入, 而执行的任何的(action, tool output) 输出是要执行的下一个操作或要发送给用户的最终响应(AgentActions 或 AgentFinish)。操作指定工具以及该工具的输入。不同的智能体有不同的推理提示风格、不同的编码输入方式以及不同的解析输出方式。
工具(Tools)
工具是代理调用的函数。 这里有两个重要的考虑因素:
给代理访问正确工具的权限 以对代理最有帮助的方式描述工具 LangChain提供了一系列广泛的工具来入门,同时也可以轻松定义自己的工具(包括自定义描述)。
工具包(Toolkits)
代理可以访问的工具集合通常比单个工具更重要。为此,LangChain提供了工具包的概念-用于实现特定目标所需的一组工具。通常一个工具包中有3-5个工具。
LangChain提供了一系列广泛的工具包来入门。
智能体执行器(AgentExecutor)
智能体执行是智能体的运行时。这是实际调用智能体并执行其选择的动作的部分。以下是此运行时的伪代码:
python
next_action = agent.get_action(...)
while next_action != AgentFinish:
observation = run(next_action)
next_action = agent.get_action(..., next_action, observation)
return next_action
虽然这看起来很简单,但此运行时为您处理了几个复杂性,包括:
- 处理智能体选择不存在的工具的情况
- 处理工具发生错误的情况
- 处理智能体生成无法解析为工具调用的输出的情况
- 在所有级别上记录和可观察性(代理决策,工具调用)-可以输出到stdout或LangSmith
可观测系统 -> LangSmith
LangSmith帮助您追踪和评估语言模型应用和智能代理,以帮助您从原型过渡到生产环境。