Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-query speaker name when multiple speaker names returned during Group Chat speaker selection #2304

Merged
merged 20 commits into from
Apr 30, 2024
Merged
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c853cf2
Added requery_on_multiple_speaker_names to GroupChat and updated _fin…
marklysze Apr 3, 2024
9357265
Removed unnecessary comments
marklysze Apr 3, 2024
be3862a
Merge branch 'main' of https://github.com/microsoft/autogen into requ…
marklysze Apr 4, 2024
3b453e0
Update to current main
marklysze Apr 4, 2024
723ff35
Tweak error message.
marklysze Apr 5, 2024
86de80a
Comment clarity
marklysze Apr 6, 2024
6c57982
Merge remote-tracking branch 'origin/main' into requery_speaker_name_…
marklysze Apr 6, 2024
c464f45
Expanded description of Group Chat requery_on_multiple_speaker_names
marklysze Apr 6, 2024
8ec1f3d
Merge remote-tracking branch 'origin/main' into requery_speaker_name_…
marklysze Apr 23, 2024
16c547d
Reworked to two-way nested chat for speaker selection with default of…
marklysze Apr 24, 2024
4fbfbbe
Adding validation of new GroupChat attributes
marklysze Apr 24, 2024
21c5af0
Updates as per @ekzhu's suggestions
marklysze Apr 25, 2024
451b726
Merge branch 'main' into requery_speaker_name_on_multiple
marklysze Apr 25, 2024
9af50e5
Update groupchat
marklysze Apr 27, 2024
6550143
Update conversable_agent.py
marklysze Apr 27, 2024
f83ffc5
Update test_groupchat.py
marklysze Apr 27, 2024
bddf71a
Merge branch 'main' into requery_speaker_name_on_multiple
sonichi Apr 29, 2024
298d36b
Removed block for manual selection in select_speaker function.
marklysze Apr 29, 2024
7e5a44a
Catered for no-selection during manual selection mode
marklysze Apr 30, 2024
9d498ad
Merge branch 'main' into requery_speaker_name_on_multiple
marklysze Apr 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions autogen/agentchat/groupchat.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ def custom_speaker_selection_func(
last_speaker: Agent, groupchat: GroupChat
) -> Union[Agent, str, None]:
```
- requery_on_multiple_speaker_names: whether to requery the LLM if multiple speaker names are returned during speaker selection.
The response with multiple names will be fed back to the LLM with a prompt asking it to select the primary speaker's name.
Applies only to "auto" speaker selection method.
Default is False, in which case if the LLM returns multiple speaker names it will not requery the LLM.
marklysze marked this conversation as resolved.
Show resolved Hide resolved
If set to True and the LLM returns multiple speaker names, a message will be sent to the LLM with that response asking the LLM to return just one name based on it.
- allow_repeat_speaker: whether to allow the same speaker to speak consecutively.
Default is True, in which case all speakers are allowed to speak consecutively.
If `allow_repeat_speaker` is a list of Agents, then only those listed agents are allowed to repeat.
Expand All @@ -77,6 +82,7 @@ def custom_speaker_selection_func(
admin_name: Optional[str] = "Admin"
func_call_filter: Optional[bool] = True
speaker_selection_method: Union[Literal["auto", "manual", "random", "round_robin"], Callable] = "auto"
requery_on_multiple_speaker_names: bool = False
allow_repeat_speaker: Optional[Union[bool, List[Agent]]] = None
allowed_or_disallowed_speaker_transitions: Optional[Dict] = None
speaker_transitions_type: Literal["allowed", "disallowed", None] = None
Expand Down Expand Up @@ -466,7 +472,7 @@ def select_speaker(self, last_speaker: Agent, selector: ConversableAgent) -> Age
# auto speaker selection
selector.update_system_message(self.select_speaker_msg(agents))
final, name = selector.generate_oai_reply(messages)
return self._finalize_speaker(last_speaker, final, name, agents)
return self._finalize_speaker(last_speaker, final, name, selector, agents)

async def a_select_speaker(self, last_speaker: Agent, selector: ConversableAgent) -> Agent:
"""Select the next speaker."""
Expand All @@ -476,9 +482,11 @@ async def a_select_speaker(self, last_speaker: Agent, selector: ConversableAgent
# auto speaker selection
selector.update_system_message(self.select_speaker_msg(agents))
final, name = await selector.a_generate_oai_reply(messages)
return self._finalize_speaker(last_speaker, final, name, agents)
return self._finalize_speaker(last_speaker, final, name, selector, agents)

def _finalize_speaker(self, last_speaker: Agent, final: bool, name: str, agents: Optional[List[Agent]]) -> Agent:
def _finalize_speaker(
self, last_speaker: Agent, final: bool, name: str, selector: ConversableAgent, agents: Optional[List[Agent]]
) -> Agent:
if not final:
# the LLM client is None, thus no reply is generated. Use round robin instead.
return self.next_agent(last_speaker, agents)
Expand All @@ -487,6 +495,41 @@ def _finalize_speaker(self, last_speaker: Agent, final: bool, name: str, agents:
mentions = self._mentioned_agents(name, agents)
joshkyh marked this conversation as resolved.
Show resolved Hide resolved
if len(mentions) == 1:
name = next(iter(mentions))
elif self.requery_on_multiple_speaker_names and len(mentions) > 1:
# We have more than one name mentioned in the response, requery and
# ask the LLM to choose one name from that response
select_name_message = [
{
"content": f"""Your role is to identify the current or next speaker based on the provided context. The valid speaker names are {[agent.name for agent in agents]}. To determine the speaker use these prioritised rules:
1. If the context refers to themselves as a speaker e.g. "As the..." , choose that speaker's name
2. If it refers to the "next" speaker name, choose that name
3. Otherwise, choose the first provided speaker's name in the context

Respond with just the name of the speaker and do not provide a reason.\nContext:\n{name}""",
"role": "system",
}
]

# Send to LLM for a response
response = selector.client.create(
context=None,
messages=select_name_message,
cache=None,
)

# Returned name
name_single = selector.client.extract_text_or_completion_object(response)[0]

# Evaluate the response for agent names
mentions = self._mentioned_agents(name_single, agents)
if len(mentions) == 1:
# Successfully identified just the one agent name on the requery
name = next(iter(mentions))
else:
# Requery failed to identify just one agent name
logger.warning(
f"GroupChat select_speaker failed to resolve the next speaker's name (including with requery). Requery speaker selection returned:\n{name_single}"
)
marklysze marked this conversation as resolved.
Show resolved Hide resolved
else:
logger.warning(
f"GroupChat select_speaker failed to resolve the next speaker's name. This is because the speaker selection OAI call returned:\n{name}"
Expand Down
Loading