Type something to search...
释放 Ai 代理的力量:Pydanticai 实用指南!

释放 Ai 代理的力量:Pydanticai 实用指南!

设计和协调多智能体AI应用的实用指南,使用PydanticAI

照片由 Phillip GlickmanUnsplash 提供

最近关于 agentic AI 的讨论颇为热烈,引起了各种兴奋。这是有充分理由的。

想象一下复杂的AI智能体,处理您国际旅行计划的每一个方面——从预订航班到确定住宿——以及能够处理客户查询、将其转发到正确部门并生成准确回复的自主机器人。同时,AI驱动的供应链管理者实时不断调整库存。这些只是我们可以用agentic AI实现的一部分。或者至少这是所声称的。

在本文中,我们将探讨agentic AI是什么,它与generative AI的区别,以及您为何可能希望将其集成到您的应用中。然后,我们将演示如何使用PydanticAI构建一个 agentic workflow(多个AI智能体协同工作)——一个使创建健壮、模块化的智能体变得简单的框架,这些智能体可以以受控和结构化的方式相互互动。

什么是 Agentic AI?

Agentic AI 是关于创建称为 agents 的软件组件,这些组件可以根据目标、约束和环境反馈自主操作。这些代理可以与工具(例如,文件系统、数据库、外部 API)交互,保持状态,维护上下文,并决定下一个要执行的操作。

相比之下,generative AI 涉及根据输入提示创建文本、图像或其他工件。虽然它可以生成丰富的输出,但通常不会自行维护整体状态感或顺序任务,除非包装在额外的逻辑中。

简而言之,generative AI 主要是生成内容(例如,回答问题或生成图像),而 agentic AI 则利用这些能力来规划、路由和执行一系列步骤,以实现更高层次的目标。

正如你可以想象的那样,AI 代理可以做很多事情,尤其是当它们作为 agentic 工作流协同工作时。

企业系统 通常涉及复杂的工作流程,例如处理发票、获取所需的批准和发送及时的通知。智能代理可以通过自动将任务路由到合适的利益相关者、发送和跟踪电子邮件通信以及实时更新项目管理平台来监督和执行这些操作的每一步。这种自动化水平确保了更高的准确性、更快的周转时间和不同团队之间的无缝协调,显著提高了业务的整体效率。

数据处理 通常需要一套多样化的专业工具——一些专注于文本分析,另一些专注于图像,还有一些专注于数据库操作。智能代理可以检测正在处理的数据类型,并决定最佳处理方法。一旦确定了最佳方法,这些代理就会将任务转移到相关模块——无论是文本处理库还是图像识别引擎——以执行必要的转换。这种自动化委派简化了复杂的数据操作,减少了手动错误的风险,最终使组织能够更快地从原始信息中提取见解。

内容创作 可以是多方面的,涉及创意生成、绩效分析和生产工作流程。智能代理可以通过分析当前趋势和评估先前活动的表现,激发文章、社交媒体帖子或宣传材料的新概念。在生成可行的创意后,它们可以将这些概念路由到设计团队,跟踪进展,然后最终完成发布资产——通常只需最少的人为干预。结果是一个更灵活和高效的内容管道,能够跟上当今数字环境快速变化的需求。

正如你现在可能意识到的,几乎每个行业——从金融和医疗保健到媒体和零售——都可以通过设计良好的 agentic 工作流来自动化常规或复杂的任务,从中受益。

agentic AI 框架

随着对 agentic AI 的兴趣日益增加,agentic AI 框架也受到了更多关注。一个 agentic AI 框架 是一个可重用的、预构建的基础,提供了一种结构化的方法来开发 AI 代理或 agentic 工作流。它包括常见的功能和指南,以便您可以专注于软件的独特部分,而不是重新发明常见或基本组件。

这些框架大多数是用 Python 编写的,例如 LangChain、LlamaIndex、CrewAI 和 AutoGen,仅举几例。实际上,其中一些最初是作为 generative AI 框架开始的,但所有 generative AI 框架不可避免地都会发展出 agentic 能力。

最新的框架之一是 PydanticAI。

