AutoGen 技术博客系列 (九):从 v0.2 到 v0.4 的迁移指南

AutoGen系列一:基础介绍与入门教程

AutoGen系列二:深入自定义智能体

AutoGen系列三:内置智能体的应用与实战

AutoGen系列四: 自定义智能体的高级技巧

AutoGen系列五: 智能体团队协作的深度剖析与实践

AutoGen系列六: SelectorGroupChat 的原理与实践

AutoGen 技术博客系列 (七):状态管理与组件序列化解析

AutoGen 技术博客系列 (八):# 深入剖析 Swarm------ 智能体协作的新范式

AutoGen 技术博客系列 (九):从 v0.2 到 v0.4 的迁移指南

这是一份为 autogen-agentchat v0.2.* 版本用户提供的迁移指南,旨在帮助用户升级到 v0.4 版本,该版本引入了一组新的 API 和功能。v0.4 版本包含重大变更,请仔细阅读本指南。我们仍在 0.2 分支中维护 v0.2 版本,但强烈建议您升级到 v0.4 版本。

注意v0.4 不再拥有 pyautogen PyPI 包的管理员权限,自 0.2.34 版本起,该包的发布不再来自微软。如需继续使用 v0.2 版本的 AutoGen,请使用 autogen-agentchat~=0.2 进行安装。请阅读我们关于分支的澄清声明。

什么是 v0.4?

自 2023 年 AutoGen 发布以来,我们积极倾听社区以及来自小型初创公司和大型企业用户的反馈,并基于这些反馈构建了 AutoGen v0.4。这是一个从头开始重写的版本,采用异步、事件驱动架构,旨在解决可观测性、灵活性、交互控制和扩展性等问题。

v0.4 API 是分层的:核心 API 是基础层,提供了一个可扩展的、事件驱动的参与者框架,用于创建智能体工作流;AgentChat API 构建在核心 API 之上,提供了一个任务驱动的高级框架,用于构建交互式智能体应用程序,它是 AutoGen v0.2 的替代品。

本指南主要关注 v0.4 的 AgentChat API,但您也可以仅使用核心 API 构建自己的高级框架。

新用户 :直接跳转到 AgentChat 教程开始使用 v0.4

本指南内容

我们提供了一份详细指南,说明如何将现有代码库从 v0.2 迁移到 v0.4。有关如何迁移的详细信息,请参阅以下每个功能。

  • 模型客户端

  • 与 OpenAI 兼容的 API 的模型客户端

  • 模型客户端缓存

  • 助手智能体

  • 多模态智能体

  • 用户代理

  • 可对话智能体和注册回复

  • 保存和加载智能体状态

  • 双智能体聊天

  • 工具使用

  • 聊天结果

  • v0.2 和 v0.4 消息之间的转换

  • 群聊

  • 恢复群聊

  • 保存和加载群聊状态

  • 带工具使用的群聊

  • 带自定义选择器(Stateflow)的群聊

  • 嵌套聊天

  • 顺序聊天

  • GPTAssistantAgent

  • 长上下文处理

  • 可观测性和控制

  • 代码执行器

以下 v0.2 中的功能将在未来的 v0.4.* 版本中提供:

  • 模型客户端成本 #4835

  • 可教学智能体

  • RAG 智能体

当缺失的功能可用时,我们将更新本指南。

模型客户端

v0.2 中,您可以按如下方式配置模型客户端并创建 OpenAIWrapper 对象:

ini 复制代码
from autogen.oai import OpenAIWrapper

config_list = [
    {"model": "gpt-4o", "api_key": "sk-xxx"},
    {"model": "gpt-4o-mini", "api_key": "sk-xxx"},
]
model_client = OpenAIWrapper(config_list=config_list)

注意:在 AutoGen 0.2 中,OpenAI 客户端会尝试列表中的配置,直到找到一个可用的。而 0.4 版本需要选择特定的模型配置。

v0.4 中,我们提供了两种创建模型客户端的方法。

使用组件配置

AutoGen 0.4 有一个通用的组件配置系统,模型客户端是其一个很好的应用场景。以下是创建 OpenAI 聊天完成客户端的示例:

arduino 复制代码
from autogen_core.models import ChatCompletionClient

config = {
    "provider": "OpenAIChatCompletionClient",
    "config": {
        "model": "gpt-4o",
        "api_key": "sk-xxx"  # 也可以使用 os.environ["..."]
    }
}
model_client = ChatCompletionClient.load_component(config)

直接使用模型客户端类

  • Open AI
ini 复制代码
from autogen_ext.models.openai import OpenAIChatCompletionClient
model_client = OpenAIChatCompletionClient(model="gpt-4o", api_key="sk-xxx")
  • Azure OpenAI
ini 复制代码
from autogen_ext.models.openai import AzureOpenAIChatCompletionClient
model_client = AzureOpenAIChatCompletionClient(
    azure_deployment="gpt-4o",
    azure_endpoint="https://<your-endpoint>.openai.azure.com/",
    model="gpt-4o",
    api_version="2024-09-01-preview",
    api_key="sk-xxx",
)

与 OpenAI 兼容的 API 的模型客户端

您可以使用 OpenAIChatCompletionClient 连接到与 OpenAI 兼容的 API,但需要指定 base_urlmodel_info

ini 复制代码
from autogen_ext.models.openai import OpenAIChatCompletionClient

