# 在异步环境中使用回调的实用指南
## 引言
在现代编程中,异步编程已成为处理大量并发请求的关键技术。特别是当我们使用异步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")]])
常见问题和解决方案
-
线程安全问题
- 确保你的回调处理器是线程安全的,尤其是当在异步任务中使用同步回调时。
-
回调未传播
- 在Python<=3.10环境中,请确保在调用其他可运行对象时,正确传递配置或回调。
总结和进一步学习资源
在异步环境中使用回调需要对线程安全和回调传播有深入了解。下一个步骤,你可以查看如何将回调附加到可运行对象的其他指南。
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---