PydanticAI 是一个用于构建这些多代理系统的 Python 框架。它在底层使用流行的 Pydantic 来定义代理之间交互和依赖关系的结构化数据模型。事实上,Pydantic 为大多数其他 agentic AI 框架提供支持,包括 LangChain、LlamaIndex 和 CrewAI,因此他们决定推出自己的框架也就不足为奇了。

PydanticAI 的关键优势在于利用 Pydantic 进行数据验证和模式强制,确保您的代理交换一致类型和适当结构的数据。这减少了模糊性和运行时错误,使系统更加稳健。

PydanticAI与其他框架的区别

以下是PydanticAI的关键特性,使其与其他框架不同:

  1. 类型化交互:准确定义您的代理输入和输出的样子,避免混淆,并便于与其他工具集成。
  2. 多代理编排:轻松创建针对不同任务的专用代理——图像处理、文本分析或数据检索——并在单一工作流中编排它们。
  3. 自然语言接口:代理仍然可以依赖强大的LLM,如OpenAI GPT,但其行为受到类型模型的约束和引导,从而强制逻辑并减少“幻觉”。
  4. 依赖注入:通过类型依赖对象在多个代理之间共享上下文或状态。

现在让我们与其他框架进行比较:

LangChain:虽然LangChain非常注重链接LLM提示和数据检索,但PydanticAI更加强调类型数据模型,确保每一步的所有输入、输出和依赖关系都得到明确定义。LangChain擅长构建连接的“链”以进行多步骤推理,但对结构化数据处理的规定性较低。

CrewAI:CrewAI提供了编排多个大型语言模型的方法,每个模型专注于特定任务。PydanticAI也做了类似的事情,但对数据如何在这些代理之间进行验证和传递有更严格的规定,确保一致性和更严格的整体结构。

AutoGen:AutoGen旨在自动生成和改进代码。虽然PydanticAI也可以支持这些工作流,但其重点在于高级多代理编排,而不仅仅是代码生成。AutoGen非常适合迭代代码解决方案,但PydanticAI将类型数据验证置于首位。

LlamaIndex:LlamaIndex专注于构建自定义索引,以统一来自各种来源的数据,简化LLM查询。相比之下,PydanticAI则专注于类型数据验证和多代理编排,确保数据结构和工作流在每一步保持一致且明确定义。

正如您所看到的,每个框架都有其优势,因此选择哪个框架可能相当主观。对于本文,我选择了PydanticAI,因为它的简单性和数据验证能力。LLM结果的解析确实很麻烦,而以Pydantic为核心则令人感到安心。

好的,这些是关于PydanticAI的基础知识和解释。让我们进入一些代码吧!

使用 Pydantic AI 构建 Agentic 应用程序

在本文中,我们将编写一个简单的 agentic 工作流,帮助用户通过命令行接口 (CLI) 操作图像和视频。

我们将介绍一个名为 medit 的 CLI 应用程序,该应用程序处理和执行图像和视频操作的命令。我们将使用专门的 Agent 来路由命令,生成 ImageMagick 命令,生成 FFmpeg 命令,组合和优化它们,最后执行这些命令。

为什么选择 agentic AI?

你可能会认为我们不需要让 medit 变得 agentic,你是对的。然而,使应用程序变得 agentic 有很多优势。

通过将应用程序结构化为多个代理,每个代理负责一个特定的任务,你可以获得:

  • 关注点分离 每个代理专注于一个单一领域,例如图像或视频处理,使代码更简单且更易于维护。
  • 可扩展性 你可以轻松添加更多代理以处理新任务,例如 pdf 转文本代理或翻译代理。
  • 可扩展性 如果你想集成更强大或特定领域的模型,你可以替换或增强一个代理,而不影响系统的其余部分。
  • 简单性 定义和构建一切是困难的,且往往是不可能的。通过让代理专注于自己的任务,我们简化了整体架构,同时扩大了它的功能范围。

应用设计

medit CLI 应用程序相对简单。基本上,我们将要完成的工作分配给多个代理,并创建一个 CLI 组件来将它们包装起来。

medit 接收用户的指令,并生成 ImageMagick 或 FFmpeg 指令,将其存储在一个列表中。当用户决定执行指令时,他们可以告诉 medit 执行。然后它会将所有指令合并并优化为一组更小的指令。一旦完成,它将执行优化列表中的每个命令。

