3、LangChain基础:LangChain 基础

LangChain 模块和体系

LangChain 是一个用于开发由大型语言模型(LLMs)驱动的应用程序的框架。

官方文档:https://python.langchain.com/docs/introduction/

LangChain 简化了LLM应用程序生命周期的每个阶段:

  • 开发:使用LangChain的开源构建模块和组件构建您的应用程序。利用第三方集成和模板快速启动。
  • 生产部署:使用LangSmith检查、监控和评估您的链,以便您可以持续优化并自信地部署。
  • 部署:使用LangServe将任何链转换为API。

具体而言,该框架包括以下开源库:

  • **<font style="color:rgb(28, 30, 33);">langchain-core</font>**:基本抽象和LangChain表达语言。
  • **<font style="color:rgb(28, 30, 33);">langchain-community</font>**:第三方集成。
    • 合作伙伴包(例如 **<font style="color:rgb(28, 30, 33);">langchain-openai</font>****<font style="color:rgb(28, 30, 33);">langchain-anthropic</font>** 等):一些集成已进一步拆分为仅依赖于 **<font style="color:rgb(28, 30, 33);">langchain-core</font>** 的轻量级包。
  • **<font style="color:rgb(28, 30, 33);">langchain</font>**:构成应用程序认知架构的链、代理和检索策略。
  • langgraph:通过将步骤建模为图中的边缘和节点,使用LLMs构建稳健且有状态的多参与者应用程序。
  • langserve:将LangChain链部署为REST API。
  • LangSmith:一个开发平台,可让您调试、测试、评估和监控LLM应用程序。

LLM & Chat models PromptTemplates, OutputParses Chains

LLMs

将字符串作为输入并返回字符串的语言模型。 这些通常是较旧的模型(较新的模型通常是 <font style="color:rgb(28, 30, 33);">ChatModels</font>,见上文)。 尽管底层模型是字符串输入、字符串输出,LangChain 封装器还允许这些模型接受消息作为输入。 这使它们可以与 ChatModels 互换使用。 当消息作为输入传入时,它们将在传递给底层模型之前在内部格式化为字符串。 LangChain 不提供任何 LLMs,而是依赖于第三方集成。

Messages(消息)

一些语言模型将消息列表作为输入并返回消息。 有几种不同类型的消息。 所有消息都有 <font style="color:rgb(28, 30, 33);">role</font><font style="color:rgb(28, 30, 33);">content</font><font style="color:rgb(28, 30, 33);">response_metadata</font> 属性。 <font style="color:rgb(28, 30, 33);">role</font> 描述了消息的发出者是谁。 LangChain 为不同的角色设计了不同的消息类。 <font style="color:rgb(28, 30, 33);">content</font> 属性描述了消息的内容。 这可以是几种不同的内容:

  • 一个字符串(大多数模型处理这种类型的内容)
  • 一个字典列表(用于多模态输入,其中字典包含有关该输入类型和该输入位置的信息)
HumanMessage

这代表用户发送的消息。

AIMessage

这代表模型发送的消息。除了 <font style="color:rgb(28, 30, 33);">content</font> 属性外,这些消息还有: **<font style="color:rgb(28, 30, 33);">response_metadata</font>** <font style="color:rgb(28, 30, 33);">response_metadata</font> 属性包含有关响应的其他元数据。这里的数据通常针对每个模型提供者具体化。 这是存储对数概率和标记使用等信息的地方。 **<font style="color:rgb(28, 30, 33);">tool_calls</font>** 这些表示语言模型调用工具的决定。它们作为 <font style="color:rgb(28, 30, 33);">AIMessage</font> 输出的一部分包含在内。 可以通过 <font style="color:rgb(28, 30, 33);">.tool_calls</font> 属性从中访问。 此属性返回一个字典列表。每个字典具有以下键:

  • <font style="color:rgb(28, 30, 33);">name</font>:应调用的工具的名称。
  • <font style="color:rgb(28, 30, 33);">args</font>:该工具的参数。
  • <font style="color:rgb(28, 30, 33);">id</font>:该工具调用的 id。
SystemMessage

这代表系统消息,告诉模型如何行为。并非每个模型提供者都支持这一点。

FunctionMessage

