By Sagar Shankaran, Founder of CallSphere
Create an AI agent that answers HR policy questions, looks up benefits details, checks PTO balances, and submits time-off requests — reducing the burden on HR teams while giving employees instant answers.
Key takeaways
HR departments spend a disproportionate amount of time answering the same questions: "How many PTO days do I have left?", "When is open enrollment?", "What is the parental leave policy?" These questions have definitive answers that do not require human judgment — making them ideal for an agentic solution. By offloading repetitive inquiries, HR professionals can focus on strategic work like culture initiatives, conflict resolution, and organizational development.
The critical design decision is separating read-only queries (policy lookups, balance checks) from write operations (PTO requests, benefits changes) with appropriate authorization checks.
Rather than embedding policy text directly into the agent's instructions, we store policies in a structured database that can be updated independently. This ensures the agent always references the current version.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart TD
Q{"What do you<br/>want to know?"}
A0["How do you ensure the agent<br/>gives accurate policy answers?"]
Q --> A0 --> ANS0(["See answer"])
style ANS0 fill:#059669,stroke:#047857,color:#fff
A1["What if an employee asks<br/>something the agent cannot…"]
Q --> A1 --> ANS1(["See answer"])
style ANS1 fill:#059669,stroke:#047857,color:#fff
A2["How do you handle PTO requests<br/>that span holidays?"]
Q --> A2 --> ANS2(["See answer"])
style ANS2 fill:#059669,stroke:#047857,color:#fff
style Q fill:#4f46e5,stroke:#4338ca,color:#fff
from dataclasses import dataclass
from datetime import date, timedelta
from typing import Optional
from agents import Agent, Runner, function_tool
import json
@dataclass
class PolicyDocument:
policy_id: str
title: str
category: str
content: str
effective_date: date
last_updated: date
POLICY_DATABASE: dict[str, PolicyDocument] = {
"pto-001": PolicyDocument(
policy_id="pto-001",
title="Paid Time Off Policy",
category="time_off",
content="""Employees accrue PTO based on tenure:
- 0-2 years: 15 days/year (1.25 days/month)
- 3-5 years: 20 days/year (1.67 days/month)
- 6+ years: 25 days/year (2.08 days/month)
PTO requests must be submitted at least 5 business days in advance.
Manager approval is required for requests exceeding 3 consecutive days.
Unused PTO carries over up to 5 days into the next calendar year.""",
effective_date=date(2026, 1, 1),
last_updated=date(2026, 1, 15),
),
"benefits-001": PolicyDocument(
policy_id="benefits-001",
title="Health Benefits Overview",
category="benefits",
content="""Three plan tiers available: Bronze, Silver, Gold.
Open enrollment runs November 1-30 each year.
New hires can enroll within 30 days of start date.
Life changes (marriage, birth) trigger a special enrollment window.""",
effective_date=date(2026, 1, 1),
last_updated=date(2026, 2, 1),
),
}
@function_tool
def search_policies(query: str, category: str = "") -> str:
"""Search HR policies by keyword and optional category."""
results = []
query_lower = query.lower()
for policy in POLICY_DATABASE.values():
if category and policy.category != category:
continue
if (query_lower in policy.title.lower()
or query_lower in policy.content.lower()):
results.append({
"policy_id": policy.policy_id,
"title": policy.title,
"category": policy.category,
"content": policy.content,
"last_updated": str(policy.last_updated),
})
if not results:
return json.dumps({"message": "No matching policies found. "
"Please contact HR for assistance."})
return json.dumps(results)
The PTO system integrates with employee records to show accrued, used, and available balances. The request tool validates dates and submits for approval.
@dataclass
class PTORecord:
employee_id: str
accrued: float
used: float
pending: float
carry_over: float
@property
def available(self) -> float:
return self.accrued + self.carry_over - self.used - self.pending
PTO_RECORDS: dict[str, PTORecord] = {}
@function_tool
def get_pto_balance(employee_id: str) -> str:
"""Get current PTO balance for an employee."""
record = PTO_RECORDS.get(employee_id)
if not record:
return json.dumps({"error": "Employee PTO record not found"})
return json.dumps({
"accrued_this_year": record.accrued,
"carried_over": record.carry_over,
"used": record.used,
"pending_approval": record.pending,
"available": record.available,
})
@function_tool
def submit_pto_request(
employee_id: str,
start_date: str,
end_date: str,
reason: str = "",
) -> str:
"""Submit a PTO request for approval."""
record = PTO_RECORDS.get(employee_id)
if not record:
return json.dumps({"error": "Employee not found"})
start = date.fromisoformat(start_date)
end = date.fromisoformat(end_date)
days_requested = (end - start).days + 1
# Validate advance notice
if (start - date.today()).days < 5:
return json.dumps({
"status": "rejected",
"reason": "PTO requests require 5 business days advance notice.",
})
# Validate sufficient balance
if days_requested > record.available:
return json.dumps({
"status": "rejected",
"reason": f"Insufficient balance. Requested {days_requested} days "
f"but only {record.available} available.",
})
record.pending += days_requested
needs_manager = days_requested > 3
return json.dumps({
"status": "submitted",
"days": days_requested,
"requires_manager_approval": needs_manager,
"estimated_response": "1-2 business days",
})
@dataclass
class BenefitsEnrollment:
employee_id: str
plan_tier: str
dependents: int
monthly_premium: float
hsa_balance: float
next_open_enrollment: date
BENEFITS_DB: dict[str, BenefitsEnrollment] = {}
@function_tool
def get_benefits_summary(employee_id: str) -> str:
"""Retrieve current benefits enrollment summary."""
enrollment = BENEFITS_DB.get(employee_id)
if not enrollment:
return json.dumps({"error": "No benefits enrollment found"})
return json.dumps({
"plan": enrollment.plan_tier,
"dependents_covered": enrollment.dependents,
"monthly_premium": f"${enrollment.monthly_premium:.2f}",
"hsa_balance": f"${enrollment.hsa_balance:.2f}",
"next_open_enrollment": str(enrollment.next_open_enrollment),
})
hr_faq_agent = Agent(
name="HRBot",
instructions="""You are HRBot, an HR self-service assistant.
Answer employee questions about policies, benefits, and PTO.
Always cite the specific policy when answering policy questions.
For PTO requests, confirm the dates and check the balance before submitting.
Never share one employee's information with another employee.
If a question requires human judgment, direct the employee to their HR Business Partner.""",
tools=[search_policies, get_pto_balance, submit_pto_request, get_benefits_summary],
)
The agent retrieves policy text from a versioned database rather than relying on its training data. Each policy document includes an effective date and last-updated timestamp. When policies change, you update the database — the agent immediately reflects the new information without retraining.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
The agent is instructed to recognize its boundaries. If no matching policy is found or the question involves subjective judgment (workplace conflicts, accommodation requests), it escalates to the appropriate HR representative with context about what the employee was asking.
Add a company holiday calendar to the data layer. The PTO calculation tool subtracts company holidays from the requested range before computing the days charged, ensuring employees are not double-penalized for days the office is already closed.
#HRFAQ #PTOManagement #Benefits #EmployeeSelfService #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
The 2026 desktop AI agent landscape — ServiceNow Project Arc, Anthropic Claude offerings, OpenAI agents, and Google Mariner. A buyer's map.
An agentic-AI perspective on Anthropic Skills system, covering orchestration patterns, tool use, and how agent tooling fits production agent stacks.
Enterprise CIO Guide perspective on Comet's general-availability launch put an agentic browser in front of millions of consumers, and it works better than the demos suggested.
Enterprise CIO Guide perspective on Harvey AI's enterprise rollout numbers show legal agents have moved past the pilot stage at AmLaw 100 firms.
Enterprise CIO Guide perspective on Hippocratic AI's deployment numbers show healthcare voice agents are moving from pilot to production across major US health systems.
An agentic-AI perspective on Claude Agent SDK loops, covering orchestration patterns, tool use, and how agent orchestration fits production agent stacks.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco