在现代Python开发中,异步编程越来越普遍,尤其是在涉及到AI模型的调用时,为了不阻塞主程序的执行,异步回调显得尤为重要。本指南将向您展示如何在异步环境中有效地使用回调,同时提供详细的代码示例。
技术背景介绍
在异步编程模型中,回调函数用于在特定事件发生后执行某个逻辑,而不阻塞事件循环。对于使用语言模型(LLM)和其他链式调用(Chain/Tool/Agent)的应用程序,通过使用异步回调,您可以实现更高效的程序。
核心原理解析
使用异步回调处理程序 (AsyncCallbackHandler
) 可以确保在异步程序中调用模型时不会阻塞。相反,如果使用同步回调处理程序 (BaseCallbackHandler
),即使在异步方法中使用,系统也会通过 run_in_executor
异步调用它,但这可能引发线程安全问题。
代码实现演示
以下代码展示了如何在异步环境中使用自定义的同步和异步回调处理程序。
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)
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()],
)
async def main():
await chat.agenerate([[HumanMessage(content="Tell me a joke")]])
# 运行异步方法
asyncio.run(main())
应用场景分析
- 实时数据处理:在实时聊天机器人中使用,可以在用户交互过程中调整模型响应。
- 大规模数据分析:在处理大量文本数据时,异步回调可以提高吞吐量。
- API聚合服务:在构建需要调用多个外部API的服务时,异步回调确保通过事件驱动模式优化性能。
实践建议
- 线程安全:确保同步回调处理器是线程安全的,尤其是在多线程环境中使用时。
- 错误处理:在每个回调函数中处理异常,防止未捕获的异常导致程序崩溃。
- 性能监控:监控回调处理的响应时间,确保不会因过度等待导致性能下降。
如果遇到问题欢迎在评论区交流。
—END—