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_url
和 model_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
包装器。
您可以使用 DiskCacheStore
或 RedisStore
来存储缓存。
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_messages
或 assistant.on_messages_stream
来处理传入消息。此外,on_messages
和 on_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_messages
、on_reset
和 produced_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
中,没有内置方法来保存和加载智能体的状态,您需要自己实现,通过导出 ConversableAgent
的 chat_messages
属性,并通过 chat_messages
参数重新导入。
在 v0.4
中,您可以在智能体上调用 save_state
和 load_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_state
和 load_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
中,您可以从 run
或 run_stream
方法获取一个 TaskResult
对象。TaskResult
对象包含 messages
,它是聊天的消息历史,包括智能体的私有(工具调用等)和公共消息。
TaskResult
和 ChatResult
之间有一些显著差异:
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
中,您可以简单地再次使用相同的群聊对象调用 run
或 run_stream
来恢复聊天。要导出和加载状态,您可以使用 save_state
和 load_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
中,GPTAssistantAgent
是 AssistantAgent
的一个变体,专门用于与 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
类及其子类(如 LocalCodeExecutor
和 RemoteCodeExecutor
)实现。例如,使用 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
,当收到需要执行代码的消息时,智能体可以调用代码执行器来执行代码。