Skip to content

Commit 7ba4936

Browse files
authored
Re-commit code from microsoft#2182 to Microsoft branch (microsoft#2233)
1 parent 26666da commit 7ba4936

File tree

2 files changed

+124
-6
lines changed

2 files changed

+124
-6
lines changed

autogen/agentchat/groupchat.py

+31-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ class GroupChat:
2828
When set to True and when a message is a function call suggestion,
2929
the next speaker will be chosen from an agent which contains the corresponding function name
3030
in its `function_map`.
31+
- select_speaker_message_template: customize the select speaker message (used in "auto" speaker selection), which appears first in the message context and generally includes the agent descriptions and list of agents. The string value will be converted to an f-string, use "{roles}" to output the agent's and their role descriptions and "{agentlist}" for a comma-separated list of agent names in square brackets. The default value is:
32+
"You are in a role play game. The following roles are available:
33+
{roles}.
34+
Read the following conversation.
35+
Then select the next role from {agentlist} to play. Only return the role."
36+
- select_speaker_prompt_template: customize the select speaker prompt (used in "auto" speaker selection), which appears last in the message context and generally includes the list of agents and guidance for the LLM to select the next agent. The string value will be converted to an f-string, use "{agentlist}" for a comma-separated list of agent names in square brackets. The default value is:
37+
"Read the above conversation. Then select the next role from {agentlist} to play. Only return the role."
3138
- speaker_selection_method: the method for selecting the next speaker. Default is "auto".
3239
Could be any of the following (case insensitive), will raise ValueError if not recognized:
3340
- "auto": the next speaker is selected automatically by LLM.
@@ -75,6 +82,13 @@ def custom_speaker_selection_func(
7582
speaker_transitions_type: Literal["allowed", "disallowed", None] = None
7683
enable_clear_history: Optional[bool] = False
7784
send_introductions: bool = False
85+
select_speaker_message_template: str = """You are in a role play game. The following roles are available:
86+
{roles}.
87+
Read the following conversation.
88+
Then select the next role from {agentlist} to play. Only return the role."""
89+
select_speaker_prompt_template: str = (
90+
"Read the above conversation. Then select the next role from {agentlist} to play. Only return the role."
91+
)
7892
role_for_select_speaker_messages: Optional[str] = "system"
7993

8094
_VALID_SPEAKER_SELECTION_METHODS = ["auto", "manual", "random", "round_robin"]
@@ -164,6 +178,13 @@ def __post_init__(self):
164178
agents=self.agents,
165179
)
166180

181+
# Check select_speaker_message_template and select_speaker_prompt_template have values
182+
if self.select_speaker_message_template is None or len(self.select_speaker_message_template) == 0:
183+
raise ValueError("select_speaker_message_template cannot be empty or None.")
184+
185+
if self.select_speaker_prompt_template is None or len(self.select_speaker_prompt_template) == 0:
186+
raise ValueError("select_speaker_prompt_template cannot be empty or None.")
187+
167188
if self.role_for_select_speaker_messages is None or len(self.role_for_select_speaker_messages) == 0:
168189
raise ValueError("role_for_select_speaker_messages cannot be empty or None.")
169190

@@ -237,17 +258,22 @@ def select_speaker_msg(self, agents: Optional[List[Agent]] = None) -> str:
237258
"""Return the system message for selecting the next speaker. This is always the *first* message in the context."""
238259
if agents is None:
239260
agents = self.agents
240-
return f"""You are in a role play game. The following roles are available:
241-
{self._participant_roles(agents)}.
242261

243-
Read the following conversation.
244-
Then select the next role from {[agent.name for agent in agents]} to play. Only return the role."""
262+
roles = self._participant_roles(agents)
263+
agentlist = f"{[agent.name for agent in agents]}"
264+
265+
return_msg = self.select_speaker_message_template.format(roles=roles, agentlist=agentlist)
266+
return return_msg
245267

246268
def select_speaker_prompt(self, agents: Optional[List[Agent]] = None) -> str:
247269
"""Return the floating system prompt selecting the next speaker. This is always the *last* message in the context."""
248270
if agents is None:
249271
agents = self.agents
250-
return f"Read the above conversation. Then select the next role from {[agent.name for agent in agents]} to play. Only return the role."
272+
273+
agentlist = f"{[agent.name for agent in agents]}"
274+
275+
return_prompt = self.select_speaker_prompt_template.format(agentlist=agentlist)
276+
return return_prompt
251277

252278
def introductions_msg(self, agents: Optional[List[Agent]] = None) -> str:
253279
"""Return the system message for selecting the next speaker. This is always the *first* message in the context."""

test/agentchat/test_groupchat.py