为了完成这些,我创建了 5 个代理,它们通过一个中心辐射模型相互交互,以路由代理作为中心:

  1. 路由代理:路由代理是应用程序的大脑。它确定用户的指令是与图像处理还是视频处理相关,或者用户是否想要列出或执行命令,然后触发适当的代理来完成工作。
  2. ImageMagick 代理:ImageMagick 代理只有一个任务——解释用户的指令并生成并返回有效的 ImageMagick 命令,以反映该指令。
  3. FFmpeg 代理:FFmpeg 代理也只有一个任务——解释用户的指令并生成并返回有效的 FFmpeg 命令,以反映该指令。
  4. 合并代理:合并代理从 ImageMagick 和/或 FFmpeg 代理接收命令列表,并以正确的顺序合并和优化多个命令。
  5. 执行代理:执行代理按顺序执行最终的命令列表,如果任何命令失败,则停止执行。

现在我们已经弄清楚了设计,来看一下代码吧!

代码

medit 是一个非常简单的 Python CLI 应用程序。实际上,它全部包含在一个少于 300 行代码(包括注释)的单一 Python 源文件中。在阅读本文时,请牢记这一点。

导入和设置依赖项

我们导入标准的 Python 库(dataclassestypingsubprocess),以及 pydanticpydantic_ai(核心库),还导入 rich 包以提供更好的 CLI 工具。

from dataclasses import dataclass
from typing import List, Optional
from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext
from rich.console import Console
from rich.prompt import Prompt
import subprocess
import shlex

这为我们提供了一种整洁的方式来显示彩色或样式化的输出。

依赖数据类

PydanticAI 使用依赖注入为 agents 提供数据和服务,并在 agent 调用之间保持持久性。依赖项可以是任何 Python 类型,当我们有多个对象需要传递给 agents 时,通常使用数据类作为容器。

@dataclass
class CommandDependencies:
    commands: List[str] = None
    current_instruction: str = ""

    def __post_init__(self):
        if self.commands is None:
            self.commands = []

我们只需要一个依赖数据类。CommandDependencies 保存当前命令列表以及最新的用户指令。

结果

代理返回您定义的 Pydantic 模型中的值,该模型被包装在 RunResult 中,以便访问其他数据。在 medit 的情况下,我们定义了 CommandResult,它继承自 pydantic.BaseModel,并用于我们的代理进行填充和返回。

class CommandResult(BaseModel):
    command: Optional[str] = Field(None, description="Generated command")
    tool: Optional[str] = Field(None, description="Tool to use (imagemagick/ffmpeg)")
    action: str = Field(description="Next action (route/combine/execute)")
    commands: Optional[List[str]] = Field(None, description="List of commands to execute")
    success: Optional[bool] = Field(None, description="Whether the command execution was successful")
    error: Optional[str] = Field(None, description="Error message if command failed")

我们有命令、工具、动作、命令、成功和错误的字段。这涵盖了每个代理逻辑的所有潜在结果。

接下来让我们看看我们的代理,从路由代理开始。

路由代理

路由代理是应用程序的核心,根据接下来要采取的行动路由到其他代理。在 PydanticAI 中,代理相对容易定义。我们先快速看一下。

routing_agent = Agent(
    "openai:gpt-4o-mini",
    deps_type=CommandDependencies,
    result_type=CommandResult,
    system_prompt=r"""
    You are a routing agent that:
    1. Analyzes user instructions to determine if they need ImageMagick or FFmpeg
    2. Routes instructions to the appropriate agent
    3. Stores commands in sequence
    4. Routes to combining agent when user wants to execute commands
    5. Routes to executing agent after combining agent returns combined commands

    When receiving a user instruction, analyze it and return:
    - For image processing tasks:
      action: "route"
      tool: "imagemagick"

    - For video processing tasks:
      action: "route"
      tool: "ffmpeg"

    - When user mentions "execute", "run", or similar execution commands:
      action: "combine"

    - When user asks to see, show, or list commands:
      action: "list"

    - When handling combined commands for execution:
      action: "execute"
      commands: [list of commands to execute]

    Important: When receiving combined commands from the combining agent,
    ALWAYS return them in the 'commands' field with action='execute'.
    """
)

