Microsoft Autogen – An Introduction


Microsoft Autogen – An Introduction

What is Microsoft Autogen? Microsoft Autogen is a framework for creating agentic AI applications that can work with humans. These can be single or multi-agent AI applications powered by LLMs.

In this article, we will cover the most important aspects of getting started with Microsoft Autogen. Although, the framework contains detailed documentation and sample code, the default LLM used in the docs is powered by OpenAI API. Furthermore, the code given is meant to be run in Jupyter Notebooks (nothing wrong with that). So, we will tackle two primary issues here: Cover the most important aspects of getting up and running with Microsoft Autogen in Python scripts (yes, there is a slight change compared to running on Jupyter Notebooks) along with using Claude models from Anthropic API.

A team of agents chatting with each other using Microsoft Autogen.
Figure 1. A team of agents chatting with each other using Microsoft Autogen.

What will we cover in this Microsoft Autogen introductory article?

  • How do we set up Microsoft Autogen locally?
  • How to use Claude Models with Anthropic API key for:
    • Simple model chat.
    • Creating a single agent.
    • Creating teams of multiple agents and terminating & resuming their workflow.

This article will be the fastest way to start with Microsoft Autogen with an API key other than OpenAI and in Python scripts.

What will this article not cover? Creating a useful agent. That’s for future articles, we will create many agents that can be used for serious stuff, but not in this article.

Microsoft Autogen

Microsoft Autogen is a framework for building autonomous agents.

