langChain入门2-LCEL基本示例

LangChain Expression Language 既LCEL,是langchain核心中的核心,可以让我们方便的使用最基本的组件构建复杂的chains,并且支持一些开箱即用的功能包括流式输出、并行、以及日志输出。 我们从两个最常用的langchain例子,来了解LCEL的使用。

基本示例1:prompt + model + output parser

这是最最基础且常见的langChain使用场景,将prompt template和一个llm连接到一起。 这里语言模型我们使用的是openAI chatgpt(如果你没法访问留言),同时你需要安装langchain的一些基本库。

shell 复制代码
pip install --upgrade --quiet langchain-core langchain-community langchain-openai

我们让llm根据我们给出的topic讲一个笑话。

python 复制代码
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()
output_parser = StrOutputParser()

# 这里就是LCEL
chain = prompt | model | output_parser

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

可以看到我们得到了一个笑话(虽然这并不可笑:)。

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

让我们注意这行代码,我们使用LCEL将不同的组件编排到一起。

python 复制代码
chain = prompt | model | output_parser

这个|运算符非常类似unix的管道操作符,一个组件的输出作为另一个组件的输入。

在这个chain中,用户的输入传递给prompt template,组成了完整的template ,然后传递给模型,然后模型输出传递给输出解释器。

让我们看看每个组件实际发生了什么,以便更好的理解。

prompt

prompt是BasePromptTemplate的子类,在这个过程中输入了一个字典类型变量并产出一个PromptValue。

python 复制代码
prompt_value = prompt.invoke({"topic": "ice cream"})  
prompt_value

PromptValue是一个包裹好的prompt,可以传递给语言模型。

python 复制代码
ChatPromptValue(messages=[HumanMessage(content='tell me a short joke about ice cream')])

prompt_value可以转为message形式(结构化)。

python 复制代码
prompt_value.to_messages()
python 复制代码
[HumanMessage(content='tell me a short joke about ice cream')]

也可以转为string

python 复制代码
prompt_value.to_string()
vbnet 复制代码
'Human: tell me a short joke about ice cream'

Model

PromptValue 传递给model,在这个例子中model是一个ChatModel,输出一个BaseMessage。补充一个知识点,在langChain中,大语言模型分为LLM和ChatModel,LLM输入输出都是string,而ChatModel的输入输出都是BaseMessage的子类,分为AIMessage(模型输出)、HumanMessage(用户输入)、SystemMessage(系统输入)。

python 复制代码
message = model.invoke(prompt_value)
message

model的输出是AIMessage类型。

python 复制代码
AIMessage(content="Why don't ice creams ever get invited to parties?\n\nBecause they always bring a melt down!")

Output parser

最后我们的模型输出结果传递给输出解释器,StrOutputParser会将Message转为String。

python 复制代码
output_parser.invoke(message)
swift 复制代码
"Why did the ice cream go to therapy? \n\nBecause it had too many toppings and couldn't find its cone-fidence!"

回顾整个流程

flowchart LR A[Input: topic=ice cream] --Dict--> B[PromptTemplate] --PromptValue-->C[ChatModel]--ChatMessage-->D[StrOutputParser]--String-->E[Result]

首先我们解释一下什么是RAG,RAG(retrieval augmented generation ) 是检索增强式生成的意思,具体点来说就是通过检索一些相关信息,来组成prompt的上下文,llm会根据上下文内容生成,而不是根据自己学习过的知识生成,可以有效降低幻觉问题。

下面我们造一个demo,首先定义好一些知识,然后在输入大模型之前,我们先查询这些知识,根据这些知识,大模型再组织语言输出。

python 复制代码
# Requires:
# 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(search_kwargs={"k": 1})

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?")

可以看到 大模型回答对了我们这个它不了解的问题。

arduino 复制代码
'Harrison worked at Kensho.'

在这个示例中,编排的chain是:

python 复制代码
chain = setup_and_retrieval | prompt | model | output_parser

vectorStore

我首先看看vectorstore,这里使用了词向量技术,将两段内容使用OpenAIEmbeddings转为向量存储到了内存中。(如果不了解词向量,可以简单把它看成把一段文字的意思提取出来,存在一个多维数组中,在查询时,会把问题也矢量化,然后找到之前存入的与之比较匹配的数据,是一种相似性搜索技术。)

python 复制代码
vectorstore = DocArrayInMemorySearch.from_texts(
    ["harrison worked at kensho", "bears like to eat honey"],
    embedding=OpenAIEmbeddings(),
)

retriever

retriever是对vectorstore的一种封装,支持LCEL,我们也可以像调用其他组件一样,直接调用retriever。注意这里search_kwargs={"k": 1}意思是只返回相似度最高的那条数据。

python 复制代码
retriever = vectorstore.as_retriever(search_kwargs={"k": 1})
arduino 复制代码
retriever.invoke("where did harrison work?")

>>> [Document(page_content='harrison worked at kensho')]

RunnableParallel

我们使用RunnableParallel对输入prompt template的数据进行预处理。RunnableParallel可以并行的处理其中的多个组件,最终将结果统一输出。将retriever的结果作为context,用户输入则原封不动作为question(使用RunnablePassthrough()保留原始输入)。最终组成一个dict传递给prompt template。

python 复制代码
setup_and_retrieval = RunnableParallel(
    {"context": retriever, "question": RunnablePassthrough()}
)

后续的步骤和上方的基本示例1相似,这里不再赘述。让我们回顾一下整个流程。

flowchart TD Question --> B[RunnableParallel] B--Question-->C[Retriever] B--Question-->D[RunnablePassThrough] C--context=retreved docs-->E D--question=Quesstion-->E[PromptTemplate] E--PromptValue-->ChatModel--ChatMessage-->StrOutputParser--str-->Result
相关推荐
lucas_AI26 分钟前
ToolSpace:把 804 个真实工具环境打包成 Agent 练级场,35B 小模型暴涨 18 分
llm·agent
怕浪猫9 小时前
小程序成长计划上新:10 亿 Token 现在能调 DeepSeek-v4.1-flash了
人工智能·aigc·ai编程
stormzhangV13 小时前
未来十年的建议
人工智能·aigc·agent
孟健16 小时前
我用Grok Bot本地剪口播视频,3段提示词搞定气口切除、字幕与封面
人工智能·python·aigc
小碗细面17 小时前
Magpie 实战教程:一个本地网关,让 Claude Code 跑 Kimi、Codex 跑 DeepSeek
aigc·ai编程
threerocks20 小时前
2027 年最赚钱的 AI 创业方向
aigc·openai·ai编程
lyai00721 小时前
读完 DeepSeek Harness 源码,我给自己画了一张「最小 CLI Agent」施工图
llm·agent
西安小哥1 天前
大模型 Agent 做日常任务,卡住的从来不是模型能力
aigc
goehou1 天前
缓存该删还是该改,LLM 服务里的双写问题
redis·缓存·llm·一致性·系统设计
又过二十1 天前
我把 5.5 万 Star的AI生成PPT项目ppt-master改造成了桌面应用
aigc·ppt