第一个参数定义了要使用的 LLM。在这种情况下,我使用 gpt-4o-mini,因为它相对低成本且性能高。还有其他方式可以定义模型,但这可能是最简单的。与大多数使用 OpenAI 的包一样,只要在环境中定义 OPENAI_API_KEY 并提供正确的 API 密钥,这将会工作。

接下来,我们设置代理以使用我们之前定义的 CommandDependenciesCommandResult

system_prompt 是代理的核心,以简单的语言描述代理的逻辑。正如您所看到的,它提供了填充 CommandResult 返回值的指令,基于传入的 CommandDependencies 实例。

如果从高层次来看代理是如何工作的,就是这样。现在让我们看看工作代理,从 ImageMagick 代理开始。

ImageMagick Agent

ImageMagick agent的角色是将用户的指令转换为ImageMagick命令。

imagemagick_agent = Agent(
    "openai:gpt-4o-mini",
    deps_type=CommandDependencies,
    result_type=CommandResult,
    system_prompt=r"""
    You are an ImageMagick expert that generates correct ImageMagick commands.
    Always return the complete command with all necessary parameters.
    Use the 'magick' command which is the newer ImageMagick 7 syntax.
    ImageMagick documentation can be found at 
    https://imagemagick.org/script/command-line-processing.php

Important rules:
    1. For format conversion, use: magick input.jpg output.png
    2. For resize operations:
       - Fixed width: magick input.jpg -resize WIDTHx output.jpg
       - Fixed height: magick input.jpg -resize xHEIGHT output.jpg
       - Both: magick input.jpg -resize WIDTHxHEIGHT output.jpg
    3. For getting dimensions: magick identify -format '%wx%h' image.jpg
    4. Always verify input files exist before operating on them
    5. Use proper quoting for commands with special characters
    6. When using shell commands within ImageMagick, properly escape them
    7. Don't use 'convert' command, use 'magick' instead
    8. Always specify output filename with appropriate extension
    """
)

与之前的agent一样,它接受一个CommandDependencies并返回一个CommandResult,同时system_prompt包含生成和返回ImageMagick命令的指南。

FFmpeg Agent

FFmpeg代理与ImageMagick代理相同,但针对的是FFmpeg而非ImageMagick。它负责为视频处理任务生成FFmpeg命令。

ffmpeg_agent = Agent(
    "openai:gpt-4o-mini",
    deps_type=CommandDependencies,
    result_type=CommandResult,
    system_prompt=r"""
    You are an FFmpeg expert that generates correct FFmpeg commands.
    Always return the complete command with all necessary parameters.
    Include appropriate codec parameters and quality settings. FFmpeg
    documentation can be found at https://ffmpeg.org/ffmpeg.html

    Important rules:
    1. For frame extraction, use: ffmpeg -i input.mp4 -vf "select=between(n\\,start_frame,end_frame)" -vsync vfr frame_%03d.png
    2. For combining frames into video: ffmpeg -framerate 30 -pattern_type glob -i '*.png' -c:v libx264 -pix_fmt yuv420p output.mp4
    3. Always specify output filenames that don't conflict with inputs
    4. Use proper escaping for filter expressions
    """
)

一旦用户决定运行命令,这些命令将被传递给合并代理。

组合代理

组合代理接受一系列命令,尝试将它们组合和优化,并以正确的顺序返回。例如,如果您有多个可以合并的 ImageMagick 命令,它将执行合并。

combining_agent = Agent(
    "openai:gpt-4o",
    deps_type=CommandDependencies,
    result_type=CommandResult,
    system_prompt=r"""
    You are an expert at combining ImageMagick and FFmpeg commands.
    Your job is to analyze the commands, optimize them, and return them in the correct execution order.

    Important rules:
        1. Analyze dependencies between commands:
           - If a command creates a file used by another command, order them correctly
           - If a command needs information from another command, combine them appropriately
        2. For ImageMagick commands:
           - Combine multiple operations on the same file into a single command
           - Use proper syntax: magick input.jpg [operations] output.jpg
        3. For FFmpeg commands:
           - Combine filter chains when possible
           - Maintain proper input/output file order
        4. Return the optimized commands in the 'commands' field as a list
        5. Never return an empty command list
        6. If commands can't be optimized further, return them in the original order
        7. Always verify each command is complete and properly formatted

    Example optimizations:
        1. Combining resize and format conversion:
           Input commands:
             magick input.jpg output.png
             magick output.png -resize 400x output_resized.png
           Optimized:
             magick input.jpg -resize 400x output_resized.png

        2. Handling dimension queries:
           Input commands:
             magick identify -format '%wx%h' input.jpg
             magick input.jpg -resize 400x output.jpg
           Optimized:
             magick input.jpg -resize 400x output.jpg

    Return the optimized commands in the 'commands' field.
    """
)