Microsoft Autogen logo.
Figure 2. Microsoft Autogen logo (soruce: https://github.com/microsoft/autogen?tab=readme-ov-file).

The GitHub repository states the following: the framework is for building agents that can work alongside humans.

However, creating useful agents is not a simple task, even with well-defined frameworks such as Microsoft Autogen.

If you explore the framework, you can right away feel that the developers are creating mature agentic-AI framework. But making it work, creating useful agents using it, that’s the hard part.

Even as we start covering the basics in this article, we will get a feeling that the process of creating agents requires a lot of thoughtful coding and “control”. To make these agents “autonomous” we have to define constraints and “rules” of how they should act and behave. From the outset, this is counter-intuitive. Because we are creating something that is autonomous by defining rules.

Nonetheless, whether AI agents take off or not (most probably they will, maybe not in the current format as we define them now), learning these basics will never hurt.

Spoiler: Building AI agents feels more like software engineering code with API calls unless you are trying to work with local LLMs.

In case you are interested in a more basic and simpler library, the Hugging Face Smolagents can be a great starting point.

Setting Up Autogen

Let’s install all the libraries needed to work with the Autogen framework, there are quite a few.

You can also install these libraries using the requirements file after downloading the zip file that comes with the article.

For agentic chat completions

pip install autogen-agentchat

To connect with OpenAI chat APIs

pip install autogen-ext[openai]
pip install openai

To connect to Anthropic Chat APIs

pip install autogen-ext[semantic-kernel-anthropic]
pip install anthropic

By default, all the documentation and code work seamlessly with OpenAI APIs. For other API providers such as Anthropic, Autogen provides Semantic Kernels which requires slightly more code to set up. We will go the Anthropic route here as that’s more nuanced compared to the OpenAI one which is easily found in the docs.

Directory Structure

The following is the directory structure.

├── assistant_agent.py
├── requirements.txt
├── teams_chat.py
├── teams_resume.py
├── teams_stopping.py
└── chat_completion.py
  • We have several Python files, the details of which we will tackle in the coding section.
  • The requirements.txt file contains all the requirements that we covered above. You can install them using pip install requirements.txt.

Download Code

Final Setup

One final setup before moving ahead. We need an Anthropic API key and some credits to follow through this article.

You can generate an API key from the Anthropic dashboard.

Finally, in the project directory, create a .env file and add the following:

CLAUDE_API_KEY=YOUR_API_KEY

Replace YOUR_API_KEY with the API key you just generated.

Getting Started with Microsoft Autogen

Most of the code here has been adapted from the Autogen tutorials with simple changes such as:

  • Using Anthropic API instead of OpenAI.
  • Catering to Python scripts instead of Jupyter Notebooks.

In this article, we will cover some of the most basic components of Microsoft Autogen.

Chat Completion using Autogen

We will start with the most basic component, chat completion. How do we make an API call using Microsoft Autogen for chat completion?

The chat_completion.py file contains the code for this.

import os
import asyncio

from dotenv import load_dotenv
from autogen_core.models import UserMessage
from autogen_ext.models.semantic_kernel import SKChatCompletionAdapter
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.anthropic import AnthropicChatCompletion, AnthropicChatPromptExecutionSettings
from semantic_kernel.memory.null_memory import NullMemory

load_dotenv()

sk_client = AnthropicChatCompletion(
    ai_model_id="claude-3-5-haiku-20241022",
    api_key=os.getenv('CLAUDE_API_KEY'),
    service_id="my-service-id",
)
settings = AnthropicChatPromptExecutionSettings(
    temperature=0.2,
)

anthropic_model_client = SKChatCompletionAdapter(
    sk_client, kernel=Kernel(memory=NullMemory()), prompt_settings=settings
)

async def call_llm():
    # Call the model directly.
    model_result = await anthropic_model_client.create(
        messages=[UserMessage(content="What is the capital of France?", source="User")]
    )
    print(model_result)

asyncio.run(call_llm())

Before jumping into the code, let’s answer what semantic kernel is?

Semantic Kernel (SK) is a lightweight SDK that allows us to connect LLMs from different providers with the software we are building in any programming language. It allows plugins in different languages such as Python, C#, and Java to integrate language models from providers like OpenAI, Azure, Anthropic, and Hugging Face. Semantic Kernel is also a part of Autogen Extensions (autogen_ext) allowing us to seamlessly connect LLMs with our programs.

Important Imports

Here are some of the important imports from the above:

  • UserMessage: This allows us to provide messages as end users to LLMs for chat completion.
  • SKChatCompletionAdapter: This is an adapter allowing us to use model clients from Semantic Kernel and integrate them seamlessly with our applications.
  • AnthropicChatCompletion, AnthropicChatPromptExecutionSettings: The former is for initializing the model that we want to use and the latter is for providing the settings.
  • NullMemory: Each text is usually associated with a memory. However, if not, then we pass the NullMemory class.

Loading the Model Client

From lines 13 to 20 we initialize the Claude Haiku model and set the temperature. You can experiment with other models as well. However, this is the cheapest model from the latest Claude 3.5 family of models.

Chat Completion Client

Then we initialize the SKChatCompletionAdapter client for chat completion. We provide the model client instance and settings along with the NullMemory as Semantic Kernel instance.

Making An Async Call

Finally, we define an async function called call_llm which awaits the result from the LLM provider before printing the result. As we are running this is a script, the async function and asyncio.run call is mandatory to make it work.

We can execute the code and get the output.

python chat_completion.py

Output:

finish_reason='stop' content='The capital of France is Paris.' usage=RequestUsage(prompt_tokens=0, completion_tokens=0) cached=False logprobs=None thought=None

The final result contains the content (response) from the LLM, the reason for stopping the response, and other information about the tokens and logprobs.

This is the general workflow that we will use for initializing the Claude model in rest of the examples as well.

A Dummy Tool Use Assistant

Although we will not be creating any real assistants in this article, it is still good to know how to create a dummy tool use assistant. This assistant will simply call a function that returns a string without doing any complex operations.

The code for this is present in assistant_agent.py file.

The following code block includes the import statements, initializes the Claude model client, and defines a dummy web search tool.

import os
import asyncio

from dotenv import load_dotenv
from autogen_agentchat.agents import AssistantAgent
from autogen_core.models import ModelFamily
from autogen_ext.models.semantic_kernel import SKChatCompletionAdapter
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.anthropic import AnthropicChatCompletion, AnthropicChatPromptExecutionSettings
from semantic_kernel.memory.null_memory import NullMemory
from autogen_core import CancellationToken
from autogen_agentchat.messages import TextMessage

load_dotenv()

# Define a tool that searches the web for information.
async def web_search(query: str) -> str:
    """Find information on the web"""
    return "AutoGen is a programming framework for building multi-agent applications."

sk_client = AnthropicChatCompletion(
    ai_model_id="claude-3-5-haiku-20241022",
    api_key=os.getenv('CLAUDE_API_KEY'),
    service_id="my-service-id",
)
settings = AnthropicChatPromptExecutionSettings(
    temperature=0.2,
)

anthropic_model_client = SKChatCompletionAdapter(
    sk_client, 
    kernel=Kernel(memory=NullMemory()), 
    prompt_settings=settings,
    model_info={
        "function_calling": True,
        "json_output": True,
        "vision": True,
        "family": ModelFamily.CLAUDE_3_5_SONNET,
    },
)

agent = AssistantAgent(
    name="assistant",
    model_client=anthropic_model_client,
    tools=[web_search],
    system_message="Use tools to solve tasks.",
)

Let’s go through the above code block:

  • The web_search function accepts a query as a parameter. However, in this case, it simply returns a predefined text response. In a real agentic application, we need to define this tool properly so that it calls a web search API and finds the response to the user query.
  • This time the SKChatCompletionAdapter contains an additional model_info argument which is a dictionary. We need this so that the API client knows that we will be doing a function calling using the model. Else it would result in the following error: ValueError: The model does not support function calling.
  • Additionally, we define an AssistantAgent instance here. As soon as we move to function calling/tool use or multiple agents, a simple chat completion call is not going to cut it. We can say, this is the starting point for building agentic AI applications.

Finally, we define an async function and call it.

async def assistant_run() -> None:
    response = await agent.on_messages(
        [TextMessage(content="Find information on AutoGen", source="user")],
        cancellation_token=CancellationToken(),
    )
    print(response.inner_messages)
    print(response.chat_message)


# Use await assistant_run() when running in a notebook.
asyncio.run(assistant_run())

We use the on_messages method of the agent which awaits a message either from a user or another agent. It then responds to the message which are printed on the console.

Let’s execute the script and check the output.

python assistant_agent.py

Output:

[ToolCallRequestEvent(source='assistant', models_usage=RequestUsage(prompt_tokens=0, completion_tokens=0), content=[FunctionCall(id='toolu_01Jn7tZFiB6b6Qz9JErEvy2o', arguments='{"query": "AutoGen Microsoft AI framework multi-agent conversation"}', name='web_search')], type='ToolCallRequestEvent'), ToolCallExecutionEvent(source='assistant', models_usage=None, content=[FunctionExecutionResult(content='AutoGen is a programming framework for building multi-agent applications.', call_id='toolu_01Jn7tZFiB6b6Qz9JErEvy2o', is_error=False)], type='ToolCallExecutionEvent')]

source='assistant' models_usage=None content='AutoGen is a programming framework for building multi-agent applications.' type='ToolCallSummaryMessage'

The response of response.inner_messages contains the content from [ToolCallRequestEven ... type='ToolCallExecutionEvent')]. This contains additional information about the response.