custom_model_client = OpenAIChatCompletionClient(
    model="custom-model-name",
    base_url="https://custom-model.com/reset/of/the/path",
    api_key="placeholder",
    model_info={
        "vision": True,
        "function_calling": True,
        "json_output": True,
        "family": "unknown",
    },
)

注意:我们并未测试所有与 OpenAI 兼容的 API,其中许多 API 与 OpenAI API 的工作方式不同,尽管它们可能声称支持 OpenAI API。在使用之前,请务必进行测试。

未来将添加对其他托管模型的支持。

模型客户端缓存

v0.2 中,您可以通过 LLM 配置中的 cache_seed 参数设置缓存种子,缓存默认启用。

makefile 复制代码
llm_config = {
    "config_list": [{"model": "gpt-4o", "api_key": "sk-xxx"}],
    "seed": 42,
    "temperature": 0,
    "cache_seed": 42,
}

v0.4 中,缓存默认未启用,要使用缓存,需要在模型客户端周围使用 ChatCompletionCache 包装器。

您可以使用 DiskCacheStoreRedisStore 来存储缓存。

arduino 复制代码
pip install -U "autogen-ext[openai, diskcache, redis]"

以下是使用 diskcache 进行本地缓存的示例:

python 复制代码
import asyncio
import tempfile
from autogen_core.models import UserMessage
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.models.cache import ChatCompletionCache, CHAT_CACHE_VALUE_TYPE
from autogen_ext.cache_store.diskcache import DiskCacheStore
from diskcache import Cache

async def main():
    with tempfile.TemporaryDirectory() as tmpdirname:
        # 初始化原始客户端
        openai_model_client = OpenAIChatCompletionClient(model="gpt-4o")

        # 然后初始化 CacheStore,这里使用 diskcache.Cache
        # 您也可以使用 redis,如下所示:
        # from autogen_ext.cache_store.redis import RedisStore
        # import redis
        # redis_instance = redis.Redis()
        # cache_store = RedisCacheStore[CHAT_CACHE_VALUE_TYPE](redis_instance)
        cache_store = DiskCacheStore[CHAT_CACHE_VALUE_TYPE](Cache(tmpdirname))
        cache_client = ChatCompletionCache(openai_model_client, cache_store)

        response = await cache_client.create([UserMessage(content="Hello, how are you?", source="user")])
        print(response)  # 应打印来自 OpenAI 的响应
        response = await cache_client.create([UserMessage(content="Hello, how are you?", source="user")])
        print(response)  # 应打印缓存的响应

asyncio.run(main())

助手智能体

v0.2 中,您可以按如下方式创建助手智能体:

ini 复制代码
from autogen.agentchat import AssistantAgent

llm_config = {
    "config_list": [{"model": "gpt-4o", "api_key": "sk-xxx"}],
    "seed": 42,
    "temperature": 0,
}
assistant = AssistantAgent(
    name="assistant",
    system_message="You are a helpful assistant.",
    llm_config=llm_config,
)

v0.4 中,创建方式类似,但需要指定 model_client 而不是 llm_config

ini 复制代码
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient

model_client = OpenAIChatCompletionClient(model="gpt-4o", api_key="sk-xxx", seed=42, temperature=0)
assistant = AssistantAgent(
    name="assistant",
    system_message="You are a helpful assistant.",
    model_client=model_client,
)

然而,使用方式有所不同。在 v0.4 中,不再调用 assistant.send,而是调用 assistant.on_messagesassistant.on_messages_stream 来处理传入消息。此外,on_messageson_messages_stream 方法是异步的,后者返回一个异步生成器,用于流式传输智能体的内部思考过程。

以下是在 v0.4 中直接调用助手智能体的示例,延续上述代码:

ini 复制代码
import asyncio
from autogen_agentchat.messages import TextMessage
from autogen_agentchat.agents import AssistantAgent
from autogen_core import CancellationToken
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    assistant = AssistantAgent(
        name="assistant",
        system_message="You are a helpful assistant.",
        model_client=model_client,
    )

    cancellation_token = CancellationToken()
    response = await assistant.on_messages([TextMessage(content="Hello!", source="user")], cancellation_token)
    print(response)

asyncio.run(main())

CancellationToken 可用于在调用 cancellation_token.cancel() 时异步取消请求,这将导致 on_messages 调用的 await 引发 CancelledError

多模态智能体

v0.4 中的 AssistantAgent 如果模型客户端支持,则支持多模态输入。模型客户端的 vision 能力用于确定智能体是否支持多模态输入。

ini 复制代码
import asyncio
from pathlib import Path
from autogen_agentchat.messages import MultiModalMessage
from autogen_agentchat.agents import AssistantAgent
from autogen_core import CancellationToken, Image
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    assistant = AssistantAgent(
        name="assistant",
        system_message="You are a helpful assistant.",
        model_client=model_client,
    )

    cancellation_token = CancellationToken()
    message = MultiModalMessage(
        content=["Here is an image:", Image.from_file(Path("test.png"))],
        source="user",
    )
    response = await assistant.on_messages([message], cancellation_token)
    print(response)

asyncio.run(main())

用户代理

v0.2 中,您可以按如下方式创建用户代理:

ini 复制代码
from autogen.agentchat import UserProxyAgent

user_proxy = UserProxyAgent(
    name="user_proxy",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=10,
    code_execution_config=False,
    llm_config=False,
)

此用户代理将通过控制台接收用户输入,如果传入消息以 "TERMINATE" 结尾,则会终止。

