《LlamaIndex 工作流:事件驱动的抽象与实战指南》
在现代编程中,事件驱动的抽象是一种强大的工具,能够帮助我们构建高效、灵活的系统。LlamaIndex 提供了一种名为“Workflow”的事件驱动抽象,它通过链式处理多个事件来实现复杂的业务逻辑。本文将深入探讨 LlamaIndex 中的 Workflow 如何工作,并通过实际示例帮助你快速上手。
一、Workflow 概述
Workflow 是 LlamaIndex 中的一种事件驱动抽象,用于将多个事件串联起来。每个 Workflow 由多个步骤组成,每个步骤负责处理特定类型的事件并发出新的事件。
二、Workflow 的工作原理
Workflow 通过使用 @step()
装饰器来装饰函数,从而推断每个步骤的输入和输出类型,确保每个步骤只在接收到可接受的事件时运行。
三、创建一个简单的 Workflow
让我们通过一个简单的示例来理解 Workflow 的创建过程。假设我们想要创建一个生成笑话并进行评论的 Workflow。
from llama_index.core.workflow import (
Event,
StartEvent,
StopEvent,
Workflow,
step,
)
# 安装 llama-index-llms-openai 如果你还没有安装
from llama_index.llms.openai import OpenAI
class JokeEvent(Event):
joke: str
class JokeFlow(Workflow):
llm = OpenAI()
@step()
async def generate_joke(self, ev: StartEvent) -> JokeEvent:
topic = ev.topic
prompt = f"Write your best joke about {topic}."
response = await self.llm.acomplete(prompt)
return JokeEvent(joke=str(response))
@step()
async def critique_joke(self, ev: JokeEvent) -> StopEvent:
joke = ev.joke
prompt = f"Give a thorough analysis and critique of the following joke: {joke}"
response = await self.llm.acomplete(prompt)
return StopEvent(result=str(response))
w = JokeFlow(timeout=60, verbose=False)
result = await w.run(topic="pirates")
print(str(result))
四、逐步解析
-
定义 Workflow 事件
class JokeEvent(Event): joke: str
JokeEvent
是一个用户定义的 Pydantic 对象,控制属性和辅助方法。 -
设置 Workflow 类
class JokeFlow(Workflow): llm = OpenAI()
JokeFlow
通过继承Workflow
类来实现。 -
Workflow 入口点
@step() async def generate_joke(self, ev: StartEvent) -> JokeEvent: topic = ev.topic prompt = f"Write your best joke about {topic}." response = await self.llm.acomplete(prompt) return JokeEvent(joke=str(response))
generate_joke
是 Workflow 的入口点,处理StartEvent
并返回JokeEvent
。 -
Workflow 出口点
@step() async def critique_joke(self, ev: JokeEvent) -> StopEvent: joke = ev.joke prompt = f"Give a thorough analysis and critique of the following joke: {joke}" response = await self.llm.acomplete(prompt) return StopEvent(result=str(response))
critique_joke
是 Workflow 的出口点,处理JokeEvent
并返回StopEvent
。 -
运行 Workflow
w = JokeFlow(timeout=60, verbose=False) result = await w.run(topic="pirates") print(str(result))
创建并运行 Workflow,使用
await
等待结果。
五、可视化 Workflow
Workflow 可以通过类型注解进行可视化,帮助调试。
pip install llama-index-utils-workflow
from llama_index.utils.workflow import (
draw_all_possible_flows,
draw_most_recent_execution,
)
# 绘制所有可能的路径
draw_all_possible_flows(JokeFlow, filename="joke_flow_all.html")
# 绘制最近一次执行
w = JokeFlow()
await w.run(topic="Pirates")
draw_most_recent_execution(w, filename="joke_flow_recent.html")
六、全局上下文/状态
你可以选择在步骤之间使用全局上下文,例如多个步骤访问用户的原始查询输入。
from llama_index.core.workflow import Context
@step(pass_context=True)
async def query(self, ctx: Context, ev: MyEvent) -> StopEvent:
query = ctx.data.get("query")
val = ...
result = ...
ctx.data["key"] = val
return StopEvent(result=result)
七、等待多个事件
上下文不仅持有数据,还提供缓冲和等待多个事件的工具。
from llama_index.core import get_response_synthesizer
@step(pass_context=True)
async def synthesize(
self, ctx: Context, ev: QueryEvent | RetrieveEvent
) -> StopEvent | None:
data = ctx.collect_events(ev, [QueryEvent, RetrieveEvent])
if data is None:
return None
query_event, retrieve_event = data
synthesizer = get_response_synthesizer()
response = synthesizer.synthesize(
query_event.query, nodes=retrieve_event.nodes
)
return StopEvent(result=response)
八、手动触发事件
事件可以通过 self.send_event(event)
方法手动触发。
from llama_index.core.workflow import step, Context, Event, Workflow
class MyEvent(Event):
pass
class MyEventResult(Event):
result: str
class GatherEvent(Event):
pass
class MyWorkflow(Workflow):
@step()
async def dispatch_step(self, ev: StartEvent) -> MyEvent | GatherEvent:
self.send_event(MyEvent())
self.send_event(MyEvent())
return GatherEvent()
@step()
async def handle_my_event(self, ev: MyEvent) -> MyEventResult:
return MyEventResult(result="result")
@step(pass_context=True)
async def gather(
self, ctx: Context, ev: GatherEvent | MyEventResult
) -> StopEvent | None:
events = ctx.collect_events([MyEventResult, MyEventResult])
if not events:
return None
return StopEvent(result=events)
九、逐步执行
Workflow 内置了逐步执行的工具,允许你控制执行并调试状态。
w = JokeFlow(...)
w.run_step(topic="Pirates")
while not w.is_done():
w.run_step()
result = w.get_result()
十、装饰非类函数
你还可以在不继承的情况下装饰和附加步骤到 Workflow。
from llama_index.core.workflow import (
Event,
StartEvent,
StopEvent,
Workflow,
step,
)
from llama_index.llms.openai import OpenAI
class JokeEvent(Event):
joke: str
joke_flow = Workflow(timeout=60, verbose=True)
@step(workflow=joke_flow)
async def generate_joke(ev: StartEvent) -> JokeEvent:
topic = ev.topic
prompt = f"Write your best joke about {topic}."
llm = OpenAI()
response = await llm.acomplete(prompt)
return JokeEvent(joke=str(response))
@step(workflow=joke_flow)
async def critique_joke(ev: JokeEvent) -> StopEvent:
joke = ev.joke
prompt = f"Give a thorough analysis and critique of the following joke: {joke}"
response = await llm.acomplete(prompt)
return StopEvent(result=str(response))
十一、总结
LlamaIndex 的 Workflow 提供了一种强大而灵活的事件驱动抽象,帮助你构建复杂的业务逻辑。通过本文的介绍和示例,希望你能快速掌握 Workflow 的使用方法,并在实际项目中应用。
参考文献:
扩展阅读:
希望这篇博客能为你带来启发和帮助,让我们在编程的世界里,更加高效地驾驭事件驱动的抽象!