67 LlamaIndex 工作流:事件驱动的抽象与实战指南

《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))
四、逐步解析
  1. 定义 Workflow 事件

    class JokeEvent(Event):
        joke: str
    

    JokeEvent 是一个用户定义的 Pydantic 对象,控制属性和辅助方法。

  2. 设置 Workflow 类

    class JokeFlow(Workflow):
        llm = OpenAI()
    

    JokeFlow 通过继承 Workflow 类来实现。

  3. 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

  4. 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

  5. 运行 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 的使用方法,并在实际项目中应用。

参考文献:

扩展阅读:

希望这篇博客能为你带来启发和帮助,让我们在编程的世界里,更加高效地驾驭事件驱动的抽象!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

需要重新演唱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值