LCEL简化了从基础组件构建复杂链的过程,并支持像流处理、并行处理和日志记录等开箱即用的功能。

最简案例: prompt + model + output parser

最基本也是最常见的 LCEL 案例就是将一个 Prompt 模版跟一个模型串联起来。下面,我们将创建一条链,它接收一个主题并由此生成一个笑话。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

# Prompt模版
prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
# 模型
model = ChatOpenAI(model="gpt-4")
# 输出解析器
output_parser = StrOutputParser()

# 串联成链,用 LCEL 将不同组件组合成一个单一链条
chain = prompt | model | output_parser

# 代入主题内容,生成结果
chain.invoke({"topic": "ice cream"})

运行这段代码,将会输出类似下面的笑话:

1
"Why don't ice creams ever get invited to parties?\n\nBecause they always drip when things heat up!"

在上面代码中,| 符号类似于 Unix 管道操作符,它可以将不同组件链接在一起,并将上一个组件的输出作为下一个组件的输入。在上面这个链条中,用户输入被传递给提示模板,然后提示模板的输出被传递给模型,再将模型的输出传递给输出解析器。

下面,让我们分别来看看这条链中的每个组件,以便能够更好地理解它们的工作原理。

1. Prompt

prompt 是 BasePromptTemplate 的一个实例,它可以接收一个字典形式的模版变量,并返回一个 PromptValue 。在这里,PromptValue 是一个对已就绪的提示词的封装,它可以传递给 LLM(单字符串输入) 或 ChatModel(消息序列输入,多轮对话)。因为它既能以 BaseMessage 进行输出,也能以字符串进行输出,所以它可以与任一种语言模型一起工作。

1
2
3
4
5
6
7
8
9
10
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 传递给 模型。在这里,我们的模型是一个 ChatModel,也就是说它将输出一个 BaseMessage(子类)。

1
2
3
message = model.invoke(prompt_value)
message
# > AIMessage(content="Why don't ice creams ever get invited to parties?\n\nBecause they always bring a melt down!")

如果我们选择的模型是 LLM,将输出一个字符串

1
2
3
4
5
from langchain_openai.llms import OpenAI

llm = OpenAI(model="gpt-3.5-turbo-instruct")
llm.invoke(prompt_value)
# > '\n\nRobot: Why did the ice cream truck break down? Because it had a meltdown!'

3. 输出解析器

最后,我们把模型的输出传递给 output_parser。output_parser 是 BaseOutputParser 的一个实例,可以接收一个字符串或 BaseMessage 对象,并将它们转变成一个字符串。

1
2
output_parser.invoke(message)
# > "Why did the ice cream go to therapy? \n\nBecause it had too many toppings and couldn't find its cone-fidence!"

4. 完整流程

  1. 将选定的主题 {“topic”: “ice cream”} 做为输入。

  2. prompt 组件接收用户输入,使用 topic 字段生成提示词,并由此构建 PromptValue 对象。

  3. model 组件消费上面生成的提示词,将它传递给 OpenAI LLM 进行推理,并将推理结果封装成一个 ChatMessage 对象。

  4. 最后 output_parser 组件读取 ChatMessage,并转化成一个 Python 字符串。

    注:如果需要关注任一组件的输出结果,可以如下逐一测试该链的拆解部分。

1
2
3
4
5
6
7
input = {"topic": "ice cream"}

prompt.invoke(input)
# > ChatPromptValue(messages=[HumanMessage(content='tell me a short joke about ice cream')])

(prompt | model).invoke(input)
# > AIMessage(content="Why did the ice cream go to therapy?\nBecause it had too many toppings and couldn't cone-trol itself!")