AI Agents实战——探索多代理系统

528 阅读36分钟

本章内容包括:

  • 使用AutoGen Studio构建多代理系统
  • 构建一个简单的多代理系统
  • 创建可以在群聊中协作工作的代理
  • 使用CrewAI构建代理团队和多代理系统
  • 扩展代理数量并使用CrewAI探索处理模式

现在,让我们从AutoGen到CrewAI,探索两个成熟的多代理平台。我们将从AutoGen开始,这是一个微软项目,支持多个代理,并提供一个工作室来帮助你使用这些代理。我们将探讨微软的一个项目,名为AutoGen,它支持多个代理,还提供了一个工作室,帮助你更轻松地与代理一起工作。接下来,我们将进行更多的AutoGen代理编码实践,通过对话和群聊协作来解决任务。

然后,我们将过渡到CrewAI,一个自提的企业代理系统,它采取不同的方式。CrewAI平衡了基于角色的和自治的代理,这些代理可以是顺序的或层次结构灵活的任务管理系统。我们将探索CrewAI如何解决多样化和复杂的问题。

多代理系统融合了单代理系统使用的许多相同工具,但它们受益于能够为其他代理提供外部反馈和评估的能力。支持和批评代理解决方案的这种能力,使得多代理系统更具威力。我们将在下一节介绍多代理系统,从AutoGen Studio开始。

4.1 使用AutoGen Studio介绍多代理系统

AutoGen Studio是一个强大的工具,背后运用多个代理来解决用户指令的任务和问题。这个工具已经被用来开发本书中一些更复杂的代码。因此,它是一个非常适合入门的实用多代理系统。

图4.1展示了AutoGen采用的代理连接/通信模式的示意图。AutoGen是一个对话式多代理平台,因为通信是通过自然语言进行的。自然语言对话似乎是代理之间最自然的通信模式,但这不是唯一的方法,正如你稍后会看到的那样。

image.png

AutoGen支持各种对话模式,从群聊和层级式到更常见且简单的代理通信。在代理通信中,一个代理充当代理人,将通信指引到相关代理以完成任务。代理就像一个服务员,接收订单并将其传送到厨房,然后厨房做出食物,最后服务员将做好的食物送到客人面前。

AutoGen中的基本模式使用一个UserProxy和一个或多个助手代理。图4.2展示了用户代理根据人类的指示,随后指引一个被启用编写代码的助手代理来执行任务。每次助手完成任务后,代理代理会进行审查、评估并提供反馈给助手。这个迭代循环将持续进行,直到代理对结果满意为止。

image.png

代理的好处在于它能够替代所需的人类反馈和评估,在大多数情况下,它做得相当好。虽然它并不能完全消除对人类反馈和评估的需求,但它整体上能够产生更完整的结果。而且,虽然迭代循环是耗时的,但这是你可以用来喝咖啡或处理其他任务的时间。

AutoGen Studio是由AutoGen团队开发的一个工具,提供了一个有用的入门介绍,帮助你理解可对话代理。在接下来的练习中,我们将安装Studio并进行一些实验,看看平台的表现如何。这些工具仍处于快速开发周期中,因此,如果你遇到任何问题,请参考AutoGen GitHub仓库中的文档。

4.1.1 安装和使用AutoGen Studio

在Visual Studio Code(VS Code)中打开chapter_04文件夹,创建一个本地Python虚拟环境,并安装requirements.txt文件。如果你需要帮助,参考附录B安装本章所有练习的依赖项。

在VS Code中打开一个终端(Ctrl-,Cmd-),指向你的虚拟环境,并使用命令4.1中显示的命令运行AutoGen Studio。你首先需要为你的OpenAI密钥定义一个环境变量。因为8080和8081端口非常常见,如果你有其他服务在运行,建议将端口更改为8082或你选择的其他端口。

命令 4.1 启动AutoGen Studio

# 在Bash中设置环境变量(Git Bash)
export OPENAI_API_KEY=”<your API key>”          #1

# 使用PowerShell设置环境变量
$env:VAR_NAME =”<your API key>"                #1

autogenstudio ui --port 8081     #2

#1 根据你的终端类型使用适当的命令。

#2 如果你的机器上有端口冲突,修改端口。

在浏览器中导航到AutoGen Studio界面,如图4.3所示(写作时的版本)。虽然界面可能会有所不同,但有一点是肯定的:主要界面仍然是聊天界面。输入一个需要编码的复杂任务。此处使用的示例是:“创建一个显示Google搜索中‘GPT Agents’术语流行度的图表。”

image.png

代理助手生成代码片段来执行或完成各种子任务,代理们通过任务协作工作。在示例中,用户代理代理尝试执行这些代码片段并评估输出。在许多情况下,证明代码能够运行并产生所需的输出就足以让用户代理批准任务的完成。

如果你遇到任何助手代理请求的问题,可以让代理尝试不同的方法或另一个问题。这突出了使用已过期且不再工作的包或库的代理系统中存在的一个更大问题。因此,通常最好让代理执行动作,而不是编写代码来作为工具执行动作。

提示
推荐使用Docker执行AutoGen和AutoGen Studio,尤其是在处理可能影响操作系统的代码时。Docker可以隔离并虚拟化代理的环境,从而隔离可能有害的代码。使用Docker可以帮助缓解任何可能阻止代理进程运行的二级窗口或网站。

