跳到主要内容
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 的许多组件都实现了 Runnable 接口,该接口支持异步执行。这意味着您可以使用 Python 中的 await 关键字异步运行 Runnables。

await some_runnable.ainvoke(some_input)

其他组件,例如未实现 Runnable 接口嵌入模型向量存储,通常仍遵循相同的规则,并在同一个类中包含带“a”前缀的异步版本方法。

例如,

await some_vectorstore.aadd_documents(documents)

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

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

委托给同步方法

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

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

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

性能

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

开销的两个主要来源是

  1. 委托给同步方法 时,线程间上下文切换的开销。这可以通过提供原生的异步实现来解决。
  2. LCEL 中,链中出现的任何“廉价函数”将要么作为任务调度到事件循环中运行(如果它们是异步的),要么在单独的线程中运行(如果它们是同步的),而不是直接内联运行。

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

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

兼容性

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

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

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

请阅读 RunnableConfig 传播 以获取更多详情,了解如何手动将 RunnableConfig 沿着调用链向下传播(或升级到 Python 3.11,在该版本中这不再是问题)。

如何在 IPython 和 Jupyter Notebooks 中使用

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