Skip to main content
Ioana is PPC Romania’s Romanian-speaking voice agent that helps existing customers with invoice and payment questions by checking balances, payment status and explaining payment methods after Electel/Gaztel identification. The agent handles calls routed from IVR on the invoices branch.

View Agent

Open in Wonderful Platform

Overview

FieldValue
MarketUtilities - Billing Support
VerticalUtilities
ModelGPT Realtime (gpt-realtime) with task model GPT-5.2
CompanyPPC
LanguageRomanian only
ChannelsVoice

Skills

  • identification - Identifies customer accounts using Electel/Gaztel codes or Connection ID, calls check_context_metadata immediately, and sets the active account for the rest of the call
  • billing_and_payments - Handles invoice and balance inquiries (amount due, overdue invoices, paid/unpaid status) and allows customers to report proof of payment (demoplata) for disputed invoices
  • payment_methods - Explains how customers can pay (ATM, cash, bank transfer, internet banking, direct debit, etc.) strictly based on the approved payment-method knowledge base tool
  • invoice_copy - Sends a copy of the customer’s invoice via SMS after confirming the active account and the SMS send action

Key Tools

ToolPurpose
identify_and_get_status()Sets up authentication by calling 2 APIs in parallel (Electel/Gaztel) and stores customer data in KV for faster access
invoice_and_balance()Retrieves invoice and balance information including amount due, overdue invoices, payment status, and due dates from PPC systems
report_proof_of_payment()Records proof of payment (demoplata) when customers claim they’ve already paid an invoice, matching invoice amounts against stored invoices
get_payment_method_details()Answers user questions about payment methods by querying a Gemini model with file_search over a predefined PPC knowledge base
get_invoice()Retrieves invoice copy from database according to customer ID for SMS delivery
check_context_metadata()Checks context metadata immediately after switching to identification skill
summary_and_forward()Summarizes the call before forwarding to a human agent with relevant information
end_conversation()Ends the conversation when there’s no need to forward to a human agent
save_start_time()Saves the start time in KV using start_time as a timestamp for metrics tracking

Prompting Techniques

Multi-Skill Architecture: The agent uses a multi-skill approach where it dynamically switches between specialized skills (identification, billing_and_payments, payment_methods, invoice_copy) based on customer needs. Only one skill is active at a time to ensure focused assistance. Professional Romanian Tone: The agent maintains a professional, warm, and concise tone in Romanian. It asks one question at a time, uses polite forms of asking, and avoids direct imperatives like “spune-mi”. When customers have debt, it states it clearly without judgment. Context-Aware Instructions: The agent is instructed that customers have already selected “invoices” in the IVR and have been greeted in the first system message, so it should not reintroduce itself. It uses Romanian language with occasional English words and handles Romanian phone numbers and Romanian-specific terms. Specialized Transcription Context: Uses Soniox transcription with extensive Romanian domain context including PPC-specific terms, invoice terminology, payment methods, and Romanian city/name examples for better accuracy.
You are **IOANA**, a helpful and professional Voice AI Agent for **P-P-C Romania**, supporting **invoice and billing questions only**.

Your goal is to assist existing customers with their invoice according to the scope's description.

Ask **one question at a time**.

Lessons Learned

What worked
  • Multi-skill architecture allows focused handling of different customer needs (identification, billing, payment methods, invoice copy)
  • Parallel API calls in identification tool (identify_and_get_status) for faster authentication
  • Comprehensive Romanian transcription context with domain-specific terms significantly improves accuracy
  • Structured tool-based approach for each skill ensures consistent data retrieval and actions
  • Dynamic, case-specific instructions instead of exhaustive prompt conditions: Rather than including all possible scenarios in the main prompt (e.g., “if invoice is paid, say X; if unpaid, say Y; if credit exists, say Z…”), tools generate targeted instructions dynamically based on the actual data state. This approach:
    • Reduces prompt complexity and token usage
    • Ensures the agent receives only relevant, actionable guidance for the current situation
    • Makes the system more maintainable as new cases can be handled in code logic rather than prompt updates
    Example from invoice_and_balance() tool:
    // Generate minimal, clear English instructions based on actual data state
    const instructions: string[] = [];
    
    // Payment status instructions - dynamically generated based on actual payment state
    if (isInvoicePaid) {
      instructions.push(`CRITICAL: Invoice payment status: PAID (este achitata). 
        When stating payment status, use 'este achitata' (is paid), 
        NOT 'deja confirmata' (already confirmed).`);
    } else if (paymentStatus === "NOT_PAID") {
      instructions.push(`Payment status: Most recent invoice is not paid.`);
    }
    
    // Credit vs Invoice logic - only included when relevant
    if (shouldOnlyMentionCredit) {
      instructions.push(`CRITICAL: Current invoice amount is null/unknown, 
        but credit has value (${balance.credit_ron} RON). 
        When user asks about amount due, mention ONLY the credit amount.`);
    }
    
    // Invoice presentation - only included if invoice exists
    if (hasCurrent && !shouldOnlyMentionCredit) {
      instructions.push(`Most recent invoice: ${currentInvoice.amount_ron} RON, 
        due ${currentInvoice.due_date}. 
        Present this invoice separately when user asks about invoices.`);
    }
    
    result.agent_context = instructions.join(" ");
    
    This ensures the agent receives precise, contextual guidance rather than parsing through all possible conditions in the prompt.
  • Separation of data retrieval from presentation: The identification tool (identify_and_get_status) fetches and normalizes all customer data from APIs, stores it in KV, but intentionally does not output any profile information to avoid the agent accidentally mentioning customer details prematurely. Only when the billing tool (invoice_and_balance) is called does it retrieve the relevant data from KV and generate contextual instructions for the agent to use. This separation ensures:
    • Data is fetched once during identification and reused efficiently
    • The agent only receives information when it’s contextually relevant to the conversation
    • Reduced risk of the agent mentioning customer details before they’re needed or appropriate Example pattern:
    // In identify_and_get_status() - fetch and store, but don't output profile info
    await context.kv.set("account_info", {
      eneltel: normalizedCode,
      name: customerName,
      address: address,
      // ... all data stored
    });
    
    return {
      result: {
        status: "success",
        identified: true,
        // NO customer name or profile details in agent_instructions
        agent_instructions: "Check conversation history for user intent..."
      }
    };
    
    // Later, in invoice_and_balance() - retrieve and generate contextual instructions
    const accountInfo = await context.kv.get("account_info");
    const invoiceInfo = await context.kv.get("invoice_info");
    
    // Only generate instructions about data that's relevant NOW
    if (hasCurrent && !shouldOnlyMentionCredit) {
      instructions.push(`Most recent invoice: ${currentInvoice.amount_ron} RON...`);
    }
    
Challenges
  • Handling Romanian language nuances and pronunciation of bank names/acronyms (solved with diacritics rules for terms like “PPC” → “pipisii”, “BCR” → “becere”)
  • Managing multiple invoices when customers report payment for several invoices at once (solved with parallel processing and matching logic)