Added ability to specify 'role' field for select speaker messages for Group Chats (Replaces PR #2167) (#2199)

* Re-commit of code from PR (#2167) addressing #1861, due to wrong basing

* Update website/docs/topics/non-openai-models/best-tips-for-nonopenai-models.md

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>

* 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 <ekzhu@users.noreply.github.com>
This commit is contained in:
Mark Sze 2024-04-01 09:54:17 +11:00 committed by GitHub
parent fd96d3d1f5
commit 3f63db32b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 165 additions and 9 deletions

View File

@ -61,6 +61,7 @@ class GroupChat:
"clear history" phrase in user prompt. This is experimental feature.
See description of GroupChatManager.clear_agents_history function for more info.
- send_introductions: send a round of introductions at the start of the group chat, so agents know who they can speak to (default: False)
- role_for_select_speaker_messages: sets the role name for speaker selection when in 'auto' mode, typically 'user' or 'system'. (default: 'system')
"""
agents: List[Agent]
@ -74,6 +75,7 @@ class GroupChat:
speaker_transitions_type: Literal["allowed", "disallowed", None] = None
enable_clear_history: Optional[bool] = False
send_introductions: bool = False
role_for_select_speaker_messages: Optional[str] = "system"
_VALID_SPEAKER_SELECTION_METHODS = ["auto", "manual", "random", "round_robin"]
_VALID_SPEAKER_TRANSITIONS_TYPE = ["allowed", "disallowed", None]
@ -162,6 +164,9 @@ class GroupChat:
agents=self.agents,
)
if self.role_for_select_speaker_messages is None or len(self.role_for_select_speaker_messages) == 0:
raise ValueError("role_for_select_speaker_messages cannot be empty or None.")
@property
def agent_names(self) -> List[str]:
"""Return the names of the agents in the group chat."""
@ -411,7 +416,7 @@ Then select the next role from {[agent.name for agent in agents]} to play. Only
selected_agent = self.next_agent(last_speaker, graph_eligible_agents)
elif speaker_selection_method.lower() == "random":
selected_agent = self.random_select_speaker(graph_eligible_agents)
else:
else: # auto
selected_agent = None
select_speaker_messages = self.messages.copy()
# If last message is a tool call or function call, blank the call so the api doesn't throw
@ -420,7 +425,10 @@ Then select the next role from {[agent.name for agent in agents]} to play. Only
if select_speaker_messages[-1].get("tool_calls", False):
select_speaker_messages[-1] = dict(select_speaker_messages[-1], tool_calls=None)
select_speaker_messages = select_speaker_messages + [
{"role": "system", "content": self.select_speaker_prompt(graph_eligible_agents)}
{
"role": self.role_for_select_speaker_messages,
"content": self.select_speaker_prompt(graph_eligible_agents),
}
]
return selected_agent, graph_eligible_agents, select_speaker_messages

View File

@ -1176,6 +1176,71 @@ def test_custom_speaker_selection_overrides_transition_graph():
assert "teamA_executor" in speakers
def test_role_for_select_speaker_messages():
agent1 = autogen.ConversableAgent(
"alice",
max_consecutive_auto_reply=10,
human_input_mode="NEVER",
llm_config=False,
default_auto_reply="This is alice speaking.",
)
agent2 = autogen.ConversableAgent(
"bob",
max_consecutive_auto_reply=10,
human_input_mode="NEVER",
llm_config=False,
default_auto_reply="This is bob speaking.",
)
groupchat = autogen.GroupChat(
agents=[agent1, agent2],
messages=[{"role": "user", "content": "Let's have a chat!"}],
max_round=3,
)
# Run the select agents function to get the select speaker messages
selected_agent, agents, messages = groupchat._prepare_and_select_agents(agent1)
# Test default is "system"
assert len(messages) == 2
assert messages[-1]["role"] == "system"
# Test as "user"
groupchat.role_for_select_speaker_messages = "user"
selected_agent, agents, messages = groupchat._prepare_and_select_agents(agent1)
assert len(messages) == 2
assert messages[-1]["role"] == "user"
# Test as something unusual
groupchat.role_for_select_speaker_messages = "SockS"
selected_agent, agents, messages = groupchat._prepare_and_select_agents(agent1)
assert len(messages) == 2
assert messages[-1]["role"] == "SockS"
# Test empty string and None isn't accepted
# Test with empty strings
with pytest.raises(ValueError) as e:
groupchat = autogen.GroupChat(
agents=[agent1, agent2],
messages=[{"role": "user", "content": "Let's have a chat!"}],
max_round=3,
role_for_select_speaker_messages="",
)
assert "role_for_select_speaker_messages cannot be empty or None." in str(e.value)
with pytest.raises(ValueError) as e:
groupchat = autogen.GroupChat(
agents=[agent1, agent2],
messages=[{"role": "user", "content": "Let's have a chat!"}],
max_round=3,
role_for_select_speaker_messages=None,
)
assert "role_for_select_speaker_messages cannot be empty or None." in str(e.value)
if __name__ == "__main__":
# test_func_call_groupchat()
# test_broadcast()
@ -1190,5 +1255,6 @@ if __name__ == "__main__":
# test_invalid_allow_repeat_speaker()
# test_graceful_exit_before_max_round()
# test_clear_agents_history()
test_custom_speaker_selection_overrides_transition_graph()
# test_custom_speaker_selection_overrides_transition_graph()
test_role_for_select_speaker_messages()
# pass

View File

@ -0,0 +1,59 @@
# Tips for Non-OpenAI Models
Here are some tips for using non-OpenAI Models with AutoGen.
## Finding the right model
Every model will perform differently across the operations within your AutoGen
setup, such as speaker selection, coding, function calling, content creation,
etc. On the whole, larger models (13B+) perform better with following directions
and providing more cohesive responses.
Content creation can be performed by most models.
Fine-tuned models can be great for very specific tasks, such as function calling
and coding.
Specific tasks, such as speaker selection in a Group Chat scenario, that require
very accurate outputs can be a challenge with most open source/weight models. The
use of chain-of-thought and/or few-shot prompting can help guide the LLM to provide
the output in the format you want.
## Validating your program
Testing your AutoGen setup against a very large LLM, such as OpenAI's ChatGPT or
Anthropic's Claude 3, can help validate your agent setup and configuration.
Once a setup is performing as you want, you can replace the models for your agents
with non-OpenAI models and iteratively tweak system messages, prompts, and model
selection.
## Chat template
AutoGen utilises a set of chat messages for the conversation between AutoGen/user
and LLMs. Each chat message has a role attribute that is typically `user`,
`assistant`, or `system`.
A chat template is applied during inference and some chat templates implement rules about
what roles can be used in specific sequences of messages.
For example, when using Mistral AI's API the last chat message must have a role of `user`.
In a Group Chat scenario the message used to select the next speaker will have a role of
`system` by default and the API will throw an exception for this step. To overcome this the
GroupChat's constructor has a parameter called `role_for_select_speaker_messages` that can
be used to change the role name to `user`.
```python
groupchat = autogen.GroupChat(
agents=[user_proxy, coder, pm],
messages=[],
max_round=12,
# Role for select speaker message will be set to 'user' instead of 'system'
role_for_select_speaker_messages='user',
)
```
If the chat template associated with a model you want to use doesn't support the role
sequence and names used in AutoGen you can modify the chat template. See an example of
this on our [vLLM page](/docs/topics/non-openai-models/local-vllm#chat-template).
## Discord
Join AutoGen's [#alt-models](https://discord.com/channels/1153072414184452236/1201369716057440287)
channel on their Discord and discuss non-OpenAI models and configurations.

View File

@ -31,7 +31,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Now you can set up the Mistral model you want to use."
"Now you can set up the Mistral model you want to use. See the list of [models here](https://docs.mistral.ai/platform/endpoints/)."
]
},
{
@ -59,7 +59,7 @@
"source": [
"## Two-Agent Coding Example\n",
"\n",
"In this example, we run a two-agent chat to count how many prime numbers between 1 and 10000 using coding."
"In this example, we run a two-agent chat to count the number of prime numbers between 1 and 10,000 using coding."
]
},
{
@ -182,7 +182,7 @@
"source": [
"## Tool Call Example\n",
"\n",
"In this example, instead of writing code, we will have two agent playing chess against each other using tool to make moves.\n",
"In this example, instead of writing code, we will have two agents playing chess against each other using tool calling to make moves.\n",
"\n",
"First install the `chess` package by running the following command:"
]
@ -200,7 +200,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Write function for making a move."
"Write the function for making a move."
]
},
{
@ -269,7 +269,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Register tools for the agents. See [tutorial chapter on tool use](/docs/tutorial/tool-use) \n",
"Register tools for the agents. See the [tutorial chapter on tool use](/docs/tutorial/tool-use) \n",
"for more information."
]
},
@ -303,7 +303,7 @@
"Register nested chats for the player agents.\n",
"Nested chats allows each player agent to chat with the board proxy agent\n",
"to make a move, before communicating with the other player agent.\n",
"See [nested chats tutorial chapter](/docs/tutorial/conversation-patterns#nested-chats)\n",
"See the [nested chats tutorial chapter](/docs/tutorial/conversation-patterns#nested-chats)\n",
"for more information."
]
},

View File

@ -1183,6 +1183,29 @@
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Changing the select speaker role name\n",
"\n",
"As part of the Group chat process, when the select_speaker_method is set to 'auto' (the default value),\n",
"a select speaker message is sent to the LLM to determine the next speaker.\n",
"\n",
"Each message in the chat sequence has a `role` attribute that is typically `user`,\n",
"`assistant`, or `system`. The select speaker message is the last in the chat\n",
"sequence when used and, by default, has a role of `system`.\n",
"\n",
"When using some models, such as Mistral through Mistral.AI's API, the role on\n",
"the last message in the chat sequence has to be `user`.\n",
"\n",
"To change the default behaviour, Autogen provides a way to set the value of the\n",
"select speaker message's role to any string value by setting the\n",
"`role_for_select_speaker_messages` parameter in the GroupChat's constructor. The\n",
"default value is `system` and by setting it to `user` you can accommodate the\n",
"last message role requirement of Mistral.AI's API."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [