在异步环境中使用回调的实用指南

31 阅读2分钟
# 在异步环境中使用回调的实用指南

## 引言

在现代编程中,异步编程已成为处理大量并发请求的关键技术。特别是当我们使用异步API时,理解如何有效利用回调机制是至关重要的。本指南旨在帮助你在异步环境中使用自定义回调处理器,以避免阻塞事件循环。

## 主要内容

### 理解回调机制

回调是指在特定事件发生时调用的函数。在异步编程中,回调函数通常用于处理异步任务的完成事件。

### 使用AsyncCallbackHandler

为了避免在事件循环中阻塞,推荐使用并扩展`AsyncCallbackHandler`。如果使用同步回调处理器,在异步方法中运行,则可能会导致线程安全问题。

### Python版本注意事项

在Python<=3.10环境中,使用`RunnableLambda``RunnableGenerator``@tool`时,需要确保配置或回调用已正确传递给子可运行对象,否则回调将不会被正确传播。

## 代码示例

以下代码展示了如何在异步环境中使用自定义回调处理器:

```python
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 MyCustomSyncHandler(BaseCallbackHandler):
    def on_llm_new_token(self, token: str, **kwargs) -> None:
        print(f"Sync handler being called in a `thread_pool_executor`: token: {token}")

class MyCustomAsyncHandler(AsyncCallbackHandler):
    """Async callback handler that can be used to handle callbacks from langchain."""

    async def on_llm_start(
        self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
    ) -> None:
        """Run when chain starts running."""
        print("zzzz....")
        await asyncio.sleep(0.3)
        class_name = serialized["name"]
        print("Hi! I just woke up. Your llm is starting")

    async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
        """Run when chain ends running."""
        print("zzzz....")
        await asyncio.sleep(0.3)
        print("Hi! I just woke up. Your llm is ending")

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

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

常见问题和解决方案

  1. 线程安全问题

    • 确保你的回调处理器是线程安全的,尤其是当在异步任务中使用同步回调时。
  2. 回调未传播

    • 在Python<=3.10环境中,请确保在调用其他可运行对象时,正确传递配置或回调。

总结和进一步学习资源

在异步环境中使用回调需要对线程安全和回调传播有深入了解。下一个步骤,你可以查看如何将回调附加到可运行对象的其他指南。

参考资料

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

---END---