[在异步环境中使用回调:全面指南]

122 阅读2分钟

在异步环境中使用回调:全面指南

引言

在现代编程中,回调在异步环境中扮演着重要角色。特别是当我们处理大型语言模型(LLM)或其他需要异步处理的任务时,理解如何有效使用回调可以帮助我们提高程序的效率和稳定性。本篇文章将介绍如何使用与扩展异步回调处理程序(AsyncCallbackHandler),并给出完整的代码示例。

主要内容

1. 回调的基础

回调是指把一个函数作为参数传递给另一个函数,在满足特定条件时调用它。回调可以分为同步和异步两种类型。在异步环境中,异步回调可以避免阻塞事件循环,从而提高程序的并发性能。

2. 创建自定义的异步回调处理程序

在异步环境中使用自定义回调处理程序可以帮助我们灵活地处理不同的事件。我们需要确保回调处理程序是线程安全的,以免在多线程环境中引发问题。

import asyncio
from typing import Any, Dict, List
from langchain_anthropic import ChatAnthropic
from langchain_core.callbacks import AsyncCallbackHandler, BaseCallbackHandler
from langchain_core.messages import HumanMessage
from langchain_core.outputs import LLMResult

class MyCustomAsyncHandler(AsyncCallbackHandler):
    """异步回调处理程序,用于处理来自 LangChain 的回调。"""

    async def on_llm_start(self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any) -> None:
        """在链开始运行时调用。"""
        print("zzzz....")
        await asyncio.sleep(0.3)
        print("Hi! I just woke up. Your llm is starting")

    async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
        """在链结束运行时调用。"""
        print("zzzz....")
        await asyncio.sleep(0.3)
        print("Hi! I just woke up. Your llm is ending")

3. 使用自定义回调

我们可以在初始化 Chat 模型时,将自定义回调处理程序传入 callback 参数中。

# 使用API代理服务提高访问稳定性
chat = ChatAnthropic(
    model="claude-3-sonnet-20240229",
    max_tokens=25,
    streaming=True,
    callbacks=[MyCustomAsyncHandler()]
)

await chat.agenerate([[HumanMessage(content="Tell me a joke")]])

常见问题和解决方案

  1. 线程安全问题: 确保回调处理程序是线程安全的,特别是在使用 run_in_executor 时。

  2. 回调传播问题: 在 python<=3.10 中,必须显式传递配置或回调,以确保在嵌套调用时回调被正确传播。

总结和进一步学习资源

回调是管理异步操作的重要工具。通过理解和使用异步回调处理程序,我们可以在避免阻塞事件循环的同时灵活地响应不同的事件。建议进一步阅读有关可运行对象(Runnable)和工具(@tool)如何与回调交互的资源。

参考资料

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---