用Ray构建AI代理工作流

APPLICATION Nov 9, 2024

Ray 是什么?为什么它成为我们最喜​​欢的构建AI代理应用程序的部署解决方案?

由于 MotleyCrew 最初是作为多代理框架出现的,因此其核心概念是团队——代理团队背后的协调机制。在探索现实世界的代理应用程序时,我们逐渐确信代理协调对其没有任何特殊性。我们的任务、任务单元和任务图抽象在很多情况下都很有用,但在更多情况下它们要么不适用,要么是多余的。此外,在实际应用中,可维护性和可扩展性等因素比开发的简易性和代码的美观性更为重要。因此,我们研究了现有的部署解决方案,Ray 立即成为我们的最爱之一。

Ray 为 Python 应用程序添加了分布式计算功能。它不是为 AI 应用程序量身定制的解决方案,而是已经存在多年的东西。它允许在多个进程甚至机器上并行运行任务(你可以使用它设置分布式集群!),并使用单个装饰器将常规 Python 函数转换为任务。

Ray 还提供了一种声明计算图的方法。这是通过将一个任务的输出绑定到另一个任务的输入来实现的:

Python:

@ray.remote
def first_task():
    ...

@ray.remote
def second_task(input):
    ...

first_task_ref = first_task.bind()
# the first task's result will be passed to the second task
second_task_ref = second_task.bind(first_task_ref)

ray.get(second_task_ref.execute())  # lazily execute the tasks

execute() 方法是非阻塞的,并返回一个可以由 ray.get() 等待的未来。调用 execute() 时,获取结果所需的所有任务都按拓扑顺序执行。在这种情况下, first_task 首先执行,其输出被输入到  second_task。Ray 的调度程序根据可用资源分派任务。

这种模式类似于 MotleyCrew 的任务 DAG,它设置了任务相互依赖的顺序,只是 Ray 以懒惰而不是急切的方式运行它们。

所有这些使 Ray 的执行 DAG 成为运行代理工作流的绝佳解决方案,自然支持并行执行和批处理。

为了说明这一点,让我们使用 Ray 复制 MotleyCrew 的带有图像的博客示例。这里我们有两个任务:一个是就给定主题撰写博客文章,另一个是说明它。

请查看完整代码,或按照精简版本操作。

第一个任务是使用编写代理和搜索网络的辅助研究代理编写帖子正文。帖子的主题作为参数提供。

Python:

@ray.remote
def produce_blog_post(topic: str):
    researcher = CrewAIMotleyAgent(
        role="Senior Research Analyst",
        goal="Uncover cutting-edge developments in various fields, doing web search if necessary",
        tools=[DuckDuckGoSearchRun()]
    )

    writer = ReActToolCallingMotleyAgent(
        name="AI writer agent",
        tools=[researcher]
    )

    prompt = "<long prompt here about writing a post on the given topic>"

    blog_post = writer.invoke({"prompt": prompt})
    return blog_post

第二项任务是说明帖子。

Python:

@ray.remote
def create_illustrations(blog_post: str):
    image_generator_tool = DallEImageGeneratorTool(...)

    illustrator = ReActToolCallingMotleyAgent(
        name="Illustrator",
        description="Create beautiful and insightful illustrations for a blog post",
        tools=[image_generator_tool],
    )

    prompt = "<long prompt here about illustrating the given post>"

    illustrated_blog_post = illustrator.invoke({"prompt": prompt})
    return illustrated_blog_post

现在让我们形成任务 DAG。有一个称为输入节点的抽象,可用于将输入传递给需要首先执行的任务。我们将通过它传递主题:

Python:

with InputNode() as topic:
    blog_post_ref = produce_blog_post.bind(topic=topic)  # Create writing node
illustrated_blog_post_ref = create_illustrations.bind(
        blog_post=blog_post_ref
    )  # Create illustration node

要执行图表,我们需要做的就是在我们感兴趣的参考对象(在我们的例子中是带插图的博客文章)上调用 execute() 方法。它是异步的,因此我们可以进行批处理。

Python:

topics = ["AI", "neuroscience", "astrophysics"]
blog_post_refs = [illustrated_blog_post_ref.execute(topic) for topic in topics]  # Does not block
print("Dispatched posts creation")

blog_posts = ray.get(blog_post_refs)  # Wait for all the posts

现在我们有 3 篇博客文章,使用 Ray 计算图无缝并行编写!

这篇文章只是触及了 Ray 功能的表面。Ray 最近推出了一项“工作流”功能,提供持久性保证和条件嵌套。它甚至允许实现动态扩展的工作流,例如我们的研究代理。有关更详细的描述,请参阅 Ray 工作流文档


原文链接:Using Ray for building agentic workflows

汇智网翻译整理,转载请标明出处

Tags