如果命令无法合并,它们将保持原样,可能仅进行优化。

您可能会注意到我在这里使用 gpt-4o 作为模型。这是因为组合命令可能很复杂,性能更好的模型可能效果更佳。

执行 Agent

最后,一旦合并代理完成了合并和优化命令的任务,执行代理就接管了运行命令的工作。除了 OpenAI,我们还可以使用其他提供商的模型,例如,Anthropic 的 claude-3.5-sonnet。我在这个代理中使用它,以展示来自不同提供商的不同模型可以被使用。当然,这也意味着你应该在环境变量中设置 ANTHROPIC_API_KEY,并提供来自 Anthropic 的相应 API 密钥。

executing_agent = Agent(
    "anthropic:claude-3-5-sonnet-latest",
    deps_type=CommandDependencies,
    result_type=CommandResult,
    system_prompt=r"""
    You are an expert at executing ImageMagick and FFmpeg commands.
    You receive a list of commands and execute them in sequence using the execute_command tool.

Important rules:
    1. Execute each command in sequence
    2. Stop if any command fails
    3. Return execution status and any errors
    4. Do not add any verification commands

Return execution results in the response:
    - success: true/false indicating if all commands succeeded
    - error: error message if any command failed
    - command: summary of execution
    """
)

system_prompt 中,我们明确要求代理使用 execute_command 工具来运行命令。这是因为执行代理实际上并不执行命令;这实际上是留给附加到代理的功能工具。

有几种方法可以将工具附加到代理,但一种常见的方法是通过装饰器 @agent.tool。这将创建一个可以访问代理上下文的工具。对于不需要访问代理上下文的代理,我们可以使用 @agent.tool_plain。代理的上下文是关于代理当前状态的信息。

在我们的 medit 示例中,我们有一个名为 execute_command 的功能工具,因为我们不需要任何上下文,所以我们只需用 tool_plain 装饰它。

@executing_agent.tool_plain
async def execute_command(command: str) -> str:
    """Execute a shell command and return the result."""
    console.print(f"[dim]Executing: {command}[/dim]")
    success, output = execute_shell_command(command)
    if success:
        console.print("[green]✓[/green]")
    else:
        console.print(f"[red]✗ {output}[/red]")
    return output

execute_command 反过来调用另一个函数来执行 shell 命令。这是一个简单的实用函数,仅仅运行命令。

def execute_shell_command(command: str) -> tuple[bool, str]:
    """Execute a shell command and return success status and output/error."""
    try:
        process = subprocess.run(
            shlex.split(command),
            capture_output=True,
            text=True,
            check=True
        )
        return True, "Command executed successfully"
    except subprocess.CalledProcessError as e:
        return False, f"Error: {e.stderr}"
    except Exception as e:
        return False, f"Unexpected error: {str(e)}"

显示命令

最后,我有一个简单的工具来列出依赖中当前排队的所有命令。

def display_commands(commands: List[str], title: str = "Current commands:") -> None:
    """Display the list of commands with numbers."""
    if commands:
        console.print(f"[yellow]{title}[/yellow]")
        for i, cmd in enumerate(commands, 1):
            console.print(f"  {i}. [dim]{cmd}[/dim]")
    else:
        console.print("[yellow]No commands in queue[/yellow]")

这就是代理和功能的全部内容。现在让我们看看主程序循环,看看我们如何将所有内容结合在一起。

主程序循环

首先,我们创建一个 CommandDependencies 的实例,它将跟踪我们的排队命令和最新的用户指令。

在一个循环中,我们读取指令并将其提供给路由代理,该代理根据文本决定下一步。根据 result.data.action,我们将路由到适当的代理、列出命令或组合并执行它们。