v0.4 中,用户代理只是一个仅接收用户输入的智能体,无需其他特殊配置。您可以按如下方式创建用户代理:

ini 复制代码
from autogen_agentchat.agents import UserProxyAgent

user_proxy = UserProxyAgent("user_proxy")

有关更多详细信息以及如何使用超时自定义输入函数,请参阅 UserProxyAgent

可对话智能体和注册回复

v0.2 中,您可以按如下方式创建可对话智能体并注册回复函数:

python 复制代码
from typing import Any, Dict, List, Optional, Tuple, Union
from autogen.agentchat import ConversableAgent

llm_config = {
    "config_list": [{"model": "gpt-4o", "api_key": "sk-xxx"}],
    "seed": 42,
    "temperature": 0,
}
conversable_agent = ConversableAgent(
    name="conversable_agent",
    system_message="You are a helpful assistant.",
    llm_config=llm_config,
    code_execution_config={"work_dir": "coding"},
    human_input_mode="NEVER",
    max_consecutive_auto_reply=10,
)

def reply_func(
    recipient: ConversableAgent,
    messages: Optional[List[Dict]] = None,
    sender: Optional[Agent] = None,
    config: Optional[Any] = None,
) -> Tuple[bool, Union[str, Dict, None]]:
    # 自定义回复逻辑
    return True, "Custom reply"

# 注册回复函数
conversable_agent.register_reply([ConversableAgent], reply_func, position=0)
# 注意:异步回复函数仅在使用异步发送时调用

v0.4 中,我们可以简单地创建一个自定义智能体,并实现 on_messageson_resetproduced_message_types 方法,而无需猜测 reply_func 的功能、其参数以及 position 的值。

python 复制代码
from typing import Sequence
from autogen_core import CancellationToken
from autogen_agentchat.agents import BaseChatAgent
from autogen_agentchat.messages import TextMessage, ChatMessage
from autogen_agentchat.base import Response

class CustomAgent(BaseChatAgent):
    async def on_messages(self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken) -> Response:
        return Response(chat_message=TextMessage(content="Custom reply", source=self.name))

    async def on_reset(self, cancellation_token: CancellationToken) -> None:
        pass

    @property
    def produced_message_types(self) -> Sequence[type[ChatMessage]]:
        return (TextMessage,)

然后,您可以像使用 AssistantAgent 一样使用自定义智能体。有关更多详细信息,请参阅自定义智能体教程。

保存和加载智能体状态

v0.2 中,没有内置方法来保存和加载智能体的状态,您需要自己实现,通过导出 ConversableAgentchat_messages 属性,并通过 chat_messages 参数重新导入。

v0.4 中,您可以在智能体上调用 save_stateload_state 方法来保存和加载其状态。

python 复制代码
import asyncio
import json
from autogen_agentchat.messages import TextMessage
from autogen_agentchat.agents import AssistantAgent
from autogen_core import CancellationToken
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    assistant = AssistantAgent(
        name="assistant",
        system_message="You are a helpful assistant.",
        model_client=model_client,
    )

    cancellation_token = CancellationToken()
    response = await assistant.on_messages([TextMessage(content="Hello!", source="user")], cancellation_token)
    print(response)

    # 保存状态
    state = await assistant.save_state()

    # (可选)将状态写入磁盘
    with open("assistant_state.json", "w") as f:
        json.dump(state, f)

    # (可选)从磁盘加载状态
    with open("assistant_state.json", "r") as f:
        state = json.load(f)
        print(state)  # 检查状态,其中包含聊天历史

    # 继续聊天
    response = await assistant.on_messages([TextMessage(content="Tell me a joke.", source="user")], cancellation_token)
    print(response)

    # 加载状态,使智能体恢复到最后一条消息之前的状态
    await assistant.load_state(state)

    # 再次进行相同的聊天
    response = await assistant.on_messages([TextMessage(content="Tell me a joke.", source="user")], cancellation_token)

asyncio.run(main())

您也可以在任何团队(如 RoundRobinGroupChat)上调用 save_stateload_state 来保存和加载整个团队的状态。

双智能体聊天

v0.2 中,您可以按如下方式创建用于代码执行的双智能体聊天:

ini 复制代码
from autogen.coding import LocalCommandLineCodeExecutor
from autogen.agentchat import AssistantAgent, UserProxyAgent

llm_config = {
    "config_list": [{"model": "gpt-4o", "api_key": "sk-xxx"}],
    "seed": 42,
    "temperature": 0,
}

assistant = AssistantAgent(
    name="assistant",
    system_message="You are a helpful assistant. Write all code in python. Reply only 'TERMINATE' if the task is done.",
    llm_config=llm_config,
    is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"),
)

user_proxy = UserProxyAgent(
    name="user_proxy",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=10,
    code_execution_config={"code_executor": LocalCommandLineCodeExecutor(work_dir="coding")},
    llm_config=False,
    is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"),
)

chat_result = user_proxy.initiate_chat(assistant, message="Write a python script to print 'Hello, world!'")
# Intermediate messages are printed to the console directly.
print(chat_result)

v0.4 中,您可以按如下方式创建用于代码执行的双智能体聊天:

python 复制代码
import asyncio
from autogen_agentchat.agents import AssistantAgent, CodeExecutorAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import TextMentionTermination, MaxMessageTermination
from autogen_agentchat.ui import Console
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    assistant = AssistantAgent(
        name="assistant",
        system_message="You are a helpful assistant. Write all code in python. Reply only 'TERMINATE' if the task is done.",
        model_client=model_client,
    )

    code_executor = CodeExecutorAgent(
        name="code_executor",
        code_executor=LocalCommandLineCodeExecutor(work_dir="coding"),
    )

    # The termination condition is a combination of text termination and max message termination, either of which will cause the chat to terminate.
    termination = TextMentionTermination("TERMINATE") | MaxMessageTermination(10)

    # The group chat will alternate between the assistant and the code executor.
    group_chat = RoundRobinGroupChat([assistant, code_executor], termination_condition=termination)

    # `run_stream` returns an async generator to stream the intermediate messages.
    stream = group_chat.run_stream(task="Write a python script to print 'Hello, world!'")
    # `Console` is a simple UI to display the stream.
    await Console(stream)

asyncio.run(main())

工具使用

v0.2 中,要创建一个使用工具的聊天机器人,必须有两个智能体,一个用于调用工具,一个用于执行工具。对于每个用户请求,都需要发起一个双智能体聊天。

ini 复制代码
from autogen.agentchat import AssistantAgent, UserProxyAgent, register_function

llm_config = {
    "config_list": [{"model": "gpt-4o", "api_key": "sk-xxx"}],
    "seed": 42,
    "temperature": 0,
}

tool_caller = AssistantAgent(
    name="tool_caller",
    system_message="You are a helpful assistant. You can call tools to help user.",
    llm_config=llm_config,
    max_consecutive_auto_reply=1,  # 设置为 1,以便在每个助手回复后返回应用程序,因为我们正在构建一个聊天机器人
)

tool_executor = UserProxyAgent(
    name="tool_executor",
    human_input_mode="NEVER",
    code_execution_config=False,
    llm_config=False,
)

def get_weather(city: str) -> str:
    return f"The weather in {city} is 72 degree and sunny."

# 将工具函数注册到工具调用者和执行者
register_function(get_weather, caller=tool_caller, executor=tool_executor)

while True:
    user_input = input("User: ")
    if user_input == "exit":
        break
    chat_result = tool_executor.initiate_chat(
        tool_caller,
        message=user_input,
        summary_method="reflection_with_llm",  # 让模型反思工具使用,设置为 "last_msg" 可直接返回工具调用结果
    )
    print("Assistant:", chat_result.summary)

v0.4 中,实际上只需要一个智能体 ------AssistantAgent------ 来处理工具调用和工具执行。

python 复制代码
import asyncio

from autogen_core import CancellationToken

from autogen_ext.models.openai import OpenAIChatCompletionClient

from autogen_agentchat.agents import AssistantAgent

from autogen_agentchat.messages import TextMessage

def get_weather(city: str) -> str:  # 也可以是异步工具
    return f"The weather in {city} is 72 degree and sunny."

async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)
    assistant = AssistantAgent(
        name="assistant",
        system_message="You are a helpful assistant. You can call tools to help user.",
        model_client=model_client,
        tools=[get_weather],
        reflect_on_tool_use=True,  # 设置为 True 让模型反思工具使用,设置为 False 可直接返回工具调用结果
    )
    while True:
        user_input = input("User: ")
        if user_input == "exit":
            break
        response = await assistant.on_messages([TextMessage(content=user_input, source="user")], CancellationToken())
        print("Assistant:", response.chat_message.content)

asyncio.run(main())

在诸如 RoundRobinGroupChat 这样的群聊中使用配备工具的智能体时,只需像上面那样将工具添加到智能体中,并创建一个包含这些智能体的群聊即可。

聊天结果

v0.2 中,您可以从 initiate_chat 方法获取一个 ChatResult 对象。例如:

ini 复制代码
chat_result = tool_executor.initiate_chat(
    tool_caller,
    message=user_input,
    summary_method="reflection_with_llm",
)

print(chat_result.summary)  # 获取聊天的 LLM 反思总结
print(chat_result.chat_history)  # 获取聊天历史
print(chat_result.cost)  # 获取聊天成本
print(chat_result.human_input)  # 获取聊天请求的人工输入

有关更多详细信息,请参阅 ChatResult 文档。

v0.4 中,您可以从 runrun_stream 方法获取一个 TaskResult 对象。TaskResult 对象包含 messages,它是聊天的消息历史,包括智能体的私有(工具调用等)和公共消息。

TaskResultChatResult 之间有一些显著差异:

  • TaskResult 中的 messages 列表使用与 ChatResult.chat_history 列表不同的消息格式。
  • 没有 summary 字段。应用程序需要决定如何使用 messages 列表总结聊天。
  • TaskResult 对象中不提供 human_input,因为可以通过使用 source 字段过滤从 messages 列表中提取用户输入。
  • TaskResult 对象中不提供 cost,但是您可以根据令牌使用情况计算成本。添加成本计算将是一个很好的社区扩展。有关社区扩展,请参阅。

v0.2 和 v0.4 消息之间的转换

您可以使用以下转换函数在 autogen_agentchat.base.TaskResult.messages 中的 v0.4 消息和 ChatResult.chat_history 中的 v0.2 消息之间进行转换。

python 复制代码
from typing import Any, Dict, List, Literal

from autogen_agentchat.messages import (
    AgentEvent,
    ChatMessage,
    HandoffMessage,
    MultiModalMessage,
    StopMessage,
    TextMessage,
    ToolCallExecutionEvent,
    ToolCallRequestEvent,
    ToolCallSummaryMessage,
)