这代表函数调用的结果。除了 <font style="color:rgb(28, 30, 33);">role</font><font style="color:rgb(28, 30, 33);">content</font>,此消息还有一个 <font style="color:rgb(28, 30, 33);">name</font> 参数,传达了生成此结果所调用的函数的名称。

ToolMessage

这代表工具调用的结果。这与 FunctionMessage 不同,以匹配 OpenAI 的 <font style="color:rgb(28, 30, 33);">function</font><font style="color:rgb(28, 30, 33);">tool</font> 消息类型。除了 <font style="color:rgb(28, 30, 33);">role</font><font style="color:rgb(28, 30, 33);">content</font>,此消息还有一个 <font style="color:rgb(28, 30, 33);">tool_call_id</font> 参数,传达了调用生成此结果的工具的 id。

Prompt templates(提示模板)

提示模板有助于将用户输入和参数转换为语言模型的指令。 这可用于引导模型的响应,帮助其理解上下文并生成相关和连贯的基于语言的输出。 提示模板以字典作为输入,其中每个键代表要填充的提示模板中的变量。 提示模板输出一个 PromptValue。这个 PromptValue 可以传递给 LLM 或 ChatModel,并且还可以转换为字符串或消息列表。 存在 PromptValue 的原因是为了方便在字符串和消息之间切换。 有几种不同类型的提示模板

String PromptTemplates

这些提示模板用于格式化单个字符串,通常用于更简单的输入。 例如,构建和使用 PromptTemplate 的常见方法如下:

from langchain_core.prompts import PromptTemplate
prompt_template = PromptTemplate.from_template("Tell me a joke about {topic}")
prompt_template.invoke({
   
   "topic": "cats"})
ChatPromptTemplates

这些提示模板用于格式化消息列表。这些“模板”本身是模板列表。 例如,构建和使用 ChatPromptTemplate 的常见方法如下:

from langchain_core.prompts import ChatPromptTemplate
prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    ("user", "Tell me a joke about {topic}")
])
prompt_template.invoke({
   
   "topic": "cats"})

在上面的示例中,当调用此 ChatPromptTemplate 时,将构建两条消息。 第一条是系统消息,没有要格式化的变量。 第二条是 HumanMessage,并将根据用户传入的 <font style="color:rgb(28, 30, 33);">topic</font> 变量进行格式化。

MessagesPlaceholder

这个提示模板负责在特定位置添加消息列表。 在上面的 ChatPromptTemplate 中,我们看到了如何格式化两条消息,每条消息都是一个字符串。 但是,如果我们希望用户传入一个消息列表,我们将其插入到特定位置,该怎么办? 这就是您使用 MessagesPlaceholder 的方式。

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage
prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    MessagesPlaceholder("msgs")
])
prompt_template.invoke({
   
   "msgs": [HumanMessage(content="hi!")]})

这将生成两条消息,第一条是系统消息,第二条是我们传入的 HumanMessage。 如果我们传入了 5 条消息,那么总共会生成 6 条消息(系统消息加上传入的 5 条消息)。 这对于将一系列消息插入到特定位置非常有用。 另一种实现相同效果的替代方法是,不直接使用 <font style="color:rgb(28, 30, 33);">MessagesPlaceholder</font> 类,而是:

prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    ("placeholder", "{msgs}") # <-- 这是更改的部分
])

Output parsers(输出解析器)

这里提到的是将模型的文本输出进行解析,转换为更结构化表示的解析器。 越来越多的模型支持函数(或工具)调用,可以自动处理这一过程。 建议使用函数/工具调用,而不是输出解析。

负责接收模型的输出并将其转换为更适合下游任务的格式。 在使用LLMs生成结构化数据或规范化聊天模型和LLMs的输出时非常有用。 LangChain有许多不同类型的输出解析器。下表列出了LangChain支持的各种输出解析器及相关信息:

名称:输出解析器的名称

支持流式处理:输出解析器是否支持流式处理

具有格式说明:输出解析器是否具有格式说明。通常是可用的,除非在提示中未指定所需模式,而是在其他参数中指定(如OpenAI函数调用),或者当OutputParser包装另一个OutputParser时。

调用LLM:此输出解析器是否调用LLM。通常只有尝试纠正格式不正确的输出的输出解析器才会这样做。 输入类型:预期的输入类型。大多数输出解析器适用于字符串和消息,但有些(如OpenAI函数)需要具有特定kwargs的消息。

