侧边栏壁纸
博主头像
MobotStone AI

行动起来,活在当下

  • 累计撰写 16 篇文章
  • 累计创建 4 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

2025年了你还不知道怎么用AI 智能体工作流架构吗?

Administrator
2025-05-09 / 0 评论 / 6 点赞 / 166 阅读 / 0 字

这是关于AI智能体系列文章的第三篇。在前一篇文章中,我展示了大模型(LLMs)如何使用工具与现实世界系统互动,无需具体指令就能解决问题。虽然这种灵活性很强大,但它可能以控制力和可靠性为代价。在这里,我将讨论如何通过LLM工作流程来平衡这两种特性。我会先总体介绍如何设计这类系统,最后给出一个实施人工虚拟助手的具体例子。

所谓工作流程,就是产生预期结果的一系列步骤。比如,我发送邮件的流程通常如下:

  1. 有人给我发邮件。

  2. 我阅读邮件。

  3. 如果重要就回复,不重要就删除。

工作流程是构建自动化的核心,让我们能把任务交给计算机处理,从而要么省去亲自动手的麻烦,要么以远超人类的速度完成。

过去要实现这一点,我们需要(非常细致地)定义流程中的每一步,并将这些步骤转化为计算机代码。然而如今,我们给计算机的指令已不必如此精确。

LLM工作流程

大模型(LLMs)提供了一种让计算机按照我们意图行事的新方法。我们不必编写代码,只需用自然语言向LLMs发出指令即可。

这就引出了所谓的自主决策工作流程,本质上就是包含LLM的工作流程。Ng大神创造了自主智能体(agentic)这一术语,用来描述具有一定自主能力(即执行自主行动的能力)的系统,通常由LLM驱动

设计模式

使用LLM构建工作流程时,会涌现出一些常见的设计模式。Anthropic发布的一篇博客对此作了很好的总结。以下是简要回顾。

  • 链式模式 = 一系列基于LLM的步骤

  • 路由模式 = 使用LLM将输入分配给不同的流程

  • 并行处理:分片执行 = 同时执行多个步骤以降低延迟

  • 并行模式:投票表决 = 并行执行相同步骤多次以提高性能

  • 协调器-工作者模式 = 使用LLM分解任务并决定执行哪些步骤

  • 评估-优化模式 = 评估LLM的输出并循环给予反馈

协调器-工作机模式

协调器-工作机模式与前面几种模式有一个关键区别:它的步骤不是按预定义流程执行,而是由LLM动态决定。

这一模式可通过两种方式实现:第一种给予开发者更多控制权,第二种则赋予LLM更大自主权。

  1. 任务交接= 协调器将信息传递给其他LLM,由它们完成任务

  2. 将LLM作为工具使用= 协调器以工具调用的方式使用LLM,并自行整合信息

注:这两种方法并非互斥

评估-优化模式

相对于封闭式工作流的更进一步,是在开放式循环中运行LLM,这个循环会持续执行直到LLM的输出满足某些标准。在这些情况下,定义这些标准(即评估)是关键考虑因素。

通常来说,有三种实现方式:

  1. 基于规则的评估= 通过代码验证LLM的输出

  2. 基于机器学习的评估= 使用机器学习模型预测任务是否充分完成

  3. 用LLM作为评判者= 使用LLM来评估输出质量

LLM并非万能解药

虽然上述设计模式主要围绕LLM展开,但在用它们构建解决方案时,了解其优势与局限至关重要。例如:LLM擅长处理不可预测的用户输入,但若用于从简历中提取关键词,则成本高昂且不可靠。

对此,我认为有个实用框架可将软件分为三种类型。开发者需要根据问题约束条件,判断何种类型最适合工作流中的特定组件

类型

核心操作

可预测性

灵活性

计算复杂度

代码(软件1.0)

编写明确的代码指令

100%知道结果会怎样

只能做你规定的事

最低

机器学习(软件2.0)

筛选优质训练数据

大概能猜到

你教什么它就学什么

较高

LLM提示工程(软件3.0)

设计适合模型的上下文

全凭运气(笑)

能做出超乎你想象的事

最高

示例:人工虚拟助手(AVA)

让我们通过一个具体例子来看看这些概念的实际应用。在这里,我将使用OpenAI的Agents SDK实现一个简单的LLM工作流,为我执行任意的行政任务。

最终系统将能够处理各种请求,例如检索联系人信息和直接在我的Email账户中起草邮件。

系统设计

该工作流包含2个关键组件:规划器代理和执行器代理。它们都是配备了工具的LLM。

规划器具有只读工具。它的职责是收集信息并为执行器编写详细指令。如果不需要任何操作,它会输出一个终止工作流的二进制标志。

执行器的职责是执行“写入”操作。它的工具允许更新本地目录中的文件并向我的Gmail账户起草邮件。