图4.4展示了代理完成任务的过程。代理代理将收集任何生成的代码片段、图像或其他文档,并将其附加到消息中。你还可以通过打开“代理消息”扩展查看代理对话。在许多情况下,如果你要求代理生成图表或应用程序,次级窗口将打开并显示这些结果。

image.png

令人惊讶的是,代理们会很好地执行大多数任务并顺利完成它们。根据任务的复杂性,你可能需要与代理进一步迭代。有时,代理可能只能完成部分任务,因为它缺乏执行任务所需的技能。在下一节中,我们将探讨如何为代理添加技能。

4.1.2 在AutoGen Studio中添加技能

技能和工具,或者我们在本书中所说的“动作”,是代理扩展自己的主要方式。动作使代理能够执行代码、调用API,甚至进一步评估和检查生成的输出。AutoGen Studio目前仅提供一组基本工具,用于获取网页内容或生成图像。

备注
许多代理系统采用允许代理编写代码来解决目标的做法。然而,我们发现代码很容易被破坏,需要维护,并且可能会快速变化。因此,正如我们将在后续章节中讨论的那样,为代理提供技能/动作/工具来解决问题是更好的做法。

在以下的练习场景中,我们将添加一个技能/动作,使用OpenAI视觉模型检查图像。这将使代理代理能够提供反馈,如果我们要求助手生成具有特定内容的图像时。

在AutoGen Studio运行时,转到“构建”标签并点击“技能”,如图4.5所示。然后,点击“新建技能”按钮,打开一个代码面板,你可以将代码复制粘贴到这里。从这个标签中,你还可以配置模型、代理和代理工作流。

image.png

输入命令4.2中显示的代码,并在书籍的源代码中也提供了该代码文件 describe_image.py。将这段代码复制并粘贴到编辑器窗口中,然后点击底部的“保存”按钮。

命令 4.2 describe_image.py

import base64
import requests
import os

def describe_image(image_path='animals.png') -> str:
    """
    使用GPT-4 Vision检查并描述图像的内容。

    :param input_path: str,PNG文件的名称。
    """
    api_key = os.environ['OPEN_API_KEY']

    # 编码图像的函数
    def encode_image(image_path):      #1
        with open(image_path, "rb") as image_file:
            return base64.b64encode(image_file.read()).decode('utf-8')
    
    # 获取base64编码字符串
    base64_image = encode_image(image_path)

    headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {api_key}"
    }

    payload = {
    "model": "gpt-4-turbo",
    "messages": [
        {
        "role": "user",
        "content": [
            {
            "type": "text",
            "text": "这张图像里有什么?"
            },
            {
            "type": "image_url",
            "image_url": {
         "url": f"data:image/jpeg;base64,{base64_image}"      #2
            }
            }
        ]
        }
    ],
    "max_tokens": 300
    }

    response = requests.post(
        "https://api.openai.com/v1/chat/completions",
        headers=headers,
        json=payload)

    return response.json()["choices"][0]["message"]  #3
["content"]                                          #3

#1 编码图像并将其转换为Base64字符串的函数
#2 将图像字符串与JSON负载一起包含
#3 解包响应并返回回复的内容

describe_image函数使用OpenAI GPT-4视觉模型来描述图像中的内容。这个技能可以与现有的generate_image技能配对,作为质量评估。代理可以确认生成的图像是否符合用户的要求。

添加技能后,它必须被添加到特定的代理工作流和代理中才能使用。图4.6展示了如何将新技能添加到主助手代理的常规或默认代理工作流中。

image.png

现在,技能已被添加到主助手中,我们可以指派代理生成一个特定的图像,并使用新的describe_image技能来验证它。由于图像生成器通常在正确的文本生成方面存在问题,我们将创建一个练习任务来完成这一点。

输入命令4.3中显示的文本,指示代理为这本书创建封面图像。我们将明确指出文本需要正确,并要求代理使用新的describe_image函数来验证图像。

命令 4.3 书籍封面提示

Please create a cover for the book GPT Agents In Action, use the 
describe_image skill to make sure the title of the book is spelled 
correctly on the cover

输入提示后,稍等片刻,你可能会看到一些关于图像生成和验证过程的对话交换。最终,如果一切正常,代理将返回显示在图4.7中的结果。

image.png

令人印象深刻的是,代理协调只需几次迭代就完成了任务。除了图像,你还可以看到生成的各种辅助代码片段,以帮助完成任务。AutoGen Studio在集成技能方面表现出色,代理们可以进一步适应这些技能来完成一些目标。接下来的部分将展示这些强大的代理如何通过代码实现。

4.2 探索AutoGen

虽然AutoGen Studio是理解多代理系统的一个很棒的工具,但我们必须深入了解代码。幸运的是,使用AutoGen编码多个代理示例既简单又容易运行。我们将在下一节中介绍AutoGen的基本设置。

4.2.1 安装和使用AutoGen

在本练习中,我们将编写一个基本的多代理系统,使用用户代理和可对话代理。然而,在我们开始之前,我们需要确保AutoGen已正确安装和配置。

在VS Code中打开终端,并按照附录B中的章节4安装指令,或运行命令4.4中的pip命令。如果你已安装了requirements.txt文件,那么你也准备好运行AutoGen了。

命令 4.4 安装AutoGen

pip install pyautogen