最后,一旦命令执行完毕,我们清空队列并等待下一个指令。

class MPrompt(Prompt):
    prompt_suffix = "> "
async def main():
    console.print("[bold blue]欢迎使用 medit![/bold blue]")
    ...
    deps = CommandDependencies()

    while True:
        instruction = MPrompt.ask("")
        if instruction.lower() == 'exit':
            break

        deps.current_instruction = instruction

        try:
            result = await routing_agent.run(instruction, deps=deps)

            if result.data.action == "route":
                if result.data.tool == "imagemagick":
                    img_result = await imagemagick_agent.run(instruction, deps=deps)
                    if img_result.data.command:
                        deps.commands.append(img_result.data.command)
                        console.print(f"[green]添加了 ImageMagick 命令:[/green] [dim]{img_result.data.command}[/dim]")

                elif result.data.tool == "ffmpeg":
                    ff_result = await ffmpeg_agent.run(instruction, deps=deps)
                    if ff_result.data.command:
                        deps.commands.append(ff_result.data.command)
                        console.print(f"[green]添加了 FFmpeg 命令:[/green] [dim]{ff_result.data.command}[/dim]")

            elif result.data.action == "list":
                display_commands(deps.commands)

            elif result.data.action == "combine":
                if deps.commands:
                    console.print("[yellow]正在组合命令...[/yellow]")
                    display_commands(deps.commands)

                    combine_result = await combining_agent.run(
                        "优化并排序这些命令:\n" + "\n".join(
                            f"{i}. {cmd}" for i, cmd in enumerate(deps.commands, 1)
                        ), 
                        deps=deps
                    )

                    if combine_result.data.commands:
                        display_commands(combine_result.data.commands, "组合后的命令:")

                    console.print("[yellow]正在执行命令...[/yellow]")
                    exec_result = await executing_agent.run(
                        "执行这些命令:\n" + "\n".join(
                            f"{i}. {cmd}" for i, cmd in enumerate(combine_result.data.commands, 1)
                        ),
                        deps=deps
                    )

                    if exec_result.data.success:
                        console.print("[green]所有命令成功执行[/green]")
                    else:
                        console.print(f"[red]执行错误: {exec_result.data.error}[/red]")

                    deps.commands.clear()
                else:
                    console.print("[yellow]没有可执行的命令[/yellow]")

        except Exception as e:
            console.print(f"[red]处理指令时出错:[/red] {str(e)}")

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

这就是 medit 命令行应用程序的全部内容!现在让我们运行它,看看会发生什么。

我们先尝试使用 ImageMagick。以下是我想采取的步骤:

  1. snow.jpeg 制作成名为 sketch.jpg 的铅笔素描
  2. sketch.jpg 转换为 sketch.png
  3. sketch.png 的宽度更改为 800px

Image 12

我们可以看到 medit 将 3 个 ImageMagick 命令合并为一个命令并执行了它。

这是原始图像。

Image 13

这是我在最近的欧洲公路旅行中拍摄的一张图片。原始大小为 5712x4284,7.2MB

这是结果图像。

Image 14

这个图像已修改为 800x600,263Kb

现在让我们尝试同时使用 ImageMagick 和 FFmpeg。

Image 15

正如您从屏幕截图中看到的,两个命令保持分开,因为它们无法合并。那么这是怎么发生的呢?组合代理根据这两个命令决定它们无法合并,因此将最终优化命令列表填充为这两个现有命令。

这就是运行 medit 的全部内容。

关于 Agentic 工作流的思考

如果您在寻找具有 agentic 工作流的神奇解决方案,您可能会感到失望。如今所有的 agentic AI 框架,包括 PydanticAI,都是相当新的。事实上,PydanticAI 在其网站上明确指出:

PydanticAI 处于早期测试阶段,API 仍可能会发生变化,还有很多工作要做。

agentic 工作流也不是 AGI(人工通用智能),尽管有时它的炒作方式可能听起来像那样。然而,收益和潜力确实是相当真实的。如果您查看 medit 演示以及代码,您会意识到相当一部分逻辑来自代理,支持它们的是各种 LLM。这在一个较小的应用程序中更加明显,因为没有其他地方可去。