from autogen_core import FunctionCall, Image

from autogen_core.models import FunctionExecutionResult

def convert_to_v02_message(
    message: AgentEvent | ChatMessage,
    role: Literal["assistant", "user", "tool"],
    image_detail: Literal["auto", "high", "low"] = "auto",
) -> Dict[str, Any]:
    """将 v0.4 AgentChat 消息转换为 v0.2 消息。

    Args:
        message (AgentEvent | ChatMessage): 要转换的消息。
        role (Literal["assistant", "user", "tool"]): 消息的角色。
        image_detail (Literal["auto", "high", "low"], 可选): 多模态消息中图像内容的详细级别。默认为 "auto"。

    Returns:
        Dict[str, Any]: 转换后的 AutoGen v0.2 消息。
    """
    v02_message: Dict[str, Any] = {}
    if isinstance(message, TextMessage | StopMessage | HandoffMessage | ToolCallSummaryMessage):
        v02_message = {"content": message.content, "role": role, "name": message.source}
    elif isinstance(message, MultiModalMessage):
        v02_message = {"content": [], "role": role, "name": message.source}
        for modal in message.content:
            if isinstance(modal, str):
                v02_message["content"].append({"type": "text", "text": modal})
            elif isinstance(modal, Image):
                v02_message["content"].append(modal.to_openai_format(detail=image_detail))
            else:
                raise ValueError(f"无效的多模态消息内容: {modal}")
    elif isinstance(message, ToolCallRequestEvent):
        v02_message = {"tool_calls": [], "role": "assistant", "content": None, "name": message.source}
        for tool_call in message.content:
            v02_message["tool_calls"].append(
                {
                    "id": tool_call.id,
                    "type": "function",
                    "function": {"name": tool_call.name, "args": tool_call.arguments},
                }
            )
    elif isinstance(message, ToolCallExecutionEvent):
        tool_responses: List[Dict[str, str]] = []
        for tool_result in message.content:
            tool_responses.append(
                {
                    "tool_call_id": tool_result.call_id,
                    "role": "tool",
                    "content": tool_result.content,
                }
            )
        content = "\n\n".join([response["content"] for response in tool_responses])
        v02_message = {"tool_responses": tool_responses, "role": "tool", "content": content}
    else:
        raise ValueError(f"无效的消息类型: {type(message)}")
    return v02_message

def convert_to_v04_message(message: Dict[str, Any]) -> AgentEvent | ChatMessage:
    """将 v0.2 消息转换为 v0.4 AgentChat 消息。"""
    if "tool_calls" in message:
        tool_calls: List[FunctionCall] = []
        for tool_call in message["tool_calls"]:
            tool_calls.append(
                FunctionCall(
                    id=tool_call["id"],
                    name=tool_call["function"]["name"],
                    arguments=tool_call["function"]["args"],
                )
            )
        return ToolCallRequestEvent(source=message["name"], content=tool_calls)
    elif "tool_responses" in message:
        tool_results: List[FunctionExecutionResult] = []
        for tool_response in message["tool_responses"]:
            tool_results.append(
                FunctionExecutionResult(
                    call_id=tool_response["tool_call_id"],
                    content=tool_response["content"],
                )
            )
        return ToolCallExecutionEvent(source="tools", content=tool_results)
    elif isinstance(message["content"], list):
        content: List[str | Image] = []
        for modal in message["content"]:  # type: ignore
            if modal["type"] == "text":  # type: ignore
                content.append(modal["text"])  # type: ignore
            else:
                content.append(Image.from_uri(modal["image_url"]["url"]))  # type: ignore
        return MultiModalMessage(content=content, source=message["name"])
    elif isinstance(message["content"], str):
        return TextMessage(content=message["content"], source=message["name"])
    else:
        raise ValueError(f"无法转换消息: {message}")

群聊

v0.2 中,您需要创建一个 GroupChat 类并将其传递给 GroupChatManager,并且需要有一个用户代理作为参与者来发起聊天。对于一个简单的作家和评论家场景,您可以如下操作:

ini 复制代码
from autogen.agentchat import AssistantAgent, GroupChat, GroupChatManager

llm_config = {
    "config_list": [{"model": "gpt-4o", "api_key": "sk-xxx"}],
    "seed": 42,
    "temperature": 0,
}

writer = AssistantAgent(
    name="writer",
    description="A writer.",
    system_message="You are a writer.",
    llm_config=llm_config,
    is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("APPROVE"),
)

critic = AssistantAgent(
    name="critic",
    description="A critic.",
    system_message="You are a critic, provide feedback on the writing. Reply only 'APPROVE' if the task is done.",
    llm_config=llm_config,
)

# 创建一个包含作家和评论家的群聊
groupchat = GroupChat(agents=[writer, critic], messages=[], max_round=12)

# 创建一个群聊管理器来管理群聊,使用轮询选择方法
manager = GroupChatManager(groupchat=groupchat, llm_config=llm_config, speaker_selection_method="round_robin")

# 与编辑者发起聊天,中间消息将直接打印到控制台
result = editor.initiate_chat(
    manager,
    message="Write a short story about a robot that discovers it has feelings.",
)

print(result.summary)

v0.4 中,您可以使用 RoundRobinGroupChat 来实现相同的行为。

ini 复制代码
import asyncio

from autogen_agentchat.agents import AssistantAgent

from autogen_agentchat.teams import RoundRobinGroupChat

from autogen_agentchat.conditions import TextMentionTermination

from autogen_agentchat.ui import Console

from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    writer = AssistantAgent(
        name="writer",
        description="A writer.",
        system_message="You are a writer.",
        model_client=model_client,
    )

    critic = AssistantAgent(
        name="critic",
        description="A critic.",
        system_message="You are a critic, provide feedback on the writing. Reply only 'APPROVE' if the task is done.",
        model_client=model_client,
    )

    # 终止条件是文本终止,当收到 "APPROVE" 文本时聊天将终止
    termination = TextMentionTermination("APPROVE")

    # 群聊将在作家和评论家之间交替
    group_chat = RoundRobinGroupChat([writer, critic], termination_condition=termination, max_turns=12)

    # `run_stream` 返回一个异步生成器来流式传输中间消息
    stream = group_chat.run_stream(task="Write a short story about a robot that discovers it has feelings.")
    # `Console` 是一个简单的 UI 来显示流
    await Console(stream)

asyncio.run(main())

对于基于 LLM 的发言者选择,您可以使用 SelectorGroupChat 代替。有关更多详细信息,请参阅 Selector Group Chat 教程和 SelectorGroupChat

注意 :在 v0.4 中,在群聊中使用工具时不需要在用户代理上注册函数。您可以像在工具使用部分所示的那样将工具函数传递给 AssistantAgent。智能体将在需要时自动调用工具。如果您的工具输出格式不正确,您可以使用 reflect_on_tool_use 参数让模型反思工具使用。

恢复群聊

v0.2 中,恢复群聊有点复杂。您需要显式地保存群聊消息,并在想要恢复聊天时重新加载它们。有关更多详细信息,请参阅 v0.2 中的恢复群聊。

v0.4 中,您可以简单地再次使用相同的群聊对象调用 runrun_stream 来恢复聊天。要导出和加载状态,您可以使用 save_stateload_state 方法。

ini 复制代码
import asyncio
import json

from autogen_agentchat.agents import AssistantAgent

from autogen_agentchat.teams import RoundRobinGroupChat

from autogen_agentchat.conditions import TextMentionTermination

from autogen_agentchat.ui import Console

from autogen_ext.models.openai import OpenAIChatCompletionClient

def create_team() -> RoundRobinGroupChat:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    writer = AssistantAgent(
        name="writer",
        description="A writer.",
        system_message="You are a writer.",
        model_client=model_client,
    )

    critic = AssistantAgent(
        name="critic",
        description="A critic.",
        system_message="You are a critic, provide feedback on the writing. Reply only 'APPROVE' if the task is done.",
        model_client=model_client,
    )

    # 终止条件是文本终止,当收到 "APPROVE" 文本时聊天将终止
    termination = TextMentionTermination("APPROVE")

    # 群聊将在作家和评论家之间交替
    group_chat = RoundRobinGroupChat([writer, critic], termination_condition=termination)

    return group_chat

async def main() -> None:
    # 创建团队
    group_chat = create_team()

    # `run_stream` 返回一个异步生成器来流式传输中间消息
    stream = group_chat.run_stream(task="Write a short story about a robot that discovers it has feelings.")
    # `Console` 是一个简单的 UI 来显示流
    await Console(stream)

    # 保存群聊和所有参与者的状态
    state = await group_chat.save_state()
    with open("group_chat_state.json", "w") as f:
        json.dump(state, f)

    # 创建一个具有相同参与者配置的新团队
    group_chat = create_team()

    # 加载群聊和所有参与者的状态
    with open("group_chat_state.json", "r") as f:
        state = json.load(f)
    await group_chat.load_state(state)

    # 恢复聊天
    stream = group_chat.run_stream(task="Translate the story into Chinese.")
    await Console(stream)

asyncio.run(main())

带工具使用的群聊

v0.2 的群聊中,若要使用工具,需在用户代理上注册工具函数,并将用户代理纳入群聊。如此,其他智能体发出的工具调用会被路由至用户代理执行。但我们发现这种方式存在诸多问题,比如工具调用路由可能无法按预期工作,且不支持函数调用的模型无法接收工具调用请求与结果。

v0.4 中,无需在用户代理上注册工具函数。因为在 v0.4 里,智能体能够直接调用工具,只要在创建 AssistantAgent 时将工具函数作为参数传入即可。例如,在群聊场景下,若有多个智能体,每个智能体都可按如下方式配置工具:

ini 复制代码
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient


def get_weather(city: str) -> str:
    return f"The weather in {city} is 72 degree and sunny."


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    agent1 = AssistantAgent(
        name="agent1",
        system_message="You can use the get_weather tool to answer user questions.",
        model_client=model_client,
        tools=[get_weather]
    )

    agent2 = AssistantAgent(
        name="agent2",
        system_message="You are another agent in the group chat.",
        model_client=model_client
    )

    termination = TextMentionTermination("END")
    group_chat = RoundRobinGroupChat([agent1, agent2], termination_condition=termination)

    stream = group_chat.run_stream(task="Ask about the weather in New York")
    await Console(stream)


asyncio.run(main())

在上述示例中,agent1 被配置为可使用 get_weather 工具。当群聊运行时,若 agent1 认为需要,便会调用该工具。

带自定义选择器(Stateflow)的群聊

v0.2 中,没有直接支持带自定义选择器(如 Stateflow)的群聊功能。