接下来,将chapter_04/OAI_CONFIG_LIST.example复制到OAI_CONFIG_LIST,并删除文件名中的.example。然后,在VS Code中打开新文件,并根据你的API服务要求,在命令4.5所示的OAI_CONFIG_LIST文件中输入你的OpenAI或Azure配置。填写你的API密钥、模型和其他细节。AutoGen将与任何符合OpenAI客户端要求的模型一起使用。这意味着你可以通过LM Studio或其他服务(如Groq、Hugging Face等)使用本地LLM。

命令 4.5 OAI_CONFIG_LIST

[
    {
        "model": "gpt-4",                     #1
        "api_key": "<your OpenAI API key here>",            #2
        "tags": ["gpt-4", "tool"]
    },
    {
        "model": "<your Azure OpenAI deployment name>",      #3
        "api_key": "<your Azure OpenAI API key here>",      #4
        "base_url": "<your Azure OpenAI API base here>",     #5
        "api_type": "azure",
        "api_version": "2024-02-15-preview"
    }    
]

#1 选择模型;推荐使用GPT-4。
#2 使用你通常使用的服务密钥。
#3 选择模型;推荐使用GPT-4。
#4 使用你通常使用的服务密钥。
#5 更改基础URL允许你指向其他服务,而不仅仅是Azure OpenAI。

现在,我们可以查看一个基本的多代理聊天代码,使用开箱即用的UserProxyConversableAgent代理。在VS Code中打开autogen_start.py,并查看文件中的各部分,然后运行该文件。

命令 4.6 autogen_start.py

from autogen import ConversableAgent, UserProxyAgent, config_list_from_json

config_list = config_list_from_json(
    env_or_file="OAI_CONFIG_LIST")      #1

assistant = ConversableAgent(
    "agent", 
    llm_config={"config_list": config_list})      #2