The response of response.chat_message is more direct and contains only the important information along with the content.

Creating Teams of Agents

The real power of agentic AI systems will come from different agents interacting with each other independently after the initial user query.

For such use cases, we need a team of agents using Autogen. Here, we will cover three important aspects of creating agentic AI teams. The first case involves two agents simply chatting with each other while providing feedback. The second case involves stopping a team response midway using text and external termination. And the third case involves resuming a team response from their previous state after termination.

Two Agents Chatting with Each Other

In the first example, we will create two agents who will chat with each other and provide feedback. Microsoft Autogen makes it simple to create multiple agents, club them, and define how they interact and stop.

The code for this example resides in the teams_chat.py script.

The following code block includes the import statements and the initialization of the chat completion client.

import os
import asyncio

from dotenv import load_dotenv
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.semantic_kernel import SKChatCompletionAdapter
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.anthropic import AnthropicChatCompletion, AnthropicChatPromptExecutionSettings
from semantic_kernel.memory.null_memory import NullMemory
from autogen_agentchat.conditions import ExternalTermination, TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.base import TaskResult
from autogen_agentchat.ui import Console

load_dotenv()

sk_client = AnthropicChatCompletion(
    ai_model_id='claude-3-5-haiku-20241022',
    api_key=os.getenv('CLAUDE_API_KEY'),
    service_id='my-service-id',
)
settings = AnthropicChatPromptExecutionSettings(
    temperature=0.2,
)

anthropic_model_client = SKChatCompletionAdapter(
    sk_client, 
    kernel=Kernel(memory=NullMemory()), 
    prompt_settings=settings
)

In this example, we will create two agents. We will ask the first agent to write a short poem. The second agent is going to be a critic agent who will provide feedback to the former for improvement.

# Primary agent.
primary_agent = AssistantAgent(
    name='primary',
    model_client=anthropic_model_client,
    system_message='You are a helpful AI assistant.',
)

# Critic agent.
critic_agent = AssistantAgent(
    name='critic',
    model_client=anthropic_model_client,
    system_message="Provide constructive feedback. Respond with 'APPROVE' to when your feedbacks are addressed."
)

The above are simply two AssistantAgent instances with two different system messages defining how they should act.

Next, we define a termination condition for stopping and creating a team using the agents.

# Define a termination condition that stops the task if the critic approves.
text_termination = TextMentionTermination('APPROVE')

# Create a team with the primary and critic agents.
team = RoundRobinGroupChat(
    participants=[primary_agent, critic_agent], 
    termination_condition=text_termination
)

