Every employee has experienced this: You have a salary question. You emailed the wrong department. They forward it. Two days later, you finally get an answer.
Or worse, you don’t know which department to contact at all.
What if an AI could:
No forms. No “please contact HR at…”. Just ask in plain English and get an answer.
That’s exactly what we built using Multi-Agent AI with CrewAI, and in this post, we’ll show you exactly how it works.
A Multi-Agent System is a setup where multiple specialised AI agents work together, each handling a specific domain.
Think of it like a company:
In AI, we do the same thing:
Employee Query
│
▼
┌─────────────────────┐
│ Manager Agent │ ← reads the query, decides who handles it
│ (Smart Router) │
└──────────┬──────────┘
│
┌────────┼────────┐
▼ ▼ ▼
HR Accounts IT
Agent Agent Agent
The beautiful part? The Manager is an AI, no manual routing code, no if/elif chains. The Manager LLM understands context and delegates intelligently.
We chose CrewAI for this demo because:
┌───────────────────────────────────────────────────────┐
│ TECHCORP EMPLOYEE SUPPORT AI │
│ │
│ Employee: "My laptop won't connect to VPN" │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ MANAGER AGENT │ │
│ │ (gpt-4o-mini) │ │
│ │ "This is an IT │ │
│ │ issue → route to │ │
│ │ IT Agent" │ │
│ └────────┬────────────┘ │
│ │ delegates │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ IT AGENT │ │
│ │ "Here are the │ │
│ │ steps to fix VPN: │ │
│ │ 1. Check settings │ │
│ │ 2. Restart client │ |
│ │ 3. ..." │ │
│ └─────────────────────┘ │
│ │ │
│ ▼ |
| Final answer returned to employee |
└───────────────────────────────────────────────────────┘
Agent | Department | Handles |
|---|---|---|
HR Agent | Human Resources | Leave, policies, onboarding, WFH |
Accounts | Agent Finance | Salary, expenses, reimbursement, invoices |
IT Agent | IT Support | Laptop, VPN, software, access, accounts |
The Manager is not defined as a separate Agent object in CrewAI. Instead, you pass a manager_llm to the Crew. CrewAI creates the manager internally. This manager:
Project Structure:
multi_agent_demo/
├── agents.py ← HR, Accounts, IT agent definitions
├── tasks.py ← The employee query task
├── main.py ← Assemble crew and run
├── .env ← Your OpenAI API key
└── requirements.txt
pip install crewai crewai-tools langchain-openai python-dotenv
bash
# .env
OPENAI_API_KEY=sk-your-key-here
from crewai import Agent
llm = "gpt-4o-mini"
# ── HR Agent ──
hr_agent = Agent(
role="HR Department Specialist",
goal=(
"Answer all Human Resources queries from employees. "
"Help with leave, policies, onboarding, and hiring questions."
),
backstory=(
"You are a senior HR specialist at TechCorp with 8 years of experience."
"Employees get 18 paid leaves, 12 casual, 6 sick per year. "
"Leave must be applied 2 days in advance. "
"You are approachable, empathetic, and follow HR protocols."
),
tools=[],
llm=llm,
verbose=True,
)
# ── Accounts Agent ──
accounts_agent = Agent(
role="Accounts & Finance Department Specialist",
goal=(
"Handle all finance queries -- salary, expenses, invoices, reimbursements."
),
backstory=(
"You are a finance specialist at TechCorp. "
"Salaries are credited on the last working day of every month. "
"Expense claims must be submitted within 30 days with receipts. "
"Reimbursement takes 7-10 working days."
),
tools=[],
llm=llm,
verbose=True,
)
# ── IT Agent ──
it_agent = Agent(
role="IT Support Specialist",
goal=(
"Resolve all technical issues -- laptop, VPN, software, access."
),
backstory=(
"You are a level-2 IT support engineer at TechCorp. "
"You handle hardware, software, email/account access, and VPN. "
"You escalate urgent issues to the on-site IT team. "
"You give step-by-step guidance and are patient with non-technical users."
),
tools=[],
llm=llm,
verbose=True,
)
Notice something? Each agent has a detailed backstory, this is where you put the company’s policies and knowledge. The agent answers from this context, just like a trained employee would.
In a hierarchical system, we only need one task: the employee’s query. The Manager decides who handles it.
from crewai import Task
from agents import hr_agent # default agent (Manager overrides this)
def create_employee_task(employee_query: str, employee_name: str):
return Task(
description=(
f"Employee {employee_name} has submitted this query:\n\n"
f"'{employee_query}'\n\n"
"Instructions:\n"
"1. Understand exactly what the employee is asking\n"
"2. Provide a complete, accurate response\n"
"3. List any follow-up steps clearly\n"
"4. Be professional and empathetic\n"
"5. End with: 'If you have more questions, feel free to ask!'"
),
expected_output=(
"A complete, professional response that directly addresses the query, "
"includes relevant policy details or steps, and is ready to send."
),
agent=hr_agent, # The Manager will override this automatically
)
This is where the magic happens: Process.hierarchical:
from dotenv import load_dotenv
from crewai import Crew, Process
from agents import hr_agent, accounts_agent, it_agent
from tasks import create_employee_task
load_dotenv()
# Manager uses a smart LLM to route correctly
manager_llm = "gpt-4o-mini"
def run_employee_support(employee_name: str, employee_query: str):
task = create_employee_task(employee_query, employee_name)
crew = Crew(
agents=[hr_agent, accounts_agent, it_agent],
tasks=[task],
process=Process.hierarchical, # ← Manager routes automatically
manager_llm=manager_llm,
verbose=True,
)
result = crew.kickoff()
print(result.raw)
return result.raw
if __name__ == "__main__":
run_employee_support(
employee_name="Ravi Kumar",
employee_query="I want to apply for 3 days leave next week. What is the process?"
)
python main.py
Employee: Ravi Kumar
Query: "I want to apply for 3 days leave next week from Monday to Wednesday."
Manager Agent thinks:
→ "This is about leave application -- HR domain"
→ Delegates to: HR Agent
HR Agent responds:
"Hi Ravi! Here's how to apply for leave:
1. Log in to the HRMS portal at hrms.techcorp.com
2. Go to Leave Management → Apply Leave
3. Select Leave Type: Paid Leave
4. Choose dates: Monday to Wednesday (3 days)
5. Add reason: Family function
6. Submit for manager approval
You currently have 8 paid leaves remaining -- more than enough!
Please apply at least 2 days in advance per company policy.
If you have more questions, feel free to ask!"
Employee: Priya Sharma
Query: "My salary for this month has not been credited yet."
Manager Agent thinks:
→ "This is about salary -- Finance/Accounts domain"
→ Delegates to: Accounts Agent
Accounts Agent responds:
"Hi Priya! I understand your concern about the salary delay.
At TechCorp, salaries are credited on the last working day of
every month. If today is before the last working day, your
salary is still being processed.
If today is after the last working day:
1. Check your registered bank account (allow 1-2 hours for bank processing)
2. Check your payslip on the HRMS portal
3. Email accounts@techcorp.com with your employee ID
If you have more questions, feel free to ask!"
Employee: Anil Mehta
Query: "My laptop won't connect to VPN. I have a meeting in 2 hours."
Manager Agent thinks:
→ "This is a VPN/technical issue -- IT Support domain"
→ Delegates to: IT Agent (marks as HIGH priority)
IT Agent responds:
"Hi Anil! Let's fix your VPN issue quickly.
Step 1: Restart the VPN client (Cisco AnyConnect / GlobalProtect)
Step 2: Check your internet connection
Step 3: Clear VPN cache -- go to Settings → Clear Cache
Step 4: Reinstall VPN client if above doesn't work
If still not working:
→ Call IT Helpdesk: 1800-XXX-XXXX (24/7)
→ Or email it-urgent@techcorp.com with 'URGENT' in subject
Given your 2-hour deadline, I recommend calling directly.
If you have more questions, feel free to ask!"
# WITHOUT multi-agent: You write manual routing
if "leave" in query or "holiday" in query:
response = hr_bot.answer(query)
elif "salary" in query or "payroll" in query:
response = accounts_bot.answer(query)
elif "laptop" in query or "vpn" in query:
response = it_bot.answer(query)
else:
response = "Please contact the appropriate department."
# PROBLEM: "I can't access my payslip on the HR portal"
# → Is this Accounts? Or IT?
# → Your manual code gets this WRONG
# WITH multi-agent: Manager LLM understands context
crew = Crew(
agents=[hr_agent, accounts_agent, it_agent],
process=Process.hierarchical,
manager_llm=manager_llm,
)
result = crew.kickoff() # Manager figures it out automatically ✅
# "I can't access my payslip on the HR portal"
# → Manager: "Payslip = Finance content BUT access issue = IT problem"
# → Manager routes to IT Agent ✅
The Manager LLM understands the nuance that keyword matching misses.
Right now, our agents answer from their backstory knowledge. In production, you’d give them real tools:
from crewai_tools import tool
@tool("Check Leave Balance")
def check_leave_balance(employee_id: str) -> str:
"""
Check the real-time leave balance for an employee.
Use when an employee asks about available leaves.
"""
# Query your HRMS API or database here
response = requests.get(f"https://hrms.techcorp.com/api/leaves/{employee_id}")
return response.json()
# Add to HR Agent:
hr_agent = Agent(
role="HR Department Specialist",
tools=[check_leave_balance], # ← Now agent can check REAL data!
...
)
Benefit | Description |
|---|---|
Smart routing | Manager understands context, not just keywords |
Specialisation | Each agent focuses on one domain = better answers |
Scalable | Add a new department? Just add a new Agent |
No routing code | Remove hundreds of if/elif lines from your codebase |
Handles ambiguity | "Payslip access" → IT, not Accounts -- LLM gets this right |
Easy to update | Change HR policy? Update agent backstory, not code |
Challenge | Description |
|---|---|
Latency | Manager call + specialist call = extra 1-2 seconds |
Cost | 2 LLM calls per query instead of 1 |
Occasional misrouting | Complex queries may go to the wrong agent |
Overkill for simple apps | If you have 1 agent, skip the Manager |
Add More Departments
legal_agent = Agent(
role="Legal Department Specialist",
goal="Handle contract, NDA, compliance, and legal queries.",
backstory="Expert in company legal policies and employment law...",
...
)
admin_agent = Agent(
role="Admin & Facilities Specialist",
goal="Handle office access, transport, pantry, and facility requests.",
...
)
crew = Crew(
agents=[hr_agent, accounts_agent, it_agent, legal_agent, admin_agent],
# Manager automatically handles all 5 departments!
...
)
Add Memory (Remember Past Conversations)
crew = Crew(
agents=[hr_agent, accounts_agent, it_agent],
tasks=[task],
process=Process.hierarchical,
manager_llm=manager_llm,
memory=True, # ← Agents remember previous queries in a session
)
Multi-agent AI systems with a Manager routing pattern are a game-changer for building intelligent support systems.
Instead of writing complex routing logic with hundreds of if/elif conditions, you let the Manager LLM understand context and delegate intelligently, just like a real manager would.
The result: A system that handles any employee query, routes it to the right specialist, and replies with a complete, accurate answer, all without the employee needing to know which department to contact.