v0.4 中,SelectorGroupChat 类提供了基于自定义逻辑选择发言者的功能。通过自定义选择器函数,可以实现类似 Stateflow 的复杂状态流转逻辑。例如,根据消息内容、智能体状态等因素决定下一个发言的智能体。以下是一个简单示例:

ini 复制代码
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient


def custom_selector(team, messages):
    # 简单示例:总是选择第一个智能体发言
    return team.agents[0]


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    agent1 = AssistantAgent(
        name="agent1",
        system_message="Agent 1 in the group.",
        model_client=model_client
    )

    agent2 = AssistantAgent(
        name="agent2",
        system_message="Agent 2 in the group.",
        model_client=model_client
    )

    termination = TextMentionTermination("END")
    group_chat = SelectorGroupChat([agent1, agent2], termination_condition=termination, selector=custom_selector)

    stream = group_chat.run_stream(task="Start the group chat")
    await Console(stream)


asyncio.run(main())

在这个示例中,custom_selector 函数简单地选择第一个智能体发言。实际应用中,可以根据更复杂的逻辑来选择发言者,实现类似 Stateflow 的功能。

嵌套聊天

v0.2 中,实现嵌套聊天较为复杂,需要手动管理不同智能体之间的交互以及消息传递,并且难以跟踪和管理嵌套层次。

v0.4 中,由于其事件驱动和分层的架构,嵌套聊天变得更加直观和易于管理。例如,可以在一个群聊中,让某个智能体发起一个子聊天,而无需复杂的手动管理。以下是一个简单的概念示例:

ini 复制代码
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    parent_agent1 = AssistantAgent(
        name="parent_agent1",
        system_message="Parent agent 1.",
        model_client=model_client
    )

    parent_agent2 = AssistantAgent(
        name="parent_agent2",
        system_message="Parent agent 2.",
        model_client=model_client
    )

    child_agent1 = AssistantAgent(
        name="child_agent1",
        system_message="Child agent 1 for nested chat.",
        model_client=model_client
    )

    child_agent2 = AssistantAgent(
        name="child_agent2",
        system_message="Child agent 2 for nested chat.",
        model_client=model_client
    )

    child_termination = TextMentionTermination("CHILD_END")
    child_group_chat = RoundRobinGroupChat([child_agent1, child_agent2], termination_condition=child_termination)

    def nested_chat_handler(parent_messages):
        async def run_nested_chat():
            task = "Some task for nested chat based on parent messages"
            stream = child_group_chat.run_stream(task)
            async for message in stream:
                # 可以在这里处理子聊天的消息,例如发送回父聊天
                pass
        asyncio.create_task(run_nested_chat())

    parent_agent1.register_event_handler("on_message", nested_chat_handler)

    parent_termination = TextMentionTermination("PARENT_END")
    parent_group_chat = RoundRobinGroupChat([parent_agent1, parent_agent2], termination_condition=parent_termination)

    stream = parent_group_chat.run_stream(task="Start the parent chat")
    await Console(stream)


asyncio.run(main())

在上述示例中,parent_agent1 注册了一个事件处理程序,当收到消息时,会发起一个子群聊 child_group_chat

顺序聊天

v0.2 中,实现顺序聊天需要手动控制智能体之间的消息传递顺序,并且难以动态调整顺序。

v0.4 中,可以通过自定义团队类或者利用现有的团队类(如 RoundRobinGroupChat 并结合自定义逻辑)来实现顺序聊天。例如,创建一个新的团队类,按照预定义的顺序依次让智能体发言:

ini 复制代码
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import BaseGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient


class SequentialChatGroup(BaseGroupChat):
    def __init__(self, agents, termination_condition):
        super().__init__(agents, termination_condition)
        self.current_agent_index = 0

    async def _select_next_speaker(self, messages):
        speaker = self.agents[self.current_agent_index]
        self.current_agent_index = (self.current_agent_index + 1) % len(self.agents)
        return speaker


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    agent1 = AssistantAgent(
        name="agent1",
        system_message="First agent in sequential chat.",
        model_client=model_client
    )

    agent2 = AssistantAgent(
        name="agent2",
        system_message="Second agent in sequential chat.",
        model_client=model_client
    )

    termination = TextMentionTermination("END")
    sequential_group_chat = SequentialChatGroup([agent1, agent2], termination_condition=termination)

    stream = sequential_group_chat.run_stream(task="Start sequential chat")
    await Console(stream)


asyncio.run(main())

在上述示例中,SequentialChatGroup 类继承自 BaseGroupChat,并自定义了 _select_next_speaker 方法,按照顺序选择智能体发言。

GPTAssistantAgent

v0.2 中,没有专门的 GPTAssistantAgent 类。

v0.4 中,GPTAssistantAgentAssistantAgent 的一个变体,专门用于与 OpenAI 的 GPT Assistant API 进行交互。使用 GPTAssistantAgent 时,需要提供 assistant_id,它代表在 OpenAI 平台上创建的特定助手。例如:

ini 复制代码
import asyncio
from autogen_agentchat.agents import GPTAssistantAgent
from autogen_agentchat.messages import TextMessage
from autogen_core import CancellationToken
from autogen_ext.models.openai import OpenAIChatCompletionClient


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", api_key="sk-xxx")

    assistant = GPTAssistantAgent(
        name="gpt_assistant",
        assistant_id="your_assistant_id",
        model_client=model_client
    )

    cancellation_token = CancellationToken()
    response = await assistant.on_messages([TextMessage(content="Hello!", source="user")], cancellation_token)
    print(response)


