跳到主要内容
Open on GitHub

使用 Langchain 的异步编程

前提条件

基于 LLM 的应用程序通常涉及大量的 I/O 密集型操作,例如向语言模型、数据库或其他服务发出 API 调用。异步编程(或 async 编程)是一种范例,它允许程序并发执行多个任务,而不会阻塞其他任务的执行,从而提高效率和响应能力,尤其是在 I/O 密集型操作中。

注意

在阅读本指南之前,您应该熟悉 Python 中的异步编程。如果您不熟悉,请在网上查找合适的资源来学习如何在 Python 中进行异步编程。本指南专门关注在异步上下文中与 LangChain 一起工作所需了解的内容,并假设您已经熟悉异步编程。

Langchain 异步 API

许多 LangChain API 被设计为异步的,允许您构建高效且响应迅速的应用程序。

通常,任何可能执行 I/O 操作(例如,发出 API 调用、读取文件)的方法都将具有异步 counterparts。

在 LangChain 中,异步实现与同步实现位于相同的类中,异步方法带有 "a" 前缀。例如,同步的 invoke 方法有一个名为 ainvoke 的异步 counterparts。

LangChain 的许多组件实现了 Runnable 接口,其中包括对异步执行的支持。这意味着您可以使用 Python 中的 await 关键字异步运行 Runnables。

await some_runnable.ainvoke(some_input)

其他组件(如 Embedding ModelsVectorStore)虽然没有实现 Runnable 接口,但通常仍然遵循相同的规则,并在同一类中包含带有 "a" 前缀的异步版本方法。

例如,

await some_vectorstore.aadd_documents(documents)

使用 LangChain 表达式语言 (LCEL) 创建的 Runnables 也可以异步运行,因为它们实现了完整的 Runnable 接口

有关更多信息,请查看您正在使用的特定组件的 API 参考

委托给同步方法

大多数流行的 LangChain 集成都实现了对其 API 的异步支持。例如,许多 ChatModel 实现的 ainvoke 方法使用 httpx.AsyncClient 向模型提供商的 API 发出异步 HTTP 请求。

当异步实现不可用时,LangChain 尝试提供默认实现,即使这会产生轻微的开销。

默认情况下,LangChain 会将未实现的异步方法的执行委托给同步 counterparts。LangChain 几乎总是假设同步方法应被视为阻塞操作,并且应在单独的线程中运行。这是通过使用 asyncio.loop.run_in_executor 功能完成的,该功能由 asyncio 库提供。LangChain 使用 asyncio 库提供的默认执行器,该执行器延迟初始化一个线程池执行器,其中包含默认数量的线程,这些线程在给定的事件循环中重用。虽然这种策略由于线程之间的上下文切换而产生轻微的开销,但它保证了每个异步方法都有一个开箱即用的默认实现。

性能

LangChain 中的异步代码通常应该表现良好,开箱即用,开销极小,并且不太可能成为大多数应用程序的瓶颈。

两个主要的开销来源是

  1. 当委托给同步方法时,线程之间上下文切换的成本。这可以通过提供原生异步实现来解决。
  2. LCEL 中,任何作为链一部分出现的“廉价函数”都将被安排为事件循环中的任务(如果是异步的)或在单独的线程中运行(如果是同步的),而不是直接内联运行。

您应该期望的延迟开销在几十微秒到几毫秒之间。

更常见的性能问题来源是用户在异步上下文中意外阻塞事件循环,方法是调用同步代码(例如,调用 invoke 而不是 ainvoke)。

兼容性

LangChain 仅与 asyncio 库兼容,该库作为 Python 标准库的一部分分发。它不适用于其他异步库,如 triocurio

在 Python 3.9 和 3.10 中,asyncio 的任务不接受 context 参数。由于此限制,LangChain 无法在某些情况下自动将 RunnableConfig 向下传播到调用链中。

如果您在使用 Python 3.9 或 3.10 的异步代码中遇到流式传输、回调或追踪问题,这很可能是原因。

请阅读 Propagation RunnableConfig 以了解更多详细信息,以了解如何手动将 RunnableConfig 向下传播到调用链中(或升级到 Python 3.11,其中不再存在此问题)。

如何在 ipython 和 jupyter notebooks 中使用

从 IPython 7.0 开始,IPython 支持异步 REPL。这意味着您可以在 IPython REPL 和 Jupyter Notebooks 中使用 await 关键字,而无需任何额外的设置。有关更多信息,请参阅 IPython 博客文章


此页是否对您有帮助?