Langchain 异步编程
基于 LLM 的应用程序通常涉及大量 I/O 密集型操作,例如调用语言模型、数据库或其他服务的 API。异步编程(或 async programming)是一种允许程序并发执行多个任务而不阻塞其他任务执行的范式,尤其是在 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 接口 的组件,如 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 中的异步代码通常应该开箱即用,性能相对较好,开销最小,在大多数应用程序中不太可能成为瓶颈。
两种主要的开销来源是:
- 当委托给同步方法时,线程间上下文切换的成本。可以通过提供原生的异步实现来解决这个问题。
- 在 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 博客文章。