Skip to content
Learn Agentic AI
Learn Agentic AI14 min read1 views

Building an HR FAQ Agent: Policy Questions, Benefits Inquiries, and PTO Management

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.

Why HR Teams Need an FAQ Agent

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.

Policy Knowledge Base

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.

flowchart TD
    START["Building an HR FAQ Agent: Policy Questions, Benef…"] --> A
    A["Why HR Teams Need an FAQ Agent"]
    A --> B
    B["Policy Knowledge Base"]
    B --> C
    C["PTO Balance and Request Tools"]
    C --> D
    D["Benefits Lookup Tool"]
    D --> E
    E["Assembling the HR FAQ Agent"]
    E --> F
    F["FAQ"]
    F --> DONE["Key Takeaways"]
    style START fill:#4f46e5,stroke:#4338ca,color:#fff
    style DONE fill:#059669,stroke:#047857,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)

PTO Balance and Request Tools

The PTO system integrates with employee records to show accrued, used, and available balances. The request tool validates dates and submits for approval.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

@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",
    })

Benefits Lookup Tool

@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),
    })

Assembling the HR FAQ Agent

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],
)

FAQ

How do you ensure the agent gives accurate policy answers?

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.

What if an employee asks something the agent cannot answer?

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.

How do you handle PTO requests that span holidays?

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

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

Learn Agentic AI

Fine-Tuning LLMs for Agentic Tasks: When and How to Customize Foundation Models

When fine-tuning beats prompting for AI agents: dataset creation from agent traces, SFT and DPO training approaches, evaluation methodology, and cost-benefit analysis for agentic fine-tuning.

AI Interview Prep

7 Agentic AI & Multi-Agent System Interview Questions for 2026

Real agentic AI and multi-agent system interview questions from Anthropic, OpenAI, and Microsoft in 2026. Covers agent design patterns, memory systems, safety, orchestration frameworks, tool calling, and evaluation.

Learn Agentic AI

Adaptive Thinking in Claude 4.6: How AI Agents Decide When and How Much to Reason

Technical exploration of adaptive thinking in Claude 4.6 — how the model dynamically adjusts reasoning depth, its impact on agent architectures, and practical implementation patterns.

Learn Agentic AI

How NVIDIA Vera CPU Solves the Agentic AI Bottleneck: Architecture Deep Dive

Technical analysis of NVIDIA's Vera CPU designed for agentic AI workloads — why the CPU is the bottleneck, how Vera's architecture addresses it, and what it means for agent performance.

Learn Agentic AI

Claude Opus 4.6 with 1M Context Window: Complete Developer Guide for Agentic AI

Complete guide to Claude Opus 4.6 GA — 1M context at standard pricing, 128K output tokens, adaptive thinking, and production patterns for building agentic AI systems.

Large Language Models

Why Enterprises Need Custom LLMs: Base vs Fine-Tuned Models in 2026

Custom LLMs outperform base models for enterprise use cases by 40-65%. Learn when to fine-tune, RAG, or build custom models — with architecture patterns and ROI data.