+93-1
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,97 @@ def test_role_for_select_speaker_messages():
12411241
assert "role_for_select_speaker_messages cannot be empty or None." in str(e.value)
12421242

12431243

1244+
def test_select_speaker_message_and_prompt_templates():
1245+
"""
1246+
In this test, two agents are part of a group chat which has customized select speaker message and select speaker prompt templates. Both valid and empty string values will be used.
1247+
The expected behaviour is that the customized speaker selection message and prompts will override the default values or throw exceptions if empty.
1248+
"""
1249+
1250+
agent1 = autogen.ConversableAgent(
1251+
"Alice",
1252+
description="A wonderful employee named Alice.",
1253+
human_input_mode="NEVER",
1254+
llm_config=False,
1255+
)
1256+
agent2 = autogen.ConversableAgent(
1257+
"Bob",
1258+
description="An amazing employee named Bob.",
1259+
human_input_mode="NEVER",
1260+
llm_config=False,
1261+
)
1262+
1263+
# Customised message, this is always the first message in the context
1264+
custom_msg = """You are the CEO of a niche organisation creating small software tools for the healthcare sector with a small team of specialists. Call them in sequence.
1265+
The job roles and responsibilities are:
1266+
{roles}
1267+
You must select only from {agentlist}."""
1268+
1269+
# Customised prompt, this is always the last message in the context
1270+
custom_prompt = """Read the above conversation.
1271+
Then select the next job role from {agentlist} to take action.
1272+
RETURN ONLY THE NAME OF THE NEXT ROLE."""
1273+
1274+
# Test empty is_termination_msg function
1275+
groupchat = autogen.GroupChat(
1276+
agents=[agent1, agent2],
1277+
messages=[],
1278+
speaker_selection_method="auto",
1279+
max_round=10,
1280+
select_speaker_message_template=custom_msg,
1281+
select_speaker_prompt_template=custom_prompt,
1282+
)
1283+
1284+
# Test with valid strings, checking for the correct string and roles / agentlist to be included
1285+
1286+
assert groupchat.select_speaker_msg() == custom_msg.replace(
1287+
"{roles}", "Alice: A wonderful employee named Alice.\nBob: An amazing employee named Bob."
1288+
).replace("{agentlist}", "['Alice', 'Bob']")
1289+
1290+
assert groupchat.select_speaker_prompt() == custom_prompt.replace("{agentlist}", "['Alice', 'Bob']")
1291+
1292+
# Test with empty strings
1293+
with pytest.raises(ValueError, match="select_speaker_message_template cannot be empty or None."):
1294+
groupchat = autogen.GroupChat(
1295+
agents=[agent1, agent2],
1296+
messages=[],
1297+
speaker_selection_method="auto",
1298+
max_round=10,
1299+
select_speaker_message_template="",
1300+
select_speaker_prompt_template="Not empty.",
1301+
)
1302+
1303+
with pytest.raises(ValueError, match="select_speaker_prompt_template cannot be empty or None."):
1304+
groupchat = autogen.GroupChat(
1305+
agents=[agent1, agent2],
1306+
messages=[],
1307+
speaker_selection_method="auto",
1308+
max_round=10,
1309+
select_speaker_message_template="Not empty.",
1310+
select_speaker_prompt_template=None,
1311+
)
1312+
1313+
# Test with None
1314+
with pytest.raises(ValueError, match="select_speaker_message_template cannot be empty or None."):
1315+
groupchat = autogen.GroupChat(
1316+
agents=[agent1, agent2],
1317+
messages=[],
1318+
speaker_selection_method="auto",
1319+
max_round=10,
1320+
select_speaker_message_template=None,
1321+
select_speaker_prompt_template="Not empty.",
1322+
)
1323+
1324+
with pytest.raises(ValueError, match="select_speaker_prompt_template cannot be empty or None."):
1325+
groupchat = autogen.GroupChat(
1326+
agents=[agent1, agent2],
1327+
messages=[],
1328+
speaker_selection_method="auto",
1329+
max_round=10,
1330+
select_speaker_message_template="Not empty.",
1331+
select_speaker_prompt_template="",
1332+
)
1333+
1334+
12441335
if __name__ == "__main__":
12451336
# test_func_call_groupchat()
12461337
# test_broadcast()
@@ -1256,5 +1347,6 @@ def test_role_for_select_speaker_messages():
12561347
# test_graceful_exit_before_max_round()
12571348
# test_clear_agents_history()
12581349
# test_custom_speaker_selection_overrides_transition_graph()
1259-
test_role_for_select_speaker_messages()
1350+
# test_role_for_select_speaker_messages()
1351+
test_select_speaker_message_and_prompt_templates()
12601352
# pass

0 commit comments

Comments
 (0)