Skip to content

Commit a36b6a8

Browse files
marklyszeekzhu
andauthored
Added ability to specify 'role' field for select speaker messages for Group Chats (Replaces PR microsoft#2167) (microsoft#2199)
* Re-commit of code from PR (microsoft#2167) addressing microsoft#1861, due to wrong basing * Update website/docs/topics/non-openai-models/best-tips-for-nonopenai-models.md Co-authored-by: Eric Zhu <[email protected]> * Removed unnecessary notebook images * Update conversation-patterns.ipynb Updated to include note about being applicable when auto. * Updated to include checks that the role is not blank/None. Added tests. * Changed try-except to use pytest --------- Co-authored-by: Eric Zhu <[email protected]>
1 parent 188c1b8 commit a36b6a8

File tree

5 files changed

+165
-9
lines changed

5 files changed

+165
-9
lines changed

autogen/agentchat/groupchat.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def custom_speaker_selection_func(
6161
"clear history" phrase in user prompt. This is experimental feature.
6262
See description of GroupChatManager.clear_agents_history function for more info.
6363
- send_introductions: send a round of introductions at the start of the group chat, so agents know who they can speak to (default: False)
64+
- role_for_select_speaker_messages: sets the role name for speaker selection when in 'auto' mode, typically 'user' or 'system'. (default: 'system')
6465
"""
6566

6667
agents: List[Agent]
@@ -74,6 +75,7 @@ def custom_speaker_selection_func(
7475
speaker_transitions_type: Literal["allowed", "disallowed", None] = None
7576
enable_clear_history: Optional[bool] = False
7677
send_introductions: bool = False
78+
role_for_select_speaker_messages: Optional[str] = "system"
7779

7880
_VALID_SPEAKER_SELECTION_METHODS = ["auto", "manual", "random", "round_robin"]
7981
_VALID_SPEAKER_TRANSITIONS_TYPE = ["allowed", "disallowed", None]
@@ -162,6 +164,9 @@ def __post_init__(self):
162164
agents=self.agents,
163165
)
164166

167+
if self.role_for_select_speaker_messages is None or len(self.role_for_select_speaker_messages) == 0:
168+
raise ValueError("role_for_select_speaker_messages cannot be empty or None.")
169+
165170
@property
166171
def agent_names(self) -> List[str]:
167172
"""Return the names of the agents in the group chat."""
@@ -411,7 +416,7 @@ def _prepare_and_select_agents(
411416
selected_agent = self.next_agent(last_speaker, graph_eligible_agents)
412417
elif speaker_selection_method.lower() == "random":
413418
selected_agent = self.random_select_speaker(graph_eligible_agents)
414-
else:
419+
else: # auto
415420
selected_agent = None
416421
select_speaker_messages = self.messages.copy()
417422
# If last message is a tool call or function call, blank the call so the api doesn't throw
@@ -420,7 +425,10 @@ def _prepare_and_select_agents(
420425
if select_speaker_messages[-1].get("tool_calls", False):
421426
select_speaker_messages[-1] = dict(select_speaker_messages[-1], tool_calls=None)
422427
select_speaker_messages = select_speaker_messages + [
423-
{"role": "system", "content": self.select_speaker_prompt(graph_eligible_agents)}
428+
{
429+
"role": self.role_for_select_speaker_messages,
430+
"content": self.select_speaker_prompt(graph_eligible_agents),
431+
}
424432
]
425433
return selected_agent, graph_eligible_agents, select_speaker_messages
426434

test/agentchat/test_groupchat.py

+67-1
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,71 @@ def custom_speaker_selection_func(last_speaker: Agent, groupchat: GroupChat) ->
11761176
assert "teamA_executor" in speakers
11771177

11781178

1179+
def test_role_for_select_speaker_messages():
1180+
agent1 = autogen.ConversableAgent(
1181+
"alice",
1182+
max_consecutive_auto_reply=10,
1183+
human_input_mode="NEVER",
1184+
llm_config=False,
1185+
default_auto_reply="This is alice speaking.",
1186+
)
1187+
agent2 = autogen.ConversableAgent(
1188+
"bob",
1189+
max_consecutive_auto_reply=10,
1190+
human_input_mode="NEVER",
1191+
llm_config=False,
1192+
default_auto_reply="This is bob speaking.",
1193+
)
1194+
1195+
groupchat = autogen.GroupChat(
1196+
agents=[agent1, agent2],
1197+
messages=[{"role": "user", "content": "Let's have a chat!"}],
1198+
max_round=3,
1199+
)
1200+
1201+
# Run the select agents function to get the select speaker messages
1202+
selected_agent, agents, messages = groupchat._prepare_and_select_agents(agent1)
1203+
1204+
# Test default is "system"
1205+
assert len(messages) == 2
1206+
assert messages[-1]["role"] == "system"
1207+
1208+
# Test as "user"
1209+
groupchat.role_for_select_speaker_messages = "user"
1210+
selected_agent, agents, messages = groupchat._prepare_and_select_agents(agent1)
1211+
1212+
assert len(messages) == 2
1213+
assert messages[-1]["role"] == "user"
1214+
1215+
# Test as something unusual
1216+
groupchat.role_for_select_speaker_messages = "SockS"
1217+
selected_agent, agents, messages = groupchat._prepare_and_select_agents(agent1)
1218+
1219+
assert len(messages) == 2
1220+
assert messages[-1]["role"] == "SockS"
1221+
1222+
# Test empty string and None isn't accepted
1223+
1224+
# Test with empty strings
1225+
with pytest.raises(ValueError) as e:
1226+
groupchat = autogen.GroupChat(
1227+
agents=[agent1, agent2],
1228+
messages=[{"role": "user", "content": "Let's have a chat!"}],
1229+
max_round=3,
1230+
role_for_select_speaker_messages="",
1231+
)
1232+
assert "role_for_select_speaker_messages cannot be empty or None." in str(e.value)
1233+
1234+
with pytest.raises(ValueError) as e:
1235+
groupchat = autogen.GroupChat(
1236+
agents=[agent1, agent2],
1237+
messages=[{"role": "user", "content": "Let's have a chat!"}],
1238+
max_round=3,
1239+
role_for_select_speaker_messages=None,
1240+
)
1241+
assert "role_for_select_speaker_messages cannot be empty or None." in str(e.value)
1242+
1243+
11791244
if __name__ == "__main__":
11801245
# test_func_call_groupchat()
11811246
# test_broadcast()
@@ -1190,5 +1255,6 @@ def custom_speaker_selection_func(last_speaker: Agent, groupchat: GroupChat) ->
11901255
# test_invalid_allow_repeat_speaker()
11911256
# test_graceful_exit_before_max_round()
11921257
# test_clear_agents_history()
1193-
test_custom_speaker_selection_overrides_transition_graph()
1258+
# test_custom_speaker_selection_overrides_transition_graph()
1259+
test_role_for_select_speaker_messages()
11941260
# pass
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Tips for Non-OpenAI Models
2+
3+
Here are some tips for using non-OpenAI Models with AutoGen.
4+
5+
## Finding the right model
6+
Every model will perform differently across the operations within your AutoGen
7+
setup, such as speaker selection, coding, function calling, content creation,
8+
etc. On the whole, larger models (13B+) perform better with following directions
9+
and providing more cohesive responses.
10+
11+
Content creation can be performed by most models.
12+
13+
Fine-tuned models can be great for very specific tasks, such as function calling
14+
and coding.
15+
16+
Specific tasks, such as speaker selection in a Group Chat scenario, that require
17+
very accurate outputs can be a challenge with most open source/weight models. The
18+
use of chain-of-thought and/or few-shot prompting can help guide the LLM to provide
19+
the output in the format you want.
20+
21+
## Validating your program
22+
Testing your AutoGen setup against a very large LLM, such as OpenAI's ChatGPT or
23+
Anthropic's Claude 3, can help validate your agent setup and configuration.
24+
25+
Once a setup is performing as you want, you can replace the models for your agents
26+
with non-OpenAI models and iteratively tweak system messages, prompts, and model
27+
selection.
28+
29+
## Chat template
30+
AutoGen utilises a set of chat messages for the conversation between AutoGen/user
31+
and LLMs. Each chat message has a role attribute that is typically `user`,
32+
`assistant`, or `system`.
33+
34+
A chat template is applied during inference and some chat templates implement rules about
35+
what roles can be used in specific sequences of messages.
36+
37+
For example, when using Mistral AI's API the last chat message must have a role of `user`.
38+
In a Group Chat scenario the message used to select the next speaker will have a role of
39+
`system` by default and the API will throw an exception for this step. To overcome this the
40+
GroupChat's constructor has a parameter called `role_for_select_speaker_messages` that can
41+
be used to change the role name to `user`.
42+
43+
```python
44+
groupchat = autogen.GroupChat(
45+
agents=[user_proxy, coder, pm],
46+
messages=[],
47+
max_round=12,
48+
# Role for select speaker message will be set to 'user' instead of 'system'
49+
role_for_select_speaker_messages='user',
50+
)
51+
```
52+
53+
If the chat template associated with a model you want to use doesn't support the role
54+
sequence and names used in AutoGen you can modify the chat template. See an example of
55+
this on our [vLLM page](/docs/topics/non-openai-models/local-vllm#chat-template).
56+
57+
## Discord
58+
Join AutoGen's [#alt-models](https://discord.com/channels/1153072414184452236/1201369716057440287)
59+
channel on their Discord and discuss non-OpenAI models and configurations.

website/docs/topics/non-openai-models/cloud-mistralai.ipynb

+6-6
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"cell_type": "markdown",
3232
"metadata": {},
3333
"source": [
34-
"Now you can set up the Mistral model you want to use."
34+
"Now you can set up the Mistral model you want to use. See the list of [models here](https://docs.mistral.ai/platform/endpoints/)."
3535
]
3636
},
3737
{
@@ -59,7 +59,7 @@
5959
"source": [
6060
"## Two-Agent Coding Example\n",
6161
"\n",
62-
"In this example, we run a two-agent chat to count how many prime numbers between 1 and 10000 using coding."
62+
"In this example, we run a two-agent chat to count the number of prime numbers between 1 and 10,000 using coding."
6363
]
6464
},
6565
{
@@ -182,7 +182,7 @@
182182
"source": [
183183
"## Tool Call Example\n",
184184
"\n",
185-
"In this example, instead of writing code, we will have two agent playing chess against each other using tool to make moves.\n",
185+
"In this example, instead of writing code, we will have two agents playing chess against each other using tool calling to make moves.\n",
186186
"\n",
187187
"First install the `chess` package by running the following command:"
188188
]
@@ -200,7 +200,7 @@
200200
"cell_type": "markdown",
201201
"metadata": {},
202202
"source": [
203-
"Write function for making a move."
203+
"Write the function for making a move."
204204
]
205205
},
206206
{
@@ -269,7 +269,7 @@
269269
"cell_type": "markdown",
270270
"metadata": {},
271271
"source": [
272-
"Register tools for the agents. See [tutorial chapter on tool use](/docs/tutorial/tool-use) \n",
272+
"Register tools for the agents. See the [tutorial chapter on tool use](/docs/tutorial/tool-use) \n",
273273
"for more information."
274274
]
275275
},
@@ -303,7 +303,7 @@
303303
"Register nested chats for the player agents.\n",
304304
"Nested chats allows each player agent to chat with the board proxy agent\n",
305305
"to make a move, before communicating with the other player agent.\n",
306-
"See [nested chats tutorial chapter](/docs/tutorial/conversation-patterns#nested-chats)\n",
306+
"See the [nested chats tutorial chapter](/docs/tutorial/conversation-patterns#nested-chats)\n",
307307
"for more information."
308308
]
309309
},

website/docs/tutorial/conversation-patterns.ipynb

+23
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,29 @@
11831183
]
11841184
},
11851185
{
1186+
"cell_type": "markdown",
1187+
"metadata": {},
1188+
"source": [
1189+
"### Changing the select speaker role name\n",
1190+
"\n",
1191+
"As part of the Group chat process, when the select_speaker_method is set to 'auto' (the default value),\n",
1192+
"a select speaker message is sent to the LLM to determine the next speaker.\n",
1193+
"\n",
1194+
"Each message in the chat sequence has a `role` attribute that is typically `user`,\n",
1195+
"`assistant`, or `system`. The select speaker message is the last in the chat\n",
1196+
"sequence when used and, by default, has a role of `system`.\n",
1197+
"\n",
1198+
"When using some models, such as Mistral through Mistral.AI's API, the role on\n",
1199+
"the last message in the chat sequence has to be `user`.\n",
1200+
"\n",
1201+
"To change the default behaviour, Autogen provides a way to set the value of the\n",
1202+
"select speaker message's role to any string value by setting the\n",
1203+
"`role_for_select_speaker_messages` parameter in the GroupChat's constructor. The\n",
1204+
"default value is `system` and by setting it to `user` you can accommodate the\n",
1205+
"last message role requirement of Mistral.AI's API."
1206+
]
1207+
},
1208+
{
11861209
"cell_type": "markdown",
11871210
"metadata": {},
11881211
"source": [

0 commit comments

Comments
 (0)