LangChain系列文章
LangChain Expression Language (LCEL)使得从基本组件构建复杂链变得简单,并支持流式处理、并行处理和日志记录等开箱即用的功能。
最基本和常见的用例是将提示模板和模型链接在一起。要看看这是如何工作的,让我们创建一个链条,输入一个主题然后生成一个笑话:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from dotenv import load_dotenv
load_dotenv()
prompt = ChatPromptTemplate.from_template("给我讲个关于{topic}的短篇笑话。")
model = ChatOpenAI()
output_parser = StrOutputParser()
chain = prompt | model | output_parser
respose = chain.invoke({"topic": "冰淇淋"})
print('joke >> ', respose)
输出
zgpeace@zgpeaces-MacBook-Pro:~/Workspace/LLM/langchain-llm-app(develop?) ? python LCEL/pipe_operator.py
joke >> 有一天,冰淇淋和巧克力一起去参加派对。冰淇淋非常兴奋地对巧克力说:“今天真是个美好的日子!我们可以尽情享受派对,还能交到很多新朋友!”
巧克力笑着回答道:“是啊,我也觉得很开心。不过,我希望派对上没有巧克力味的冰淇淋。”
冰淇淋一听,惊讶地问:“为什么?你不喜欢和我一起参加派对吗?”
巧克力笑容满面地解释说:“当然不是!我只是觉得,如果有太多巧克力味的冰淇淋,那会让我觉得自己是个传说中的巧克力涂鸦,而不是独一无二的巧克力块。”
冰淇淋听后,哈哈大笑:“原来你是担心自己会被错认,真是个巧克力的狂热爱好者!”
zgpeace@zgpeaces-MacBook-Pro:~/Workspace/LLM/langchain-llm-app(develop?) ? python LCEL/pipe_operator.py
joke >> 一天,一位小男孩走进一家冰淇淋店。他对店员说:“请给我一杯冰淇淋,但是我只能付1美元。”
店员微笑着回答:“当然可以,小伙子。我们有一种特别的冰淇淋,叫做‘奇迹冰淇淋’,只要1美元就可以买到。”
小男孩很开心地接过冰淇淋,但发现冰淇淋非常小,只有一小勺。他有点失望地问:“这才是‘奇迹冰淇淋’吗?”
店员笑着说:“没错,这是‘奇迹冰淇淋’。你知道为什么吗?因为只要一小勺,你就会觉得它非常好吃,吃完后还会有一美元留在口袋里!”
请注意这行代码,我们使用LCEL将不同的组件拼接成一个单一的链。
chain = prompt | model | output_parser
竖线符号|
类似于Unix管道操作符,它将不同组件链接在一起,将一个组件的输出作为下一个组件的输入。
在这个链条中,用户输入被传递到提示模板,然后提示模板的输出被传递到模型,然后模型的输出被传递到输出解析器。让我们分别看看每个组件,真正理解发生了什么。
“prompt”是一个BasePromptTemplate
,意味着它接受一个模板变量的字典并生成一个PromptValue
。PromptValue
是一个封装完成的提示的包装器,可以传递给LLM
(以字符串作为输入)或ChatModel
(以消息序列作为输入)。它可以与任何语言模型类型一起使用,因为它定义了生成BaseMessages
和生成字符串的逻辑。
prompt_value = prompt.invoke({"topic": "ice cream"})
print('prompt_value >> ', prompt_value)
运行结果:
prompt_value >> messages=[HumanMessage(content='给我讲个关于ice cream的短篇笑话。')]
message = prompt_value.to_messages()
print('message >> ', message)
运行结果:
message >> [HumanMessage(content='给我讲个关于ice cream的短篇笑话。')]
string = prompt_value.to_string()
print('string >> ', string)
运行结果:
string >> Human: 给我讲个关于ice cream的短篇笑话。
PromptValue
然后传递给模型。在这种情况下,我们的模型是ChatModel
,这意味着它将输出BaseMessage
。
model_message = model.invoke(prompt_value)
print('model_message >> ', model_message)
AIMessage(content="Why did the ice cream go to therapy? \n\nBecause it had too many toppings and couldn't find its cone-fidence!")
model_message >> content='有一天,一个小男孩走进一家冰淇淋店。他看了看柜台上的各种各样的冰淇淋口味,然后决定尝试一种他从未尝过的新口味。\n\n他走到柜台前,问店员:“请问,这个新口味的冰淇淋是什么味道的呢?”\n\n店员微笑着回答:“这是我们最新推出的‘辣椒冰淇淋’,非常特别哦!”\n\n小男孩疑惑地问:“辣椒?冰淇淋?这是真的吗?”\n\n店员点点头:“是真的,你可以试试看。”\n\n小男孩有些犹豫,但还是决定尝试一下。他接过一小勺辣椒冰淇淋送进嘴里。几秒钟后,他的脸变得扭曲起来,眼泪顺着脸颊滑落。\n\n店员担心地问:“怎么样?辣吗?”\n\n小男孩用颤抖的声音回答:“不,不是辣。这是最奇怪的冰淇淋口味,它尝起来像是冰凉的火焰!”\n\n店员忍不住笑了起来:“哈哈哈,你被辣椒冰淇淋给骗了!其实,那只是普通的香草冰淇淋,但我们在上面撒了一些辣椒粉,看你的反应会不会很有趣。”\n\n小男孩虽然被捉弄了一下,但随后也加入了店员的笑声。他觉得这个冰淇淋店真是个有趣的地方,于是他决定尝试更多不同的口味,发掘更多有趣的事情。从那天起,他成了这家冰淇淋店的忠实顾客。'
如果我们的模型是一个LLM,它会输出一个字符串。
from langchain.llms import OpenAI
llm = OpenAI(model="gpt-3.5-turbo-instruct")
llm_message = llm.invoke(prompt_value)
print('llm_message >> ', llm_message)
'\n\nRobot: Why did the ice cream go to therapy? Because it had a rocky road.'
llm_message >>
有一天,一个小女孩去买冰淇淋,店员问她想要什么口味的冰淇淋,她说:“我想要巧克力和香草混合的冰淇淋。”店员回答说:“抱歉,我们没有这种口味的冰淇淋。”小女孩沮丧地说:“那就给我一杯巧克力冰淇淋和一杯香草冰淇淋吧,我自己混合一下!”
最后,我们将我们的模型输出传递给输出解析器,它是一个BaseOutputParser
,这意味着它接受字符串或BaseMessage
作为输入。StrOutputParser
专门将任何输入简单地转换为字符串。
output_parser_message = output_parser.invoke(model_message)
"Why did the ice cream go to therapy? \n\nBecause it had too many toppings and couldn't find its cone-fidence!"
output_parser_message >> 有一天,三个朋友去吃冰淇淋。第一个朋友点了一个巧克力口味的冰淇淋,吃了一口后突然皱起了眉头。他说:“这冰淇淋好苦啊!”
第二个朋友很好奇,也点了同样的巧克力口味冰淇淋,结果吃了一口后也皱起了眉头,说:“你说得没错,这冰淇淋怎么这么苦呢?”
第三个朋友看着两位朋友的表情,心想可能他们遇到了特别苦的冰淇淋,于是他决定尝试一下。他点了一个草莓口味的冰淇淋,吃了一口后却开心地笑了起来。他说:“哈哈,你们两个怎么这么笨呀!你们点的是巧克力口味的冰淇淋,当然会苦啦!我点的是草莓口味的,怎么可能会苦呢?”
要跟着这些步骤走:
{"topic": "ice cream"}
PromptValue
。OpenAI LLM
模型进行评估。模型生成的输出是一个ChatMessage
对象。output_parser
组件接受ChatMessage
,并将其转换为Python
字符串,然后从调用方法中返回。请注意,如果你对任何组件的输出感到好奇,你可以随时测试一个较小版本的链条,比如 prompt
或 prompt | model
,以查看中间结果:
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!")
https://github.com/zgpeace/pets-name-langchain/tree/develop
https://python.langchain.com/docs/expression_language/get_started