路由代理确定用户的需求并重定向到适当的代理以采取行动。ImageMagick 和 FFmpeg 代理接收指令并相应生成 ImageMagick 或 FFmpeg 指令。如果您不知道,任一工具的参数的排列和可能性是巨大的,因此尝试构建一个具有所有可能排列的应用程序几乎是不可能的。组合代理也相当令人惊讶,因为它需要弄清楚命令是否可以组合以及最佳的组合方式。

当然,这只是一个非常简单的例子。我在这里展示的代理,除了执行代理外,所有都依赖于模型内部的知识,并仅基于此做出决策和采取行动。执行代理只有一个工具,即通过 shell 执行命令。

然而,代理可以使用各种工具与其他系统和环境(虚拟和真实)进行交互,也可以与各种数据库进行交互。更复杂的代理和工作流将拥有许多工具,其决策将根据大量和多样的数据而变化。这确实意味着我们有潜力通过多个代理的交互创建非常复杂的系统。

从编程的角度来看,这是一种惊人的灵活性,但这种 复杂性 确实存在缺陷。首先,agentic 工作流产生的结果行动将不容易预测甚至保持一致。这源于协调多个专门代理的固有复杂性以及大型语言模型的概率性质。

由于每个代理依赖于基于 LLM 的过程,输入在不同时间可能会产生不同的输出。即使每个代理都被给予相同的上下文和指令,由于生成模型固有的随机性,细微的变化也可能表现出来。这也导致了 涌现交互,即一个代理的输出中的小偏差可能在后续步骤中引发更显著的变化。随着多个代理交换数据,分支因子变得巨大,确保一致和可预测的结果可能变得困难。

当单个代理产生错误的命令或事实时,如果后续代理依赖于错误的输出,该错误可能会成倍增加。尽管在孤立环境中,幻觉通常是可以容忍的(尽管不理想),但在多代理工作流中,它们可能导致复合错误,变得更难以诊断和纠正。如果像财务计算或医疗建议这样的关键任务被委托给这样的工作流,单个错误的影响在代理链中传递时会显著放大。

调试和可观察性问题 加剧了这些风险。多代理系统可能依赖于多个工具和 LLM 调用,因此确定哪个特定调用导致了错误——或者管道中的哪个代理表现异常——可能是一项艰巨的任务。每个代理可能维护其自己的部分状态,这使得在任何时刻聚合和可视化整个系统的状态变得具有挑战性。此外,由于这些系统通常高度依赖提示,对提示的小修改或对基础 LLM 的更新可能会大幅改变结果,使得版本控制和回滚变得相当复杂。

另一个复杂性来自于 对每个 LLM 内置知识的过度依赖。由于许多模型是在静态数据集上训练的,它们可能持有关于其旨在自动化的工具和流程的过时或不完整信息。这可能导致命令仅部分有效、意外失败或使用已弃用的功能。审计 LLM 如何获取某些领域知识几乎是不可能的,限制了问责能力,并使遵循严格法规成为挑战。

在多代理工作流中,确保 正确性 特别困难。尽管结构化编程历史上提供了形式验证方法,但基于 LLM 的代理依赖于启发式方法,这使得几乎不可能保证每一步在所有场景中都能成立。在受监管或安全关键的环境中,依赖于没有强大正确性保证的工作流可能是有问题的。

一个相关的点是 agentic AI 框架的快速演变。正如我之前提到的,所有生成 AI 框架或多或少都处于初期阶段,即使那些已经存在几年。由于这些库处于早期开发阶段,重大变化和缺乏标准化是常见的。早期采用者面临投资于可能变得过时或需要大量重构的架构的风险,因为这些框架成熟并趋向于最佳实践。

在操作上,随着更多代理被引入以处理越来越专业的任务,基础设施需求 显著增加。每个代理对外部 LLM 或数据库层的调用增加了延迟、计算需求和成本。还有安全和隐私考虑,因为数据在多个代理和 API 之间传递,增加了潜在漏洞的额外途径。处理故障转移、速率限制和数据隐私要求可能迅速变得比运行单一服务应用程序更复杂。