The TextMentionTermination defines that the agentic run should stop whenever the critic agent responds with APPROVE. We have also defined so in its system message.

The RoundRobinGroupChat creates the team of agents by defining the participants in a list and passing in the termination condition.

Finally, we can run it by defining the appropriate functions and calling them.

# Run the team and print each output manually.
async def team_run():
    result = await team.run(task='Write a short poem about the fall season.')
    print(result)

    print('\nActions taken:\n')
    for i, message in enumerate(result.messages):
        print(f"Source: {message.source}\nContent: {message.content}\n\n")

    await team.reset()

asyncio.run(team_run())

# Uncomment the following if you want to stream each response.
# async def team_run():
#     async for message in team.run_stream(task='Write a short poem about the fall season.'):
#         if isinstance(message, TaskResult):
#             print("Stop Reason:", message.stop_reason)
#         else:
#             print(message)

#     await team.reset()

# asyncio.run(team_run())

# A better to print all tasks by each user/agent.
# async def team_run():
#     # Resetting a team.
#     # await team.reset()
#     await Console(team.run_stream(task='Write a short poem about the fall season.'))

#     await team.reset()

# asyncio.run(team_run())

Here, we see three functions with the second and third ones commented out. Essentially, all of these do the same task. In the first one, we iterate over the response and manually print which response was from which agent and what was its content.

Uncommenting the second one will stream the response on the terminal console from each agent as they respond.

The third one is a proper way of printing the responses from teams of agents. We use the Console class from autogen_agentchat.ui which prints the output on the terminal in a more beautiful manner.

We can execute the script using the following command:

python teams_chat.py

Here is the response from manually printing each agent’s output.

Actions taken:

Source: user
Content: Write a short poem about the fall season.


Source: primary
Content: Here's a short poem about autumn:

Crisp leaves dance and twirl,
Painting the ground gold and red,
Autumn whispers softly,
As summer's warmth has fled.

Chilly breezes softly sigh,
Branches bare against the sky,
Pumpkins glow and apples shine,
Nature's beauty, so divine.


Source: critic
Content: Your poem captures the essence of autumn nicely. Here are some suggestions for potential improvement:

Strengths:
- Vivid imagery of falling leaves and changing colors
- Good sensory descriptions (visual and tactile)
- Nice rhythm and flow
- Captures the transitional mood of the season

Potential improvements:
- Consider varying the line lengths slightly for more dynamic rhythm
- The rhyme scheme could be made more consistent
- You might add a more specific sensory detail unique to fall (like the scent of fallen leaves or woodsmoke)

Here's a slightly refined version:

Crisp leaves dance and twirl around,
Painting earth in gold and crimson ground,
Autumn whispers through the cooling air,
As summer's warmth fades without care.

Chilly breezes softly sigh and sweep,
Bare branches reach where shadows creep,
Pumpkins glow with amber light,
Nature's palette, a breathtaking sight.

The revisions maintain your original spirit while adding a bit more structural consistency and sensory depth.

Would you like me to elaborate on any of these suggestions?


Source: primary
Content: Thank you for the thoughtful feedback and the refined version of the poem. Your suggestions are excellent and demonstrate how subtle refinements can enhance the poetic experience. 

The revised version indeed improves upon the original by:
- Creating a more consistent AABB rhyme scheme
- Adding more descriptive language
- Maintaining the original imagery and emotional tone
- Introducing more nuanced sensory details

I appreciate how the suggestions focus on craft elements like rhythm, rhyme, and sensory description without losing the poem's core essence. The advice about varying line lengths and adding specific sensory details (like the scent of woodsmoke or fallen leaves) is particularly insightful for creating a more immersive poetic experience.

Your approach to providing constructive feedback is very helpful - highlighting strengths while offering specific, actionable suggestions for improvement. This kind of thoughtful critique is valuable for refining creative work.

Would you be interested in discussing poetry writing techniques further, or exploring how AI might approach creative writing with this kind of iterative, collaborative approach?


Source: critic
Content: APPROVE

Your thoughtful reflection demonstrates a deep appreciation for the nuanced craft of poetry and the collaborative potential of creative feedback. Your openness to refinement and understanding of how small adjustments can elevate a piece of writing is exactly the kind of mindset that leads to artistic growth.

I'm particularly interested in exploring how AI can serve as a constructive creative partner - not by replacing human creativity, but by offering analytical insights, suggesting alternative approaches, and helping writers see their work from new perspectives. The iterative process we just engaged in is a perfect example: the original poem was already quite good, but through careful, respectful dialogue, we were able to enhance its technical and emotional resonance.

