In this post, we explore AutoGen, an innovative open-source framework by Microsoft designed to create and manage AI agents capable of interacting to solve tasks collaboratively. AutoGen simplifies the development of next-gen language model applications by enabling complex workflows with minimal effort. It offers a comprehensive solution for orchestrating, automating, and optimizing language model interactions.
1. Multi-Agent Conversations: AutoGen enables the creation of multi-agent systems where agents can converse with each other and with users to accomplish various tasks. These agents can be customized to fit specific needs and integrated with different tools and language models.
2. Diverse Conversation Patterns: The framework supports various conversation patterns, allowing for flexible and dynamic interactions. Developers can design agents with different levels of autonomy and configure them to follow specific conversation topologies, enhancing their ability to handle complex workflows.
3. Integration and Tool Support: AutoGen provides seamless integration with large language models (LLMs) and various tools, enabling agents to perform tasks autonomously or with human assistance. This includes support for code execution and the use of external APIs.
4. Autonomous and Human-in-the-Loop Workflows: The framework facilitates both fully autonomous workflows and those that involve human intervention, providing flexibility in how tasks are completed. This ensures that agents can operate independently while also allowing for human oversight when necessary.
5. Research-Driven Development: AutoGen is powered by collaborative research from institutions like Microsoft, Penn State University, and the University of Washington, ensuring that it remains at the forefront of AI and machine learning advancements.
The core aim of this project is to leverage AutoGen to recreate a focus group using AI agents. By simulating the dynamics of a focus group, we can explore how different agents interact, provide insights, and collaborate to achieve specific objectives. This practical application not only demonstrates the capabilities of AutoGen but also provides valuable insights into how multi-agent systems can be utilized in real-world scenarios. We’ll provide to each agent a background to base their thought on, a specific agent will act as moderator and then another agent will analysis the output. The base code can be found In this repo
In this blog post, we will explore how to create trackable agents using the AutoGen framework by Microsoft. These agents will be able to process and display messages in a user-friendly manner using Streamlit. Let’s walk through the creation of three key components: TrackableAssistantAgent
, TrackableUserProxyAgent
, and TrackableGroupChatManager
.
The TrackableAssistantAgent
class extends the AssistantAgent
class from the AutoGen framework. This agent is designed to process incoming messages and display them using Streamlit’s chat interface. Here’s how we define it:
class TrackableAssistantAgent(AssistantAgent):
def _process_received_message(self, message, sender, silent):
with st.chat_message(sender.name):
st.markdown(message)
return super()._process_received_message(message, sender, silent)
TrackableAssistantAgent
inherits from AssistantAgent
._process_received_message
is overridden to add custom behavior.st.chat_message(sender.name)
, messages are displayed in the chat interface with the sender’s name.We’ll do the same for the rest of assistants
class TrackableUserProxyAgent(UserProxyAgent):
def _process_received_message(self, message, sender, silent):
with st.chat_message(sender.name):
st.markdown(message)
return super()._process_received_message(message, sender, silent)
class TrackableGroupChatManager(GroupChatManager):
def _process_received_message(self, message, sender, silent):
with st.chat_message(sender.name):
st.markdown(message)
return super()._process_received_message(message, sender, silent)
The generate_notice
function is designed to generate a notice message tailored to a specific role. Here’s a detailed breakdown of the function:
def generate_notice(role: str = "researcher", base_notice: Optional[str] = None) -> str:
"""
Generates a notice message based on the role.
Parameters:
role (str): The role of the agent.
base_notice (Optional[str]): The base notice message.
Returns:
str: The generated notice message.
"""
if base_notice is None:
base_notice = (
'You are part of a research panel to gather relevant information of a new product that our client is launching. We appreciate your collaboration.'
)
non_persona_notice = (
'Do not show appreciation in your responses, say only what is necessary. '
'If "Thank you" or "You\'re welcome" are said in the conversation, then say TERMINATE '
'to indicate the conversation is finished and this is your last message.'
)
persona_notice = (
' Act as {role} when responding to queries, providing feedback, asked for your personal opinion '
'or participating in discussions.'
)
if role.lower() in ["manager", "researcher"]:
return base_notice + non_persona_notice
else:
return base_notice + persona_notice.format(role=role)
The generate_notice
function is designed to create a tailored notice message based on the role of an agent. Let’s break down how this function works in a friendly and easy-to-understand manner.
The generate_notice
function takes two parameters: role
and base_notice
. The role
parameter specifies the role of the agent, with a default value of “researcher”. The base_notice
parameter is an optional string that can be used to provide a custom base notice message. If no base_notice
is provided, the function uses a default message.
If no base_notice is provided, the function sets it to a default message that welcomes the agent to a research panel. The function then defines two additional notice messages. The first one, non_persona_notice, instructs agents to keep their responses strictly professional and to use “TERMINATE” to end the conversation if “Thank you” or “You’re welcome” is mentioned. The second one, persona_notice, tells the agent to act according to their role, providing a more personalized touch. Finally, the function decides which notice to append to the base_notice based on the agent’s role. If the role is “manager” or “researcher”, the function appends the non_persona_notice. Otherwise, it appends the persona_notice, formatted with the given role.
custom_speaker_selection
FunctionThe custom_speaker_selection
function ensures that the Researcher interacts with each participant in a group chat 2-3 times. It alternates between the Researcher and participants, tracking interactions to maintain a balanced conversation. Here’s a detailed explanation of how this function works.
The custom_speaker_selection
function takes two parameters: last_speaker
and group_chat
. The last_speaker
is the agent who last spoke in the chat, and group_chat
is the group chat context containing all agents.
def custom_speaker_selection(last_speaker: Optional[Agent], group_chat: GroupChat) -> Optional[Agent]:
"""
Custom function to ensure the Researcher interacts with each participant 2-3 times.
Alternates between the Researcher and participants, tracking interactions.
"""
The function first checks if the group_chat
object has an interaction_counters
attribute. If not, it initializes this attribute as a dictionary to track the number of interactions for each participant (excluding the Researcher).
if not hasattr(group_chat, 'interaction_counters'):
group_chat.interaction_counters = {agent.name: 0 for agent in group_chat.agents if agent.name != "Researcher"}
A maximum number of interactions per participant is defined to limit the conversation length.
max_interactions = 6
The function then decides the next speaker based on who spoke last.
None
to end the conversation.if last_speaker and last_speaker.name == "Researcher":
next_participant = min(group_chat.interaction_counters, key=group_chat.interaction_counters.get)
if group_chat.interaction_counters[next_participant] < max_interactions:
group_chat.interaction_counters[next_participant] += 1
return next((agent for agent in group_chat.agents if agent.name == next_participant), None)
else:
return None # End the conversation if all participants have reached the maximum interactions
else:
return next((agent for agent in group_chat.agents if agent.name == "Researcher"), None)
create_research_panel
The create_research_panel
function initializes a panel of research assistant agents based on consumer profiles.
def create_research_panel() -> None:
consumer_profiles = {}
assistant_agents = []
for profile in consumer_profiles:
agent = TrackableAssistantAgent(
name=profile["name"],
llm_config=llm_config,
system_message=profile["system_message"],
human_input_mode=profile["human_input_mode"] # Ensure the agent asks for human input
)
assistant_agents.append(agent)
for agent in assistant_agents:
print(f"Created agent: {agent.name}")
return assistant_agents
consumer_profiles
is an empty dictionary intended to hold profiles of consumers.assistant_agents
is an empty list to store created agents.consumer_profiles
to create TrackableAssistantAgent
instances.llm_config
), system message, and human input mode.assistant_agents
list.create_group_chat
The create_group_chat
function sets up a group chat with the specified agents and a custom speaker selection method.
def create_group_chat(agents:list, custom_selection):
groupchat = GroupChat(
agents=agents,
speaker_selection_method = custom_selection,
messages=[],
max_round=30)
# create a UserProxyAgent instance named "user_proxy"
user_proxy = TrackableUserProxyAgent(
name="user_proxy",
code_execution_config={"last_n_messages": 2, "work_dir": "groupchat", 'use_docker':False},
system_message="A human admin.",
human_input_mode="NEVER"
)
# Initialise the manager
manager = TrackableGroupChatManager(
groupchat=groupchat,
llm_config=llm_config,
system_message="You are a research manager agent that can manage a group chat of multiple agents made up of a researcher agent and many people made up of a panel. You will limit the discussion between the panelists and help the researcher in asking the questions. Please ask the researcher first on how they want to conduct the panel." + generate_notice(),
is_termination_msg=lambda x: True if "TERMINATE" in x.get("content") else False,
)
return groupchat, user_proxy, manager
GroupChat
instance with the provided agents and custom speaker selection method.TrackableUserProxyAgent
named “user_proxy” to act as a human admin with specific configuration settings.human_input_mode="NEVER"
).TrackableGroupChatManager
to manage the group chat.llm_config
, and a detailed system message.summarization_agent
The summarization_agent
function creates an agent for summarizing the group chat discussions.
def summarization_agent(summary_prompt:str=summary_agent_prompt):
# Get response from the groupchat for user prompt
# Generate system prompt for the summary agent
summary_agent = TrackableAssistantAgent(
name="SummaryAgent",
llm_config=llm_config,
system_message=summary_prompt + generate_notice(),
)
summary_proxy = TrackableUserProxyAgent(
name="summary_proxy",
code_execution_config={"last_n_messages": 2, "work_dir": "groupchat", 'use_docker':False},
system_message="A human admin.",
human_input_mode="TERMINATE"
)
return summary_agent, summary_proxy
TrackableAssistantAgent
named “SummaryAgent”.llm_config
and a system message that combines the provided summary prompt with a generated notice.TrackableUserProxyAgent
named “summary_proxy” to assist with summarization.In conclusion, while I won’t get into all the nitty-gritty details of the application here, I hope the attached images give you a good visual understanding of how it all comes together. This project is built upon the impressive groundwork laid out in the AutoGen Focus Group project.
What stands out the most is the seamless interaction between AI agents, especially when they are given a specific background to operate from. It’s fascinating to see how these agents can emulate human-like discussions, providing valuable insights in a structured and efficient manner.
To move this project into production, several steps need to be taken:
You can check out the Streamlit app to see it in action: Streamlit App
This journey into AI-driven research panels is just beginning, and I am excited to see how these technologies will continue to evolve and enhance our capabilities. Stay tuned for more updates as we progress!