Skip to main content
Open on GitHub

使用 LangChain 进行异步编程

前置条件

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

注意

在阅读本文指南之前,您应该熟悉 Python 中的异步编程。如果您不熟悉,请在线查找合适的资源学习如何在 Python 中进行异步编程。 本指南专门专注于让您了解在异步环境中使用 LangChain 所需的知识,假设您已经熟悉异步

Langchain 异步 API

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

通常,任何可能执行 I/O 操作(例如,进行 API 调用、读取文件)的方法都会有一个异步对应版本。

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

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

await some_runnable.ainvoke(some_input)

其他组件,如 嵌入模型向量存储,如果未实现 可运行接口,通常仍遵循相同的规则,并在同一类中包含以 "a" 为前缀的方法的异步版本。

例如,

await some_vectorstore.aadd_documents(documents)

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

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

委托以同步方法

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

当没有异步实现可用时,LangChain 会尝试提供默认实现,即使这会带来 轻微的开销。

默认情况下,LangChain 会将未实现的异步方法的执行委托给其同步对应方法。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,这很可能是原因所在。

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

如何在 ipython 和 jupyter notebook 中使用

自 IPython 7.0 版本起,IPython 支持异步 REPL。这意味着您可以在 IPython REPL 和 Jupyter Notebooks 中直接使用 await 关键字,而无需任何额外配置。更多信息,请参阅 IPython 博客文章