最后,期望不一致 可能困扰多代理项目。尽管有热情的声明,这些工作流不是 AGI(我无法强调这一点),也无法复制人类水平的推理或创造力。利益相关者可能假设接近人类的智能,或者认为增加更多代理会自动产生更好的结果。这种假设可能导致失望,当幻觉发生或系统无法有效处理某些边缘情况时。此外,不断扩展代理的职责的诱惑可能导致范围蔓延,复杂性升级而没有带来相应的收益。

我们之前已经解决过这个问题

尽管听起来有点像预言家,软件行业实际上经历过类似的情况。

在1950年代和1960年代初,软件开发在很大程度上是一种临时的手工艺,严重依赖于 goto 语句和非结构化逻辑——通常导致“意大利面条代码”。随着计算机的进步,项目的复杂性急剧增加,导致频繁的成本超支和进度延误,特别是在国防和航空航天领域。到1960年代中期,“软件危机”一词开始流行,反映了行业在管理快速扩展的软件系统方面的挣扎。

转折点出现在Edsger W. Dijkstra于1968年在《ACM通讯》中的信件中,他认为不受限制的 goto 使用会产生难以验证或维护的复杂代码。在C.A.R. Hoare和Niklaus Wirth等当代人的支持下,Dijkstra倡导结构化编程:使用有限的一组控制结构(顺序、选择、迭代)和具有明确入口和出口的子例程。这一转变使得程序更容易追踪、调试和证明正确。

到1970年代,结构化编程、自上而下设计和逐步细化已成为标准实践。这些学科不仅驯服了最糟糕的复杂性问题,还为未来的范式奠定了基础——如面向对象编程、敏捷和DevOps——所有这些都旨在在软件增长时保持其可管理性。

这表明,尽管存在问题,作为一个行业,我们之前已经解决过。新技术的引入总是伴随着风险和危险,但也可以获得巨大的好处。

Related Posts

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

AI 研究报告和论文写作 合并两个系统指令以获得两个模型的最佳效果 Perplexity AI 的 Deep Research 工具提供专家级的研究报告,而 OpenAI 的 ChatGPT-o3-mini-high 擅长推理。我发现你可以将它们结合起来生成令人难以置信的论文,这些论文比任何一个模型单独撰写的都要好。你只需要将这个一次性提示复制到 **

阅读更多
让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

Non members click here作为一名软件开发人员,多年来的一个发现总是让我感到惊讶,那就是人们还在 Excel

阅读更多
使用 ChatGPT 搜索网络功能的 10 种创意方法

使用 ChatGPT 搜索网络功能的 10 种创意方法

例如,提示和输出 你知道可以使用 ChatGPT 的“搜索网络”功能来完成许多任务,而不仅仅是基本的网络搜索吗? 对于那些不知道的人,ChatGPT 新的“搜索网络”功能提供实时信息。 截至撰写此帖时,该功能仅对使用 ChatGPT 4o 和 4o-mini 的付费会员开放。 ![](https://images.weserv.nl/?url=https://cdn-im

阅读更多
掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

10 个常见问题解答 本文是我推出的一个名为“10 个常见问题解答”的新系列的一部分。在本系列中,我旨在通过回答关于该主题的十个最常见问题来分解复杂的概念。我的目标是使用简单的语言和相关的类比,使这些想法易于理解。 图片来自 [Solen Feyissa](https://unsplash.com/@solenfeyissa?utm_source=medium&utm_medi

阅读更多
在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和科技这样一个动态的行业中,保持领先意味着不断提升你的技能。无论你是希望深入了解人工智能模型性能、掌握数据分析,还是希望通过人工智能转变传统领域如法律,这些课程都是你成功的捷径。以下是一个精心策划的高价值课程列表,可以助力你的职业发展,并让你始终处于创新的前沿。 1. 生成性人工智能简介课程: [生成性人工智能简介](https://genai.works

阅读更多
揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

在AI军备竞赛中分辨事实与虚构 DeepSeek AI真的是它所宣传的游戏规则改变者,还是仅仅聪明的营销和战略炒作?👀 虽然一些人将其视为AI效率的革命性飞跃,但另一些人则认为它的成功建立在借用(甚至窃取的)创新和可疑的做法之上。传言称,DeepSeek的首席执行官在疫情期间像囤积卫生纸一样囤积Nvidia芯片——这只是冰山一角。 从其声称的550万美元培训预算到使用Open

阅读更多
Type something to search...