asyncio.run(main())

GPTAssistantAgent 允许用户利用在 OpenAI 平台上预先配置好的助手功能,例如自定义工具、知识库等。

长上下文处理

v0.2 中,长上下文处理较为困难,因为没有内置的机制来有效管理和总结长对话历史。用户需要手动处理上下文,例如截断消息历史或者使用外部工具进行总结。

v0.4 中,通过引入智能体状态管理和更灵活的消息处理机制,长上下文处理得到了显著改善。例如,AssistantAgent 类提供了 summary 方法,可以在需要时对对话历史进行总结。此外,v0.4 的架构允许更方便地集成外部总结工具或者自定义总结逻辑。以下是一个简单示例,展示如何在对话过程中进行总结:

ini 复制代码
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.messages import TextMessage
from autogen_core import CancellationToken
from autogen_ext.models.openai import OpenAIChatCompletionClient


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    assistant = AssistantAgent(
        name="assistant",
        system_message="You are a helpful assistant.",
        model_client=model_client
    )

    cancellation_token = CancellationToken()
    messages = [
        TextMessage(content="First message", source="user"),
        TextMessage(content="Second message", source="user")
    ]
    for message in messages:
        response = await assistant.on_messages([message], cancellation_token)

    summary = await assistant.summary()
    print("Summary:", summary)


asyncio.run(main())

在这个示例中,随着对话消息的积累,调用 assistant.summary() 方法可以获取对话的总结,有助于管理长上下文。

可观测性和控制

v0.2 中,可观测性和控制能力有限。例如,很难实时监控智能体之间的交互,并且对智能体行为的控制大多依赖于手动配置参数。

v0.4 中,由于其事件驱动的架构,提供了更好的可观测性和控制能力。可以通过注册事件处理程序来监控智能体的各种事件,如消息接收、发送、工具调用等。例如,以下代码展示如何监控智能体发送消息的事件:

python 复制代码
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.messages import TextMessage
from autogen_core import CancellationToken
from autogen_ext.models.openai import OpenAIChatCompletionClient


def message_sent_handler(event):
    print(f"Message sent: {event.chat_message.content}")


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    assistant = AssistantAgent(
        name="assistant",
        system_message="You are a helpful assistant.",
        model_client=model_client
    )

    assistant.register_event_handler("on_message_sent", message_sent_handler)

    cancellation_token = CancellationToken()
    response = await assistant.on_messages([TextMessage(content="Hello!", source="user")], cancellation_token)


asyncio.run(main())

此外,通过 CancellationToken 可以在运行时取消智能体的操作,实现对智能体行为的动态控制。

代码执行器

v0.2 中,代码执行器主要通过 CodeExecutor 类及其子类(如 LocalCodeExecutorRemoteCodeExecutor)实现。例如,使用 LocalCommandLineCodeExecutor 来在本地执行代码:

ini 复制代码
from autogen.coding import LocalCommandLineCodeExecutor

code_executor = LocalCommandLineCodeExecutor()
result = code_executor.run("print('Hello, World!')")
print(result)

v0.4 中,代码执行器的功能得到了进一步整合和改进。CodeExecutor 类得到了增强,并且可以更方便地与智能体集成。例如,在 AssistantAgent 中,可以直接配置代码执行器,使得智能体在需要时能够执行代码。以下是一个示例:

ini 复制代码
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.messages import TextMessage
from autogen_core import CancellationToken
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.code_execution import LocalCodeExecutor


async def main() -> None:
    model_client = OpenAIChatCompletionClient(model="gpt-4o", seed=42, temperature=0)

    code_executor = LocalCodeExecutor()

    assistant = AssistantAgent(
        name="assistant",
        system_message="You can execute code when needed.",
        model_client=model_client,
        code_executor=code_executor
    )

    cancellation_token = CancellationToken()
    response = await assistant.on_messages([TextMessage(content="Execute print('Hello, World!')", source="user")], cancellation_token)
    print(response)


asyncio.run(main())

在这个示例中,AssistantAgent 配置了 LocalCodeExecutor,当收到需要执行代码的消息时,智能体可以调用代码执行器来执行代码。

相关推荐
羊小猪~~23 分钟前
MYSQL学习笔记(九):MYSQL表的“增删改查”
数据库·笔记·后端·sql·学习·mysql·考研
豌豆花下猫39 分钟前
Python 潮流周刊#90:uv 一周岁了,优缺点分析(摘要)
后端·python·ai
橘猫云计算机设计1 小时前
基于SSM的《计算机网络》题库管理系统(源码+lw+部署文档+讲解),源码可白嫖!
java·数据库·spring boot·后端·python·计算机网络·毕设
熬夜苦读学习1 小时前
Linux文件系统
linux·运维·服务器·开发语言·后端
坚定信念,勇往无前2 小时前
Spring Boot 如何保证接口安全
spring boot·后端·安全
程序员侠客行3 小时前
Spring事务原理详解 三
java·后端·spring·架构
Hello.Reader4 小时前
深入理解 Rust 的 `Rc<T>`:实现多所有权的智能指针
开发语言·后端·rust
yoona10204 小时前
Rust编程语言入门教程(八)所有权 Stack vs Heap
开发语言·后端·rust·区块链·学习方法
Victor3565 小时前
Zookeeper(67) Zookeeper在HBase中的应用是什么?
后端
大模型之路5 小时前
Grok-3:人工智能领域的新突破
人工智能·llm·grok-3