Build A Function Call
Learn how to build a Function Call to use with your Agent.
This guide walks you through building a function call for a demo Voice Agent application. For the complete code, see the code repository.
Getting Started
You’ll create two files:
agent_functions.py
: Contains async functions and configuration for customer lookups, appointments, and order management.agent_templates.py
: Defines the agent prompt, settings, and theAgentTemplates
factory class for industry-specific configuration.
Prerequisites
- Python 3.7+
- Familiarity with Python
- An understanding of how to use Python Virtual environments.
- Familiarity with the Deepgram Voice Agent API
Create agent_functions.py
This guide doesn’t cover the development of the business logic for this application. Please see business_logic.pyfor more details.
First, create a file called: agent_functions.py
. Then in agent_functions.py
set up the dependencies and import the business logic.
1 import json 2 from datetime import datetime, timedelta 3 import asyncio 4 from business_logic import ( 5 get_customer, 6 get_customer_appointments, 7 get_customer_orders, 8 schedule_appointment, 9 get_available_appointment_slots, 10 prepare_agent_filler_message, 11 prepare_farewell_message 12 )
Implement the Functions
We’ll implement the following functions in agent_functions.py
to handle customer and appointment management:
Function Name | Purpose |
---|---|
find_customer | Lookup by phone, email, or ID; normalizes input |
get_appointments | Retrieve all appointments for a customer |
get_orders | Retrieve order history for a customer |
create_appointment | Schedule a new appointment |
check_availability | Find available appointment slots |
agent_filler | Provide conversational filler (requires websocket param) |
end_call | End the conversation gracefully (requires websocket param) |
Find Customer
1 async def find_customer(params): 2 """Look up a customer by phone, email, or ID.""" 3 phone = params.get("phone") 4 email = params.get("email") 5 customer_id = params.get("customer_id") 6 7 result = await get_customer(phone=phone, email=email, customer_id=customer_id) 8 return result
Get Appointments
1 async def get_appointments(params): 2 """Get appointments for a customer.""" 3 customer_id = params.get("customer_id") 4 if not customer_id: 5 return {"error": "customer_id is required"} 6 7 result = await get_customer_appointments(customer_id) 8 return result
Get Orders
1 async def get_orders(params): 2 """Get orders for a customer.""" 3 customer_id = params.get("customer_id") 4 if not customer_id: 5 return {"error": "customer_id is required"} 6 7 result = await get_customer_orders(customer_id) 8 return result
Create Appointment
1 async def create_appointment(params): 2 """Schedule a new appointment.""" 3 customer_id = params.get("customer_id") 4 date = params.get("date") 5 service = params.get("service") 6 7 if not all([customer_id, date, service]): 8 return {"error": "customer_id, date, and service are required"} 9 10 result = await schedule_appointment(customer_id, date, service) 11 return result
Check Availability
1 async def check_availability(params): 2 """Check available appointment slots.""" 3 start_date = params.get("start_date") 4 end_date = params.get("end_date", (datetime.fromisoformat(start_date) + timedelta(days=7)).isoformat()) 5 6 if not start_date: 7 return {"error": "start_date is required"} 8 9 result = await get_available_appointment_slots(start_date, end_date) 10 return result
Agent Filler
1 async def agent_filler(websocket, params): 2 """ 3 Handle agent filler messages while maintaining proper function call protocol. 4 """ 5 result = await prepare_agent_filler_message(websocket, **params) 6 return result
End Call
1 async def end_call(websocket, params): 2 """ 3 End the conversation and close the connection. 4 """ 5 farewell_type = params.get("farewell_type", "general") 6 result = await prepare_farewell_message(websocket, farewell_type) 7 return result
Create Function Definitions
Next in agent_functions.py
we’ll setup FUNCTION_DEFINITIONS
which is an array that defines the API contract for the Voice Agent system. It specifies all available operations, their parameters, and usage guidelines.
Each function definition follows a JSON Schema format with:
- Name
- Description
- Parameters specification
- Required fields
- Enumerated values where applicable
1 # Function definitions that will be sent to the Voice Agent API 2 FUNCTION_DEFINITIONS = [ 3 { 4 "name": "agent_filler", 5 "description": """Use this function to provide natural conversational filler before looking up information. 6 ALWAYS call this function first with message_type='lookup' when you're about to look up customer information. 7 After calling this function, you MUST immediately follow up with the appropriate lookup function (e.g., find_customer).""", 8 "parameters": { 9 "type": "object", 10 "properties": { 11 "message_type": { 12 "type": "string", 13 "description": "Type of filler message to use. Use 'lookup' when about to search for information.", 14 "enum": ["lookup", "general"] 15 } 16 }, 17 "required": ["message_type"] 18 } 19 }, 20 { 21 "name": "find_customer", 22 "description": """Look up a customer's account information. Use context clues to determine what type of identifier the user is providing: 23 24 Customer ID formats: 25 - Numbers only (e.g., '169', '42') → Format as 'CUST0169', 'CUST0042' 26 - With prefix (e.g., 'CUST169', 'customer 42') → Format as 'CUST0169', 'CUST0042' 27 28 Phone number recognition: 29 - Standard format: '555-123-4567' → Format as '+15551234567' 30 - With area code: '(555) 123-4567' → Format as '+15551234567' 31 - Spoken naturally: 'five five five, one two three, four five six seven' → Format as '+15551234567' 32 - International: '+1 555-123-4567' → Use as is 33 - Always add +1 country code if not provided 34 35 Email address recognition: 36 - Spoken naturally: 'my email is john dot smith at example dot com' → Format as '[email protected]' 37 - With domain: '[email protected]' → Use as is 38 - Spelled out: 'j o h n at example dot com' → Format as '[email protected]'""", 39 "parameters": { 40 "type": "object", 41 "properties": { 42 "customer_id": { 43 "type": "string", 44 "description": "Customer's ID. Format as CUSTXXXX where XXXX is the number padded to 4 digits with leading zeros. Example: if user says '42', pass 'CUST0042'" 45 }, 46 "phone": { 47 "type": "string", 48 "description": """Phone number with country code. Format as +1XXXXXXXXXX: 49 - Add +1 if not provided 50 - Remove any spaces, dashes, or parentheses 51 - Convert spoken numbers to digits 52 Example: 'five five five one two three four five six seven' → '+15551234567'""" 53 }, 54 "email": { 55 "type": "string", 56 "description": """Email address in standard format: 57 - Convert 'dot' to '.' 58 - Convert 'at' to '@' 59 - Remove spaces between spelled out letters 60 Example: 'j dot smith at example dot com' → '[email protected]'""" 61 } 62 } 63 } 64 }, 65 { 66 "name": "get_appointments", 67 "description": """Retrieve all appointments for a customer. Use this function when: 68 - A customer asks about their upcoming appointments 69 - A customer wants to know their appointment schedule 70 - A customer asks 'When is my next appointment?' 71 72 Always verify you have the customer's account first using find_customer before checking appointments.""", 73 "parameters": { 74 "type": "object", 75 "properties": { 76 "customer_id": { 77 "type": "string", 78 "description": "Customer's ID in CUSTXXXX format. Must be obtained from find_customer first." 79 } 80 }, 81 "required": ["customer_id"] 82 } 83 }, 84 { 85 "name": "get_orders", 86 "description": """Retrieve order history for a customer. Use this function when: 87 - A customer asks about their orders 88 - A customer wants to check order status 89 - A customer asks questions like 'Where is my order?' or 'What did I order?' 90 91 Always verify you have the customer's account first using find_customer before checking orders.""", 92 "parameters": { 93 "type": "object", 94 "properties": { 95 "customer_id": { 96 "type": "string", 97 "description": "Customer's ID in CUSTXXXX format. Must be obtained from find_customer first." 98 } 99 }, 100 "required": ["customer_id"] 101 } 102 }, 103 { 104 "name": "create_appointment", 105 "description": """Schedule a new appointment for a customer. Use this function when: 106 - A customer wants to book a new appointment 107 - A customer asks to schedule a service 108 109 Before scheduling: 110 1. Verify customer account exists using find_customer 111 2. Check availability using check_availability 112 3. Confirm date/time and service type with customer before booking""", 113 "parameters": { 114 "type": "object", 115 "properties": { 116 "customer_id": { 117 "type": "string", 118 "description": "Customer's ID in CUSTXXXX format. Must be obtained from find_customer first." 119 }, 120 "date": { 121 "type": "string", 122 "description": "Appointment date and time in ISO format (YYYY-MM-DDTHH:MM:SS). Must be a time slot confirmed as available." 123 }, 124 "service": { 125 "type": "string", 126 "description": "Type of service requested. Must be one of the following: Consultation, Follow-up, Review, or Planning", 127 "enum": ["Consultation", "Follow-up", "Review", "Planning"] 128 } 129 }, 130 "required": ["customer_id", "date", "service"] 131 } 132 }, 133 { 134 "name": "check_availability", 135 "description": """Check available appointment slots within a date range. Use this function when: 136 - A customer wants to know available appointment times 137 - Before scheduling a new appointment 138 - A customer asks 'When can I come in?' or 'What times are available?' 139 140 After checking availability, present options to the customer in a natural way, like: 141 'I have openings on [date] at [time] or [date] at [time]. Which works better for you?'""", 142 "parameters": { 143 "type": "object", 144 "properties": { 145 "start_date": { 146 "type": "string", 147 "description": "Start date in ISO format (YYYY-MM-DDTHH:MM:SS). Usually today's date for immediate availability checks." 148 }, 149 "end_date": { 150 "type": "string", 151 "description": "End date in ISO format. Optional - defaults to 7 days after start_date. Use for specific date range requests." 152 } 153 }, 154 "required": ["start_date"] 155 } 156 }, 157 { 158 "name": "end_call", 159 "description": """End the conversation and close the connection. Call this function when: 160 - User says goodbye, thank you, etc. 161 - User indicates they're done ("that's all I need", "I'm all set", etc.) 162 - User wants to end the conversation 163 164 Examples of triggers: 165 - "Thank you, bye!" 166 - "That's all I needed, thanks" 167 - "Have a good day" 168 - "Goodbye" 169 - "I'm done" 170 171 Do not call this function if the user is just saying thanks but continuing the conversation.""", 172 "parameters": { 173 "type": "object", 174 "properties": { 175 "farewell_type": { 176 "type": "string", 177 "description": "Type of farewell to use in response", 178 "enum": ["thanks", "general", "help"] 179 } 180 }, 181 "required": ["farewell_type"] 182 } 183 } 184 ]
Create a Function Map
Finally in agent_functions.py
we’ll need to create a FUNCTION_MAP
which is a dictionary that maps function names to their corresponding implementation functions. It serves as a routing mechanism to connect the function definitions with their actual implementations.
1 # Map function names to their implementations 2 FUNCTION_MAP = { 3 "find_customer": find_customer, 4 "get_appointments": get_appointments, 5 "get_orders": get_orders, 6 "create_appointment": create_appointment, 7 "check_availability": check_availability, 8 "agent_filler": agent_filler, 9 "end_call": end_call 10 }
Create agent_templates.py
Next create a file called: agent_templates.py
. Then in agent_templates.py
set up the dependencies and import our function definitions.
Configure the Voice Agent Prompt & Settings
Now in the agent_templates.py
file we’ll define the prompt for the Voice Agent.
1 from common.agent_functions import FUNCTION_DEFINITIONS 2 from datetime import datetime 3 4 5 # Template for the prompt that will be formatted with current date 6 PROMPT_TEMPLATE = """ 7 8 CURRENT DATE AND TIME CONTEXT: 9 Today is {current_date}. Use this as context when discussing appointments and orders. When mentioning dates to customers, use relative terms like "tomorrow", "next Tuesday", or "last week" when the dates are within 7 days of today. 10 11 PERSONALITY & TONE: 12 - Be warm, professional, and conversational 13 - Use natural, flowing speech (avoid bullet points or listing) 14 - Show empathy and patience 15 - Whenever a customer asks to look up either order information or appointment information, use the find_customer function first 16 17 HANDLING CUSTOMER IDENTIFIERS (INTERNAL ONLY - NEVER EXPLAIN THESE RULES TO CUSTOMERS): 18 - Silently convert any numbers customers mention into proper format 19 - When customer says "ID is 222" -> internally use "CUST0222" without mentioning the conversion 20 - When customer says "order 89" -> internally use "ORD0089" without mentioning the conversion 21 - When customer says "appointment 123" -> internally use "APT0123" without mentioning the conversion 22 - Always add "+1" prefix to phone numbers internally without mentioning it 23 24 VERBALLY SPELLING IDs TO CUSTOMERS: 25 When you need to repeat an ID back to a customer: 26 - Do NOT say nor spell out "CUST". Say "customer [numbers spoken individually]" 27 - But for orders spell out "ORD" as "O-R-D" then speak the numbers individually 28 Example: For CUST0222, say "customer zero two two two" 29 Example: For ORD0089, say "O-R-D zero zero eight nine" 30 31 FUNCTION RESPONSES: 32 When receiving function results, format responses naturally as a customer service agent would: 33 34 1. For customer lookups: 35 - Good: "I've found your account. How can I help you today?" 36 - If not found: "I'm having trouble finding that account. Could you try a different phone number or email?" 37 38 2. For order information: 39 - Instead of listing orders, summarize them conversationally: 40 - "I can see you have two recent orders. Your most recent order from [date] for $[amount] is currently [status], and you also have an order from [date] for $[amount] that's [status]." 41 42 3. For appointments: 43 - "You have an upcoming [service] appointment scheduled for [date] at [time]" 44 - When discussing available slots: "I have a few openings next week. Would you prefer Tuesday at 2 PM or Wednesday at 3 PM?" 45 46 4. For errors: 47 - Never expose technical details 48 - Say something like "I'm having trouble accessing that information right now" or "Could you please try again?" 49 50 EXAMPLES OF GOOD RESPONSES: 51 ✓ "Let me look that up for you... I can see you have two recent orders." 52 ✓ "Your customer ID is zero two two two." 53 ✓ "I found your order, O-R-D zero one two three. It's currently being processed." 54 55 EXAMPLES OF BAD RESPONSES (AVOID): 56 ✗ "I'll convert your ID to the proper format CUST0222" 57 ✗ "Let me add the +1 prefix to your phone number" 58 ✗ "The system requires IDs to be in a specific format" 59 60 FILLER PHRASES: 61 IMPORTANT: Never generate filler phrases (like "Let me check that", "One moment", etc.) directly in your responses. 62 Instead, ALWAYS use the agent_filler function when you need to indicate you're about to look something up. 63 64 Examples of what NOT to do: 65 - Responding with "Let me look that up for you..." without a function call 66 - Saying "One moment please" or "Just a moment" without a function call 67 - Adding filler phrases before or after function calls 68 69 Correct pattern to follow: 70 1. When you need to look up information: 71 - First call agent_filler with message_type="lookup" 72 - Immediately follow with the relevant lookup function (find_customer, get_orders, etc.) 73 2. Only speak again after you have the actual information to share 74 75 Remember: ANY phrase indicating you're about to look something up MUST be done through the agent_filler function, never through direct response text. 76 """
Next in the same file we’ll define the settings for the Voice Agent.
1 VOICE = "aura-2-thalia-en" 2 3 # this gets updated by the agent template 4 FIRST_MESSAGE = "" 5 6 # audio settings 7 USER_AUDIO_SAMPLE_RATE = 48000 8 USER_AUDIO_SECS_PER_CHUNK = 0.05 9 USER_AUDIO_SAMPLES_PER_CHUNK = round(USER_AUDIO_SAMPLE_RATE * USER_AUDIO_SECS_PER_CHUNK) 10 11 AGENT_AUDIO_SAMPLE_RATE = 16000 12 AGENT_AUDIO_BYTES_PER_SEC = 2 * AGENT_AUDIO_SAMPLE_RATE 13 14 VOICE_AGENT_URL = "wss://agent.deepgram.com/v1/agent/converse" 15 16 AUDIO_SETTINGS = { 17 "input": { 18 "encoding": "linear16", 19 "sample_rate": USER_AUDIO_SAMPLE_RATE, 20 }, 21 "output": { 22 "encoding": "linear16", 23 "sample_rate": AGENT_AUDIO_SAMPLE_RATE, 24 "container": "none", 25 }, 26 } 27 28 LISTEN_SETTINGS = { 29 "provider": { 30 "type": "deepgram", 31 "model": "nova-3", 32 } 33 } 34 35 THINK_SETTINGS = { 36 "provider": { 37 "type": "open_ai", 38 "model": "gpt-4o-mini", 39 "temperature": 0.7, 40 }, 41 "prompt": PROMPT_TEMPLATE, 42 "functions": FUNCTION_DEFINITIONS, 43 } 44 45 SPEAK_SETTINGS = { 46 "provider": { 47 "type": "deepgram", 48 "model": VOICE, 49 } 50 } 51 52 AGENT_SETTINGS = { 53 "language": "en", 54 "listen": LISTEN_SETTINGS, 55 "think": THINK_SETTINGS, 56 "speak": SPEAK_SETTINGS, 57 "greeting": FIRST_MESSAGE, 58 } 59 60 SETTINGS = {"type": "Settings", "audio": AUDIO_SETTINGS, "agent": AGENT_SETTINGS}
Finally in the same file we’ll define the factory class AgentTemplates
which will be used to configure the Voice Agent. This class will be used to configure the Voice Agent for different industries.
1 class AgentTemplates: 2 PROMPT_TEMPLATE = PROMPT_TEMPLATE 3 4 def __init__( 5 self, 6 industry="tech_support", 7 voiceModel="aura-2-thalia-en", 8 voiceName="", 9 ): 10 self.voiceName = voiceName 11 self.voiceModel = voiceModel 12 self.personality = "" 13 self.company = "" 14 self.first_message = "" 15 self.capabilities = "" 16 17 self.industry = industry 18 19 self.prompt = self.PROMPT_TEMPLATE.format( 20 current_date=datetime.now().strftime("%A, %B %d, %Y") 21 ) 22 23 self.voice_agent_url = VOICE_AGENT_URL 24 self.settings = SETTINGS 25 self.user_audio_sample_rate = USER_AUDIO_SAMPLE_RATE 26 self.user_audio_secs_per_chunk = USER_AUDIO_SECS_PER_CHUNK 27 self.user_audio_samples_per_chunk = USER_AUDIO_SAMPLES_PER_CHUNK 28 self.agent_audio_sample_rate = AGENT_AUDIO_SAMPLE_RATE 29 self.agent_audio_bytes_per_sec = AGENT_AUDIO_BYTES_PER_SEC 30 31 match self.industry: 32 case "tech_support": 33 self.tech_support() 34 case "healthcare": 35 self.healthcare() 36 case "banking": 37 self.banking() 38 case "pharmaceuticals": 39 self.pharmaceuticals() 40 case "retail": 41 self.retail() 42 43 self.first_message = f"Hello! I'm {self.voiceName} from {self.company} customer service. {self.capabilities} How can I help you today?" 44 45 self.settings["agent"]["speak"]["provider"]["model"] = self.voiceModel 46 self.settings["agent"]["think"]["prompt"] = self.prompt 47 self.settings["agent"]["greeting"] = self.first_message 48 49 self.prompt = self.personality + "\n\n" + self.prompt 50 51 def tech_support( 52 self, company="TechStyle", agent_voice="aura-2-thalia-en", voiceName="" 53 ): 54 if voiceName == "": 55 voiceName = self.get_voice_name_from_model(agent_voice) 56 self.voiceName = voiceName 57 self.company = company 58 self.voiceModel = agent_voice 59 60 self.personality = f"You are {self.voiceName}, a friendly and professional customer service representative for {self.company}, an online electronics and accessories retailer. Your role is to assist customers with orders, appointments, and general inquiries." 61 62 self.capabilities = "I'd love to help you with your order or appointment." 63 64 def healthcare( 65 self, company="HealthFirst", agent_voice="aura-2-andromeda-en", voiceName="" 66 ): 67 if voiceName == "": 68 voiceName = self.get_voice_name_from_model(agent_voice) 69 self.voiceName = voiceName 70 self.company = company 71 self.voiceModel = agent_voice 72 73 self.personality = f"You are {self.voiceName}, a compassionate and knowledgeable healthcare assistant for {self.company}, a leading healthcare provider. Your role is to assist patients with appointments, medical inquiries, and general health information." 74 75 self.capabilities = "I can help you schedule appointments or answer questions about our services." 76 77 def banking( 78 self, company="SecureBank", agent_voice="aura-2-apollo-en", voiceName="" 79 ): 80 if voiceName == "": 81 voiceName = self.get_voice_name_from_model(agent_voice) 82 self.voiceName = voiceName 83 self.company = company 84 self.voiceModel = agent_voice 85 86 self.personality = f"You are {self.voiceName}, a professional and trustworthy banking representative for {self.company}, a secure financial institution. Your role is to assist customers with account inquiries, transactions, and financial services." 87 88 self.capabilities = ( 89 "I can assist you with your account or any banking services you need." 90 ) 91 92 def pharmaceuticals( 93 self, company="MedLine", agent_voice="aura-2-helena-en", voiceName="" 94 ): 95 if voiceName == "": 96 voiceName = self.get_voice_name_from_model(agent_voice) 97 self.voiceName = voiceName 98 self.company = company 99 self.voiceModel = agent_voice 100 101 self.personality = f"You are {self.voiceName}, a professional and trustworthy pharmaceutical representative for {self.company}, a secure pharmaceutical company. Your role is to assist customers with account inquiries, transactions, and appointments. You MAY NOT provide medical advice." 102 103 self.capabilities = "I can assist you with your account or appointments." 104 105 def retail(self, company="StyleMart", agent_voice="aura-2-aries-en", voiceName=""): 106 if voiceName == "": 107 voiceName = self.get_voice_name_from_model(agent_voice) 108 self.voiceName = voiceName 109 self.company = company 110 self.voiceModel = agent_voice 111 112 self.personality = f"You are {self.voiceName}, a friendly and attentive retail associate for {self.company}, a trendy clothing and accessories store. Your role is to assist customers with product inquiries, orders, and style recommendations." 113 114 self.capabilities = ( 115 "I can help you find the perfect item or check on your order status." 116 ) 117 118 def travel(self, company="TravelTech", agent_voice="aura-2-arcas-en", voiceName=""): 119 if voiceName == "": 120 voiceName = self.get_voice_name_from_model(agent_voice) 121 self.voiceName = voiceName 122 self.company = company 123 self.voiceModel = agent_voice 124 125 self.personality = f"You are {self.voiceName}, a friendly and professional customer service representative for {self.company}, a tech-forward travel agency. Your role is to assist customers with travel bookings, appointments, and general inquiries." 126 127 self.capabilities = ( 128 "I'd love to help you with your travel bookings or appointments." 129 ) 130 131 @staticmethod 132 def get_available_industries(): 133 """Return a dictionary of available industries with display names""" 134 return { 135 "tech_support": "Tech Support", 136 "healthcare": "Healthcare", 137 "banking": "Banking", 138 "pharmaceuticals": "Pharmaceuticals", 139 "retail": "Retail", 140 "travel": "Travel", 141 } 142 143 def get_voice_name_from_model(self, model): 144 return model.split("-")[2].split("-")[0].capitalize()
Call the functions from client.py
This guide doesn’t cover the development of the client for this application. Please see client.py for more details.
In the client.py
file we’ll need reference agent_templates.py
which will define the settings for the Voice Agent.
1 settings = self.agent_templates.settings
What’s Next?
- For more ideas and function code samples for using Function Calling with your Agent check out this repository.