对话模式
在上一章节中,我们使用了双代理对话,可以通过initiate_chat
方法来启动。双代理聊天是一种有用的对话模式,但AutoGen提供了更多。在本章中,我们将首先深入探讨双代理聊天模式和聊天结果,然后我们将向您展示涉及两个以上代理的几种对话模式。
概览
- 双代理聊天: 最简单的对话模式,其中两个代理互相聊天。
- 顺序聊天: 两个代理人之间的一系列聊天,通过一个携带机制连接在一起,该机制将前一次聊天的摘要带到下一次聊天的上下文中。
- Group Chat: a single chat involving more than two agents. An important question in group chat is: What agent should be next to speak? To support different scenarios, we provide different ways to organize agents in a group chat:
- 嵌套聊天: 将工作流程打包为单个代理,以便在更大的工作流程中重复使用。
双代理聊天和聊天结果
双代理聊天是最简单的对话模式。我们使用每个ConversableAgent
代理的initiate_chat
方法来启动双代理聊天。我们已经在之前章节中看到了多个双代理聊天的示例,但尚未涵盖细节。
下图展示了双智能体聊天的工作原理。
一个双代理聊天需要两个输入:一条消息,这是由调用者提供的字符串;以及上下文,用于指定聊天的各种参数。发送方代理使用其聊天初始化方法(即ConversableAgent
的generate_init_message
方法)从输入生成初始消息,并将其发送给接收方代理以开始聊天。发送方代理是调用initiate_chat
方法的代理,而接收方代理是另一个代理。
一旦聊天结束,聊天记录会由聊天摘要器处理。摘要器会对聊天记录进行总结,并计算聊天的Token使用量。你可以通过配置initiate_chat
方法的summary_method
参数来选择摘要类型。默认情况下,它是聊天的最后一条消息(即summary_method='last_msg'
)。
下面的示例是学生代理和教师代理之间的两人对话。其总结器使用基于LLM的总结。
import os
from autogen import ConversableAgent
student_agent = ConversableAgent(
name="Student_Agent",
system_message="You are a student willing to learn.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
)
teacher_agent = ConversableAgent(
name="Teacher_Agent",
system_message="You are a math teacher.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
)
chat_result = student_agent.initiate_chat(
teacher_agent,
message="What is triangle inequality?",
summary_method="reflection_with_llm",
max_turns=2,
)
What is triangle inequality?
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Triangle inequality theorem is a fundamental principle in geometry that states that the sum of the lengths of any two sides of a triangle must always be greater than the length of the third side. In a triangle with sides of lengths a, b, and c, the theorem can be written as:
a + b > c
a + c > b
b + c > a
Each of these represents the condition for one specific side (a, b, or c). All must be true for a triangle to exist.
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Thank you for the explanation. This theorem helps in understanding the basic properties of a triangle. It can also be useful when solving geometric problems or proving other mathematical theorems. Can you give me an example of how we can use the triangle inequality theorem?
--------------------------------------------------------------------------------
>>>>>>>> USING AUTO REPLY...
Absolutely! Here's an example:
Suppose you're given three line segments with lengths 10, 7, and 3 units. The question is: "Can these three line segments form a triangle?"
To answer this, you would use the triangle inequality theorem. Adding any two side lengths together should be greater than the third:
- For sides 10 and 7: 10 + 7 = 17, which is larger than 3.
- For sides 10 and 3: 10 + 3 = 13, which is larger than 7.
- For sides 7 and 3: 7 + 3 = 10, which is equal to the length of the third side (10), but not greater.
So, these three lines cannot form a triangle, because not all pairs of sides satisfy the triangle inequality theorem.
--------------------------------------------------------------------------------
让我们看看摘要是什么样子的。摘要存储在被initiate_chat
方法返回的ChatResult
类型的chat_result
对象中。
print(chat_result.summary)
The triangle inequality theorem states that in a triangle, the sum of the lengths of any two sides must always be greater than the length of the third side. This principle is significant in geometry and is used in solving problems or proving theorems. For instance, if given three line segments, you can determine if they can form a triangle using this theorem.
在上面的例子中,总结方法设置为reflection_with_llm
,该方法从对话中获取信息列表,并通过调用LLM进行总结。总结方法首先尝试使用接收者的LLM,如果不可用,则使用发送者的LLM。在这种情况下,接收者是“Teacher_Agent”,发送者是“Student_Agent”。LLM的输入提示是以下默认提示:
print(ConversableAgent.DEFAULT_SUMMARY_PROMPT)
Summarize the takeaway from the conversation. Do not add any introductory phrases.
你也可以通过设置initiate_chat
的summary_prompt
参数来使用自定义提示。
ChatResult
对象中还有一些其他有用的信息,包括对话历史、人类输入和代币消耗。
# Get the chat history.
import pprint
pprint.pprint(chat_result.chat_history)
[{'content': 'What is triangle inequality?', 'role': 'assistant'},
{'content': 'Triangle inequality theorem is a fundamental principle in '
'geometry that states that the sum of the lengths of any two '
'sides of a triangle must always be greater than the length of '
'the third side. In a triangle with sides of lengths a, b, and c, '
'the theorem can be written as:\n'
'\n'
'a + b > c\n'
'a + c > b\n'
'b + c > a\n'
'\n'
'Each of these represents the condition for one specific side (a, '
'b, or c). All must be true for a triangle to exist.',
'role': 'user'},
{'content': 'Thank you for the explanation. This theorem helps in '
'understanding the basic properties of a triangle. It can also be '
'useful when solving geometric problems or proving other '
'mathematical theorems. Can you give me an example of how we can '
'use the triangle inequality theorem?',
'role': 'assistant'},
{'content': "Absolutely! Here's an example:\n"
'\n'
"Suppose you're given three line segments with lengths 10, 7, and "
'3 units. The question is: "Can these three line segments form a '
'triangle?"\n'
'\n'
'To answer this, you would use the triangle inequality theorem. '
'Adding any two side lengths together should be greater than the '
'third:\n'
'\n'
'- For sides 10 and 7: 10 + 7 = 17, which is larger than 3.\n'
'- For sides 10 and 3: 10 + 3 = 13, which is larger than 7.\n'
'- For sides 7 and 3: 7 + 3 = 10, which is equal to the length of '
'the third side (10), but not greater.\n'
'\n'
'So, these three lines cannot form a triangle, because not all '
'pairs of sides satisfy the triangle inequality theorem.',
'role': 'user'}]
聊天结果中的聊天信息是从接收者代理的角度来看的——发送者是“助手”,接收者是“用户”。
# Get the cost of the chat.
pprint.pprint(chat_result.cost)
({'gpt-4-0613': {'completion_tokens': 399,
'cost': 0.04521,
'prompt_tokens': 709,
'total_tokens': 1108},
'total_cost': 0.04521},
{'total_cost': 0})
顺序聊天
这个模式的名称不言自明 —— 它是由两个代理之间的一系列对话组成的,这些对话通过一种称为carryover的机制链接在一起,该机制将前一次对话的摘要带入下一次对话的上下文中。
这种模式对于可以分解为相互依赖的子任务的复杂任务非常有用。下图展示了这种模式的工作原理。
在这种模式中,一对代理首先开始一个双代理聊天,然后对话的总结成为下一个双代理聊天的延续。下一个聊天将延续传递给上下文的carryover
参数,以生成其初始消息。
随着对话的进行,遗留信息会不断积累,因此每次后续聊天都会从之前所有聊天的遗留信息开始。
上图显示了所有聊天中的不同接收代理, 然而,序列中的接收代理允许重复。
为了说明这种模式,让我们考虑一个简单的算术操作符代理的例子。一个代理(称为“Number_Agent”)负责生成一个数字,而其他代理负责对这个数字执行特定的算术操作,例如加1、乘以2等。
# The Number Agent always returns the same numbers.
number_agent = ConversableAgent(
name="Number_Agent",
system_message="You return me the numbers I give you, one number each line.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
human_input_mode="NEVER",
)
# The Adder Agent adds 1 to each number it receives.
adder_agent = ConversableAgent(
name="Adder_Agent",
system_message="You add 1 to each number I give you and return me the new numbers, one number each line.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
human_input_mode="NEVER",
)
# The Multiplier Agent multiplies each number it receives by 2.
multiplier_agent = ConversableAgent(
name="Multiplier_Agent",
system_message="You multiply each number I give you by 2 and return me the new numbers, one number each line.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
human_input_mode="NEVER",
)
# The Subtracter Agent subtracts 1 from each number it receives.
subtracter_agent = ConversableAgent(
name="Subtracter_Agent",
system_message="You subtract 1 from each number I give you and return me the new numbers, one number each line.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
human_input_mode="NEVER",
)
# The Divider Agent divides each number it receives by 2.
divider_agent = ConversableAgent(
name="Divider_Agent",
system_message="You divide each number I give you by 2 and return me the new numbers, one number each line.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
human_input_mode="NEVER",
)
数字代理先与第一个操作员代理交谈,然后与第二个操作员代理交谈,以此类推。每次交谈后,对话中的最后一条消息(即操作员代理的算术运算结果)将用作对话的摘要。这是通过summary_method
参数指定的。最终,我们将得到算术运算的结果。
# Start a sequence of two-agent chats.
# Each element in the list is a dictionary that specifies the arguments
# for the initiate_chat method.
chat_results = number_agent.initiate_chats(
[
{
"recipient": adder_agent,
"message": "14",
"max_turns": 2,
"summary_method": "last_msg",
},
{
"recipient": multiplier_agent,
"message": "These are my numbers",
"max_turns": 2,
"summary_method": "last_msg",
},
{
"recipient": subtracter_agent,
"message": "These are my numbers",
"max_turns": 2,
"summary_method": "last_msg",
},
{
"recipient": divider_agent,
"message": "These are my numbers",
"max_turns": 2,
"summary_method": "last_msg",
},
]
)
********************************************************************************
Start a new chat with the following message:
14
With the following carryover:
********************************************************************************
14
--------------------------------------------------------------------------------
15
--------------------------------------------------------------------------------
15
--------------------------------------------------------------------------------
16
--------------------------------------------------------------------------------
********************************************************************************
Start a new chat with the following message:
These are my numbers
With the following carryover:
16
********************************************************************************
These are my numbers
Context:
16
--------------------------------------------------------------------------------
32
--------------------------------------------------------------------------------
32
--------------------------------------------------------------------------------
64
--------------------------------------------------------------------------------
********************************************************************************
Start a new chat with the following message:
These are my numbers
With the following carryover:
16
64
********************************************************************************
These are my numbers
Context:
16
64
--------------------------------------------------------------------------------
15
63
--------------------------------------------------------------------------------
15
63
--------------------------------------------------------------------------------
14
62
--------------------------------------------------------------------------------
********************************************************************************
Start a new chat with the following message:
These are my numbers
With the following carryover:
16
64
14
62
********************************************************************************
These are my numbers
Context:
16
64
14
62
--------------------------------------------------------------------------------
8
32
7
31
--------------------------------------------------------------------------------
8
32
7
31
--------------------------------------------------------------------------------
4
16
3.5
15.5
--------------------------------------------------------------------------------
首先要注意的是,initiate_chats
方法接受一个字典列表,每个字典包含 initiate_chat
方法的参数。
其次,序列中的每次聊天最多进行2轮,如设置max_turns=2
所指定的,这意味着每个算术操作会执行两次。因此,你可以在第一次聊天中看到数字14变为15,然后再变为16,在第二次聊天中数字16变为32,然后再变为64,依此类推。
第三,随着聊天的进行,遗留问题会累积。在第二次聊天中,遗留问题是第一次聊天的摘要“16”。在第三次聊天中,遗留问题是第一次和第二次聊天的摘要,即列表“16”和“64”,并对这两个数字进行操作。在第四次也是最后一次聊天中,遗留问题是之前所有聊天的摘要,即列表“16”、“64”、“14”和“62”,并对所有这些数字进行操作。
最后要注意的是,initiate_chats
方法返回一个由 ChatResult
对象组成的列表,序列中的每个聊天对应一个对象。
print("First Chat Summary: ", chat_results[0].summary)
print("Second Chat Summary: ", chat_results[1].summary)
print("Third Chat Summary: ", chat_results[2].summary)
print("Fourth Chat Summary: ", chat_results[3].summary)
First Chat Summary: 16
Second Chat Summary: 64
Third Chat Summary: 14
62
Fourth Chat Summary: 4
16
3.5
15.5
除了从同一个发送者代理调用initiate_chats
,你还可以调用高级函数autogen.agentchat.initiate_chats
来启动一系列不同发送者代理之间的双代理对话。此函数允许你为序列中的每个对话指定发送者代理。
群聊
到目前为止,我们只看到了涉及两个代理或一系列两代理对话的对话模式。AutoGen 提供了一个更通用的对话模式,称为群组聊天,它涉及两个以上的代理。群组聊天的核心思想是,所有代理都为一个单一的对话线程做出贡献,并共享相同的上下文。这对于需要多个代理之间协作的任务非常有用。
下图展示了群聊的工作原理。
一个群聊由一种特殊代理类型GroupChatManager
来协调。
在群聊的第一步中,群聊管理器选择一个代理发言。然后,被选中的代理发言并将消息发送回群聊管理器,群聊管理器将消息广播给组中所有其他代理。这个过程重复进行,直到对话结束。
群聊管理器可以使用多种策略来选择下一个代理。目前,支持以下策略:
round_robin
: 群聊管理器根据提供的代理顺序,以轮询的方式选择代理。random
: 群聊管理器随机选择代理。manual
: 群聊管理器通过请求人类输入来选择代理。auto
: 默认策略,使用群组聊天管理器的LLM来选择代理。
为了说明这种模式,让我们考虑一个简单的例子,即与前一个例子中相同的算术操作符代理之间的群聊,目标是通过由代理驱动的一系列算术操作将数字转换为特定的目标数字。
在这个例子中,我们使用auto
策略来选择下一个代理。为了帮助群聊管理器选择下一个代理,我们还设置了代理的description
。如果没有description
,群聊管理器将使用代理的system_message
,这可能不是最佳选择。
# The `description` attribute is a string that describes the agent.
# It can also be set in `ConversableAgent` constructor.
adder_agent.description = "Add 1 to each input number."
multiplier_agent.description = "Multiply each input number by 2."
subtracter_agent.description = "Subtract 1 from each input number."
divider_agent.description = "Divide each input number by 2."
number_agent.description = "Return the numbers given."
我们首先创建一个GroupChat
对象并提供代理列表。如果
我们使用round_robin
策略,这个列表将指定
代理的选择顺序。我们还将群聊初始化
使用空消息列表和最大轮数为6,这意味着
最多会有6次选择发言人,代理发言并广播消息的迭代。
from autogen import GroupChat
group_chat = GroupChat(
agents=[adder_agent, multiplier_agent, subtracter_agent, divider_agent, number_agent],
messages=[],
max_round=6,
)
现在我们创建一个GroupChatManager
对象并将GroupChat
对象作为输入提供。我们还需要指定Group Chat Manager的llm_config
,以便它可以使用LLM来选择下一个代理(auto
策略)。
from autogen import GroupChatManager
group_chat_manager = GroupChatManager(
groupchat=group_chat,
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
)
最后,我们有之前的Number Agent来启动一个双代理聊天与Group Chat Manager,它在内部运行群聊,并在内部群聊完成时终止双代理聊天。因为Number Agent被我们选择为发言者,它被视为群聊的第一轮。
chat_result = number_agent.initiate_chat(
group_chat_manager,
message="My number is 3, I want to turn it into 13.",
summary_method="reflection_with_llm",
)
My number is 3, I want to turn it into 13.
--------------------------------------------------------------------------------
6
--------------------------------------------------------------------------------
7
--------------------------------------------------------------------------------
14
--------------------------------------------------------------------------------
13
--------------------------------------------------------------------------------
13
--------------------------------------------------------------------------------
你可以看到,首先选择的是Number Agent发言,然后Group Chat Manager选择Multiplier Agent发言,接着是Adder Agent,以此类推。群聊中的每个代理都对数字进行操作,最终结果是13。
我们可以查看一下由initiate_chat
方法返回的ChatResult
对象提供的群聊摘要。
print(chat_result.summary)
The agents cooperatively manipulated the initial number (3) through multipliying, adding, and subtracting operations to reach the target number (13).
发送介绍
在前面的例子中,我们设置了description
来帮助群聊管理器选择下一个代理。然而,这仅帮助了群聊管理器,并没有帮助参与的代理相互了解。有时,让每个代理在群聊中向其他代理介绍自己是有用的。这可以通过设置send_introductions=True
来实现。
group_chat_with_introductions = GroupChat(
agents=[adder_agent, multiplier_agent, subtracter_agent, divider_agent, number_agent],
messages=[],
max_round=6,
send_introductions=True,
)
在内部,Group Chat Manager 在群聊开始之前向群聊中的所有代理发送一条包含代理名称和描述的信息。
顺序聊天中的群聊
群聊也可以作为顺序聊天的一部分使用。在这种情况下,群聊管理器被视为两个代理聊天序列中的常规代理。
# Let's use the group chat with introduction messages created above.
group_chat_manager_with_intros = GroupChatManager(
groupchat=group_chat_with_introductions,
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
)
# Start a sequence of two-agent chats between the number agent and
# the group chat manager.
chat_result = number_agent.initiate_chats(
[
{
"recipient": group_chat_manager_with_intros,
"message": "My number is 3, I want to turn it into 13.",
},
{
"recipient": group_chat_manager_with_intros,
"message": "Turn this number to 32.",
},
]
)
********************************************************************************
Start a new chat with the following message:
My number is 3, I want to turn it into 13.
With the following carryover:
********************************************************************************
My number is 3, I want to turn it into 13.
--------------------------------------------------------------------------------
6
--------------------------------------------------------------------------------
7
--------------------------------------------------------------------------------
14
--------------------------------------------------------------------------------
13
--------------------------------------------------------------------------------
Your number is 13.
--------------------------------------------------------------------------------
********************************************************************************
Start a new chat with the following message:
Turn this number to 32.
With the following carryover:
Your number is 13.
********************************************************************************
Turn this number to 32.
Context:
Your number is 13.
--------------------------------------------------------------------------------
26
--------------------------------------------------------------------------------
14
--------------------------------------------------------------------------------
28
--------------------------------------------------------------------------------
15
--------------------------------------------------------------------------------
30
--------------------------------------------------------------------------------
/Users/ekzhu/autogen/autogen/agentchat/chat.py:46: UserWarning: Repetitive recipients detected: The chat history will be cleared by default if a recipient appears more than once. To retain the chat history, please set 'clear_history=False' in the configuration of the repeating agent.
warnings.warn(
在上面的例子中,Group Chat Manager运行了两次群聊。第一次数字3变成了13,这次群聊的最后一条消息被用作下次群聊的延续,下次群聊从13开始。
你也可以从警告消息中看到,默认情况下,群聊管理器的历史记录在第一次群聊后被清除。如果你想保留群聊管理器的历史记录,可以在第一次聊天时设置clear_history=False
。
受限的发言者选择
群聊是一种强大的对话模式,但如果参与的代理数量较多,可能会难以控制。AutoGen 提供了一种通过使用 GroupChat
类的 allowed_or_disallowed_speaker_transitions
参数来约束下一个发言者选择的方式。
allowed_or_disallowed_speaker_transitions
参数是一个字典,它将给定的代理映射到一个可以选择(或不可选择)接下来发言的代理列表。speaker_transitions_type
参数指定了这些转换是允许的还是禁止的。
这里是一个示例:
allowed_transitions = {
number_agent: [adder_agent, number_agent],
adder_agent: [multiplier_agent, number_agent],
subtracter_agent: [divider_agent, number_agent],
multiplier_agent: [subtracter_agent, number_agent],
divider_agent: [adder_agent, number_agent],
}
在这个例子中,为每个智能体指定了允许的转换。
Number Agent 后面可以跟 Adder Agent 和 Number Agent,Adder Agent 后面可以跟 Multiplier Agent 和 Number Agent,依此类推。我们把这个放入群聊中,看看它是如何工作的。speaker_transitions_type
设置为 allowed
,因此这些转换是正向约束。
constrained_graph_chat = GroupChat(
agents=[adder_agent, multiplier_agent, subtracter_agent, divider_agent, number_agent],
allowed_or_disallowed_speaker_transitions=allowed_transitions,
speaker_transitions_type="allowed",
messages=[],
max_round=12,
send_introductions=True,
)
constrained_group_chat_manager = GroupChatManager(
groupchat=constrained_graph_chat,
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
)
chat_result = number_agent.initiate_chat(
constrained_group_chat_manager,
message="My number is 3, I want to turn it into 10. Once I get to 10, keep it there.",
summary_method="reflection_with_llm",
)
My number is 3, I want to turn it into 10. Once I get to 10, keep it there.
--------------------------------------------------------------------------------
4
--------------------------------------------------------------------------------
8
--------------------------------------------------------------------------------
7
--------------------------------------------------------------------------------
3.5
--------------------------------------------------------------------------------
4.5
--------------------------------------------------------------------------------
9
--------------------------------------------------------------------------------
8
--------------------------------------------------------------------------------
4
--------------------------------------------------------------------------------
5
--------------------------------------------------------------------------------
10
--------------------------------------------------------------------------------
10
--------------------------------------------------------------------------------
这一次,代理是根据我们指定的约束条件进行选择的。
更改选择发言人角色名称
作为群聊过程的一部分,当select_speaker_method设置为'auto'(默认值)时,会向LLM发送一个选择发言者的消息,以确定下一个发言者。
聊天序列中的每条消息都有一个role
属性,通常是user
、assistant
或system
。当使用选择发言者消息时,它是聊天序列中的最后一条消息,默认情况下,其角色为system
。
在使用一些模型时,例如通过Mistral.AI的API使用Mistral模型时,聊天序列中最后一条消息的角色必须是user
。
要更改默认行为,Autogen 提供了一种方法,通过在 GroupChat 的构造函数中设置 role_for_select_speaker_messages
参数,将选择发言者消息的角色值设置为任何字符串值。默认值为 system
,通过将其设置为 user
,可以满足 Mistral.AI API 的最后一条消息角色要求。
嵌套聊天
之前对话模式(双代理聊天、顺序聊天和群聊)对于构建复杂的工作流程非常有用,然而它们并未暴露单一的对话接口,这在问答机器人和个人助理等场景中往往是必需的。在其他一些情况下,将工作流程打包成单一代理以便在更大工作流中重用也非常有用。AutoGen提供了一种通过使用嵌套聊天来实现这一点的方式。
嵌套聊天功能由嵌套聊天处理器驱动,该处理器是ConversableAgent
的一个可插拔组件。下图展示了当接收到消息时,嵌套聊天处理器如何触发一系列嵌套聊天。
当一条消息到来并通过人在回路组件时,嵌套聊天处理器会根据用户指定的条件检查该消息是否应触发嵌套聊天。如果条件满足,嵌套聊天处理器会启动一系列使用顺序聊天模式指定的嵌套聊天。在每个嵌套聊天中,发送方代理始终是触发嵌套聊天的同一代理。最后,嵌套聊天处理器使用嵌套聊天的结果来生成对原始消息的响应。默认情况下,嵌套聊天处理器使用最后一个聊天的摘要作为响应。
这是一个使用嵌套聊天来构建算术代理的示例,该代理将算术操作、基于代码的验证和诗歌打包到一个代理中。此算术代理接受诸如“将数字3转换为13”的数字转换请求,并返回描述转换尝试的诗歌。
首先我们定义代理。我们重用了之前示例中的group_chat_manager_with_intros
来协调算术操作。
import tempfile
temp_dir = tempfile.gettempdir()
arithmetic_agent = ConversableAgent(
name="Arithmetic_Agent",
llm_config=False,
human_input_mode="ALWAYS",
# This agent will always require human input to make sure the code is
# safe to execute.
code_execution_config={"use_docker": False, "work_dir": temp_dir},
)
code_writer_agent = ConversableAgent(
name="Code_Writer_Agent",
system_message="You are a code writer. You write Python script in Markdown code blocks.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
human_input_mode="NEVER",
)
poetry_agent = ConversableAgent(
name="Poetry_Agent",
system_message="You are an AI poet.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": os.environ["OPENAI_API_KEY"]}]},
human_input_mode="NEVER",
)
现在我们使用顺序聊天模式定义嵌套聊天。所有的发送者始终是artihmetic_agent
。
nested_chats = [
{
"recipient": group_chat_manager_with_intros,
"summary_method": "reflection_with_llm",
"summary_prompt": "Summarize the sequence of operations used to turn " "the source number into target number.",
},
{
"recipient": code_writer_agent,
"message": "Write a Python script to verify the arithmetic operations is correct.",
"summary_method": "reflection_with_llm",
},
{
"recipient": poetry_agent,
"message": "Write a poem about it.",
"max_turns": 1,
"summary_method": "last_msg",
},
]
现在我们将嵌套聊天处理程序注册到arithmetic_agent
并设置触发嵌套聊天的条件。
arithmetic_agent.register_nested_chats(
nested_chats,
# The trigger function is used to determine if the agent should start the nested chat
# given the sender agent.
# In this case, the arithmetic agent will not start the nested chats if the sender is
# from the nested chats' recipient to avoid recursive calls.
trigger=lambda sender: sender not in [group_chat_manager_with_intros, code_writer_agent, poetry_agent],
)
最后,我们调用 generate_reply
从 arithmetic_agent
获取响应——这将触发一系列嵌套聊天,并返回最后一个嵌套聊天的摘要作为响应。
# Instead of using `initiate_chat` method to start another conversation,
# we can use the `generate_reply` method to get single reply to a message directly.
reply = arithmetic_agent.generate_reply(
messages=[{"role": "user", "content": "I have a number 3 and I want to turn it into 7."}]
)
>>>>>>>> NO HUMAN INPUT RECEIVED.
>>>>>>>> USING AUTO REPLY...
********************************************************************************
Start a new chat with the following message:
I have a number 3 and I want to turn it into 7.
With the following carryover:
********************************************************************************
I have a number 3 and I want to turn it into 7.
--------------------------------------------------------------------------------
To give you the result, I'll add 1 to the number you gave me. So your new number is 4.
--------------------------------------------------------------------------------
8
--------------------------------------------------------------------------------
7
--------------------------------------------------------------------------------
7
--------------------------------------------------------------------------------
7
--------------------------------------------------------------------------------
********************************************************************************
Start a new chat with the following message:
Write a Python script to verify the arithmetic operations is correct.
With the following carryover:
First, 1 was added to the initial number 3 to make it 4. Then it was multiplied by 2 which resulted in 8. Finally, 1 was subtracted from 8 to reach the target number 7.
********************************************************************************
Write a Python script to verify the arithmetic operations is correct.
Context:
First, 1 was added to the initial number 3 to make it 4. Then it was multiplied by 2 which resulted in 8. Finally, 1 was subtracted from 8 to reach the target number 7.
--------------------------------------------------------------------------------
Here is a Python script to verify the aforementioned arithmetic operations:
```python
# defining the initial value
initial_number = 3
# Adding 1 to initial number
initial_number += 1
assert initial_number == 4, "The first operation failed!"
# Multiplying the result by 2
initial_number *= 2
assert initial_number == 8, "The second operation failed!"
# Subtracting 1 from the result
initial_number -= 1
assert initial_number == 7, "The final operation failed!"
print("All operations were carried out successfully!")
```
In the script, the entire process is broken down into steps. The `assert` function is used to verify the result at every step. If any of the operations doesn't yield the expected result, an `AssertionError` exception will be raised. If all operations pass, the message "All operations were carried out successfully!" will be printed.
--------------------------------------------------------------------------------
>>>>>>>> NO HUMAN INPUT RECEIVED.
>>>>>>>> USING AUTO REPLY...
>>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...
exitcode: 0 (execution succeeded)
Code output:
All operations were carried out successfully!
--------------------------------------------------------------------------------
Certainly, that means the python script was successful and every arithmetic operation performed correctly given the initial input and the steps performed.
--------------------------------------------------------------------------------
********************************************************************************
Start a new chat with the following message:
Write a poem about it.
With the following carryover:
First, 1 was added to the initial number 3 to make it 4. Then it was multiplied by 2 which resulted in 8. Finally, 1 was subtracted from 8 to reach the target number 7.
The Python script successfully performed and verified the arithmetic operations on the initial number provided. The steps included adding 1 to the initial number, multiplying the result by 2, and finally subtracting 1. The assert function was used to check the result at each step, and confirmed that all operations were carried out correctly.
********************************************************************************
Write a poem about it.
Context:
First, 1 was added to the initial number 3 to make it 4. Then it was multiplied by 2 which resulted in 8. Finally, 1 was subtracted from 8 to reach the target number 7.
The Python script successfully performed and verified the arithmetic operations on the initial number provided. The steps included adding 1 to the initial number, multiplying the result by 2, and finally subtracting 1. The assert function was used to check the result at each step, and confirmed that all operations were carried out correctly.
--------------------------------------------------------------------------------
From numbers, logic, pure mathematical creation,
Ponder this tale of numeric manipulation.
In the universe of Python where operations exist,
A story of integers and functions persist.
Three was the number from where we began,
Oblivious to the journey and its grandiosely plan.
Added with 1, the sum it adorned,
A sweet quadruple in the dawn was formed.
The saga continued with a twist of the tale,
The four was multiplied, while the winds wail.
The duo of four unfolded its wings,
An octet presence in our midst it brings.
Then enters subtraction, sly and clever,
Removing one to alter the endeavor.
From eight, subtracted one in delight,
To finally bask in the glow of seven's light.
Each operation, together they conspired,
In this tale of integers, creatively inspired.
Through life's equation, the script ran so free,
Amidst the language of Python, a symphony, you see.
Tested with assert, cross-checked the chain,
Confirming accuracy in program's domain.
Each move calculated, each step so right,
In the maze of coding, found was the light.
Such is the tale, of numbers and operations,
A dance among digits, logical iterations,
Just another day, in this AI poet's life,
Cutting through ambiguity, like a razor-sharp knife.
--------------------------------------------------------------------------------
返回的是一首诗,描述了从3到7的转换尝试。
嵌套聊天处理程序的实现使用了
register_reply
方法,该方法允许您对
ConversableAgent
进行广泛的定制。GroupChatManager 使用相同的机制来实现群聊。
嵌套聊天是一种强大的对话模式,允许你将复杂的工作流程封装到一个单一的代理中。你可以通过让工具调用代理与工具执行代理启动嵌套聊天来隐藏工具使用,然后利用嵌套聊天的结果生成响应。详见用于工具使用的嵌套聊天笔记本的示例。
总结
在本章中,我们讨论了两代理聊天、顺序聊天、群组聊天和嵌套聊天模式。你可以像搭积木一样组合这些模式来创建复杂的工作流程。你也可以使用register_reply
来创建新的模式。
这是关于基本AutoGen概念的最后一章。在下一章中,我们将为您提供一些下一步操作的提示。