将系统拆分为两个专门的LLM组件的一个关键优势是:它能处理比单一组件更复杂的任务。此外,通过分离读取和写入功能,我们降低了系统执行不良操作(例如删除重要信息)的风险。

创建智能体

我使用OpenAI的Agents SDK来实现规划器和执行器。为了确保规划器能可靠地输出用户备注、执行器指令和一个二进制exec_required标志,我们可以通过Pydantic强制模型使用结构化输出

from pydantic import BaseModel

# defining structured output for Planner
class PlannerOutput(BaseModel):
    exec_required: bool
    exec_inst: str
    user_note: str

创建规划器智能体时我们可以使用这个类,以确保其输出符合此格式。

from agents import Agent, ModelSettings
from tools.functions import read_instructions # custom function
from tools.for_agents import * # custom agent tools

# import openai sk and other environment variables from .env file
from dotenv import load_dotenv
load_dotenv()

# reading instructions from seperate files
planner_instructions = read_instructions("ava.md") 
                           + read_instructions("planner.md")

# creating planner agent
planner_agent = Agent(
    name="Planner Agent",
    instructions=planner_instructions,
    tools=[read_dir_struct, read_file_contents],
    model_settings=ModelSettings(temperature=0.5),
    output_type=PlannerOutput,
)

由于规划器的指令较长,这里不做展示,想要源码的朋友们可以私信。该规划器被赋予两个工具,分别用于读取文件夹目录结构和文件内容,这些工具在此文件中定义。

我们同样可以创建一个执行器代理。不过不需要为它定义特殊的结构化输出,并会为其提供额外的工具来写邮件和覆盖文件。

# read instructions
executor_instructions = read_instructions("ava.md") 
                            + read_instructions("executor.md")
# Executor Agent
executor_agent = Agent(
    name="Executor Agent",
    instructions=executor_instructions,
    tools=[read_dir_struct, read_file_contents, 
               write_email_draft, overwrite_existing_file],
    model_settings=ModelSettings(temperature=0),
)

OAuth 授权

为了能让系统与我的Gmail账户交互,我需要完成一些前期准备工作,具体步骤可以了解如何获取gmail授权。

获取授权后,我们就可以在主脚本中调用该函数。

from tools.gmail import get_gmail_service

# check if token.json exists and initialize Gmail service if needed
if not os.path.exists(os.getenv("GOOGLE_TOKEN_PATH")):
    print("--- Token not found, starting authentication process ---")
    try:
        get_gmail_service()  # This will automatically handle the auth flow
        print("--- Authentication successful ---")
    except Exception as e:
        print(f"--- Authentication failed: {str(e)} ---")
        return

运行工作流

要运行这个工作流,我们需要创建一个异步函数,这样代理(agents)就可以从OpenAI的API流式传输tokens(通过这种方式,我们能实时查看代理在做什么并展示给用户)。我把这个函数称为main()

from agents import Runner

async def main():

    # read request from request.txt
    with open("request.txt", "r") as file:
        request = file.read()

    # run planner agent
    result = Runner.run_streamed(
        planner_agent, 
        request,
    )

    # handle stream events
    print("--- Analyzing ---")
    await handle_stream_events(result)

    # print planner agent's output
    print()
    print("--- Planner Agent Output ---")
    print(result.final_output.user_note)
    print()

    # check if execution is required
    if result.final_output.exec_required:
        result = Runner.run_streamed(
            executor_agent,
            result.final_output.exec_inst
        )
    
        print("--- Executing ---")
        await handle_stream_events(result)

        print()
        print("--- Executor Agent Output ---")
        print(result.final_output)
        print()

handle_stream_events() 是一个自定义函数,它会打印诸如LLM token输出和工具调用之类的信息。这个函数并非我们讨论的核心内容,但感兴趣的读者可以私信获取全部代码

演示

现在我们可以运行这个工作流程了!系统可以访问email-guides文件夹和directory.csv文件,从而帮助撰写特定格式的邮件并了解收件人是谁。下面是我让系统写一封"电话跟进"邮件的示例。

在这里使用带有通用工具的LLMs的好处是系统可以执行各种各样的其他任务,例如:在directory.csv中添加/删除联系人、将新的邮件模板添加到email-guides文件夹、建议在新联系人和现有联系人之间进行三方介绍,以及无数其他功能。

接下来的内容

与传统软件系统相比,LLM工作流让我们能创建更灵活的自动化方案。本文我们回顾了常见设计模式,然后实现了一个由2个配备工具的专用LLM组成的简单智能工作流。

虽然闭合式工作流能在使用LLM构建时兼顾确定性和灵活性,但某些应用场景更适合完全开放式地调用LLM。这就引出了"循环中的LLM"概念,这将是我们系列下一篇文章的重点。

6
博主关闭了所有页面的评论