Introduction to AutoGen and Customer Support Bots
Modern customer support demands speed, consistency, and scalability that traditional human-only teams struggle to deliver. Enter AutoGen — Microsoft's open-source framework for building conversational multi-agent systems powered by large language models. This tutorial walks you through building a fully functional customer support bot using AutoGen, from concept to deployment-ready code.
AutoGen lets you create specialized AI agents that collaborate, reason, and take action autonomously. For customer support, this means you can design a system where one agent triages inquiries, another looks up order details, a third handles technical troubleshooting, and a supervisor agent orchestrates the entire flow — all while seamlessly handing off to a human operator when needed.
What Is AutoGen?
AutoGen is a framework that enables the creation of conversational agents that can communicate with each other, use tools, and incorporate human feedback. Each agent is powered by an LLM (like GPT-4, Claude, or open-source models) and can be assigned distinct roles, capabilities, and behavioral instructions. Agents can engage in multi-turn conversations, invoke functions, execute code, and even reflect on their own outputs.
The key building blocks in AutoGen include:
- ConversableAgent — The base agent class that can send and receive messages
- AssistantAgent — An agent optimized for generating responses and solving tasks
- UserProxyAgent — A proxy that represents a human user, capable of executing code and providing feedback
- GroupChat — A container for multiple agents with a shared conversation context
- GroupChatManager — Orchestrates turn-taking and speaker selection in group chats
Why AutoGen for Customer Support?
Traditional single-agent chatbots suffer from context overload, role confusion, and limited tool-use capabilities. AutoGen solves these problems by decomposing complex support workflows across multiple specialized agents:
- Separation of concerns — One agent handles empathy and triage, another accesses CRM data, a third manages technical documentation
- Tool orchestration — Agents can call APIs, query databases, and execute code to actually resolve issues rather than just offering canned responses
- Human-in-the-loop — AutoGen natively supports pausing execution for human approval or intervention at critical decision points
- Scalability — Add or swap agents as your product and support needs evolve without rewriting the entire system
- Auditability — Every inter-agent message is logged, making it easy to review and improve the support pipeline
Setting Up Your Environment
Before diving into code, install the required packages. You'll need the AutoGen library along with an LLM provider. This guide uses OpenAI's GPT-4, but AutoGen supports many backends including Azure OpenAI, Anthropic, and local models via LiteLLM.
# Create a new virtual environment
python -m venv autogen_env
source autogen_env/bin/activate # On Windows: autogen_env\Scripts\activate
# Install AutoGen and dependencies
pip install pyautogen openai
# Set your API key as an environment variable
export OPENAI_API_KEY="your-api-key-here"
Create a configuration file for your LLM settings. AutoGen uses a flexible configuration system:
# config.json
{
"model": "gpt-4-turbo",
"temperature": 0.3,
"max_tokens": 2000,
"timeout": 120
}
Core Architecture of a Customer Support Bot with AutoGen
Our customer support system will consist of four specialized agents working together in a group chat:
- TriageAgent — The first point of contact. Greets the customer, classifies the issue (order inquiry, technical support, billing, or general question), and routes accordingly
- OrderSupportAgent — Handles order tracking, shipping status, returns, and refunds. Has access to a mock order database via function calls
- TechSupportAgent — Handles product troubleshooting, installation guidance, and bug reports. Has access to a knowledge base search tool
- HumanEscalationAgent — A proxy agent that represents a human supervisor for cases requiring manual review or sensitive decisions (refunds above a threshold, account security issues)
The conversation flow follows this pattern:
Customer Message → TriageAgent → [OrderSupportAgent | TechSupportAgent] → Resolution
↓ (if escalation needed)
HumanEscalationAgent → Resolution
Building the Bot Step by Step
Step 1: Defining the Agents
Start by importing AutoGen and creating the foundational agent classes. Each agent gets a unique name, a system message that defines its persona, and an LLM configuration.
import autogen
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager
from typing import Dict, List, Optional
import json
import os
# Load LLM configuration
config_list = [
{
"model": "gpt-4-turbo",
"api_key": os.environ.get("OPENAI_API_KEY"),
"temperature": 0.3,
}
]
# The customer proxy agent - represents the actual user
customer_proxy = UserProxyAgent(
name="Customer",
human_input_mode="NEVER", # Auto-reply for simulation; use "ALWAYS" for real human input
max_consecutive_auto_reply=0,
code_execution_config=False,
system_message="You are a customer reaching out for support. You describe your issue clearly."
)
# Triage agent - the front-line support agent
triage_agent = AssistantAgent(
name="TriageAgent",
llm_config={"config_list": config_list},
system_message="""You are the front-line customer support triage specialist.
Your responsibilities:
1. Greet the customer warmly and empathetically
2. Classify their issue into one of these categories:
- ORDER_INQUIRY: Questions about order status, shipping, returns, refunds
- TECH_SUPPORT: Product troubleshooting, installation, bugs, technical questions
- BILLING: Payment issues, invoice questions, subscription changes
- GENERAL: Account management, company policies, other non-technical questions
3. For ORDER_INQUIRY, transfer to OrderSupportAgent
4. For TECH_SUPPORT, transfer to TechSupportAgent
5. For BILLING or complex GENERAL issues, transfer to HumanEscalationAgent
6. For simple GENERAL questions, answer directly
Always include a brief summary of the issue when transferring."""
)
Step 2: Setting Up Agent Roles and Personas
Now define the specialized support agents with detailed system messages that shape their behavior. The quality of these prompts directly impacts the bot's effectiveness.
# Order support agent with access to order database
order_support_agent = AssistantAgent(
name="OrderSupportAgent",
llm_config={"config_list": config_list},
system_message="""You are an order support specialist.
Your responsibilities:
1. Look up order details using the provided functions
2. Provide shipping status, tracking numbers, and delivery estimates
3. Process return requests and issue refunds (up to $100 automatically)
4. For refunds exceeding $100, escalate to HumanEscalationAgent
5. Always confirm the customer's identity by asking for their order ID or email
6. Be empathetic about delays and offer concrete solutions
Available functions:
- lookup_order(order_id: str) -> Dict - Retrieves order details
- get_shipping_status(tracking_number: str) -> Dict - Gets current shipping status
- initiate_return(order_id: str, reason: str) -> Dict - Starts a return process
- issue_refund(order_id: str, amount: float) -> Dict - Issues a refund
When you need to escalate, say: 'I'm transferring you to our escalations team for further assistance.'
"""
)
# Technical support agent with knowledge base access
tech_support_agent = AssistantAgent(
name="TechSupportAgent",
llm_config={"config_list": config_list},
system_message="""You are a technical support engineer.
Your responsibilities:
1. Diagnose technical issues methodically
2. Search the knowledge base for relevant documentation
3. Provide step-by-step troubleshooting instructions
4. Collect diagnostic information when needed (error codes, OS version, etc.)
5. Escalate to HumanEscalationAgent if the issue is:
- A confirmed bug requiring engineering intervention
- A security vulnerability report
- An issue you cannot resolve after 3 troubleshooting attempts
Available functions:
- search_knowledge_base(query: str) -> List[Dict] - Searches product documentation
- create_bug_report(product: str, description: str, severity: str) -> Dict - Files a bug report
- get_diagnostic_guide(issue_type: str) -> Dict - Returns structured diagnostic steps
Be patient, systematic, and avoid jargon unless the customer demonstrates technical expertise."""
)
Step 3: Creating the Conversation Flow with GroupChat
AutoGen's GroupChat orchestrates multi-agent conversations. You define the participants, a speaker selection strategy, and a manager to coordinate turns.
# Human escalation agent
human_escalation_agent = UserProxyAgent(
name="HumanEscalationAgent",
human_input_mode="ALWAYS", # Pauses for actual human input
max_consecutive_auto_reply=0,
code_execution_config=False,
system_message="""You are a senior customer support manager.
You handle escalated cases including:
- High-value refunds (>$100)
- Billing disputes
- Account security concerns
- Confirmed product bugs requiring engineering
- Any case where the automated agents cannot resolve the issue
You have full authority to approve refunds, adjust accounts, and contact engineering teams.
Respond professionally and resolve the customer's issue definitively."""
)
# Define the group chat participants
participants = [
customer_proxy,
triage_agent,
order_support_agent,
tech_support_agent,
human_escalation_agent
]
# Create the group chat with auto speaker selection
group_chat = GroupChat(
agents=participants,
messages=[],
max_round=15, # Prevent infinite loops
speaker_selection_method="auto", # AutoGen's built-in speaker selection
allow_repeat_speaker=True, # Allow agents to speak multiple times
)
# Create the group chat manager
manager = GroupChatManager(
groupchat=group_chat,
llm_config={"config_list": config_list},
system_message="""You are the conversation manager for customer support.
Your role is to ensure smooth handoffs between agents and that the customer's issue
is fully resolved. Guide the conversation toward resolution efficiently.
Never let the conversation end without a clear resolution or proper escalation."""
)
Step 4: Implementing Tool Use for Real-World Actions
AutoGen agents can register functions as tools. These functions are automatically described to the LLM, which decides when to call them. Here's how to implement the order lookup and knowledge base search tools:
# Mock data stores
MOCK_ORDERS = {
"ORD-12345": {
"order_id": "ORD-12345",
"customer_email": "jane@example.com",
"status": "shipped",
"tracking_number": "TRK-987654321",
"items": [{"product": "Wireless Headphones", "quantity": 1, "price": 79.99}],
"order_date": "2024-01-15",
"estimated_delivery": "2024-01-22"
},
"ORD-67890": {
"order_id": "ORD-67890",
"customer_email": "bob@example.com",
"status": "processing",
"tracking_number": None,
"items": [{"product": "Smart Thermostat", "quantity": 2, "price": 129.99}],
"order_date": "2024-01-18",
"estimated_delivery": "2024-01-25"
}
}
MOCK_KNOWLEDGE_BASE = [
{"title": "Headphones Not Pairing",
"content": "Ensure Bluetooth is enabled. Hold power button for 5 seconds until LED flashes blue. Select 'AudioPro X2' in device settings. If issues persist, reset by holding power + volume up for 10 seconds.",
"category": "connectivity"},
{"title": "Thermostat Installation Guide",
"content": "1. Turn off HVAC power. 2. Remove old thermostat. 3. Connect wires: Red to R, White to W, Green to G, Yellow to Y. 4. Mount base plate. 5. Attach display. 6. Restore power and follow on-screen setup.",
"category": "installation"},
{"title": "App Crashing on Startup",
"content": "Clear app cache in Settings > Apps > [App Name] > Storage > Clear Cache. If problem persists, uninstall and reinstall. Ensure OS version 12.0+ is installed. Known conflict with VPN apps — temporarily disable VPN.",
"category": "bugs"}
]
# Tool functions for OrderSupportAgent
def lookup_order(order_id: str) -> Dict:
"""Look up an order by its ID and return the full order details."""
order_id = order_id.strip().upper()
if order_id in MOCK_ORDERS:
return {"success": True, "order": MOCK_ORDERS[order_id]}
return {"success": False, "message": f"Order {order_id} not found. Please verify the order ID."}
def get_shipping_status(tracking_number: str) -> Dict:
"""Get the current shipping status for a tracking number."""
tracking_number = tracking_number.strip().upper()
# Mock shipping status
if tracking_number == "TRK-987654321":
return {
"success": True,
"status": "In Transit",
"location": "Distribution Center - Springfield",
"estimated_delivery": "2024-01-22",
"carrier": "FastShip Express",
"updates": [
{"date": "2024-01-17", "status": "Picked up"},
{"date": "2024-01-18", "status": "Arrived at sort facility"},
{"date": "2024-01-19", "status": "Departed sort facility"}
]
}
return {"success": False, "message": "Tracking number not found or not yet in system."}
def initiate_return(order_id: str, reason: str) -> Dict:
"""Initiate a return for an order. Returns a return authorization."""
order_id = order_id.strip().upper()
if order_id in MOCK_ORDERS:
return {
"success": True,
"return_id": f"RET-{order_id}-001",
"status": "Return Authorized",
"instructions": "A prepaid return label has been emailed. Drop off at any FastShip location.",
"refund_amount": MOCK_ORDERS[order_id]["items"][0]["price"],
"refund_timeline": "5-7 business days after receipt"
}
return {"success": False, "message": "Unable to process return for this order."}
def issue_refund(order_id: str, amount: float) -> Dict:
"""Issue a refund for an order. Auto-approved up to $100."""
if amount > 100:
return {
"success": False,
"requires_escalation": True,
"message": f"Refund of ${amount:.2f} exceeds auto-approval limit. Escalating to manager."
}
return {
"success": True,
"refund_id": f"RFND-{order_id}-{int(amount)}",
"amount": amount,
"status": "Processed",
"timeline": "3-5 business days to appear on statement"
}
# Tool functions for TechSupportAgent
def search_knowledge_base(query: str) -> List[Dict]:
"""Search the knowledge base for articles matching the query."""
query_lower = query.lower()
results = []
for article in MOCK_KNOWLEDGE_BASE:
if query_lower in article["title"].lower() or query_lower in article["content"].lower():
results.append(article)
return results if results else [{"title": "No Results", "content": "No matching articles found."}]
def create_bug_report(product: str, description: str, severity: str) -> Dict:
"""File a bug report for engineering review."""
return {
"success": True,
"bug_id": f"BUG-{hash(description) % 10000:04d}",
"product": product,
"severity": severity,
"status": "Triaged",
"assigned_to": "Engineering Team",
"estimated_response": "24-48 hours"
}
def get_diagnostic_guide(issue_type: str) -> Dict:
"""Return a structured diagnostic guide for common issue types."""
guides = {
"connectivity": {
"steps": [
"Check if device is powered on",
"Verify Bluetooth/WiFi is enabled on source device",
"Check device battery level (charge if below 20%)",
"Restart both devices",
"Check for interference from other wireless devices",
"Factory reset the device as last resort"
],
"common_fixes": ["Restart", "Re-pair", "Update firmware"]
},
"performance": {
"steps": [
"Close other applications",
"Check for software updates",
"Clear temporary files/cache",
"Check available storage (need at least 1GB free)",
"Run built-in diagnostics"
],
"common_fixes": ["Update software", "Free up storage", "Reduce background tasks"]
}
}
return guides.get(issue_type, {"steps": ["Gather error details", "Reproduce issue", "Contact support"], "common_fixes": ["Restart device"]})
# Register the tools with the agents
# Tools are registered using the register_function method
from autogen import register_function
# Register order support tools
register_function(
lookup_order,
caller=order_support_agent,
executor=customer_proxy,
name="lookup_order",
description="Look up an order by its ID and return full order details including status and tracking."
)
register_function(
get_shipping_status,
caller=order_support_agent,
executor=customer_proxy,
name="get_shipping_status",
description="Get current shipping status and tracking updates for a tracking number."
)
register_function(
initiate_return,
caller=order_support_agent,
executor=customer_proxy,
name="initiate_return",
description="Initiate a return process for an order. Requires order_id and reason."
)
register_function(
issue_refund,
caller=order_support_agent,
executor=customer_proxy,
name="issue_refund",
description="Issue a refund for an order. Auto-approved up to $100. Above $100 requires escalation."
)
# Register tech support tools
register_function(
search_knowledge_base,
caller=tech_support_agent,
executor=customer_proxy,
name="search_knowledge_base",
description="Search the product knowledge base for troubleshooting articles."
)
register_function(
create_bug_report,
caller=tech_support_agent,
executor=customer_proxy,
name="create_bug_report",
description="File a bug report for engineering team review."
)
register_function(
get_diagnostic_guide,
caller=tech_support_agent,
executor=customer_proxy,
name="get_diagnostic_guide",
description="Get a structured diagnostic guide for a specific issue type."
)
Step 5: Handling Escalations and Human Handoff
The HumanEscalationAgent uses human_input_mode="ALWAYS", which means AutoGen will pause execution and wait for real human input whenever this agent is selected to speak. This creates a seamless handoff for cases that require human judgment.
To make escalations smooth, the specialized agents should prepare a clear handoff summary. Here's a helper pattern you can embed in agent system messages:
# Enhanced escalation protocol in system messages
ESCALATION_PROTOCOL = """
ESCALATION PROTOCOL:
When escalating to HumanEscalationAgent, you MUST include:
1. ESCALATION_REASON: [Brief reason for escalation]
2. CASE_SUMMARY: [2-3 sentence summary of the interaction so far]
3. CUSTOMER_DETAILS: [Any identifying information gathered]
4. RECOMMENDED_ACTION: [Your suggested resolution for the manager's consideration]
5. URGENCY: [LOW/MEDIUM/HIGH]
Format this clearly so the human manager can quickly assess and act.
"""
# Add this to agent system messages that may escalate
order_support_agent.system_message += ESCALATION_PROTOCOL
tech_support_agent.system_message += ESCALATION_PROTOCOL
Complete Code Example
Below is the complete, runnable customer support bot. It brings together all the components we've built: agent definitions, tool registrations, group chat configuration, and the conversation initiation logic.
#!/usr/bin/env python3
"""
Complete Customer Support Bot built with AutoGen
Multi-agent system for handling order inquiries, technical support, and escalations.
"""
import autogen
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager, register_function
from typing import Dict, List, Optional
import json
import os
import sys
# ============================================================================
# CONFIGURATION
# ============================================================================
config_list = [
{
"model": "gpt-4-turbo",
"api_key": os.environ.get("OPENAI_API_KEY", "your-api-key-here"),
"temperature": 0.3,
"max_tokens": 1500,
}
]
# ============================================================================
# MOCK DATA
# ============================================================================
MOCK_ORDERS = {
"ORD-12345": {
"order_id": "ORD-12345",
"customer_email": "jane@example.com",
"status": "shipped",
"tracking_number": "TRK-987654321",
"items": [{"product": "Wireless Headphones", "quantity": 1, "price": 79.99}],
"order_date": "2024-01-15",
"estimated_delivery": "2024-01-22"
},
"ORD-67890": {
"order_id": "ORD-67890",
"customer_email": "bob@example.com",
"status": "processing",
"tracking_number": None,
"items": [{"product": "Smart Thermostat", "quantity": 2, "price": 129.99}],
"order_date": "2024-01-18",
"estimated_delivery": "2024-01-25"
}
}
MOCK_KNOWLEDGE_BASE = [
{
"title": "Headphones Not Pairing",
"content": "Ensure Bluetooth is enabled. Hold power button for 5 seconds until LED flashes blue. Select 'AudioPro X2' in device settings. Reset by holding power + volume up for 10 seconds if issues persist.",
"category": "connectivity"
},
{
"title": "Thermostat Installation Guide",
"content": "1. Turn off HVAC power. 2. Remove old thermostat. 3. Connect wires: Red to R, White to W, Green to G, Yellow to Y. 4. Mount base plate. 5. Attach display. 6. Restore power and follow on-screen setup.",
"category": "installation"
},
{
"title": "App Crashing on Startup",
"content": "Clear app cache in Settings > Apps > [App Name] > Storage > Clear Cache. If problem persists, uninstall and reinstall. Ensure OS version 12.0+ is installed. Known conflict with VPN apps — temporarily disable VPN.",
"category": "bugs"
}
]
# ============================================================================
# TOOL FUNCTIONS
# ============================================================================
def lookup_order(order_id: str) -> Dict:
"""Look up an order by its ID and return the full order details."""
order_id = order_id.strip().upper()
if order_id in MOCK_ORDERS:
return {"success": True, "order": MOCK_ORDERS[order_id]}
return {"success": False, "message": f"Order {order_id} not found."}
def get_shipping_status(tracking_number: str) -> Dict:
"""Get the current shipping status for a tracking number."""
tracking_number = tracking_number.strip().upper()
if tracking_number == "TRK-987654321":
return {
"success": True,
"status": "In Transit",
"location": "Distribution Center - Springfield",
"estimated_delivery": "2024-01-22",
"carrier": "FastShip Express",
"updates": [
{"date": "2024-01-17", "status": "Picked up"},
{"date": "2024-01-18", "status": "Arrived at sort facility"},
{"date": "2024-01-19", "status": "Departed sort facility"}
]
}
return {"success": False, "message": "Tracking number not found."}
def initiate_return(order_id: str, reason: str) -> Dict:
"""Initiate a return for an order."""
order_id = order_id.strip().upper()
if order_id in MOCK_ORDERS:
return {
"success": True,
"return_id": f"RET-{order_id}-001",
"status": "Return Authorized",
"instructions": "A prepaid return label has been emailed. Drop off at any FastShip location.",
"refund_amount": sum(item["price"] * item["quantity"] for item in MOCK_ORDERS[order_id]["items"]),
"refund_timeline": "5-7 business days after receipt"
}
return {"success": False, "message": "Unable to process return."}
def issue_refund(order_id: str, amount: float) -> Dict:
"""Issue a refund. Auto-approved up to $100."""
if amount > 100:
return {
"success": False,
"requires_escalation": True,
"message": f"Refund of ${amount:.2f} exceeds auto-approval limit. Escalating to manager."
}
return {
"success": True,
"refund_id": f"RFND-{order_id}-{int(amount)}",
"amount": amount,
"status": "Processed",
"timeline": "3-5 business days"
}
def search_knowledge_base(query: str) -> List[Dict]:
"""Search the knowledge base for articles matching the query."""
query_lower = query.lower()
results = [a for a in MOCK_KNOWLEDGE_BASE if query_lower in a["title"].lower() or query_lower in a["content"].lower()]
return results if results else [{"title": "No Results", "content": "No matching articles found."}]
def create_bug_report(product: str, description: str, severity: str) -> Dict:
"""File a bug report for engineering review."""
return {
"success": True,
"bug_id": f"BUG-{abs(hash(description)) % 10000:04d}",
"product": product,
"severity": severity,
"status": "Triaged",
"assigned_to": "Engineering Team",
"estimated_response": "24-48 hours"
}
def get_diagnostic_guide(issue_type: str) -> Dict:
"""Return a structured diagnostic guide."""
guides = {
"connectivity": {
"steps": ["Check device power", "Verify Bluetooth/WiFi enabled", "Check battery level", "Restart both devices", "Check wireless interference", "Factory reset as last resort"],
"common_fixes": ["Restart", "Re-pair", "Update firmware"]
},
"performance": {
"steps": ["Close other apps", "Check for updates", "Clear cache", "Check storage (>1GB free)", "Run diagnostics"],
"common_fixes": ["Update software", "Free up storage", "Reduce background tasks"]
}
}
return guides.get(issue_type, {"steps": ["Gather details", "Reproduce issue", "Contact support"], "common_fixes": ["Restart device"]})
# ============================================================================
# ESCALATION PROTOCOL
# ============================================================================
ESCALATION_PROTOCOL = """
ESCALATION PROTOCOL:
When escalating to HumanEscalationAgent, include:
1. ESCALATION_REASON: Brief reason
2. CASE_SUMMARY: 2-3 sentence summary
3. CUSTOMER_DETAILS: Any identifying info gathered
4. RECOMMENDED_ACTION: Your suggested resolution
5. URGENCY: LOW/MEDIUM/HIGH
"""
# ============================================================================
# AGENT DEFINITIONS
# ============================================================================
customer_proxy = UserProxyAgent(
name="Customer",
human_input_mode="NEVER",
max_consecutive_auto_reply=0,
code_execution_config=False,
system_message="You are a customer seeking support. Describe your issue clearly."
)
triage_agent = AssistantAgent(
name="TriageAgent",
llm_config={"config_list": config_list},
system_message="""You are the front-line customer support triage specialist.
Responsibilities:
1. Greet warmly and empathetically
2. Classify issues: ORDER_INQUIRY, TECH_SUPPORT, BILLING, GENERAL
3. Route ORDER_INQUIRY to OrderSupportAgent
4. Route TECH_SUPPORT to TechSupportAgent
5. Route BILLING or complex GENERAL to HumanEscalationAgent
6. Answer simple GENERAL questions directly
Always include a brief issue summary when transferring."""
)
order_support_agent = AssistantAgent(
name="OrderSupportAgent",
llm_config={"config_list": config_list},
system_message="""You are an order support specialist.
Use the provided functions to look up orders, check shipping, initiate returns, and issue refunds.
Auto-approve refunds up to $100. Escalate refunds above $100.
Always confirm customer identity via order ID or email.
Be empathetic about delays and offer concrete solutions.""" + ESCALATION_PROTOCOL
)
tech_support_agent = AssistantAgent(
name="TechSupportAgent",
llm_config={"config_list": config_list},
system_message="""You are a technical support engineer.
Use search_knowledge_base to find relevant documentation.
Provide step-by-step troubleshooting. Collect diagnostic info when needed.
Escalate to HumanEscalationAgent for: confirmed bugs, security issues, or unresolved after 3 attempts.
Be patient and systematic. Avoid jargon unless the customer is technical.""" + ESCALATION_PROTOCOL
)
human_escalation_agent = UserProxyAgent(
name="HumanEscalationAgent",
human_input_mode="ALWAYS",
max_consecutive_auto_reply=0,
code_execution_config=False,
system_message="""You are a senior customer support manager.
Handle escalated cases: high-value refunds, billing disputes, security concerns, confirmed bugs.
You have full authority to resolve issues definitively.
Respond professionally and resolve the customer's issue completely."""
)
# ============================================================================
# REGISTER TOOLS
# ============================================================================
for func, caller in [
(lookup_order, order_support_agent),
(get_shipping_status, order_support_agent),
(initiate_return, order_support_agent),
(issue_refund, order_support_agent),
(search_knowledge_base, tech_support_agent),
(create_bug_report, tech_support_agent),
(get_diagnostic_guide, tech_support_agent),
]:
register_function(
func,
caller=caller,
executor=customer_proxy,
name=func.__name__,
description=func.__doc__.strip() if func.__doc__ else "No description"
)
# ============================================================================
# GROUP CHAT AND MANAGER
# ============================================================================
participants = [
customer_proxy,
triage_agent,
order_support_agent,
tech_support_agent,
human_escalation_agent
]
group_chat = GroupChat(
agents=participants,
messages=[],
max_round=15,
speaker_selection_method="auto",
allow_repeat_speaker=True,
)
manager = GroupChatManager(
groupchat=group_chat,
llm_config={"config_list": config_list},
system_message="""You are the conversation manager. Ensure smooth handoffs between agents.
Guide toward full resolution. Never end without resolution or proper escalation."""
)
# ============================================================================
# MAIN EXECUTION
# ============================================================================
def run_support_session(customer_message: str) -> None:
"""Run a customer support session with the given initial message."""
print(f"\n{'='*60}")
print(f"CUSTOMER: {customer_message}")
print(f"{'='*60}\n")
customer_proxy.initiate_chat(
manager,
message=customer_message,
clear_history=True
)
if __name__ == "__main__":
# Example: Order inquiry
run_support_session(
"Hi, I ordered some wireless headphones (order ORD-12345) and it was supposed "
"to arrive yesterday but I haven't received it. Can you help?"
)
print("\n\n" + "="*60)
print("SESSION COMPLETE - Starting next example in interactive mode")
print("="*60 + "\n")
# For interactive testing, switch customer_proxy to human_input_mode="ALWAYS"
# customer_proxy.human_input_mode = "ALWAYS"
# run_support_session("") # Will prompt for user input
Best Practices for Production Customer Support Bots
1. Design System Messages Carefully
System messages are the primary steering mechanism for agent behavior. Invest significant effort in crafting and iterating on them. Include explicit instructions about tone, boundaries, escalation criteria, and output formatting. Test each agent in isolation