输出类型:解析器返回的对象的输出类型。

描述:我们对此输出解析器的评论以及何时使用它的说明。

示例代码

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.output_parsers import StrOutputParser

model = ChatOpenAI(model="gpt-4")

messages = [
    SystemMessage(content="将以下内容从英语翻译成中文"),
    HumanMessage(content="It's a nice day today"),
]
parser = StrOutputParser()
result = model.invoke(messages)
#使用parser处理model返回的结果
response = parser.invoke(result)
print(response)
#今天天气很好

Chains(链式调用)

Chains 是 LangChain 中用于将多个步骤组合成一个工作流程的模块。它们允许你定义一系列操作,并将它们链接在一起。比如在这个Chain中,每次都会调用输出解析器。这个链条的输入类型是语言模型的输出(字符串或消息列表),输出类型是输出解析器的输出(字符串)。

我们可以使用 <font style="color:rgb(28, 30, 33);">|</font> 运算符轻松创建这个Chain。<font style="color:rgb(28, 30, 33);">|</font> 运算符在 LangChain 中用于将两个元素组合在一起。

如果我们现在看一下 LangSmith,我们会发现这个链条有两个步骤:首先调用语言模型,然后将其结果传递给输出解析器。我们可以在 LangSmith 跟踪 中看到这一点。

https://smith.langchain.com/public/f1bdf656-2739-42f7-ac7f-0f1dd712322f/r

示例代码

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.output_parsers import StrOutputParser

model = ChatOpenAI(model="gpt-4")

messages = [
    SystemMessage(content="将以下内容从英语翻译成中文"),
    HumanMessage(content="Let's go for a run"),
]
parser = StrOutputParser()

# 使用Chains方式调用
chain = model | parser  #等于 model.invoke() + parser.invoke()
response = chain.invoke(messages)
print(response)
#我们去跑步吧

LCEL & Runable interface

LCEL 英文全称 LangChain Execution Language(LangChain 表达语言) 是一种声明性的方式来链接 LangChain 组件。 LCEL 从第一天起就被设计为支持将原型投入生产,无需更改代码,从最简单的“提示 + LLM”链到最复杂的链(我们已经看到有人成功地在生产中运行了包含数百步的 LCEL 链)。以下是您可能想要使用 LCEL 的一些原因的几个亮点:

一流的流式支持 当您使用 LCEL 构建链时,您将获得可能的最佳时间到第一个标记(直到输出的第一块内容出现所经过的时间)。对于某些链,这意味着我们直接从 LLM 流式传输标记到流式输出解析器,您将以与 LLM 提供程序输出原始标记的速率相同的速度获得解析的增量输出块。

异步支持 使用 LCEL 构建的任何链都可以使用同步 API(例如,在您的 Jupyter 笔记本中进行原型设计)以及异步 API(例如,在 LangServe 服务器中)进行调用。这使得可以在原型和生产中使用相同的代码,具有出色的性能,并且能够在同一服务器中处理许多并发请求。

优化的并行执行 每当您的 LCEL 链具有可以并行执行的步骤时(例如,如果您从多个检索器中获取文档),我们会自动执行,无论是在同步接口还是异步接口中,以获得可能的最小延迟。

重试和回退 为 LCEL 链的任何部分配置重试和回退。这是使您的链在规模上更可靠的好方法。我们目前正在努力为重试/回退添加流式支持,这样您就可以获得额外的可靠性而无需任何延迟成本。

访问中间结果 对于更复杂的链,访问中间步骤的结果通常非常有用,即使在生成最终输出之前。这可以用于让最终用户知道正在发生的事情,甚至只是用于调试您的链。您可以流式传输中间结果,并且在每个 LangServe 服务器上都可以使用。

输入和输出模式 输入和输出模式为每个 LCEL 链提供了从链的结构推断出的 Pydantic 和 JSONSchema 模式。这可用于验证输入和输出,并且是 LangServe 的一个组成部分。

无缝 LangSmith 追踪 随着您的链变得越来越复杂,准确理解每一步发生的事情变得越来越重要。 使用 LCEL,所有步骤都会自动记录到 LangSmith 中,以实现最大的可观察性和可调试性。

无缝 LangServe 部署 使用 LCEL 创建的任何链都可以轻松地通过 LangServe 部署。

