By Sagar Shankaran, Founder of CallSphere
Engineer-grade walk-through of function calling on CallSphere (14 healthcare tools, hierarchical handoff) vs Vapi function calling — schemas, routing, errors.
Key takeaways
Function calling is the single most load-bearing primitive in production voice AI. On Vapi, you ship a flat list of tools attached to one assistant; the LLM picks one, Vapi POSTs to your webhook, and waits for a JSON response before continuing the call. On CallSphere, function calling is structured around an OpenAI Realtime session with 14 tools in Healthcare alone, 30+ in Real Estate, 9 in Salon, and per-agent toolsets in IT Helpdesk, all routed by an orchestrator that hands off to specialists rather than letting one model see every tool.
This post is the deep-dive: a real schedule_appointment schema, the routing logic, the error envelope, and a Mermaid sequence showing exactly which actor invokes which tool.
Voice agents fail in three predictable ways once you exceed ~10 tools on a single model:
book_appointment and reschedule_appointment and routinely picks the wrong one.The Vapi approach (one assistant, flat tool list) hits this wall fast. The CallSphere approach (hierarchical agents with scoped toolsets) sidesteps it by giving each specialist agent only the 4-6 tools it actually needs.
Vapi's function calling is straightforward and well-documented:
{
"model": {
"provider": "openai",
"model": "gpt-4o",
"tools": [
{
"type": "function",
"function": {
"name": "schedule_appointment",
"description": "Book a new appointment",
"parameters": {
"type": "object",
"properties": {
"patient_name": { "type": "string" },
"datetime": { "type": "string" },
"provider": { "type": "string" }
},
"required": ["patient_name", "datetime"]
}
},
"server": { "url": "https://your-app.com/webhooks/vapi" }
}
]
}
}
Vapi POSTs to your URL, holds the call open with filler audio, then resumes when your webhook responds. You wear all the orchestration: idempotency keys, retries, cross-tool state, fallback to a human.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent for healthcare in your browser — 60 seconds, no signup.
Where Vapi shines: simple agents with 3-5 tools and a single business domain.
Where it strains: anything with role-based permissions, multi-step flows that branch on prior tool output, or tools whose schemas change per caller (e.g., a returning patient gets different reschedule options than a new one).
CallSphere uses the OpenAI Agents SDK layered on top of the OpenAI Realtime API session. Tools are not flat — they are owned by specialist agents, and the orchestrator decides which specialist to wake up.
The Healthcare voice agent ships with 14 tools split across three specialists:
classify_intent, detect_urgency, route_to_specialistsearch_providers, get_provider_availability, schedule_appointment, reschedule_appointment, cancel_appointment, send_confirmation_smslookup_patient, verify_dob, fetch_recent_visits, request_records_release, flag_for_provider_callbackHere is the actual schedule_appointment tool schema as it ships in the Healthcare backend (NestJS + Prisma):
export const scheduleAppointmentTool = {
type: 'function' as const,
name: 'schedule_appointment',
description:
'Book a new appointment for the verified patient with a specific provider. ' +
'Only call after patient identity is verified via lookup_patient + verify_dob.',
parameters: {
type: 'object',
properties: {
patient_id: {
type: 'string',
description: 'UUID returned by lookup_patient. Never invent.',
},
provider_id: {
type: 'string',
description: 'UUID from search_providers result.',
},
appointment_type: {
type: 'string',
enum: ['new_patient', 'follow_up', 'urgent_care', 'telehealth'],
},
datetime_iso: {
type: 'string',
description: 'ISO 8601 in clinic timezone, must be in availability window',
},
reason: {
type: 'string',
description: 'Free-text chief complaint, max 200 chars',
},
},
required: ['patient_id', 'provider_id', 'appointment_type', 'datetime_iso'],
},
};
Three things to notice:
patient_id and to wait for lookup_patient. That collapses the hallucination class of bug.appointment_type is closed-set, so the model cannot invent emergency_dental_telehealth.The orchestrator uses prompt-routing — the parent agent sees a tiny tool list (hand_off_to_scheduling, hand_off_to_records, escalate_to_human) and the actual specialist tools never enter its context. This:
When the user says "I need to book a follow-up next Tuesday," the orchestrator emits hand_off_to_scheduling with a structured handoff payload. The Scheduling specialist agent wakes up with the full conversation summary plus its own 6-tool list, and runs the booking flow.
Still reading? Stop comparing — try CallSphere live.
See the healthcare AI agent handle a real call — complete, industry-specific, and live in your browser. No signup.
Every tool returns a uniform envelope:
type ToolResult<T> =
| { ok: true; data: T; idempotency_key: string }
| { ok: false; error: { code: string; message: string; retryable: boolean } };
The agent's tool-handling system prompt is trained on this shape, so on retryable: true it tries once with a 750ms backoff, on retryable: false it apologizes and offers human handoff, and on ok: true it confirms verbally.
| Dimension | Vapi | CallSphere |
|---|---|---|
| Tool ownership | Flat list on one assistant | Scoped per specialist agent |
| Max practical tools | ~10 before drift | 30+ across hierarchy |
| Routing | LLM picks from full list | Orchestrator hands off, specialist picks scoped tool |
| Schema enforcement | OpenAI function spec | OpenAI function spec + cross-tool description hints |
| Error envelope | You define | Standard ToolResult<T> shape, agent trained on it |
| Idempotency | DIY in webhook | Built-in idempotency_key in envelope |
| Multi-step flow | Stateless webhooks | Specialist holds intent state until done |
| Tool-time latency | Webhook RTT + filler audio | Local function in same K8s pod for most tools |
| Observability | Vapi dashboard logs | Postgres tool_calls table + Redis trace |
sequenceDiagram
participant Caller
participant Twilio
participant Realtime as OpenAI Realtime
participant Orch as Orchestrator Agent
participant Sched as Scheduling Specialist
participant DB as Postgres + Prisma
Caller->>Twilio: "Book follow-up Tuesday"
Twilio->>Realtime: PCM16 24kHz audio
Realtime->>Orch: transcript event
Orch->>Orch: classify intent (scheduling)
Orch->>Sched: hand_off_to_scheduling(summary, patient_id?)
Sched->>DB: lookup_patient(phone)
DB-->>Sched: { ok: true, patient_id, dob_hash }
Sched->>Caller: "Can you confirm your date of birth?"
Caller->>Sched: "March 4th, 1982"
Sched->>DB: verify_dob(patient_id, "1982-03-04")
DB-->>Sched: { ok: true }
Sched->>DB: get_provider_availability(provider_id, week)
DB-->>Sched: slots[]
Sched->>Caller: "Tuesday at 2:30 with Dr. Patel works?"
Caller->>Sched: "Yes"
Sched->>DB: schedule_appointment(...)
DB-->>Sched: { ok: true, appointment_id, idempotency_key }
Sched->>DB: send_confirmation_sms(patient_id, appointment_id)
Sched->>Caller: "Booked. Text confirmation on its way."
flag_for_provider_callback style escape hatch. Tools that cannot complete should never silently fail — they should escalate.Yes. The Salon and Real Estate front-ends include a tool-builder UI for marketing teams, but the underlying schema is the same OpenAI function spec. Engineers can drop into raw TypeScript anytime.
Yes. The CallSphere SDK accepts custom tool definitions and registers them with the specialist of your choice. Internal tooling at CallSphere uses the exact same registration path.
The default timeout is 4 seconds. On timeout, the tool returns a retryable: true error envelope, the agent retries once, and after a second timeout falls back to graceful escalation. You can override per-tool.
Three layers: scoped specialist toolsets, cross-tool description hints (e.g., "only call after lookup_patient"), and post-hoc gpt-4o-mini audit on the call log to flag suspicious sequences.
For most tools, no. CallSphere tools are usually local TypeScript or Python functions inside the same pod, so latency is sub-50ms. Webhook-style tools that hit external APIs are comparable to Vapi.
Try the interactive demo to see hierarchical tool dispatch live, or read the features overview for the full toolset map across verticals.

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.
Tbilisi professional-services firms serving relocating founders and IT companies use CallSphere AI voice and chat agents to answer enquiries 24/7 in English, Georgian and Russian and book consultations.
A how-to for Colombian education and tutoring SMBs to answer parents and students instantly, book trial classes 24/7 in Spanish and English, and grow enrollment with a CallSphere AI agent.
Ethiopian coffee exporters and cooperatives lose buyer enquiries across time zones. See how a CallSphere AI voice and chat agent answers international coffee buyers 24/7 in Amharic and English.
A practical how-to for Palau eco-resorts and dive operators on capturing every high-value, multilingual enquiry with a CallSphere AI voice and chat agent, while honouring Palau’s marine-conservation commitments.
How salons, spas and wellness SMBs across the UAE, Saudi Arabia and Qatar use CallSphere AI voice and chat agents to capture every booking 24/7 in Arabic, English and expat languages, and cut no-shows.
How estate agents and property managers in Luxembourg City and across the Grand Duchy use CallSphere to capture multilingual viewing and enquiry calls 24/7, GDPR compliant.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI