## 技术背景介绍
在开发复杂的应用程序时,事件驱动编程是一种常见的设计模式。它允许程序在特定操作或状态改变时触发事件,并执行对应的处理程序。在一些长时间运行的任务中,我们可以在各步骤之间调度自定义事件,以此来监控进度或向最终用户报告任务状态。
本文将介绍如何通过LangChain库调度自定义事件,并消费这些事件。
## 核心原理解析
LangChain支持调度自定义回调事件,通过`adispatch_custom_event`方法可以在异步环境下发出事件。此外,你还可以使用`dispatch_custom_event`在同步环境中发送事件。事件包括两个关键属性:`name`(事件名称)和`data`(事件数据),建议数据是JSON可序列化的。
## 代码实现演示
下面的代码演示如何在不同的Python版本中调度自定义事件,并处理这些事件。
### 异步事件调度
如果你使用Python >=3.11,可以自动传播配置;否则需要手动传播:
```python
from langchain_core.callbacks.manager import adispatch_custom_event
from langchain_core.runnables import RunnableLambda
from langchain_core.runnables.config import RunnableConfig
@RunnableLambda
async def foo(x: str) -> str:
await adispatch_custom_event("event1", {"x": x})
await adispatch_custom_event("event2", 5)
return x
async for event in foo.astream_events("hello world", version="v2"):
print(event)
手动配置传播(Python <=3.10)
@RunnableLambda
async def bar(x: str, config: RunnableConfig) -> str:
"""An example that shows how to manually propagate config."""
await adispatch_custom_event("event1", {"x": x}, config=config)
await adispatch_custom_event("event2", 5, config=config)
return x
async for event in bar.astream_events("hello world", version="v2"):
print(event)
异步回调处理
你可以使用异步回调处理器来消费事件:
from typing import Any, Dict, List, Optional
from uuid import UUID
from langchain_core.callbacks import AsyncCallbackHandler
class AsyncCustomCallbackHandler(AsyncCallbackHandler):
async def on_custom_event(self, name: str, data: Any, *, run_id: UUID, tags: Optional[List[str]] = None, metadata: Optional[Dict[str, Any]] = None, **kwargs: Any) -> None:
print(f"Received event {name} with data: {data}, with tags: {tags}, with metadata: {metadata} and run_id: {run_id}")
async_handler = AsyncCustomCallbackHandler()
await foo.ainvoke(1, {"callbacks": [async_handler], "tags": ["foo", "bar"]})
同步事件调度
from langchain_core.callbacks import BaseCallbackHandler
class CustomHandler(BaseCallbackHandler):
def on_custom_event(self, name: str, data: Any, *, run_id: UUID, tags: Optional[List[str]] = None, metadata: Optional[Dict[str, Any]] = None, **kwargs: Any) -> None:
print(f"Received event {name} with data: {data}, with tags: {tags}, with metadata: {metadata} and run_id: {run_id}")
@RunnableLambda
def foo(x: int, config: RunnableConfig) -> int:
dispatch_custom_event("event1", {"x": x})
dispatch_custom_event("event2", {"x": x})
return x
handler = CustomHandler()
foo.invoke(1, {"callbacks": [handler], "tags": ["foo", "bar"]})
应用场景分析
调度自定义事件对于长时间运行的任务非常有用,例如数据处理流程中的多个步骤。通过调度自定义事件,我们可以更好地追踪和记录任务的进展,并提供实时反馈给最终用户。
实践建议
- 确保事件数据是JSON可序列化的,以便更好地传递和处理。
- 在Python <=3.10环境中,记得手动传播配置对象。
- 使用版本
v2
的astream事件以确保正确地看到自定义事件。
如果遇到问题欢迎在评论区交流。
---END---