user_proxy = UserProxyAgent(      #3
    "user",
    code_execution_config={
        "work_dir": "working",
        "use_docker": False,
    },
    human_input_mode="ALWAYS",
    is_termination_msg=lambda x: x.get("content", "")
    .rstrip()
    .endswith("TERMINATE"),      #4
)    
user_proxy.initiate_chat(assistant, message="write a solution 
for fizz buzz in one line?")     #5

#1 从JSON文件OAI_CONFIG_LIST加载LLM配置。
#2 这个代理直接与LLM交互。
#3 这个代理代理用户到助手的对话。
#4 设置终止消息允许代理迭代。
#5 通过user_proxy与助手启动聊天以完成任务。

通过在VS Code的调试器中运行该文件(F5)来启动代码。命令4.6中的代码使用一个简单的任务来演示代码编写。命令4.7显示了几个可供选择的示例。这些编码任务也是作者用来评估LLM在编码能力方面的一些常见基准。

命令 4.7 简单编码任务示例

write a Python function to check if a number is prime
code a classic snake game using Pygame                   #1
code a classic asteroids game in Python using Pygame  #1

#1 为了享受这些任务的迭代,可以在Windows上使用Windows子系统(WSL),或者使用Docker。

代码启动后,几秒钟内,助手将向代理提供解决方案。此时,代理将提示你提供反馈。按下回车,基本上不给予任何反馈,这将促使代理运行代码并验证其是否按预期操作。

令人印象深刻的是,代理甚至会根据需要安装所需的包,如Pygame。然后它将运行代码,你将在终端中或作为新窗口或浏览器中看到输出。如果代码打开了一个新窗口/浏览器,你可以玩游戏或使用接口。

注意,生成的窗口/浏览器在Windows上不会自动关闭,需要退出整个程序。为避免此问题,可以通过Windows子系统(WSL)或Docker运行代码。AutoGen明确推荐使用Docker来执行代码代理,如果你熟悉容器,这是一个不错的选择。

无论哪种方式,在代理生成并运行代码后,命令4.6中设置的working_dir文件夹现在应该有一个包含代码的Python文件。这将允许你在闲暇时运行代码、进行更改,甚至请求改进,正如我们接下来要展示的那样。在下一节中,我们将探讨如何提高编码代理的能力。

4.2.2 使用代理批评者增强代码输出

多代理系统的一个强大好处是你可以在完成任务时自动分配多个角色/个性。生成或帮助编写代码对任何开发者来说都是一种极好的优势,但如果这些代码也能被审查和测试呢?在接下来的练习中,我们将向我们的代理系统添加另一个代理批评者来帮助处理编码任务。打开autogen_coding_critic.py,如以下命令4.8所示。

命令 4.8 autogen_coding_critic.py

from autogen import AssistantAgent, UserProxyAgent, config_list_from_json

config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST")

user_proxy = UserProxyAgent(
    "user",
    code_execution_config={
        "work_dir": "working",
        "use_docker": False,
        "last_n_messages": 1,
    },
    human_input_mode="ALWAYS",
    is_termination_msg=lambda x: 
x.get("content", "").rstrip().endswith("TERMINATE"),
)

engineer = AssistantAgent(
    name="Engineer",
    llm_config={"config_list": config_list},
    system_message="""
    You are a professional Python engineer, known for your expertise in 
software development.
    You use your skills to create software applications, tools, and 
games that are both functional and efficient.
    Your preference is to write clean, well-structured code that is easy 
to read and maintain.    
    """,      #1
)

critic = AssistantAgent(
    name="Reviewer",
    llm_config={"config_list": config_list},
    system_message="""
    You are a code reviewer, known for your thoroughness and commitment 
to standards.
    Your task is to scrutinize code content for any harmful or 
substandard elements.
    You ensure that the code is secure, efficient, and adheres to best 
practices.
    You will identify any issues or areas for improvement in the code 
and output them as a list.
    """,      #2
)

def review_code(recipient, messages, sender, config):      #3
    return f"""
            Review and critique the following code.

            {recipient.chat_messages_for_summary(sender)[-1]['content']}
            """                       #3                    

user_proxy.register_nested_chats(      #4
    [
        {
            "recipient": critic,
            "message": review_code,
            "summary_method": "last_msg",
            "max_turns": 1,
        }
    ],
    trigger=engineer,                 #4
)
task = """Write a snake game using Pygame."""

res = user_proxy.initiate_chat(
    recipient=engineer, 
    message=task, 
    max_turns=2, 
    summary_method="last_msg"      #5
)

#1 这次,助手被赋予了一个系统/个性消息。
#2 创建了第二个具有背景的助手批评者代理。
#3 自定义函数帮助提取代码供批评者审查。
#4 在批评者和工程师之间创建了一个嵌套对话。
#5 代理代理启动了与助手的对话,并设定最大延迟和显式摘要方法。

在VS Code的调试模式下运行autogen_coding_critic.py文件,并观察代理之间的对话。这次,在代码返回之后,批评者也会被触发进行响应。然后,批评者会为代码添加评论和建议,以改进代码。

嵌套对话在支持和控制代理互动方面表现良好,但我们将在下一节中看到一种更好的方法。在此之前,我们将在下一节回顾AutoGen缓存的重要性。

4.2.3 理解AutoGen缓存

作为一个可对话的多代理平台,AutoGen在对话迭代过程中可能会消耗大量的tokens。如果你让AutoGen处理复杂或新颖的问题,你可能甚至会遇到LLM的token限制;因此,AutoGen支持多种方法来减少token的使用。

AutoGen使用缓存来存储进度并减少token使用。缓存默认启用,你可能已经遇到过它。如果你查看当前的工作文件夹,你会注意到有一个.cache文件夹,如图4.8所示。缓存允许你的代理在对话中断时继续对话。

image.png

在代码中,你可以控制代理运行的缓存文件夹,如命令4.9所示。通过使用with语句包装initiate_chat调用,你可以控制缓存的位置和种子。这将允许你通过设置先前缓存的cache_seed,保存并返回到长期运行的AutoGen任务。

命令 4.9 设置缓存文件夹

with Cache.disk(cache_seed=42) as cache:     #1
    res = user_proxy.initiate_chat(
        recipient=engineer,
        message=task,
        max_turns=2,
        summary_method="last_msg",
        cache=cache,      #2
    )

#1 设置cache_seed表示单独的位置。
#2 将缓存设置为参数。

这种缓存能力使你能够从先前的缓存位置继续操作并捕捉之前的运行。它也可以是一个很好的方式,用于展示和检查代理对话是如何生成结果的。在下一节中,我们将探讨AutoGen支持的另一种对话模式,即群组聊天。

4.3 与代理和AutoGen的群组聊天

聊天委托和嵌套对话或会话中的一个问题是信息的传递。如果你玩过电话游戏,你就会亲身体验到信息是如何在几轮传递中迅速发生变化的。对于代理来说,这当然也是如此,嵌套或顺序的对话可能会改变任务或甚至改变预期的结果。

电话游戏

电话游戏是一种有趣且富有教育意义的游戏,展示了信息和一致性的丧失。孩子们排成一队,第一个孩子接收到只有他能听到的信息。然后,孩子们依次将信息口头传递给下一个孩子,直到最后一个孩子宣布信息给整个小组,通常这时信息已经和最初的信息大相径庭。

为了应对这一问题,AutoGen提供了群组聊天机制,代理们可以参与共享对话。这使得代理们可以查看所有过去的对话,更好地合作完成长期和复杂的任务。

图4.9展示了嵌套对话和协作群组聊天的区别。在上一节中,我们使用了嵌套聊天功能来构建一个嵌套代理对话。在本节中,我们使用群组聊天提供了更具协作性的体验。

image.png

打开autogen_coding_group.py并查看相关部分,如命令4.10所示。代码与之前的练习类似,但现在引入了GroupChatGroupChatManager。代理和消息通过群组聊天来管理,类似于Slack或Discord等应用中的消息频道。聊天管理器协调消息响应,以减少对话的重复性。

命令 4.10 autogen_coding_group.py(相关部分)

user_proxy = UserProxyAgent(
    "user",
    code_execution_config={
        "work_dir": "working",
        "use_docker": False,
        "last_n_messages": 3,
    },
    human_input_mode="NEVER",     #1
)

llm_config = {"config_list": config_list}

engineer = AssistantAgent(…      #2

critic = AssistantAgent(…       #2

groupchat = GroupChat(agents=[user_proxy, 
                              engineer, 
                              critic], 
                              messages=[], 
                              max_round=20)      #3
manager = GroupChatManager(groupchat=groupchat, 
                           llm_config=llm_config)     #4

task = """Write a snake game using Pygame."""

with Cache.disk(cache_seed=43) as cache:
    res = user_proxy.initiate_chat(
        recipient=manager,
        message=task,
        cache=cache,
    )

#1 人类输入被设置为“从不”,因此没有人类反馈。
#2 代码省略,但请参考文件中个性部分的更改。
#3 该对象保存所有代理的连接并存储消息。
#4 管理员协调对话,像主持人一样。

运行此练习,你将看到代理是如何协作的。工程师现在将从批评者那里获取反馈,并根据批评者的建议进行操作。这也允许代理参与所有的对话。

群组对话是加强代理能力的绝佳方式,因为它们可以共同协作完成任务。然而,它们通常更加冗长并且消耗更多的token。当然,随着LLM的成熟,它们的上下文token窗口的大小和token处理的价格也会增加。随着token窗口的增加,关于token消耗的担忧可能最终会消失。

AutoGen是一个强大的多代理平台,可以通过Web界面或代码进行体验。无论你偏好哪种方式,这个代理协作工具都是构建代码或其他复杂任务的出色平台。当然,它不是唯一的平台,正如你将在下一节中看到的,我们将探索一个新兴平台——CrewAI。

4.4 使用CrewAI构建代理团队

CrewAI在多代理系统领域相对较新。与AutoGen最初是从研究中开发并扩展不同,CrewAI是为企业系统量身打造的。因此,该平台更加健壮,但在某些方面的扩展性较差。

使用CrewAI,你可以构建一个代理团队,专注于任务目标的特定领域。与AutoGen不同,CrewAI不要求使用用户代理代理,而是假设代理仅在彼此之间工作。

图4.10展示了CrewAI平台的主要元素、它们如何连接以及它们的主要功能。它展示了一个顺序处理的代理系统,具有通用的研究员和写作代理。代理被分配任务,任务可能还包括工具或内存来协助它们。

image.png

CrewAI支持两种主要的处理形式:顺序处理和层级处理。图4.10展示了通过迭代给定的代理及其相关任务的顺序处理过程。在下一节中,我们将深入一些代码,设置一个代理团队,并利用它来完成一个目标并创造一个好笑的笑话。

4.4.1 创建CrewAI代理的笑话团队

CrewAI的设置比AutoGen更为复杂,但这也提供了更多的控制和附加的引导,能够为代理提供更具体的上下文,帮助其完成任务。这虽然有其难点,但它相比AutoGen提供了更多的控制。

在VS Code中打开crewai_introduction.py并查看顶部部分,如命令4.11所示。配置一个代理需要多个设置,包括角色、目标、详细程度、记忆、背景故事、委托,甚至工具(未显示)。在这个示例中,我们使用了两个代理:一个资深笑话研究员和一个笑话写手。

命令4.11 crewai_introduction.py(代理部分)

from crewai import Agent, Crew, Process, Task
from dotenv import load_dotenv

load_dotenv()

joke_researcher = Agent(      #1
    role="Senior Joke Researcher",
    goal="Research what makes things funny about the following {topic}",
    verbose=True,      #2
    memory=True,      #3
    backstory=(      #4
        "Driven by slapstick humor, you are a seasoned joke researcher"
        "who knows what makes people laugh. You have a knack for finding"
        "the funny in everyday situations and can turn a dull moment into"
        "a laugh riot."
    ),
    allow_delegation=True,     #5
)

joke_writer = Agent(     #6
    role="Joke Writer",
    goal="Write a humourous and funny joke on the following {topic}",
    verbose=True,     #7
    memory=True,      #8
    backstory=(     #9
        "You are a joke writer with a flair for humor. You can turn a"
        "simple idea into a laugh riot. You have a way with words and"
        "can make people laugh with just a few lines."
    ),
    allow_delegation=False,    #5
)

#1 创建代理并为其设定目标
#2 verbose允许代理在终端输出
#3 支持代理使用记忆
#4 背景故事是代理的背景信息——它的个性
#5 代理可以委托任务或被委托;True表示它可以委托

接下来是任务部分,如命令4.12所示。任务定义了代理完成主要目标的过程,它们还将代理与具体任务关联,定义该任务的输出,并可能包括如何执行。

命令4.12 crewai_introduction.py(任务部分)

research_task = Task(         #1
    description=(
        "Identify what makes the following topic:{topic} so funny."
        "Be sure to include the key elements that make it humourous."
        "Also, provide an analysis of the current social trends,"
        "and how it impacts the perception of humor."
    ),
    expected_output="A comprehensive 3 paragraphs long report "
                    "on the latest jokes.",               #2
    agent=joke_researcher,      #3
)

write_task = Task(   #4
    description=(
        "Compose an insightful, humourous and socially aware joke on {topic}."
        "Be sure to include the key elements that make it funny and"
        "relevant to the current social trends."
    ),
    expected_output="A joke on {topic}.",   #5
    agent=joke_writer,        #3
    async_execution=False,          #6
    output_file="the_best_joke.md",      #7
)

#1 任务描述定义了代理如何完成任务
#2 明确定义执行任务的预期输出
#3 指定处理任务的代理
#4 任务描述定义代理如何完成任务
#5 明确定义执行任务的预期输出
#6 是否异步执行任务
#7 代理将生成的任何输出

现在,我们可以看到如何将所有内容整合到一起,正如命令4.13所示的Crew部分。创建Crew时有许多选项可以设置,包括代理、任务、处理类型、记忆、缓存、每分钟最大请求数(max_rpm)以及是否共享代理团队。

命令4.13 crewai_introduction.py(团队部分)

crew = Crew(
    agents=[joke_researcher, joke_writer],    #1
    tasks=[research_task, write_task],     #2
    process=Process.sequential,      #3
    memory=True,      #4
    cache=True,     #5
    max_rpm=100,     #6
    share_crew=True,     #7
)

result = crew.kickoff(inputs={"topic": "AI engineer jokes"})
print(result)

#1 创建代理并组成团队
#2 设置代理能工作的任务
#3 定义代理如何互动
#4 是否使用记忆;如果代理/任务有记忆则需要设置
#5 是否使用缓存,类似于AutoGen
#6 系统每分钟最多允许的请求数
#7 是否共享信息,类似于群组聊天

完成设置后,在VS Code中运行文件(F5),并查看终端中的对话和来自团队的消息。正如你现在可能已经知道的,系统的目标是创作与AI工程相关的笑话。这里是代理系统运行几次后生成的一些搞笑笑话:

  • 为什么计算机会感到冷?因为它把Windows开着。
  • 为什么AI工程师不和他们的算法玩捉迷藏?因为无论他们藏在哪里,算法总是会在“过拟合”的房间找到他们!
  • AI工程师最喜欢的歌是什么?“我只是打电话来告诉你我爱你……并且收集更多的数据来改进我的语音识别软件。”
  • 为什么AI工程师破产了?因为他把所有的钱都花在了cookies上,但他的浏览器却一直吃掉它们。

在继续运行更多的笑话团队迭代之前,你应该阅读下一节。该节将展示如何为多代理系统添加可观察性。

4.4.2 使用AgentOps观察代理工作

观察像多代理系统这样的复杂组合,对于理解可能发生的各种问题至关重要。通过应用程序追踪实现的可观察性是任何复杂系统的关键要素,尤其是那些用于企业的系统。

CrewAI支持连接到一个名为AgentOps的专门代理操作平台。这个可观察性平台是通用的,旨在支持任何特定于LLM使用的代理平台的可观察性。目前,关于价格或商业化的细节尚不可得。

连接到AgentOps的过程非常简单,只需要安装该软件包、获取API密钥,并在你的代理设置中添加一行代码。接下来的练习将指导你完成连接和运行AgentOps的步骤。

命令4.14展示了如何使用pip安装agentops软件包。你可以单独安装这个软件包,或者将其作为CrewAI软件包的附加组件安装。请记住,AgentOps也可以连接到其他代理平台进行可观察性跟踪。

命令4.14 安装AgentOps

pip install agentops

或者作为CrewAI的一部分安装:

pip install crewai[agentops]

在使用AgentOps之前,你需要注册一个API密钥。以下是注册密钥的基本步骤(截至本书撰写时):

  1. 访问 app.agentops.ai 网站。
  2. 注册账户。
  3. 创建一个项目,或者使用默认项目。
  4. 转到“设置 > 项目和API密钥”。
  5. 复制和/或生成新的API密钥;这将把密钥复制到你的浏览器。
  6. 将密钥粘贴到你的项目的.env文件中。

API密钥复制后,应类似于命令4.15所示的示例。

命令4.15 env:添加AgentOps密钥

AGENTOPS_API_KEY="your API key"

接下来,我们需要在CrewAI脚本中添加几行代码。命令4.16展示了将这些内容添加到crewai_agentops.py文件中的方法。当创建你自己的脚本时,你只需要添加agentops包并在使用CrewAI时初始化它。

命令4.16 crewai_agentops.py(AgentOps新增部分)

import agentops      #1
from crewai import Agent, Crew, Process, Task
from dotenv import load_dotenv

load_dotenv()
agentops.init()     #2

#1 导入所需的agentops
#2 在加载环境变量后初始化该包

在VS Code中运行crewai_agentops.py文件(F5),并像以前一样观察代理工作。然而,现在你可以访问AgentOps仪表板,查看不同级别的代理交互。

图4.11展示了运行笑话团队以创造最佳笑话的仪表板。仪表板显示了多个统计信息,包括总时长、运行环境、提示和完成令牌、LLM调用时机以及估算成本。看到成本的展示,可能既让人清醒也能指示出代理对话可能变得多么冗长。

image.png

AgentOps平台是任何代理平台的一个出色补充。虽然它是内建于CrewAI中的,但可以将其可观察性添加到AutoGen或其他框架中,这一点非常有用。AgentOps的另一个吸引人的特点是,它专注于观察代理交互,而不是从机器学习操作平台转化而来。未来,我们可能会看到更多代理可观察性模式的出现。

一个不能过分强调的好处是,观察平台可以提供的成本观察。你注意到图4.11中,创建一个笑话的成本略高于50美分吗?代理可能非常强大,但它们也可能变得非常昂贵,因此观察这些成本的实际性和商业化是至关重要的。

在本章的最后一部分,我们将回到CrewAI,并重新审视构建能够编写游戏代码的代理。这将提供一个关于AutoGen和CrewAI能力的极好比较。

4.5 重新审视使用CrewAI的编码代理

比较多代理平台能力的一个好方法是将类似的任务实现为一个机器人。在接下来的练习中,我们将使用CrewAI作为游戏编程团队。当然,这也可以调整为其他编码任务。

打开VS Code中的 crewai_coding_crew.py,我们首先回顾列出4.17中的代理部分。在这里,我们创建了一个高级工程师、一个QA工程师和一个首席QA工程师,并为他们设置了角色、目标和背景故事。

列出4.17 crewai_coding_crew.py(代理部分)

print("## Welcome to the Game Crew")      #1
print("-------------------------------")
game = input("What is the game you would like to build?
↪ What will be the mechanics?\n")


senior_engineer_agent = Agent(
    role="Senior Software Engineer",
    goal="Create software as needed",
    backstory=dedent(
        """
        You are a Senior Software Engineer at a leading tech think tank.
        Your expertise in programming in python. and do your best to
        produce perfect code
        """
    ),
    allow_delegation=False,
    verbose=True,
)

qa_engineer_agent = Agent(
    role="Software Quality Control Engineer",
    goal="create prefect code, by analizing the code 
↪ that is given for errors",
    backstory=dedent(
        """
        You are a software engineer that specializes in checking code
        for errors. You have an eye for detail and a knack for finding
        hidden bugs.
        You check for missing imports, variable declarations, mismatched
        brackets and syntax errors.
        You also check for security vulnerabilities, and logic errors
        """
    ),
    allow_delegation=False,
    verbose=True,
)

chief_qa_engineer_agent = Agent(
    role="Chief Software Quality Control Engineer",
    goal="Ensure that the code does the job that it is supposed to do",
    backstory=dedent(
        """
        You are a Chief Software Quality Control Engineer at a leading
        tech think tank. You are responsible for ensuring that the code
        that is written does the job that it is supposed to do.
        You are responsible for checking the code for errors and ensuring
        that it is of the highest quality.
        """
    ),
    allow_delegation=True,     #2
    verbose=True,
)
#1 Allows the user to input the instructions for their game
#2 Only the chief QA engineer can delegate tasks.

向下滚动文件将显示代理任务,如列出4.18所示。任务描述和预期输出应该很容易理解。同样,每个代理都有一个特定的任务,在完成任务时提供更好的上下文。

列出4.18 crewai_coding_crew.py(任务部分)

code_task = Task(
    description=f"""
You will create a game using python, these are the instructions:
        Instructions
        ------------
        {game}             #1
        You will write the code for the game using python.""",
    expected_output="Your Final answer must be the 
↪ full python code, only the python code and nothing else.",
    agent=senior_engineer_agent,
)

qa_task = Task(
    description=f"""You are helping create a game 
↪ using python, these are the instructions:
        Instructions
        ------------
        {game}            #1
        Using the code you got, check for errors. Check for logic errors,
        syntax errors, missing imports, variable declarations, 
mismatched brackets,
        and security vulnerabilities.""",
    expected_output="Output a list of issues you found in the code.",
    agent=qa_engineer_agent,
)

evaluate_task = Task(
    description=f"""You are helping create a game 
↪ using python, these are the instructions:
        Instructions
        ------------
        {game}            #1
        You will look over the code to insure that it is complete and
        does the job that it is supposed to do. """,
    expected_output="Your Final answer must be the 
↪ corrected a full python code, only the python code and nothing else.",
    agent=chief_qa_engineer_agent,
)
#1 The game instructions are substituted into the prompt using Python formatting.

最后,我们可以通过转到文件底部来查看这如何组合,如列出4.19所示。这个团队配置就像我们之前看到的那样。每个代理和任务都被添加了,以及详细和进程属性。对于这个示例,我们将继续使用顺序方法。

列出4.19 crewai_coding_crew.py(团队部分)

crew = Crew(
    agents=[senior_engineer_agent, 
            qa_engineer_agent, 
            chief_qa_engineer_agent],
    tasks=[code_task, qa_task, evaluate_task],
    verbose=2,  
    process=Process.sequential,      #1
)

# Get your crew to work!
result = crew.kickoff()    #2

print("######################")
print(result)
#1 Process is sequential.
#2 No additional context is provided in the kickoff.

当你运行VS Code(F5)文件时,你将被提示输入编写游戏的说明。输入一些说明,比如贪吃蛇游戏或你选择的其他游戏。然后,让代理们开始工作,观察他们产生的结果。

通过增加首席QA工程师,结果通常会比AutoGen产生的结果更好,至少在开箱即用的情况下。如果你检查代码,你会看到它通常遵循良好的模式,在某些情况下,甚至可能包含测试和单元测试。

在我们完成本章之前,我们将对团队的处理模式做最后一次修改。之前,我们使用了顺序处理,如图4.10所示。图4.12展示了CrewAI中层级处理的样子。

image.png

添加这个经理是一个相对简单的过程。列出4.20展示了在一个新文件中,使用层级方法的编码团队所做的额外代码更改。除了从LangChain导入一个连接OpenAI的类外,另一个新增的部分是将这个类作为团队经理 manager_llm 添加进来。

列出4.20 crewai_hierarchy.py(团队经理部分)

from langchain_openai import ChatOpenAI      #1

crew = Crew(
    agents=[senior_engineer_agent, 
            qa_engineer_agent, 
            chief_qa_engineer_agent],
    tasks=[code_task, qa_task, evaluate_task],
    verbose=2,  
    process=Process.hierarchical,     #2
    manager_llm=ChatOpenAI(               #3
        temperature=0, model="gpt-4"      #3
    ),    #4
)         #4
#1 导入来自LangChain的LLM连接器
#2 选择层级处理时,必须设置团队经理。
#3 将团队经理设置为LLM连接器
#4 选择层级处理时,必须设置团队经理。

在VS Code中运行此文件(F5)。当被提示时,输入你想要创建的游戏。尝试使用你在AutoGen中尝试过的相同游戏;贪吃蛇游戏也是一个很好的基准示例。观察代理如何通过代码工作,并反复检查代码中的问题。

运行文件后,你还可以跳到AgentOps上查看这次运行的成本。很可能,它的成本将超过没有代理经理时的两倍。输出结果也可能不会有显著改善。这就是在构建代理系统时,未能理解事情会迅速失控的陷阱。

这种失控的一个例子是,当代理不断重复相同的动作时,常常会出现重复的任务。你可以在AgentOps中查看这个问题,如图4.13所示,通过查看重复思维的图表。

image.png

AgentOps中的重复思维图是衡量代理系统所遇到重复问题的一个极好方式。过于重复的思维模式通常意味着代理决策不足,而是不断尝试生成不同的答案。如果你遇到这个问题,应该更改代理的处理模式、任务和目标。你甚至可能需要调整系统的代理类型和数量。

多代理系统是根据工作模式分配工作和任务的极好方式。通常,工作角色会分配给一个代理角色/人格,而它需要完成的任务可能是隐性的(如AutoGen中所示),也可能是更明确的(如CrewAI中所示)。

在本章中,我们介绍了许多实用的工具和平台,你可以立即使用它们来改善工作、生活等。这完成了我们对多代理平台的探索,但它并不意味着我们对多个代理的使用和探索就此结束,因为在后续章节中我们将继续发现更多内容。

4.6 练习

使用以下练习来提升你对材料的理解:

练习1 — AutoGen中的基本代理通信
目标 — 熟悉AutoGen中的基本代理通信和设置。
任务

  • 在本地机器上设置AutoGen Studio,按照本章提供的说明操作。
  • 创建一个简单的多代理系统,其中包括一个用户代理和两个助手代理。
  • 实现一个基本任务,其中用户代理协调两个助手代理,生成简单的文本输出,如总结一段简短的文字。

练习2 — 在AutoGen Studio中实现高级代理技能
目标 — 通过添加高级技能增强代理能力。
任务

  • 开发并集成一个新技能到AutoGen代理中,使其能够从公共API获取并显示实时数据(例如天气信息或股票价格)。
  • 确保代理能够询问用户偏好(如天气的城市、股票类型),并根据用户选择显示相应的数据。

练习3 — CrewAI中的基于角色的任务管理
目标 — 探索CrewAI中的基于角色的任务管理。
任务

  • 设计一个CrewAI设置,其中多个代理被分配到特定角色(如数据获取者、分析员、报告生成者)。
  • 配置一个任务序列,其中数据获取者收集数据,分析员处理数据,报告生成者生成报告。
  • 执行该序列,观察信息流和任务委派在代理之间的过程。

练习4 — 使用AutoGen进行多代理协作的群聊系统
目标 — 理解并实现AutoGen中的群聊系统,促进代理之间的协作。
任务

  • 设置一个场景,多个代理需要协作解决复杂问题(如规划一次商务旅行行程)。
  • 使用群聊功能让代理们共享信息、提出问题,并互相更新进展。
  • 监控代理之间的互动,并评估他们在协作问题解决中的效果。

练习5 — 在CrewAI中使用AgentOps添加并测试可观察性
目标 — 在CrewAI环境中实现并评估代理的可观察性。
任务

  • 将AgentOps集成到CrewAI多代理系统中。
  • 设计一个涉及大量计算或数据处理的任务(例如,分析客户评论以确定情感趋势)。
  • 使用AgentOps监控代理的性能、成本和输出准确性。识别代理交互中的潜在低效或错误。

总结

  • AutoGen,由Microsoft开发,是一个对话式多代理平台,使用多种代理类型,如用户代理和助手代理,通过自然语言交互促进任务执行。
  • AutoGen Studio作为开发环境,允许用户创建、测试和管理多代理系统,增强了AutoGen的可用性。
  • AutoGen支持多种通信模式,包括群聊、层级通信和代理通信。代理通信涉及一个主代理(代理)在用户和其他代理之间进行接口,以简化任务完成。
  • CrewAI提供了一种结构化的方法来构建多代理系统,重点是企业应用。它强调基于角色和自主代理功能,支持灵活的、顺序的或层级的任务管理。
  • 本章中的实用练习展示了如何设置和使用AutoGen Studio,包括安装必要的组件和运行基本的多代理系统。
  • AutoGen中的代理可以装备特定技能,执行任务如代码生成、图像分析和数据获取,从而扩大其应用范围。
  • CrewAI以其比AutoGen更严格的结构化代理交互而著称,这在需要精确和受控代理行为的设置中非常有优势。
  • CrewAI支持集成内存和工具供代理通过任务完成进行消费。
  • CrewAI支持与可观察性工具(如AgentOps)的集成,这些工具提供有关代理性能、交互效率和成本管理的见解。
  • AgentOps是一个代理可观察性平台,可以帮助你轻松监控广泛的代理交互。