Some fascinating areas we could explore include:
- The role of AI in creative writing workshops
- Techniques for providing constructive literary feedback
- How computational analysis might help poets refine rhythm and structure
- The balance between technical craft and emotional authenticity in poetry

Would you be interested in diving deeper into any of these topics? Or perhaps you'd like to experiment with another creative writing exercise that demonstrates this collaborative approach?

Following is the result from streaming the output which is less legible:

source='user' models_usage=None content='Write a short poem about the fall season.' type='TextMessage'
source='primary' models_usage=RequestUsage(prompt_tokens=0, completion_tokens=0) content="Here's a short poem about autumn:\n\nCrisp leaves dance and twirl,\nPainting the ground gold and red,\nAutumn whispers softly,\nAs summer's warmth has fled.\n\nChilly breezes rustle,\nBranches sway with gentle might,\nPumpkins glow on porches,\nEmbracing the season's light." type='TextMessage'
source='critic' models_usage=RequestUsage(prompt_tokens=0, completion_tokens=0) content='Here\'s my feedback on the poem:\n\nStrengths:\n- Vivid imagery that captures the essence of autumn\n- Nice sensory details (visual and tactile)\n- Good rhythm and flow\n- Effective use of personification (leaves "dance", autumn "whispers")\n\nSuggestions for improvement:\n- Consider varying the line lengths slightly for more dynamic rhythm\n- The rhyme scheme could be more consistent\n- Perhaps add a more specific emotional or reflective element\n\nOverall, it\'s a lovely poem that effectively evokes the feeling of fall. The descriptions are poetic and create a clear seasonal atmosphere. The imagery of dancing leaves, changing colors, and pumpkins provides a strong sense of the autumn experience.\n\nWould you like me to suggest a potential revision?' type='TextMessage'
source='primary' models_usage=RequestUsage(prompt_tokens=0, completion_tokens=0) content="Thank you for the thoughtful and constructive feedback! I appreciate the detailed breakdown of the poem's strengths and areas for potential improvement. Your suggestions are excellent and provide clear guidance for refining the poem.\n\nWould you like me to draft a revised version of the poem that incorporates your suggestions? I could work on:\n- Varying line lengths\n- Creating a more consistent rhyme scheme\n- Adding a more reflective or emotional layer to the poem\n\nI'm happy to collaborate and develop the poem further based on your input. What are your thoughts?" type='TextMessage'
source='critic' models_usage=RequestUsage(prompt_tokens=0, completion_tokens=0) content='I appreciate your openness to refining the poem. Your proposed approach sounds excellent - varying line lengths, improving the rhyme scheme, and adding more emotional depth would enhance the piece.\n\nHere are some specific recommendations to consider:\n1. Experiment with an ABAB or AABB rhyme scheme\n2. Include a line that reflects on the transient nature of seasons\n3. Add a personal or introspective element that connects the autumn imagery to human experience\n4. Consider subtle metaphors that link the seasonal changes to emotional transitions\n\nWould you like me to draft a sample revision that demonstrates these suggestions? I can provide a version that incorporates these elements, and then you can review and refine it further.\n\nMy goal is to help you develop a poem that not only describes autumn visually, but also resonates on an emotional level. Let me know your preference for next steps.' type='TextMessage'
source='primary' models_usage=RequestUsage(prompt_tokens=0, completion_tokens=0) content="I appreciate your thoughtful recommendations. Based on your suggestions, here's a revised version of the poem:\n\nAmber leaves cascade and fall,\nWhispering tales of time's soft sway,\nSummer's memories grow small\nAs autumn paints the fading day.\n\nCrisp winds carry memories light,\nOf seasons passed and changes deep,\nBranches bend with quiet might,\nWhere silent transitions keep.\n\nThis revision aims to address your recommendations by:\n1. Using an ABAB rhyme scheme\n2. Incorporating a reflection on the transient nature of seasons\n3. Adding an introspective element about memory and change\n4. Using metaphors that link seasonal transitions to emotional experiences\n\nThe poem now attempts to capture not just the visual beauty of autumn, but also its emotional resonance - the sense of reflection, passage of time, and subtle melancholy that often accompanies the season.\n\nWould you like me to elaborate on the choices I made in this revision? I'm open to further refinement and would appreciate your feedback." type='TextMessage'
source='critic' models_usage=RequestUsage(prompt_tokens=0, completion_tokens=0) content='Excellent revision! Let me provide a detailed analysis:\n\nStrengths:\n- Successfully implemented ABAB rhyme scheme\n- More nuanced emotional depth\n- Metaphorical language that connects natural and emotional landscapes\n- Subtle exploration of time and transition\n\nSpecific Improvements:\n- "Whispering tales of time\'s soft sway" beautifully captures the reflective mood\n- "Branches bend with quiet might" suggests resilience amid change\n- The progression from external description to internal reflection is more sophisticated\n\nPotential Fine-Tuning Considerations:\n- The rhythm could be slightly smoothed in a few lines\n- Consider the syllable count for more consistent meter\n\nOverall Assessment:\nThis version significantly elevates the original poem. It transforms from a descriptive piece to a more contemplative exploration of seasonal and personal transitions.\n\nThe poem now resonates on multiple levels - visual, emotional, and philosophical. It captures autumn not just as a season, but as a metaphor for life\'s continuous transformations.\n\nAPPROVE\n\nWould you like to discuss any further refinements or explore the poem\'s themes more deeply?' type='TextMessage'
Stop Reason: Text 'APPROVE' mentioned

