老铁们,今天我们来聊聊如何在并行中调用 Runnables。如果你已经对 LangChain 表达语言(LCEL)和链式 Runnables 有所了解,那这篇文章你会觉得相当丝滑。我们要介绍的核心是RunnableParallel
,这个工具可以让我们同时运行多个 Runnables,就像你在家同时做饭、洗衣和学习一样高效。
技术背景介绍
首先,什么是RunnableParallel
呢?说白了,它就是一个字典,你可以把它的值设为任何可以跑起来的东西,比如函数。它会用自己接收到的输入同时调用每个值,最后返回一个字典,里面装着每个值的运行结果。
原理深度解析
RunnableParallel
不仅能让多项操作并行执行,还能在需要的时候调整某一Runnable
的输出以匹配下一个Runnable
的输入格式。通过这种并行化,我们可以创建一个如下所示的计算图:
输入
/ \
/ \
分支1 分支2
\ /
\ /
合并
在这个结构中,各个分支可以独立处理输入,然后最终的结果被合并成一个完整的响应。
实战代码演示
为了让大家能更好地理解,我们直接上代码:
from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
vectorstore = FAISS.from_texts(
["harrison worked at kensho"], 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()
retrieval_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
retrieval_chain.invoke("where did harrison work?")
在上面的代码中,我们创建了一个从文本中检索上下文的链,然后用这个上下文来回答问题。这里用到了FAISS
作为向量存储,搭配使用OpenAIEmbeddings
来提升检索精度。
优化建议分享
在并行执行多个 Runnables 时,记得使用RunnableParallel
。例如,使用它可以同时生成一个关于主题的笑话和一首两行的小诗:
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel
from langchain_openai import ChatOpenAI
model = ChatOpenAI()
joke_chain = ChatPromptTemplate.from_template("tell me a joke about {topic}") | model
poem_chain = (
ChatPromptTemplate.from_template("write a 2-line poem about {topic}") | model
)
map_chain = RunnableParallel(joke=joke_chain, poem=poem_chain)
map_chain.invoke({"topic": "bear"})
补充说明和总结
老铁们,RunnableParallel
不仅使得运行多个进程变得简单,而且这些进程可以独立执行。例如你可以将笑话链和诗歌链同时执行,这在处理相对独立的任务时尤其有用。
今天的技术分享就到这里,希望对大家有帮助。开发过程中遇到问题也可以在评论区交流~
—END—