Runable interface(可运行接口)

为了尽可能简化创建自定义链的过程,我们实现了一个 “Runnable” 协议。许多 LangChain 组件都实现了 <font style="color:rgb(28, 30, 33);">Runnable</font> 协议,包括聊天模型、LLMs、输出解析器、检索器、提示模板等等。此外,还有一些有用的基本组件可用于处理可运行对象,您可以在下面了解更多。 这是一个标准接口,可以轻松定义自定义链,并以标准方式调用它们。 标准接口包括:

  • stream: 返回响应的数据块
  • invoke: 对输入调用链
  • batch: 对输入列表调用链

这些还有相应的异步方法,应该与 asyncio 一起使用 <font style="color:rgb(28, 30, 33);">await</font> 语法以实现并发:

  • <font style="color:rgb(28, 30, 33);">astream</font>: 异步返回响应的数据块
  • <font style="color:rgb(28, 30, 33);">ainvoke</font>: 异步对输入调用链
  • <font style="color:rgb(28, 30, 33);">abatch</font>: 异步对输入列表调用链
  • <font style="color:rgb(28, 30, 33);">astream_log</font>: 异步返回中间步骤,以及最终响应
  • <font style="color:rgb(28, 30, 33);">astream_events</font>: beta 流式传输链中发生的事件(在 <font style="color:rgb(28, 30, 33);">langchain-core</font> 0.1.14 中引入)

输入类型输出类型 因组件而异:

组件 输入类型 输出类型
提示 字典 提示值
聊天模型 单个字符串、聊天消息列表或提示值 聊天消息
LLM 单个字符串、聊天消息列表或提示值 字符串
输出解析器 LLM 或聊天模型的输出 取决于解析器
检索器 单个字符串 文档列表
工具 单个字符串或字典,取决于工具 取决于工具

所有可运行对象都公开输入和输出 模式 以检查输入和输出:

  • <font style="color:rgb(28, 30, 33);">input_schema</font>: 从可运行对象结构自动生成的输入 Pydantic 模型
  • <font style="color:rgb(28, 30, 33);">output_schema</font>: 从可运行对象结构自动生成的输出 Pydantic 模型

流式运行对于使基于 LLM 的应用程序对最终用户具有响应性至关重要。 重要的 LangChain 原语,如聊天模型输出解析器提示模板检索器代理都实现了 LangChain Runnable 接口。 该接口提供了两种通用的流式内容方法:

  1. 同步 <font style="color:rgb(28, 30, 33);">stream</font> 和异步 <font style="color:rgb(28, 30, 33);">astream</font>:流式传输链中的最终输出默认实现
  2. 异步 <font style="color:rgb(28, 30, 33);">astream_events</font> 和异步 <font style="color:rgb(28, 30, 33);">astream_log</font>:这些方法提供了一种从链中流式传输中间步骤最终输出的方式。 让我们看看这两种方法,并尝试理解如何使用它们。

Stream(流)

所有 <font style="color:rgb(28, 30, 33);">Runnable</font> 对象都实现了一个名为 <font style="color:rgb(28, 30, 33);">stream</font> 的同步方法和一个名为 <font style="color:rgb(28, 30, 33);">astream</font> 的异步变体。 这些方法旨在以块的形式流式传输最终输出,尽快返回每个块。 只有在程序中的所有步骤都知道如何处理输入流时,才能进行流式传输;即,逐个处理输入块,并产生相应的输出块。 这种处理的复杂性可以有所不同,从简单的任务,如发出 LLM 生成的令牌,到更具挑战性的任务,如在整个 JSON 完成之前流式传输 JSON 结果的部分。 开始探索流式传输的最佳方法是从 LLM 应用程序中最重要的组件开始——LLM 本身!

LLM 和聊天模型

大型语言模型及其聊天变体是基于 LLM 的应用程序的主要瓶颈。 大型语言模型可能需要几秒钟才能对查询生成完整的响应。这比应用程序对最终用户具有响应性的约 200-300 毫秒的阈值要慢得多。 使应用程序具有更高的响应性的关键策略是显示中间进度;即,逐个令牌流式传输模型的输出。 我们将展示使用聊天模型进行流式传输的示例。从以下选项中选择一个:

让我们从同步 <font style="color:rgb(28, 30, 33);">stream</font> API 开始:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hugo_Hoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值