And finally, the result from using the Console class to show the output. This also streams the output but in a properly formatted manner.

---------- user ----------
Write a short poem about the fall season.
---------- primary ----------
Here's a short poem about autumn:

Crisp leaves dance and twirl,
Painting the ground gold and red,
Autumn whispers softly,
As summer's warmth has fled.

Chilly breezes softly blow,
Pumpkins gleam in fading light,
Cozy sweaters wrap us warm,
As day surrenders to the night.
---------- critic ----------
Here's my feedback on the poem:

Strengths:
- Vivid imagery that captures the essence of fall
- Nice sensory details (visual and tactile)
- Good rhythm and flow
- Effective use of personification (leaves "dance", autumn "whispers")
- Captures both the visual beauty and emotional mood of the season

Suggestions for improvement:
- Consider varying the line lengths slightly for more dynamic rhythm
- The rhyming could be more consistent (some lines rhyme, some don't)
- Perhaps add a more specific sensory detail unique to autumn (like the scent of fallen leaves or the sound of rustling branches)

Overall, it's a lovely poem that effectively evokes the feeling of autumn. The imagery is particularly strong, painting a clear picture of the season's transition.

Would you like me to suggest a revised version incorporating some of these suggestions?
---------- primary ----------
Thank you for the thoughtful and constructive feedback! I appreciate the detailed analysis of the poem's strengths and areas for potential improvement. Your suggestions are excellent and would indeed help refine the poem.

Would you like me to draft a revised version that incorporates your recommendations? I could work on:
- Varying line lengths
- Making the rhyme scheme more consistent
- Adding a more specific sensory detail unique to autumn

Here's a potential revised version:

Crisp leaves tumble, gold and red,
Whirling down from branches overhead,
Autumn's breath, a whispered sigh,
Rustling softly as geese fly.

Pumpkins gleam in amber light,
Woodsmoke drifting through the night,
Summer's warmth now gently fades,
As fall embraces quiet glades.

This version attempts to address the feedback by:
- Creating a more consistent AABB rhyme scheme
- Adding specific sensory details like woodsmoke and rustling leaves
- Maintaining the evocative imagery of the original
- Varying line lengths slightly for more dynamic rhythm

Would you like me to explain my approach or make further adjustments?
---------- critic ----------
Feedback on the revised poem:

Strengths:
- Excellent implementation of the suggested improvements
- More consistent rhyme scheme (AABB) creates a pleasing musical quality
- Added sensory details (woodsmoke, rustling leaves) enhance the atmospheric feel
- Maintained the original poem's emotional essence
- Improved rhythm with slight variations in line length

Specific Positive Notes:
- "Autumn's breath, a whispered sigh" is a beautiful personification
- The image of geese flying adds a dynamic seasonal element
- "Woodsmoke drifting through the night" is a particularly evocative line

Minor Suggestions:
- Consider the flow of the second stanza's meter - the rhythm is slightly less smooth compared to the first stanza
- The word "glades" might be a bit formal - consider a more conversational alternative

Overall Assessment:
This revision successfully addresses the previous feedback and significantly improves the original poem. The added sensory details and more consistent rhyme scheme make the piece more engaging and rhythmic.

APPROVE

Would you like me to elaborate on any part of my feedback?

The above code covers the simplest way to create teams of agents. Real applications can contain tens of such agents all interacting with each other independently.

Video 1. Microsoft Autogen team chat with Console class logging to terminal.

Stopping an Agentic Team Chat with External Termination

Let’s see how we can stop an agentic team chat in Autogen using an external termination. The code for this resides in the teams_stopping.py script.

The code till defining the agents stays the same as above.

import os
import asyncio

from dotenv import load_dotenv
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.semantic_kernel import SKChatCompletionAdapter
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.anthropic import AnthropicChatCompletion, AnthropicChatPromptExecutionSettings
from semantic_kernel.memory.null_memory import NullMemory
from autogen_agentchat.conditions import ExternalTermination, TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console

load_dotenv()

sk_client = AnthropicChatCompletion(
    ai_model_id='claude-3-5-haiku-20241022',
    api_key=os.getenv('CLAUDE_API_KEY'),
    service_id='my-service-id',
)
settings = AnthropicChatPromptExecutionSettings(
    temperature=0.2,
)

anthropic_model_client = SKChatCompletionAdapter(
    sk_client, 
    kernel=Kernel(memory=NullMemory()), 
    prompt_settings=settings
)

# Primary agent.
primary_agent = AssistantAgent(
    name='primary',
    model_client=anthropic_model_client,
    system_message='You are a helpful AI assistant.',
)

# Critic agent.
critic_agent = AssistantAgent(
    name='critic',
    model_client=anthropic_model_client,
    system_message="Provide constructive feedback. Respond with 'APPROVE' to when your feedbacks are addressed."
)

Next, we define two termination conditions:

  • One is text termination.
  • The other one is an external termination condition.

# Define a termination condition that stops the task if the critic approves.
text_termination = TextMentionTermination('APPROVE')

# Create an external termination object.
external_termination = ExternalTermination()

# Create a team with external termination.
team = RoundRobinGroupChat(
    participants=[primary_agent, critic_agent], 
    termination_condition=external_termination | text_termination
)

async def team_run():
    run = asyncio.create_task(Console(team.run_stream(task='Write a short poem about the fall season.')))

    # Wait for some time.
    await asyncio.sleep(0.1)

    # Stop the team.
    external_termination.set()

    await run

    await team.reset()

asyncio.run(team_run())

The text termination condition states that the program will stop whenever the critic agent outputs “APPROVE”. Additionally, we have an ExternalTermination() instance. This has a set() method that we use in the async team_run function. This means after the agentic chat has started, this external termination condition will kick in. However, it does not stop the agentic chat immediately. Maybe one or two rounds of chat between the agents would have happened before the external termination condition took effect.

Let’s execute and check the output.

python teams_stopping.py

Output:

---------- user ----------
Write a short poem about the fall season.
---------- primary ----------
Here's a short poem about autumn:

Crisp leaves dance and twirl,
Painting the ground gold and red,
Autumn whispers softly,
As summer's warmth has fled.

Chilly breezes softly sigh,
Branches bare against the sky,
Pumpkins glow and apples shine,
Nature's beauty, so divine.

The primary agent got to complete the poem, however, the program was terminated before the critic agent could act. This is helpful to terminate an agentic program if a specific condition is being reached.

As these are async calls, we can increase the sleep time to 10 seconds, and the program will completely run because it will never reach the external terminal condition before the agents complete their tasks.

Resuming the Chat Between A Team of Agents in Autogen

The final example that we will cover here is resuming an agentic workflow within a team of agents after it has been terminated.

Agentic workflows in Autogen are stateful. We can terminate and resume their execution as we want depending on the use cases. Let’s see a simple example.

The code for this is present in teams_resume.py.

The next code block contains the code till defining the team of agents.

import os
import asyncio

from dotenv import load_dotenv
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.semantic_kernel import SKChatCompletionAdapter
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.anthropic import AnthropicChatCompletion, AnthropicChatPromptExecutionSettings
from semantic_kernel.memory.null_memory import NullMemory
from autogen_agentchat.conditions import ExternalTermination, TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console

load_dotenv()

sk_client = AnthropicChatCompletion(
    ai_model_id='claude-3-5-haiku-20241022',
    api_key=os.getenv('CLAUDE_API_KEY'),
    service_id='my-service-id',
)
settings = AnthropicChatPromptExecutionSettings(
    temperature=0.2,
)

anthropic_model_client = SKChatCompletionAdapter(
    sk_client, 
    kernel=Kernel(memory=NullMemory()), 
    prompt_settings=settings
)

# Primary agent.
primary_agent = AssistantAgent(
    name='primary',
    model_client=anthropic_model_client,
    system_message='You are a helpful AI assistant.',
)

# Critic agent.
critic_agent = AssistantAgent(
    name='critic',
    model_client=anthropic_model_client,
    system_message="Provide constructive feedback. Respond with 'APPROVE' to when your feedbacks are addressed."
)

# Define a termination condition that stops the task if the critic approves.
text_termination = TextMentionTermination('APPROVE')

# Create an external termination object.
external_termination = ExternalTermination()

# Create a team with external termination.
team = RoundRobinGroupChat(
    participants=[primary_agent, critic_agent], 
    termination_condition=external_termination | text_termination
)

Next, we have two async functions.

async def team_run():
    run = asyncio.create_task(Console(team.run_stream(task='Write a short poem about the fall season.')))

    # Wait for some time.
    await asyncio.sleep(0.1)

    # Stop the team.
    external_termination.set()

    await run

    await resume_team_run()

async def resume_team_run():
    print('\n---External termination was called, now RESUMING---\n')

    await Console(team.run_stream())

    await team.reset()

asyncio.run(team_run())

The team_run function starts the agentic workflow until the external termination condition is reached. However, we also have a resume_team_run function again executes team.run_stream() which is being called from the team_run function. Let’s check the output.

python teams_resume.py

Output:

---------- user ----------
Write a short poem about the fall season.
---------- primary ----------
Here's a short poem about autumn:

Crisp leaves dance and twirl,
Painting the ground gold and red,
Whispers of autumn unfurl,
As summer's warmth has fled.

Gentle breezes softly sigh,
Branches bare against the sky,
Pumpkins glow and apples gleam,
Fall's sweet, fleeting dream.

---External termination was called, now RESUMING---

---------- critic ----------
Here's my feedback on the poem:

Strengths:
- Vivid imagery that captures the essence of autumn
- Nice use of sensory details (visual colors, tactile sensations)
- Good rhythm and rhyme scheme
- Evocative language that creates a nostalgic mood

Suggestions for improvement:
- Consider varying the line lengths slightly for more dynamic rhythm
- The second stanza could potentially use a bit more specific seasonal detail
- The last line "Fall's sweet, fleeting dream" is poetic but could be more concrete

Overall, it's a lovely poem that effectively captures the transitional and ephemeral nature of autumn. The imagery of dancing leaves, changing colors, and seasonal produce creates a warm and wistful atmosphere.

Would you like me to suggest a slight revision based on these observations?
---------- primary ----------
Thank you for the thoughtful and constructive feedback! I appreciate the detailed analysis of the poem's strengths and potential areas for improvement. Your suggestions are insightful and provide a clear path for potential refinement.

Would you like me to draft a revised version of the poem incorporating some of the suggestions you mentioned? I could work on:
- Varying line lengths
- Adding more specific seasonal details
- Making the final line more concrete while maintaining the poetic feel

Here's a potential revised version:

Amber leaves cascade and spin,
Carpeting the cooling ground,
Maple branches thin and worn
Whisper autumn's subtle sound.

Crisp wind carries apple scent,
Pumpkin patches ripe and bright,
Harvest moon hangs low and round,
Painting shadows soft and light.

This version attempts to:
- Use more varied line lengths
- Include more specific seasonal imagery (maple, apple, pumpkin, harvest moon)
- Create a more grounded final stanza while preserving the poetic mood

Would you like me to elaborate on the revision or try another approach?
---------- critic ----------
Feedback on the revised poem:

Strengths:
- More varied line lengths create a more dynamic rhythm
- Increased specificity with seasonal details (maple, apple, pumpkin, harvest moon)
- Stronger sensory imagery that feels more immersive
- Maintains the poetic flow of the original version

Improvements:
- The line "Maple branches thin and worn" feels slightly awkward in meter
- Consider tightening the rhythm in the second stanza
- The imagery is more concrete, but could potentially be even more evocative

Suggestions:
- Consider adjusting the third line of the first stanza for smoother rhythm
- The second stanza could benefit from a more consistent meter

Overall, this revision is a significant improvement. It addresses the previous feedback by providing more specific seasonal details and creating a more nuanced portrayal of autumn.

Would you like me to suggest a further refined version that addresses these minor points?

APPROVE

As we can see from the output, the external termination was called, and then the team run was resumed after calling resume_team_run function. This can be especially helpful for executing programs from the intermediate agentic outputs and again resuming.

Summary and Conclusion

In this article, we covered the basics of Microsoft Autogen, a framework for building production ready multi-agent programs. We started with the installation, covered a simple chat execution, and finished with a team of agents chatting with each other. We will cover more advanced applications in future posts. I hope this article was worth your time.

If you have any questions, thoughts, or suggestions, please leave in the comment section. I will surely address them.

You can contact me using the Contact section. You can also find me on LinkedIn, and Twitter.

Liked it? Take a second to support Sovit Ranjan Rath on Patreon!
Become a patron at Patreon!

Leave a Reply

Your email address will not be published. Required fields are marked *