引言
在现代编程中,异步编程变得越来越重要。尤其是在处理I/O操作和其他需要长时间等待的任务时,异步方法可以显著提高应用程序的性能。本篇文章将探讨如何在异步环境中使用回调(callbacks),为了确保我们的应用程序能够有效运行,我们将学习如何创建和使用自定义回调处理程序,特别是在Python环境中。
主要内容
什么是回调?
回调是一个常用于异步编程的概念,是指一个可调用的代码片段(通常是函数),当一个长时间运行的任务完成时被调用。通过回调,我们可以在等待任务完成时继续执行其他任务,提高程序的并发性。
异步回调处理程序
在使用异步API时,建议使用并扩展 AsyncCallbackHandler
,以避免阻塞事件循环。与同步回调处理程序不同,异步处理程序是非阻塞的,允许程序在等待响应时继续运行其他代码。
代码示例
下面是一个完整的示例,展示了如何使用自定义的同步和异步回调处理程序与 ChatAnthropic
一起工作。
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 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")
chat = ChatAnthropic(
model="claude-3-sonnet-20240229",
max_tokens=25,
streaming=True,
callbacks=[MyCustomSyncHandler(), MyCustomAsyncHandler()],
)
# 注意:为了提高访问稳定性,请考虑使用API代理服务
await chat.agenerate([[HumanMessage(content="Tell me a joke")]])
潜在的挑战和解决方案
线程安全问题
如果在异步方法中使用同步回调处理程序,潜在的问题是它会通过 run_in_executor
运行,这可能导致线程安全问题。确保您的回调处理程序是线程安全的,或者尽量使用异步回调。
Python版本限制
在Python 3.10及以下版本中,调用其他可运行对象时需要手动传播配置或回调,否则这些信息不会传递给子对象。
总结与进一步学习资源
了解如何在异步编程中有效使用回调是提高应用程序响应能力的关键。这不仅限于Python,许多现代编程语言和框架都支持类似的模式。
进一步学习资源
参考资料
- Langchain Documentation: ChatAnthropic, AsyncCallbackHandler, BaseCallbackHandler, HumanMessage, LLMResult
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
—END—