Understanding CrewAI for Customer Support Automation
CrewAI is an open-source framework that orchestrates multiple AI agents working together to accomplish complex tasks. Unlike single-agent chatbots that rely on one LLM to handle everything, CrewAI enables you to assemble a crew of specialized agents, each with distinct roles, goals, and tools, collaborating to deliver superior customer support. The framework handles agent communication, task delegation, and result aggregation automatically, letting you focus on defining the logic and personality of each agent.
At its core, a CrewAI system consists of four building blocks: Agents (the AI personas with defined roles), Tasks (specific jobs assigned to agents), Tools (functions agents can call to interact with external systems), and the Crew itself (the orchestration layer that manages execution order and inter-agent communication). For a customer support bot, this architecture lets you separate concerns — one agent might handle initial triage, another might search a knowledge base, and a third might handle escalations requiring human-like judgment.
Why Multi-Agent Support Bots Matter
Traditional support chatbots suffer from three critical limitations:
- Context collapse — a single model struggles to maintain both empathy and technical accuracy simultaneously
- Tool confusion — when one agent has access to too many tools, it frequently calls the wrong one
- No specialization — the model defaults to generic responses instead of domain-specific expertise
CrewAI solves these by letting you create agents that mirror a real support team: a triage specialist who gathers information, a technical agent who queries internal systems, and a supervisor agent who handles escalations. Each agent can be backed by different LLM providers optimized for their specific role — a lightweight model for triage and a more capable model for complex reasoning.
Prerequisites and Setup
Before building the bot, install CrewAI and its dependencies. The framework requires Python 3.10+ and works with any LLM provider that offers an API (OpenAI, Anthropic, Mistral, or local models via Ollama).
pip install crewai crewai-tools langchain-openai
Set your API keys as environment variables. For this tutorial we'll use OpenAI, but you can substitute any provider:
export OPENAI_API_KEY="sk-your-key-here"
export OPENAI_MODEL_NAME="gpt-4o"
Create a project structure that separates concerns:
customer_support_bot/
├── agents.py # Agent definitions
├── tasks.py # Task definitions
├── tools.py # Custom tools
├── crew_setup.py # Crew assembly and execution
└── utils.py # Helper functions
Step 1: Designing Your Agent Team
Start by mapping out the roles your support bot needs. A well-designed crew typically has three to five agents. For this tutorial, we'll build four agents: a Support Triage Agent that classifies and gathers information, a Knowledge Base Agent that searches documentation, a Technical Support Agent that solves specific problems, and an Escalation Agent that handles cases requiring human intervention.
Defining Agents with Roles and Goals
Each agent in CrewAI needs a role (its job title), a goal (what it aims to achieve), and a backstory (personality and context that shapes its behavior). These prompts guide the LLM's reasoning. Open your agents.py file and define the team:
from crewai import Agent
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
from langchain_openai import ChatOpenAI
# Shared LLM configuration — you can assign different models per agent
llm = ChatOpenAI(model="gpt-4o", temperature=0.3)
# --- AGENT 1: Support Triage ---
triage_agent = Agent(
role="Customer Support Triage Specialist",
goal=(
"Accurately classify the customer's issue into one of these categories: "
"billing, technical, account_access, or general_inquiry. Extract key details "
"such as product name, error messages, account type, and urgency level. "
"Always ask clarifying questions when information is incomplete."
),
backstory=(
"You are the first point of contact for all customer inquiries at a SaaS company. "
"You have 10 years of experience in customer service and can quickly identify "
"the root category of any issue. You are empathetic, patient, and thorough. "
"Your classifications determine which specialist handles the case."
),
llm=llm,
verbose=True,
allow_delegation=True,
max_iter=3 # Limit reasoning loops
)
# --- AGENT 2: Knowledge Base Agent ---
kb_agent = Agent(
role="Knowledge Base Researcher",
goal=(
"Search the internal knowledge base and public documentation for articles, "
"guides, and solutions relevant to the customer's issue. Return the most "
"relevant article titles, URLs, and a concise summary of each finding."
),
backstory=(
"You are a research librarian for a large technology company. You have indexed "
"thousands of support articles and know exactly how to find relevant information "
"using semantic search. You always cite your sources and provide direct links."
),
llm=llm,
verbose=True,
allow_delegation=False,
tools=[SerperDevTool(), ScrapeWebsiteTool()],
max_iter=5
)
# --- AGENT 3: Technical Support Agent ---
technical_agent = Agent(
role="Senior Technical Support Engineer",
goal=(
"Solve the customer's technical issue by analyzing error logs, suggesting "
"configuration changes, and providing step-by-step troubleshooting instructions. "
"Base your solutions on knowledge base articles and your technical expertise."
),
backstory=(
"You are a seasoned support engineer with deep knowledge of the company's "
"product stack, APIs, and infrastructure. You've solved thousands of cases "
"ranging from simple configuration errors to complex integration bugs. "
"You are methodical and always verify your solutions before presenting them."
),
llm=llm,
verbose=True,
allow_delegation=True,
max_iter=7
)
# --- AGENT 4: Escalation Agent ---
escalation_agent = Agent(
role="Escalation Manager",
goal=(
"Handle cases that cannot be resolved automatically. Determine whether to "
"escalate to a human team, create a support ticket with full context, and "
"draft a compassionate message explaining next steps to the customer."
),
backstory=(
"You are the final escalation point for the support system. You have authority "
"to create Jira tickets, tag engineering teams, and schedule callbacks. "
"You balance customer satisfaction with operational efficiency and never "
"leave a customer without a clear path forward."
),
llm=llm,
verbose=True,
allow_delegation=False,
max_iter=3
)
Notice the allow_delegation parameter — when set to True, an agent can pass work to other agents in the crew. The triage agent delegates to specialists; the escalation agent is a dead-end by design. The max_iter parameter prevents infinite reasoning loops by capping the number of thought-action cycles.
Step 2: Building Custom Tools
Tools give agents the ability to interact with external systems. CrewAI ships with several built-in tools (SerperDevTool for web search, ScrapeWebsiteTool for reading web pages), but for a production support bot you'll need custom tools that interface with your actual systems. Create tools.py:
from crewai_tools import tool
from typing import Optional, Dict, Any
import json
import datetime
# --- TOOL 1: Simulated Knowledge Base Search ---
@tool("knowledge_base_search")
def search_knowledge_base(query: str, category: Optional[str] = None) -> str:
"""
Search the internal knowledge base for articles matching the query.
Args:
query: The search query string
category: Optional filter for article category
Returns:
JSON string with matching articles
"""
# In production, replace this with a call to your vector database
# or documentation API (e.g., Elasticsearch, Pinecone, Algolia)
mock_kb = [
{
"id": "KB-001",
"title": "Resetting Your Password",
"category": "account_access",
"summary": "Step-by-step guide for resetting passwords via email or SMS.",
"url": "https://help.example.com/articles/kb-001"
},
{
"id": "KB-002",
"title": "Troubleshooting API Rate Limit Errors",
"category": "technical",
"summary": "Explains 429 errors and how to implement exponential backoff.",
"url": "https://help.example.com/articles/kb-002"
},
{
"id": "KB-003",
"title": "Understanding Your Invoice",
"category": "billing",
"summary": "Breakdown of invoice line items including taxes and discounts.",
"url": "https://help.example.com/articles/kb-003"
},
{
"id": "KB-004",
"title": "Two-Factor Authentication Setup",
"category": "account_access",
"summary": "Guide for enabling 2FA using authenticator apps or SMS.",
"url": "https://help.example.com/articles/kb-004"
},
{
"id": "KB-005",
"title": "Resolving 'Connection Refused' Errors",
"category": "technical",
"summary": "Diagnoses firewall, DNS, and port binding issues causing connection refusals.",
"url": "https://help.example.com/articles/kb-005"
}
]
results = [a for a in mock_kb if query.lower() in a["title"].lower()
or query.lower() in a["summary"].lower()]
if category:
results = [a for a in results if a["category"] == category]
return json.dumps(results[:3], indent=2)
# --- TOOL 2: Ticket Creation ---
@tool("create_support_ticket")
def create_support_ticket(
customer_email: str,
issue_summary: str,
priority: str,
agent_notes: str
) -> str:
"""
Create a support ticket in the internal ticketing system.
Args:
customer_email: Customer's email address
issue_summary: One-line summary of the issue
priority: One of 'low', 'medium', 'high', 'critical'
agent_notes: Detailed notes from the AI agent
Returns:
Confirmation message with ticket ID
"""
# In production, integrate with your actual ticketing system
# (Zendesk, Jira, ServiceNow, Freshdesk, etc.)
ticket_id = f"TKT-{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}-{hash(customer_email) % 10000:04d}"
ticket_data = {
"ticket_id": ticket_id,
"customer_email": customer_email,
"summary": issue_summary,
"priority": priority,
"notes": agent_notes,
"created_at": datetime.datetime.now().isoformat(),
"status": "open"
}
# Simulate persistence — replace with actual API call
print(f"[TOOL] Ticket created: {json.dumps(ticket_data, indent=2)}")
return f"Ticket {ticket_id} created successfully with {priority} priority."
# --- TOOL 3: Customer Lookup ---
@tool("customer_lookup")
def lookup_customer(email: str) -> str:
"""
Look up customer account details by email address.
Args:
email: Customer's email address
Returns:
JSON string with customer account information
"""
# Replace with your CRM/database query
mock_customers = {
"alice@example.com": {
"name": "Alice Johnson",
"plan": "Enterprise",
"account_age_days": 342,
"open_tickets": 1,
"account_status": "active"
},
"bob@example.com": {
"name": "Bob Smith",
"plan": "Starter",
"account_age_days": 15,
"open_tickets": 0,
"account_status": "trial"
}
}
customer = mock_customers.get(email.lower())
if customer:
return json.dumps(customer, indent=2)
return json.dumps({"error": "Customer not found", "email": email})
# --- TOOL 4: Sentiment Analysis ---
@tool("analyze_sentiment")
def analyze_sentiment(text: str) -> str:
"""
Analyze the sentiment of a customer message.
Args:
text: The customer message to analyze
Returns:
JSON with sentiment label and confidence score
"""
# In production, use a dedicated sentiment API or ML model
# This is a simplified keyword-based approach for demonstration
negative_keywords = ["angry", "frustrated", "terrible", "broken", "failed",
"urgent", "immediately", "worst", "horrible", "useless"]
positive_keywords = ["great", "helpful", "thanks", "awesome", "love",
"resolved", "appreciate", "excellent", "perfect"]
text_lower = text.lower()
neg_count = sum(1 for word in negative_keywords if word in text_lower)
pos_count = sum(1 for word in positive_keywords if word in text_lower)
if neg_count > pos_count:
sentiment = "negative"
confidence = min(0.95, 0.5 + neg_count * 0.15)
elif pos_count > neg_count:
sentiment = "positive"
confidence = min(0.95, 0.5 + pos_count * 0.15)
else:
sentiment = "neutral"
confidence = 0.6
return json.dumps({"sentiment": sentiment, "confidence": round(confidence, 2)})
The @tool decorator registers each function as a CrewAI tool. The docstring becomes the tool's description that the agent uses to decide when to call it. Always include type hints and detailed docstrings — agents use these to determine which tool fits the current context.
Step 3: Structuring Tasks
Tasks define the work agents perform. In CrewAI, tasks can be sequential (one after another) or hierarchical (managed by a supervisor agent). For customer support, a sequential workflow works best — triage first, then route to the appropriate specialist. Open tasks.py:
from crewai import Task
from agents import triage_agent, kb_agent, technical_agent, escalation_agent
from tools import search_knowledge_base, create_support_ticket, lookup_customer, analyze_sentiment
# --- TASK 1: Initial Triage ---
triage_task = Task(
description=(
"A customer has submitted the following inquiry: {customer_message}\n\n"
"Your job:\n"
"1. Classify the issue type (billing, technical, account_access, general_inquiry)\n"
"2. Extract key information: product name, error messages, account email, urgency\n"
"3. If information is missing, note what clarifying questions you would ask\n"
"4. Assess the customer's emotional state based on their message\n"
"5. Determine the priority level: low, medium, high, or critical\n\n"
"Output your analysis as a structured JSON object with these fields:\n"
"- category\n"
"- extracted_details (dict)\n"
"- missing_information (list)\n"
"- priority\n"
"- customer_emotional_state"
),
agent=triage_agent,
expected_output="A JSON object containing the triage analysis with all five fields populated.",
tools=[analyze_sentiment, lookup_customer],
async_execution=False
)
# --- TASK 2: Knowledge Retrieval ---
knowledge_task = Task(
description=(
"Based on the triage analysis: {triage_result}\n\n"
"Search the knowledge base for articles related to the customer's issue. "
"Use the extracted details to form precise search queries. "
"If the category is 'billing', search for billing-related articles. "
"If 'technical', search for error-specific articles.\n\n"
"Return a JSON array of relevant articles with id, title, url, and summary for each."
),
agent=kb_agent,
expected_output="A JSON array of knowledge base articles, each with id, title, url, and summary fields.",
tools=[search_knowledge_base],
context=[triage_task], # This task depends on triage_task completing first
async_execution=False
)
# --- TASK 3: Solution Generation ---
solution_task = Task(
description=(
"You have the triage analysis and knowledge base results:\n"
"Triage: {triage_result}\n"
"Knowledge Base Articles: {knowledge_results}\n\n"
"Generate a comprehensive solution for the customer. Your response must include:\n"
"1. A warm, empathetic acknowledgment of their issue\n"
"2. The specific solution steps, numbered and clearly explained\n"
"3. References to the knowledge base articles you used (include URLs)\n"
"4. Verification steps the customer should take to confirm the fix worked\n"
"5. A clear call-to-action — what should the customer do next?\n\n"
"If you cannot resolve the issue with available information, explicitly state "
"what's missing and recommend escalation."
),
agent=technical_agent,
expected_output=(
"A detailed customer-facing response with empathy, numbered solution steps, "
"article references, verification steps, and a call-to-action."
),
context=[triage_task, knowledge_task],
async_execution=False
)
# --- TASK 4: Escalation Handling (conditional) ---
escalation_task = Task(
description=(
"The automated system could not fully resolve this issue.\n"
"Triage Analysis: {triage_result}\n"
"Attempted Solution: {solution_attempt}\n\n"
"Your responsibilities:\n"
"1. Review the triage and solution attempt to understand what was tried\n"
"2. Create a formal support ticket using the create_support_ticket tool with "
" all relevant context included in the agent_notes field\n"
"3. Draft a compassionate message to the customer explaining that their issue "
" has been escalated to the human support team, including the ticket ID and "
" expected response time (typically 2-4 hours for high priority)\n"
"4. If the priority is 'critical', mention that someone will call within 30 minutes"
),
agent=escalation_agent,
expected_output=(
"A JSON object with 'ticket_id', 'ticket_status', and 'customer_message' fields. "
"The customer_message should be a polished, empathetic email-ready message."
),
tools=[create_support_ticket],
context=[triage_task, solution_task],
async_execution=False
)
The context parameter creates dependencies — tasks with context wait for their upstream tasks to complete before starting. The {variable_name} syntax in task descriptions lets you pass data between tasks. CrewAI automatically populates these from the outputs of context tasks.
Step 4: Assembling and Running the Crew
Now bring everything together in crew_setup.py. The Crew class orchestrates agent execution, handles context passing, and manages the overall workflow:
from crewai import Crew, Process
from agents import triage_agent, kb_agent, technical_agent, escalation_agent
from tasks import triage_task, knowledge_task, solution_task, escalation_task
import json
import os
from dotenv import load_dotenv
load_dotenv()
# --- Assemble the full support crew ---
support_crew = Crew(
agents=[triage_agent, kb_agent, technical_agent, escalation_agent],
tasks=[triage_task, knowledge_task, solution_task],
process=Process.sequential, # Tasks execute in defined order
verbose=True,
memory=True, # Agents remember context across tasks
planning=True, # Enable the built-in planning step before execution
manager_llm=None # Not needed for sequential process
)
# --- Assemble escalation-only crew (for fallback) ---
escalation_crew = Crew(
agents=[escalation_agent],
tasks=[escalation_task],
process=Process.sequential,
verbose=True
)
def run_support_bot(customer_message: str, customer_email: str = "") -> dict:
"""
Main entry point for the customer support bot.
Args:
customer_message: The customer's inquiry text
customer_email: Optional email for customer lookup
Returns:
Dict with the final response and metadata
"""
print(f"\n{'='*60}")
print(f"Processing customer inquiry...")
print(f"Message: {customer_message[:200]}...")
print(f"{'='*60}\n")
# Step 1: Run the main support crew
inputs = {
"customer_message": customer_message,
"customer_email": customer_email or "unknown@example.com"
}
try:
result = support_crew.kickoff(inputs=inputs)
# The result contains all task outputs
# Extract the solution (last task output)
if hasattr(result, 'tasks_output') and result.tasks_output:
solution_output = result.tasks_output[-1] if result.tasks_output else None
else:
solution_output = str(result)
# Step 2: Check if escalation is needed
# Look for escalation triggers in the solution
escalation_keywords = ["escalate", "unable to resolve", "insufficient information",
"needs human", "critical priority", "cannot determine"]
needs_escalation = any(
keyword in str(solution_output).lower()
for keyword in escalation_keywords
)
if needs_escalation:
print("\n[SYSTEM] Escalation triggered. Running escalation crew...\n")
escalation_inputs = {
"triage_result": str(result.tasks_output[0]) if result.tasks_output else "",
"solution_attempt": str(solution_output)
}
escalation_result = escalation_crew.kickoff(inputs=escalation_inputs)
return {
"status": "escalated",
"automated_response": str(solution_output),
"escalation_details": str(escalation_result),
"message": "Your issue has been escalated to our human support team."
}
return {
"status": "resolved",
"response": str(solution_output),
"message": "Automated resolution completed successfully."
}
except Exception as e:
print(f"[ERROR] Crew execution failed: {str(e)}")
# Fallback: force escalation on error
escalation_inputs = {
"triage_result": json.dumps({"error": str(e), "category": "unknown"}),
"solution_attempt": "Automated resolution failed due to system error."
}
escalation_result = escalation_crew.kickoff(inputs=escalation_inputs)
return {
"status": "error_escalated",
"error": str(e),
"escalation_details": str(escalation_result),
"message": "We encountered an error and have escalated your issue."
}
# --- Example usage ---
if __name__ == "__main__":
# Test with a sample customer inquiry
sample_message = """
Hi, I've been trying to reset my password for the past hour but the email
never arrives. I've checked my spam folder. My account is tied to
alice@example.com. This is really frustrating because I need to access
my dashboard for a client presentation in 30 minutes!
"""
response = run_support_bot(
customer_message=sample_message,
customer_email="alice@example.com"
)
print("\n" + "="*60)
print("FINAL RESPONSE:")
print(json.dumps(response, indent=2))
print("="*60)
The Process.sequential mode ensures tasks run in the order defined. For more complex workflows, CrewAI also supports Process.hierarchical where a manager agent dynamically assigns tasks. The memory=True flag enables persistent context across tasks so agents can reference earlier findings.
Step 5: Integrating with a Web Application
To deploy this bot as a real customer support endpoint, wrap it in a simple web server. Here's a FastAPI integration that exposes the bot as a REST API:
# api_server.py
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, EmailStr
from typing import Optional
import uvicorn
from crew_setup import run_support_bot
from datetime import datetime
import logging
app = FastAPI(title="Customer Support Bot API", version="1.0.0")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class SupportRequest(BaseModel):
message: str
email: Optional[EmailStr] = None
customer_id: Optional[str] = None
channel: str = "web" # web, email, chat, api
class SupportResponse(BaseModel):
request_id: str
status: str # resolved, escalated, error_escalated
response_text: str
escalation_ticket_id: Optional[str] = None
processing_time_ms: float
timestamp: str
@app.post("/api/support", response_model=SupportResponse)
async def handle_support_request(request: SupportRequest):
"""
Main endpoint for customer support inquiries.
Accepts a customer message and returns an AI-generated response.
"""
import time
start_time = time.time()
request_id = f"REQ-{datetime.now().strftime('%Y%m%d%H%M%S')}-{hash(request.message) % 100000:05d}"
logger.info(f"Processing request {request_id} from {request.email or 'anonymous'}")
try:
result = run_support_bot(
customer_message=request.message,
customer_email=request.email or ""
)
processing_time = (time.time() - start_time) * 1000
# Extract escalation ticket ID if present
ticket_id = None
if result.get("status") in ("escalated", "error_escalated"):
escalation_details = result.get("escalation_details", "")
# Parse ticket ID from escalation output if available
if "TKT-" in str(escalation_details):
import re
match = re.search(r'TKT-\d{14}-\d{4}', str(escalation_details))
if match:
ticket_id = match.group(0)
return SupportResponse(
request_id=request_id,
status=result.get("status", "unknown"),
response_text=result.get("response", result.get("message", "")),
escalation_ticket_id=ticket_id,
processing_time_ms=round(processing_time, 2),
timestamp=datetime.now().isoformat()
)
except Exception as e:
logger.error(f"Request {request_id} failed: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Processing error: {str(e)}")
@app.get("/api/health")
async def health_check():
return {"status": "healthy", "timestamp": datetime.now().isoformat()}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")
This API server handles JSON requests, tracks processing time, generates unique request IDs, and gracefully handles errors. In production, add rate limiting, authentication, and a database for persisting conversation history.
Best Practices for Production CrewAI Support Bots
1. Agent Design Principles
- Keep roles narrow — each agent should have exactly one responsibility. An agent that does triage AND solves technical issues will perform both poorly. Split responsibilities across multiple agents.
- Write detailed backstories — the backstory significantly influences agent behavior. Include specific domain knowledge, personality traits, and constraints. "You never give financial advice" is more effective than a generic "be helpful."
- Set appropriate temperature — use low temperature (0.0-0.3) for triage and classification agents where consistency matters. Use higher temperature (0.5-0.7) for agents that need creative problem-solving.
- Assign tools selectively — don't give every tool to every agent. The knowledge base agent gets search tools; the escalation agent gets ticket creation tools. This prevents tool confusion.
2. Task Orchestration Patterns
- Use context chains — link tasks via the
contextparameter rather than passing raw strings. CrewAI handles the serialization automatically and preserves structured data. - Set clear expected_output — the
expected_outputfield isn't just documentation; agents use it to self-evaluate whether they've completed the task correctly. Be specific about the format (JSON, markdown, plain text). - Implement conditional branching — the example above uses keyword detection to decide whether to escalate. In production, use structured output from agents (JSON with a "needs_escalation" boolean field) for more reliable branching.
- Cap iterations — always set
max_iteron agents that use tools. Without it, an agent might loop indefinitely trying to call a tool that returns unexpected results.
3. Handling Edge Cases
- Empty or vague messages — train your triage agent to ask clarifying questions rather than guessing. Include examples in the backstory of how to handle ambiguous inquiries.
- Multi-issue messages — customers often mention multiple problems. Your triage agent should identify all issues and either pick the most urgent or split them into separate cases.
- Abusive or threatening messages — implement a safety layer that detects policy violations before the message reaches the crew. Use a separate classifier or regex-based filter.
- Timeout handling — CrewAI tasks can take 30-60 seconds with multiple tool calls. Implement a circuit breaker: if the crew exceeds a time limit, fall back to a canned response and force escalation.
4. Monitoring and Observability
- Log every agent action — enable
verbose=Trueduring development and capture logs to a structured logging system (DataDog, CloudWatch, or a simple file) for debugging. - Track decision trails — record the output of each task so you can reconstruct why the bot gave a particular response. This is invaluable for improving prompts.
- Monitor tool call success rates — if a tool fails frequently (e.g., knowledge base returns empty results), the agent may hallucinate. Set up alerts for abnormal tool failure rates.
- Collect customer feedback — add a thumbs-up/thumbs-down mechanism to every response. Use this signal to fine-tune agent prompts and identify weak spots in the workflow.
5. Performance Optimization
- Use smaller models for simple agents — the triage agent can often use GPT-3.5-Turbo or Claude Haiku instead of GPT-4o, cutting latency and cost by 80%+ without sacrificing classification accuracy.
- Cache knowledge base results — implement a TTL-based cache for your knowledge base tool. Common queries ("password reset", "billing inquiry") shouldn't hit your vector database every time.
- Pre-warm agent sessions — if using models with slow cold starts, keep a pool of pre-initialized agent instances ready for incoming requests.
- Parallelize independent tasks — if your workflow has tasks that don't depend on each other (e.g., sentiment analysis and customer lookup), set
async_execution=Trueto run them concurrently.
Testing Your Support Bot
Before deploying, thoroughly test your crew with a diverse set of customer scenarios. Here's a test harness that validates the bot's behavior across different issue categories:
# test_bot.py
from crew_setup import run_support_bot
import json
import time
test_cases = [
{
"name": "Password Reset",
"message": "I forgot my password and the reset email isn't arriving. Help!",
"email": "alice@example.com",
"expected_category": "account_access",
"expected_priority": "high"
},
{
"name": "Billing Question",
"message": "I was charged twice on my last invoice. Can you explain the charges?",
"email": "bob@example.com",
"expected_category": "billing",
"expected_priority": "medium"
},
{
"name": "API Error",
"message": "I'm getting a 429 error when calling your API. What does this mean?",
"email": "developer@example.com",
"expected_category": "technical",
"expected_priority": "medium"
},
{
"name": "Vague Inquiry",
"message": "It's not working.",
"email": "user@example.com",
"expected_category": "general