AI Agentic Design Patterns with AutoGen
What you’ll learn
- Build and customize multi-agent systems using AutoGen.
- Assign agents different roles and enable them to collaborate on complex tasks.
- Implement agentic design patterns such as multi-agent conversations, tool use, reflection, and planning.
Hands-on Projects
You’ll create systems such as:
- Two-agent comedy chat – using ConversableAgent for constructing multi-agent conversations.
- Customer onboarding flow – sequence of chats with agents collaborating.
- Blog post with reflection – nested critic and reviewer agents refine another agent’s writing.
- Conversational chess game – agents play chess by calling tools for legal moves.
- Coding agent for financial analysis – generates plots of stock gains and integrates user functions.
- Collaborative financial agents – two systems:
- Generate code from scratch.
- Refine user-provided code.
- Custom group chat with planning – multiple agents generate a detailed stock report.
Tools & Framework
- AutoGen works with any LLM via API or local setup.
- Patterns: multi-agent collaboration, tool use, reflection, planning.
What you will learn
- Strong grasp of AutoGen’s core components.
- Practical ability to implement agentic design patterns.
- Skills to automate workflows with multi-agent AI systems.
Technology Used
- Basic Python knowledge.
- automation, AI workflows, and applied agent systems.
Learning Path
- Introduction
- Multi-Agent Comedy Chat
- Sequential Chats & Onboarding
- Reflection & Blogpost Writing
- Tool Use & Conversational Chess
- Coding & Financial Analysis
- Planning & Stock Report Generation
- Conclusion
AutoGen Multi-Agent Conversational Framework
Introduction
- AutoGen is a multi-agent conversational framework.
- Lets you create agents with different roles, personas, tasks, and capabilities.
- Enables the use of agentic design patterns to implement complex AI applications.
Example Use Case: Financial Data Analysis
Normally requires days of research, coding, and report writing. With AutoGen:
- Create agents as researcher, data collector, co-writer, executor.
- Agents can review, critique, and refine the output until it meets the standard.
Learning Structure
You’ll learn six core design patterns/use cases:
-
Multi-agent conversations – ConversableAgent
Example: two standup comedians chatting.
-
Sequential chats
Agents work step-by-step to complete a sequence of tasks. Example: customer onboarding flow.
-
Agent reflection with nested chat
Agents call other agents and iterate before producing a result.
Examples: well-written blog post, conversational chess game. -
Tool use
Provide a user-defined function for agents. Example: checking if a chess move is legal.
-
Code writing & execution
Agents generate, verify, and run code (e.g., in a sandbox). Example: financial analysis & stock gains plotting.
-
Custom multi-agent group chats with planning
Add a planning agent to manage task flow. Example: generating a detailed financial report.
Key Concepts You’ll Learn
- Multi-agent conversation & collaboration
- Sequential task execution
- Nested chat (agents managing sub-agents)
- Tool use (integrating functions)
- Code generation & execution
- Planning & group chat orchestration
1: Conversable Agent & Multi-Agent Conversation (Comedy Chat)
Key Concept: Conversable Agent
In AutoGen, an Agent is an entity that can:
- Act on behalf of human intent
- Send/receive messages
- Perform actions
- Generate replies
- Interact with other agents
ConversableAgent (built-in class)
Provides a unified interface for different agent types. Supports:
- LLM-based replies (via configurable models like GPT-3.5 Turbo)
- Code execution and tool/function execution
- Human-in-the-loop control (input modes: never, always, etc.)
- Highly customizable to fit different applications
Basic Setup Example
- Import API key and set up LLM configuration (GPT-3.5 Turbo in this course)
- Create a ConversableAgent:
- Name: Chatbot
- Config: LLM setup
- Input mode: "never" (fully autonomous)
- Use generate_reply() with a message (e.g., "Tell me a joke")
- Output: Agent generates a response, e.g., “Why did the scarecrow win an award? Because he was outstanding in his field.”
Creating Multi-Agent Conversations
Stand-up Comedy Example
- Agent 1: Cathy → system message: "You are Cathy, a stand-up comedian."
- Agent 2: Joe → system message: "You are Joe, a stand-up comedian. Start the next joke from the punchline of the previous joke."
Conversation initiated via initiate_chat() from Joe → Cathy.
Joe: “I’m Joe. Cathy, let’s keep the jokes rolling.”
Cathy: “Why did the math book look sad? Because it had too many problems.”
Joe: “At least now we know why the math book was always so negative.”
Controlling Conversation Flow
- Max Turns – limit how many back-and-forths occur
- Stopping Condition (is_termination_message) – define a rule to end chat
Conversation History & Metadata
After chat finishes, you can inspect:
- Chat history (all exchanged messages)
- Token usage (prompt vs. completion)
- Cost (based on API tokens)
- Summary (last message or reflection via LLM)
Preserving State
With multi-agent chat setup, agents can now remember prior exchanges.
Joe recalls correctly → “The Scarecrow joke (outstanding in his field).”
Lesson Wrap-Up
You learned how to:
- Create your first ConversableAgent
- Generate replies with generate_reply()
- Build a multi-agent comedy chat
- Control flow with max turns or termination messages
- Inspect history, usage, and summaries
- Enable state preservation for ongoing conversations
This is just the foundation. Next lessons → Sequential Chats, Reflection, Tool Use, Planning, Code Execution.
2. Sequential Multi-Agent Chats for Customer Onboarding
In the previous lesson, we built basic Conversable Agents and explored a comedy-style multi-agent conversation. Now, in Lesson 2, we extend this concept into a practical use case: customer onboarding. Instead of jokes, the agents work together in sequence to simulate a pipeline:
- Personal Information Agent – asks for name and location.
- Topic Preference Agent – surveys what topics the customer likes.
- Engagement Agent – uses info + interests to create a fun interaction.
- Customer Proxy Agent – represents the actual user (human in the loop).
1. Setup
from autogen import ConversableAgent
from utils import get_openai_api_key
OPENAI_API_KEY = get_openai_api_key()
llm_config = {"model": "gpt-3.5-turbo"}
Just like before, we load the OpenAI API key and configure
the LLM (default: gpt-3.5-turbo
). You can swap in gpt-4
or others.
2. Define the Agents
(a) Personal Info Collection Agent
info_agent = ConversableAgent(
name="info_agent",
system_message="You are a customer onboarding agent. Ask the customer for their name and location.",
llm_config=llm_config,
human_input_mode="NEVER",
)
(b) Topic Preference Agent
topic_agent = ConversableAgent(
name="topic_agent",
system_message="You are an onboarding agent. Ask the customer what topics they are interested in.",
llm_config=llm_config,
human_input_mode="NEVER",
)
(c) Engagement Agent
engage_agent = ConversableAgent(
name="engage_agent",
system_message="You are a fun engagement agent. Use the customer's name, location, and interests to tell them fun facts or jokes.",
llm_config=llm_config,
human_input_mode="NEVER",
)
(d) Customer Proxy Agent
customer_proxy = ConversableAgent(
name="customer",
system_message="You are the customer. Answer questions honestly when asked.",
llm_config=llm_config,
human_input_mode="ALWAYS", # requires real user input
)
The Customer Proxy acts as the real user in this pipeline.
By setting human_input_mode="ALWAYS"
, it pauses to let you (the human)
provide answers.
3. Run Sequential Chats
Step 1 – Collect Personal Info
chat1 = info_agent.initiate_chat(
recipient=customer_proxy,
message="Hello! Can you tell me your name and where you're from?",
max_turns=2,
summary_method="reflection_with_llm",
summary_prompt="Extract customer info as JSON with fields: name, location."
)
Step 2 – Survey Topics
chat2 = topic_agent.initiate_chat(
recipient=customer_proxy,
message="Great, could you tell me what topics you’re interested in reading about?",
max_turns=1,
summary_method="reflection_with_llm"
)
Step 3 – Engage the Customer
chat3 = customer_proxy.initiate_chat(
recipient=engage_agent,
message="Let’s find something to read!",
max_turns=2
)
4. Inspect Results
import pprint
print("\n--- Chat 1 Summary (Customer Info) ---")
pprint.pprint(chat1.summary)
print("\n--- Chat 2 Summary (Interests) ---")
pprint.pprint(chat2.summary)
print("\n--- Chat 3 Engagement ---")
pprint.pprint(chat3.chat_history)
print("\n--- Costs ---")
print("Chat 1 Cost:", chat1.cost)
print("Chat 2 Cost:", chat2.cost)
print("Chat 3 Cost:", chat3.cost)
✅ Expected Flow
- Chat 1: Asks your name and location (e.g.,
"Alice from New York"
). - Chat 2: Surveys your interests (e.g.,
"Dogs, Technology"
). - Chat 3: Engagement agent responds, e.g. “Hi Alice from New York! Did you know dogs can understand up to 250 words?”
💡 Key Takeaways
- This lesson introduces Sequential Multi-Agent Chats.
- Each step produces a summary that feeds into the next.
- Human participation is possible via the Customer Proxy Agent.
- This structure is perfect for onboarding pipelines, surveys, and guided flows.
In the next lessons, we’ll enhance this with reflection, tool use, and planning — making agents smarter and more autonomous in real-world tasks.
Lesson 2 Breakdown: Sequential Multi-Agent Onboarding
In this part of Lesson 2, we’ll break down how the customer onboarding simulation works, step by step. You’ll see how agents are defined, chained together, and how summaries flow between them.
1. Setup
llm_config = {"model": "gpt-3.5-turbo"}
from autogen import ConversableAgent
Here we configure the LLM backend (default: gpt-3.5-turbo
)
and import ConversableAgent
for building our agents.
2. Define the Agents
We create four agents, each with a specific role:
- onboarding_personal_information_agent – Asks only for name and location. Ends after collecting them.
- onboarding_topic_preference_agent – Asks for preferred topics. Ends once interests are gathered.
- customer_engagement_agent – Uses name + location + interests to share fun facts, jokes, or stories.
- customer_proxy_agent
– Represents the human user.
With
human_input_mode="ALWAYS"
, it pauses for your real input.
3. Define the Sequential Tasks
chats = [
{...},
{...},
{...}
]
The chats
array defines three conversations in sequence:
- Personal Info Chat
- Sender: onboarding info agent
- Recipient: you (customer proxy)
- Kickoff:
"Tell me your name and location"
- Summarizes output into JSON:
{"name": "", "location": ""}
- Topic Preference Chat
- Sender: topic preference agent
- Recipient: you
- Kickoff:
"What topics are you interested in reading about?"
- Summarized with reflection
- Engagement Chat
- Sender: you (proxy)
- Recipient: engagement agent
- Kickoff:
"Let’s find something fun to read."
- Engagement agent responds with jokes/facts using your info
4. Run the Chats
from autogen import initiate_chats
chat_results = initiate_chats(chats)
This runs the chats in order. Each result object contains: history, summary, and cost breakdown.
5. Inspect Results
Print Summaries
for chat_result in chat_results:
print(chat_result.summary)
print("\n")
Example output:
{"name": "Alice", "location": "New York"}
Alice is interested in reading about dogs.
The agent shared a fun dog fact with Alice from New York.
Print Costs
for chat_result in chat_results:
print(chat_result.cost)
print("\n")
This reveals token usage and dollar cost for each step.
✅ What Happens When You Run It
A typical run looks like this:
- Chat 1: Agent asks “What’s your name and location?” → you reply.
- Chat 2: Agent asks “What topics are you interested in?” → you reply.
- Chat 3: Engagement agent uses your info to generate a tailored response.
For example, if you say:
- Name: Alice
- Location: New York
- Topic: Dogs
The engagement agent might say:
Hey Alice from New York! Did you know dogs can smell 100,000 times better than humans? 🐶
💡 Key Takeaway
This breakdown shows how sequential multi-agent chats can form a complete onboarding pipeline. Each agent has a single purpose, and the flow feels natural — just like interacting with a real onboarding assistant.
3. Reflection & Nested Chat Pattern
Got it 👍 — this lesson is all about agent reflection and how to use the nested chat conversation pattern to improve a blog post through multiple layers of review.
🔑 Key Concepts
- Writer Agent – Generates the first draft of the blog post (e.g., about DeepLearning.AI, under 100 words).
- Critic Agent – Reflects on the writer’s draft. Instead of giving direct feedback, it uses nested chats to consult specialized reviewer agents.
- Reviewer Agents (nested under Critic):
- SEO Reviewer → Checks keywords, ranking potential, organic traffic.
- Legal Reviewer → Ensures compliance, no copyright or misleading claims.
- Ethics Reviewer → Ensures fairness, avoids bias or harm.
- Meta Reviewer → Aggregates all reviewer feedback into one final suggestion.
📚 Nested Chat Pattern
The Critic Agent doesn’t just reply directly to the Writer. Instead, it:
- Routes the draft into multiple sub-chats with reviewer agents.
- Collects structured JSON feedback from each reviewer.
- Passes everything to the Meta Reviewer, who produces a unified recommendation.
- Returns consolidated feedback to the Writer Agent for refinement.
🛠️ Workflow
🧠 Why Reflection + Nested Chat?
- Provides multi-dimensional review (SEO, legal, ethical).
- Mimics a real-world editorial workflow → Writer → Reviewers → Final Editor.
- Improves quality, trustworthiness, and compliance of generated content.
👉 In short: The Critic becomes a manager of expert reviewers. This layered structure ensures the final blog post is optimized, safe, and reliable.
3. Reflection & Nested Chat: Step-by-Step Breakdown
Perfect 👍 — you’ve built Lesson 3. Below is a concise, explicit walk-through of what each piece of code does and how the nested reflection pattern works in practice.
🔨 Step-by-Step Breakdown
1. Setup
llm_config = {"model": "gpt-3.5-turbo"}
Defines the LLM backend used by all agents. Swap to gpt-4
later if desired.
2. Task Definition
task = '''
Write a concise but engaging blogpost about
DeepLearning.AI. Make sure the blogpost is
within 100 words.
'''
A clear instruction block for the writer agent; the writer’s system prompt enforces the "within 100 words" constraint.
3. Writer Agent
writer = autogen.AssistantAgent(
name="Writer",
system_message="You are a writer. You write engaging and concise blogpost (with title) on given topics. You must polish your writing based on the feedback you receive and give a refined version. Only return your final work without additional comments.",
llm_config=llm_config,
)
The Writer produces the initial draft and, after feedback, must return only the polished blogpost (no extra commentary).
4. Critic Agent
critic = autogen.AssistantAgent(
name="Critic",
is_termination_msg=lambda x: x.get("content", "").find("TERMINATE") >= 0,
llm_config=llm_config,
system_message="You are a critic. You review the work of the writer and provide constructive feedback to help improve the quality of the content.",
)
The Critic orchestrates reflection. It can terminate when it sees a special token (here: TERMINATE
), and — crucially — it routes drafts into nested reviewer chats rather than replying directly.
5. Reviewer Agents (Specialists)
Four reviewers are defined; each returns structured JSON and concise 3-bullet feedback:
- SEO Reviewer — keyword suggestions, optimization tips, ranking potential.
- Legal Reviewer — checks compliance, flags potential copyright or misleading claims.
- Ethics Reviewer — checks for bias/harm and ensures ethical tone.
- Meta Reviewer — aggregates the reviewers’ JSON outputs into a final suggestion set.
6. Nested Chats (Reflection Workflow)
You pass the writer’s latest draft to the reviewers. Example helper function:
def reflection_message(recipient, messages, sender, config):
return f'''Review the following content.
{recipient.chat_messages_for_summary(sender)[-1]['content']}'''
Then define the review pipeline:
review_chats = [
{"recipient": SEO_reviewer, ...},
{"recipient": legal_reviewer, ...},
{"recipient": ethics_reviewer, ...},
{"recipient": meta_reviewer, ...},
]
Register nested chats with the critic so it automatically triggers the reviewers when the writer produces a draft:
critic.register_nested_chats(
review_chats,
trigger=writer,
)
7. Run the Conversation
res = critic.initiate_chat(
recipient=writer,
message=task,
max_turns=2,
summary_method="last_msg"
)
Flow during execution:
8. Get the Final Output
print(res.summary)
The final output (summary) should be the refined blogpost — concise, SEO-aware, legally safe, and ethically sound.
🎯 What You’ve Built
- A full reflection pattern where a Critic orchestrates nested reviewers.
- A Writer (producer) and Critic (controller) setup that mimics editorial workflows.
- Specialized reviewer agents (SEO, Legal, Ethics) that return structured JSON feedback.
- A Meta Reviewer that consolidates reviewer outputs into one actionable recommendation.
- An automated refine loop that produces a final polished blog post.
💡 Tips & next steps
- Use strict, structured JSON schemas for reviewer outputs to make aggregation deterministic.
- Limit reviewer verbosity — require 3 bullet points plus a compact JSON block to simplify the Meta Reviewer’s job.
- Consider adding a "confidence" score from reviewers so the Writer knows which suggestions are highest priority.
- For production, persist versions and reviewer outputs to storage for traceability & audits.
4. Building a Chess Game with AutoGen Agents
This transcript walks through how two AutoGen agents (White & Black) play chess by using tools and nested chats to ensure rules are followed.
♟️ Key Roles
- White Agent — plays first, chooses moves by calling tools.
- Black Agent — responds with its moves, also uses tools.
- Board Proxy Agent — executes tools, validates legality, updates state. It is not an LLM agent.
⚙️ Tool Use
get_legal_moves
→ returns all valid moves for the current position.make_move
→ executes a move in UCI format (e.g.,e2e4
).
Players propose these tool calls; the board proxy executes them.
🧩 Nested Chats Workflow
get_legal_moves
.make_move
updates board state.💬 Demonstration Highlights
- Game starts: White plays
e2e4
, Black respondsg8f6
. - Moves are checked and updated correctly by the board proxy.
- Chit-chat is layered in:
- “I’m going for the Sicilian Defense!”
- “Let’s see how you respond to this classic opening.”
📝 Code Structure (Simplified)
# Agents
white_agent = ConversableAgent(name="White", system_message="Play as White...")
black_agent = ConversableAgent(name="Black", system_message="Play as Black...")
board_proxy = ConversableAgent(name="Board", llm_config=None) # No LLM
# Tools
def get_legal_moves(...): ...
def make_move(move): ...
# Register tools with board
board_proxy.register_tool(get_legal_moves)
board_proxy.register_tool(make_move)
# Nested chats ensure move validation
white_agent.initiate_chat(recipient=board_proxy, message="Play e2e4")
black_agent.initiate_chat(recipient=board_proxy, message="Play g8f6")
✅ Big Takeaway
This lesson demonstrates tool use inside nested conversations:
- One agent proposes a tool call (e.g., make a move).
- Another agent (board proxy) executes it and validates legality.
- The result is summarized and returned to the players.
- The outer chat looks natural, like two people playing chess, while the inner system ensures all rules are followed.
4. Tool Use & Conversational Chess: Notebook Walkthrough
This lesson turns the full implementation into an easy-to-follow guide: how two AutoGen agents (White & Black) use tools and nested chats to play legal chess moves while still sounding like they're bantering.
🔧 Setup
Configure your LLM and import chess utilities for game logic and SVG rendering.
# Configure LLM (this demo uses GPT-4 turbo)
llm_config = {"model": "gpt-4-turbo"}
# Chess utilities
import chess
import chess.svg
from autogen import ConversableAgent # or your framework's agent class
♟️ Board Initialization
Start a fresh board and a flag to mark when a legal move has been executed.
board = chess.Board()
made_move = False
🛠 Tools (executor functions)
Two core tools: get_legal_moves
and make_move
. The board proxy actually executes these.
def get_legal_moves():
# returns list of UCI moves e.g. ['e2e4', 'd2d4', ...]
return [m.uci() for m in board.legal_moves]
def make_move(move_uci):
# validate and push; return human-friendly description + SVG
move = chess.Move.from_uci(move_uci)
if move in board.legal_moves:
board.push(move)
# sample description (piece glyphs optional)
piece = board.piece_at(move.to_square)
desc = f"Moved {piece.symbol().upper() if piece else 'piece'} from {move_uci[:2]} to {move_uci[2:]}"
svg = chess.svg.board(board=board) # optionally render board
return {"ok": True, "desc": desc, "svg": svg}
else:
return {"ok": False, "error": "Illegal move"}
The functions above are executed by the Board Proxy Agent (non-LLM), which enforces legality and updates the shared board state.
🤖 Agents
Agent roles in the demo:
- player_white — Conversable agent that proposes a move and can chitchat.
- player_black — Same as white but plays the responding color.
- board_proxy — Executes the tools, validates moves, updates
board
. It does not use an LLM for validation.
player_white = ConversableAgent(
name="White",
system_message="You play White. First call get_legal_moves, then choose one and call make_move(UCI). After move, you may add a short chat line.",
llm_config=llm_config,
human_input_mode="NEVER",
)
player_black = ConversableAgent(
name="Black",
system_message="You play Black. Same rules as White.",
llm_config=llm_config,
human_input_mode="NEVER",
)
# Board proxy is a simple executor (no model)
board_proxy = ConversableAgent(
name="BoardProxy",
llm_config=None,
system_message="I only execute tools: get_legal_moves, make_move. I enforce legality."
)
🔗 Tool Registration
Linking callers to the executor: players can propose tool calls but the board proxy runs them.
# This is conceptual — use your framework's register_function / register_tool API
board_proxy.register_tool("get_legal_moves", get_legal_moves)
board_proxy.register_tool("make_move", make_move)
# allow players to call board_proxy tools (framework-specific)
player_white.register_target(board_proxy)
player_black.register_target(board_proxy)
🔄 Nested Chats (validation before reply)
Before a player announces a move in the outer chat, they do an inner/nested chat with the board proxy to validate and execute it. The proxy returns the result, which the player summarizes in the outer conversation.
# Example flow (pseudo-runnable)
# Outer call: player proposes a move to player_black
chat_result = player_black.initiate_chat(
recipient=player_white,
message="Let's play chess! Your move.",
max_turns=2,
)
# Inside the agent logic, White will:
# 1) call board_proxy.get_legal_moves()
# 2) choose a UCI move (e.g. "e2e4")
# 3) call board_proxy.make_move("e2e4")
# 4) receive confirmation and include a short chitchat line in the outer message
▶️ Start the Demo
In the notebook the demo runs only a couple moves (controlled by max_turns
) so it's quick to show the pattern.
chat_result = player_black.initiate_chat(
player_white,
message="Let's play chess! Your move.",
max_turns=2,
)
🎉 Fun Extension: Chit-chat Mode
Give both player agents flavor text in their system prompts so they banter after each legal move:
system_message = "After a move is made, add a one-line banter sentence (e.g., 'Going Sicilian!')."\n
# Recreate agents with this system_message to get fun dialogue.
👨💻 Play as Human
If you want one player to be human-controlled in the notebook, set:
player_white = ConversableAgent(..., human_input_mode="ALWAYS")
That will pause and prompt you to type moves instead of the agent choosing them.
✅ Big takeaway
This lesson demonstrates tool use inside nested conversations: an agent proposes a tool call (choose move) → a non-LLM proxy executes and validates the tool (legal move) → results are summarized back into the outer player-to-player chat so the whole game looks natural while remaining rule-abiding.
5. Freeform Coding with AutoGen Agents
This lesson introduces coding capabilities to AutoGen agents — letting them write, run, and refine code automatically or with human oversight.
🎯 Goal
Add coding abilities to agents so they can solve tasks like financial analysis or data visualization.
- Model-generated code — agent writes code entirely from scratch.
- User-provided code — agent uses helper functions you supply.
🔧 Setup
Use GPT-4 turbo
for the code-writer and a local executor for running Python scripts.
from autogen import LocalCodeExecutor
executor = LocalCodeExecutor(
timeout=60,
work_dir="coding"
)
🤖 Agents
Code Executor Agent
- Type:
ConversableAgent
- Executes code proposed by the writer.
- Asks for confirmation if
human_input_mode="ALWAYS"
. - Default fallback: "Please continue. If everything is done, reply terminate."
Code Writer Agent
- Type:
AssistantAgent
- Generates code, but does not run it.
- Uses LLM (
GPT-4 turbo
). human_input_mode="NEVER"
(runs fully automatic).- System message includes instructions to:
- Collect data, analyze, and plot results.
- Check execution results and fix errors automatically.
- Terminate after task completion.
📊 Example Task: Financial Analysis
Show year-to-date stock gains for Nvidia and Tesla.
- Code Writer generates Python code (e.g., with
yfinance
+matplotlib
). - Code Executor runs the code.
- Plot result is returned to Code Writer.
- Conversation terminates after completion.
With human-in-the-loop, you can review/approve code before execution.
📝 User-Provided Functions
You can define helper functions and pass them to the executor. The Writer will then build shorter code using them.
import yfinance as yf
def get_stock_prices(ticker, start_date):
"""
Download stock prices from start_date to today.
Returns a DataFrame.
"""
data = yf.download(ticker, start=start_date)
return data
Another example: a custom plotting function. Update the writer’s system message with these docstrings so it knows to use them.
📂 Key Notes
- Saving code — add a special line in the block to save code to files; otherwise it’s temporary.
- Human-in-the-loop — optional, allows review before execution.
- Difference vs tool calls:
- Tool calls = deterministic (only predefined functions).
- Freeform code = flexible, creative (any Python or shell).
- Works even with models that lack built-in “tool call” support.
✅ Summary
5. demonstrates two ways of coding with AutoGen:
- Default: Writer generates full code from scratch.
- Optional: Writer leverages user-defined helper functions for cleaner results.
Flexible for many tasks: financial analysis, data processing, plotting, or running shell scripts — with or without human oversight.
5. Coding and Financial Analysis with AutoGen Agents
In this lesson, AutoGen agents gain the ability to generate, run, and refine Python code to perform financial analysis — with or without human oversight.
1. ⚙️ Setup
We start by configuring GPT-4 turbo
and a local code executor.
llm_config = {"model": "gpt-4-turbo"}
from autogen.coding import LocalCommandLineCodeExecutor
executor = LocalCommandLineCodeExecutor(
timeout=60,
work_dir="coding" # all code and outputs stored here
)
2. 🤖 Create Agents
a) Code Executor Agent
Executes Python code generated by the writer. Runs in human-in-the-loop mode (asks before execution).
from autogen import ConversableAgent
code_executor_agent = ConversableAgent(
name="code_executor_agent",
llm_config=False,
code_execution_config={"executor": executor},
human_input_mode="ALWAYS",
default_auto_reply="Please continue. If everything is done, reply 'TERMINATE'.",
)
b) Code Writer Agent
Generates Python code but never executes it directly.
from autogen import AssistantAgent
code_writer_agent = AssistantAgent(
name="code_writer_agent",
llm_config=llm_config,
code_execution_config=False,
human_input_mode="NEVER",
)
Check the writer’s default system instructions:
print(code_writer_agent.system_message)
3. 📊 Define the Task
Example: plot year-to-date stock gains for NVDA and TSLA.
import datetime
today = datetime.datetime.now().date()
message = f"Today is {today}. " \
"Create a plot showing stock gain YTD for NVDA and TLSA. " \
"Make sure the code is in markdown code block and save " \
"the figure to a file ytd_stock_gains.png."
chat_result = code_executor_agent.initiate_chat(
code_writer_agent,
message=message,
)
Display the generated plot:
import os
from IPython.display import Image
Image(os.path.join("coding", "ytd_stock_gains.png"))
4. 📝 User-Defined Functions
Instead of writing everything from scratch, define reusable helpers for the LLM to use.
a) Download stock prices
def get_stock_prices(stock_symbols, start_date, end_date):
"""
Get the stock prices for the given stock symbols between the
start and end dates.
"""
import yfinance
stock_data = yfinance.download(stock_symbols, start=start_date, end=end_date)
return stock_data.get("Close")
b) Plot stock prices
def plot_stock_prices(stock_prices, filename):
"""
Plot the stock prices for the given stock symbols and save to a file.
"""
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
for column in stock_prices.columns:
plt.plot(stock_prices.index, stock_prices[column], label=column)
plt.title("Stock Prices")
plt.xlabel("Date")
plt.ylabel("Price")
plt.grid(True)
plt.legend()
plt.savefig(filename)
5. 🔗 Update Executor & Writer
Add these functions to the executor and update the writer’s system message.
executor = LocalCommandLineCodeExecutor(
timeout=60,
work_dir="coding",
functions=[get_stock_prices, plot_stock_prices],
)
code_writer_agent_system_message += executor.format_functions_for_prompt()
code_writer_agent = ConversableAgent(
name="code_writer_agent",
system_message=code_writer_agent_system_message,
llm_config=llm_config,
code_execution_config=False,
human_input_mode="NEVER",
)
code_executor_agent = ConversableAgent(
name="code_executor_agent",
llm_config=False,
code_execution_config={"executor": executor},
human_input_mode="ALWAYS",
default_auto_reply="Please continue. If everything is done, reply 'TERMINATE'.",
)
6. ▶️ Run Task with User Functions
chat_result = code_executor_agent.initiate_chat(
code_writer_agent,
message=f"Today is {today}. "
"Download the stock prices YTD for NVDA and TSLA and create "
"a plot. Make sure the code is in markdown code block and "
"save the figure to a file stock_prices_YTD_plot.png.",
)
Image(os.path.join("coding", "stock_prices_YTD_plot.png"))
✅ Key Takeaways
- Freestyle coding: Writer agent can generate full Python code.
- Human-in-the-loop: Executor can ask for confirmation before running.
- Reusable functions: Define once, reuse for cleaner outputs.
- Files auto-saved: Code and plots stored in the
coding
folder. - Flexible: Works even with models that lack OpenAI tool-call support.
6. Multi-Agent Group Chats with Planning Agents in AutoGen
1. Objective
- Learn group chat conversation pattern: multiple agents collaborate dynamically to complete a complex task.
- Introduce planning agents to break down tasks into smaller subtasks.
- Customize speaker transitions to control agent interaction flow.
- Example Task: Generate a detailed stocks performance report over the past month.
2. Key Agents
a) Admin (User Proxy Agent)
- Acts as a user proxy to send instructions.
human_input_mode="ALWAYS"
→ asks for human feedback.- System message: “Give the task and send instructions to the writer to refine the blog post.”
b) Planner
- Decomposes a complex task into simpler subtasks.
- System message: suggests steps that can be executed via Python code.
- Description: “Given a task, determine info needed, check progress, instruct remaining steps.”
- Provides guidance after each step.
c) Engineer
- Writes Python code based on planner’s instructions.
- Uses default assistant agent system message.
- Description: “Writes code according to the plan provided by planner.”
d) Executor
- Executes Python code shared by the engineer.
- Configuration:
- Looks at last N messages for code.
- Executes in
coding/
directory. user_docker=False
.
e) Writer
- Writes and refines blog posts in Markdown format.
- Takes feedback from Admin.
- Description: “Writes blogs with titles, content in markdown, and applies feedback.”
3. Group Chat Manager
- Special AutoGen agent to manage turn-taking and conversation flow.
- Decides which agent speaks next based on:
- Conversation history
- Agent roles and descriptions
- Enables dynamic task flow without manual ordering.
4. How the Group Chat Works
- Admin sends the task to the chat manager.
- Chat manager broadcasts to all agents.
- Planner suggests subtasks (e.g., retrieve stock data, analyze, research events, draft blog).
- Engineer writes Python code.
- Executor runs the code and shares results.
- Planner reviews progress and suggests next steps.
- Writer drafts the blog post once info is ready.
- Admin provides user feedback → Writer refines post.
Note: Turn-taking is dynamic — agents can skip steps if allowed.
5. Controlling Speaker Transitions
You can define allowed/disallowed transitions:
allowed_transitions = {
"engineer": ["admin", "executor"],
"executor": ["admin", "engineer", "planner"],
}
This ensures Planner reviews before Writer starts, balancing flexibility with control.
6. Advantages of Group Chat Pattern
- Non-linear execution → agents collaborate dynamically.
- Planner support → automates task decomposition.
- Human-in-the-loop optional → admin can intervene.
- Customizable transitions → enforce order when needed.
- Scalable → handle complex, multi-step tasks.
7. Summary of Learning
- Introduced Group Chat pattern for dynamic collaboration.
- Planner helps decompose complex tasks.
- Engineer, Executor, and Writer automate Python code and blog writing.
- Speaker transitions can be customized for smoother flow.
- AutoGen enables flexible, scalable agent orchestration.
Next Steps / Advanced Features
- Multi-modal agents (vision, audio, etc.)
- Agent learning over time
- Agent evaluation and benchmarking
- Custom task-specific agents using OpenAI backend
- More controlled conversation and planning logic
6. Planning and Stock Report Generation using AutoGen Multi-Agent Group Chat
1. Objective
- Build a multi-agent group chat to automatically generate a stock report blog post.
- Example Task: "Write a blog post about Nvidia's stock price performance in the past month."
- Introduce a planning agent to decompose tasks.
- Use Engineer and Executor to handle Python code.
- Use Writer to draft and refine the blog post.
- Include Admin/User agent for feedback.
2. Agents in the Group Chat
a) Admin (User Proxy)
- Purpose: Sends task and provides feedback.
human_input_mode="ALWAYS"
→ prompts user for input.- System message: “Give the task, and send instructions to writer to refine the blog post.”
b) Planner
- Purpose: Breaks the task into sub-tasks achievable via Python.
- Monitors progress and guides remaining steps.
- System message: Guides what information to retrieve and how to handle failures.
- Description: Explains role to other agents — task decomposition and progress monitoring.
c) Engineer
- Purpose: Writes Python code following planner instructions.
- Uses AutoGen default AssistantAgent system message.
- Description: "Write code based on the plan provided by the planner."
d) Executor
- Purpose: Executes Python code shared by Engineer.
- Configuration:
- Looks at last 3 messages containing code.
- Executes in
coding/
directory. use_docker=False
human_input_mode="NEVER"
→ fully automated execution.
e) Writer
- Purpose: Drafts blog posts in Markdown.
- Takes feedback from Admin for refinement.
- System message: Guides formatting in Markdown with titles and content.
- Description: Explains role to other agents — write blog based on execution results and feedback.
3. Group Chat Setup
groupchat = autogen.GroupChat(
agents=[user_proxy, engineer, writer, executor, planner],
messages=[],
max_round=10,
)
manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config)
groupchat_result = user_proxy.initiate_chat(manager, message=task)
Max rounds: 10 → limits conversation length. The manager decides which agent speaks next.
4. Adding Speaker Transition Rules
Allows controlled flow between agents. Example: Ensure Planner reviews before Writer starts drafting.
allowed_transitions = {
user_proxy: [engineer, writer, executor, planner],
engineer: [user_proxy, executor],
writer: [user_proxy, planner],
executor: [user_proxy, engineer, planner],
planner: [user_proxy, engineer, writer],
}
groupchat = autogen.GroupChat(
agents=[user_proxy, engineer, writer, executor, planner],
messages=[],
max_round=10,
allowed_or_disallowed_speaker_transitions=allowed_transitions,
speaker_transitions_type="allowed",
)
Type: allowed → only specified transitions are permitted. Ensures Planner reviews code/results before Writer starts.
5. How the Chat Works
- Admin sends task → broadcasted to all agents.
- Planner suggests steps:
- Retrieve stock data
- Analyze data
- Research context/events
- Draft blog
- Engineer writes Python code for tasks.
- Executor runs the code and reports results.
- Planner checks progress and updates next steps.
- Writer drafts the blog post using results.
- Admin/User provides feedback.
- Writer refines the post based on feedback.
- Process iterates through
max_rounds
or until task completion. - Agents may correct errors dynamically — e.g., Engineer fixes code after Executor feedback.
6. Advantages
- Automates complex tasks like stock report generation.
- Dynamic collaboration between agents.
- Human-in-the-loop optional for feedback or adjustments.
- Controlled yet flexible flow using speaker transition rules.
- Task decomposition via Planner ensures modular and maintainable workflow.
AutoGen Course: Key Takeaways
1. Agentic Design Patterns in AutoGen
- Multi-Agent Collaboration: Multiple agents working together to accomplish complex tasks.
- Reflection: Agents can review their own actions or outputs to improve performance.
- Tool Use: Agents can call external tools or functions (e.g., Python functions, APIs) to get work done.
- Code Generation: Agents like Engineers can write and refine code automatically.
- Planning: Planner agents decompose tasks into manageable steps and monitor progress.
2. How to Apply These Patterns
- Combine these building blocks to automate tasks like:
- Stock market analysis and reporting
- Blog generation
- Data processing pipelines
- Multi-step workflows
- Customize agent roles, descriptions, and speaker transitions to maintain control while allowing flexibility.
No comments:
Post a Comment