LangChain表达式LCEL(一)

文章介绍了LangChain表达式语言LCEL,一种支持声明式编程的工具,它提供流式处理、异步API、并行执行、重试机制和中间结果访问等特性,便于构建复杂的AI应用。通过实例展示了如何使用LCEL连接提示模板、模型和输出解析器,以及在检索增强生成中的应用。
摘要由CSDN通过智能技术生成

LangChain表达式LCEL(一)

LCEL介绍

LangChain表达式语言(LCEL)是一种声明式的方式,可以将链条组合在一起。LCEL从一开始就被设计为支持将原型放入生产中,不需要改变任何代码。以下是LCEL的优点:

  • 流式支持:使用LCEL构建链时,可以得到最佳的首次得到令牌的时间(输出的第一块内容出来之前的时间)。例如,从LLM流式传输令牌到一个流式输出解析器,就可以以与LLM提供者输出原始令牌相同的速率得到解析后的、增量的输出块。
  • 异步支持:任何用LCEL构建的链都可以通过同步API以及异步API(在LangServe服务器中)进行调用。
  • 优化的并行执行:只要是LCEL链中有可以并行执行的步骤,就会自动执行,无论是在同步接口还是异步接口中,从而获得最小可能的延迟。
  • 重试和回退:在LCEL链的任何部分配置重试和回退。
  • 访问中间结果:在最终输出产生之前就能访问中间步骤的结果。可以让最终用户知道正在发生什么,甚至只是用来调试你的链。
  • 输入和输出模式:输入和输出模式为每个LCEL链提供了从你的链的结构中推断出来的Pydantic和JSONSchema模式。这可以用于验证输入和输出,是LangServe的一个重要部分。
  • 无缝的LangSmith跟踪集成:随着你的链变得越来越复杂,理解在每一步究竟发生了什么变得越来越重要。 使用LCEL,所有步骤都会自动记录到LangSmith,以实现最大的可观察性和可调试性。
  • 无缝的LangServe部署集成

LCEL使用

LCEL使得从基本组件构建复杂链条变得容易,并且支持诸如流式处理、并行处理和日志记录等开箱即用的功能。

基本示例

最基本和常见的用例是将提示模板和模型链接到一起。

示例:创建一个链条,它将接收一个主题并生成一个笑话

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
model = ChatOpenAI(model="gpt-3.5-turbo")
output_parser = StrOutputParser()

chain = prompt | model | output_parser

chain.invoke({"topic": "ice cream"})

输出:

'Why did the ice cream truck break down? It had too many "scoops"!'

chain = prompt | model | output_parser将不同的组件组合成一个单一的链条

|符号类似于unix管道操作符,它将不同的组件链接在一起,将一个组件的输出作为下一个组件的输入

在这个链条中,用户输入被传递给提示模板,然后提示模板的输出被传递给模型,然后模型的输出被传递给输出解析器。接下来看一下各个组件是如何操作的,以真正理解发生了什么。

组件解析
  1. 提示

    prompt 是一个 BasePromptTemplate,这意味着它接受一个模板变量的字典并生成一个 PromptValuePromptValue 是一个包装完成的提示的包装器,可以传递给 LLM(以字符串作为输入)或 ChatModel(以消息序列作为输入)。它可以与任何语言模型类型一起使用,因为它定义了生成 BaseMessage 和生成字符串的逻辑。

    prompt_value = prompt.invoke({"topic": "ice cream"})
    prompt_value
    

    输出:

    ChatPromptValue(messages=[HumanMessage(content='tell me a short joke about ice cream')])
    
    prompt_value.to_messages()
    

    输出:

    [HumanMessage(content='tell me a short joke about ice cream')]
    
    prompt_value.to_string()
    

    输出:

    'Human: tell me a short joke about ice cream'
    
  2. 模型

    然后将 PromptValue 传递给 model。在这种情况下,我们的 model 是一个 ChatModel,这意味着它将输出一个 BaseMessage

    message = model.invoke(prompt_value)
    message
    

    输出:

    AIMessage(content="Why did the ice cream truck break down? It couldn't handle the rocky road!")
    
  3. 输出解析器

    最后,将 model 的输出传递给 output_parser,它是一个 BaseOutputParser,意味着它可以接受字符串或 BaseMessage 作为输入。StrOutputParser 简单地将任何输入转换为字符串。

    output_parser.invoke(message)
    

    输出:

    "Why did the ice cream truck break down? It couldn't handle the rocky road!"
    
  4. 整个流程

    整个流程的步骤:

    1. 将用户输入的主题作为 {"topic": "ice cream"} 传入
    2. prompt 组件接受用户输入,然后使用主题构建提示,生成 PromptValue
    3. model 组件接受生成的提示,并将其传递给 OpenAI LLM 模型进行评估。模型生成的输出是一个 ChatMessage 对象。
    4. 最后,output_parser 组件接受一个 ChatMessage,将其转换为 Python 字符串,并从 invoke 方法返回。

    graph LR

    ​ A(输入:topic=ice cream) --> |字典| B(PromptTemplate)

    ​ B -->|PromptValue| C(ChatModel)

    ​ C -->|ChatMessage| D(StrOutputParser)

    ​ D --> |字符串| F(结果)

    还可以使用 promptprompt | model查看中间结果。

RAG搜索示例

这个示例中,运行一个检索增强生成链条,在回答问题时添加一些上下文。

# 需要安装:
# pip install langchain docarray tiktoken

from langchain_community.vectorstores import DocArrayInMemorySearch
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_openai.chat_models import ChatOpenAI
from langchain_openai.embeddings import OpenAIEmbeddings

# 向量数据库存储
vectorstore = DocArrayInMemorySearch.from_texts(
    ["harrison worked at kensho", "bears like to eat honey"],
    embedding=OpenAIEmbeddings(),
)
retriever = vectorstore.as_retriever()

template = """Answer the question based only on the following context:
{context}

Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
model = ChatOpenAI()
output_parser = StrOutputParser()

setup_and_retrieval = RunnableParallel(
    {"context": retriever, "question": RunnablePassthrough()}
)
chain = setup_and_retrieval | prompt | model | output_parser

chain.invoke("where did harrison work?")

流程如下:

  1. 首先,创建一个 RunnableParallel 对象,其中包含两个条目。第一个条目 context 将包含检索器检索到的文档结果。第二个条目 question 将包含用户的原始问题。为了传递问题,我们使用 RunnablePassthrough 来复制该条目。
  2. 将上述步骤中的字典提供给 prompt 组件。然后,它将用户输入(即 question)以及检索到的文档(即 context)用于构建提示,并输出 PromptValue
  3. model 组件接受生成的提示,并将其传递给 OpenAI LLM 模型进行评估。模型生成的输出是一个 ChatMessage 对象。
  4. 最后,output_parser 组件接受一个 ChatMessage,将其转换为 Python 字符串,并从 invoke 方法返回。

graph LR
A(问题) --> B(RunnableParallel)
B -->|问题| C(检索器)
B -->|问题| D(RunnablePassThrough)
C -->|context=检索到的文档| E(PromptTemplate)
D -->|question=问题| E
E -->|PromptValue| F(ChatModel)
F -->|ChatMessage| G(StrOutputParser)
G --> |字符串| H(结果)

  • 27
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值