Skip to main content
Open on GitHub

Langchain 异步编程

先决条件

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

note

您应该在阅读本指南之前熟悉 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 接口 的组件,如 Embedding Models 和 VectorStore,通常也遵循相同的规则,并在同一类中包含方法的异步版本,并加上“a”前缀。

例如,

await some_vectorstore.aadd_documents(documents)

使用 LangChain Expression Language (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 库兼容。它将不适用于 trio 或 curio 等其他异步库。

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

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

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

如何在 ipython 和 jupyter 笔记本中使用​

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