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 the AgentTemplates 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.

Python
1import json
2from datetime import datetime, timedelta
3import asyncio
4from 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 NamePurpose
find_customerLookup by phone, email, or ID; normalizes input
get_appointmentsRetrieve all appointments for a customer
get_ordersRetrieve order history for a customer
create_appointmentSchedule a new appointment
check_availabilityFind available appointment slots
agent_fillerProvide conversational filler (requires websocket param)
end_callEnd the conversation gracefully (requires websocket param)

Find Customer

Python
1async 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

Python
1async 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

Python
1async 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

Python
1async 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

Python
1async 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

Python
1async 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

Python
1async 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
Python
1# Function definitions that will be sent to the Voice Agent API
2FUNCTION_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.

Python
1# Map function names to their implementations
2FUNCTION_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.

Python
1from common.agent_functions import FUNCTION_DEFINITIONS
2from datetime import datetime
3
4
5# Template for the prompt that will be formatted with current date
6PROMPT_TEMPLATE = """
7
8CURRENT DATE AND TIME CONTEXT:
9Today 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
11PERSONALITY & 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
17HANDLING 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
24VERBALLY SPELLING IDs TO CUSTOMERS:
25When 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
28Example: For CUST0222, say "customer zero two two two"
29Example: For ORD0089, say "O-R-D zero zero eight nine"
30
31FUNCTION RESPONSES:
32When receiving function results, format responses naturally as a customer service agent would:
33
341. 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
382. 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
423. 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
464. 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
50EXAMPLES 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
55EXAMPLES 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
60FILLER PHRASES:
61IMPORTANT: Never generate filler phrases (like "Let me check that", "One moment", etc.) directly in your responses.
62Instead, ALWAYS use the agent_filler function when you need to indicate you're about to look something up.
63
64Examples 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
69Correct pattern to follow:
701. 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.)
732. Only speak again after you have the actual information to share
74
75Remember: 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.

Python
1VOICE = "aura-2-thalia-en"
2
3# this gets updated by the agent template
4FIRST_MESSAGE = ""
5
6# audio settings
7USER_AUDIO_SAMPLE_RATE = 48000
8USER_AUDIO_SECS_PER_CHUNK = 0.05
9USER_AUDIO_SAMPLES_PER_CHUNK = round(USER_AUDIO_SAMPLE_RATE * USER_AUDIO_SECS_PER_CHUNK)
10
11AGENT_AUDIO_SAMPLE_RATE = 16000
12AGENT_AUDIO_BYTES_PER_SEC = 2 * AGENT_AUDIO_SAMPLE_RATE
13
14VOICE_AGENT_URL = "wss://agent.deepgram.com/v1/agent/converse"
15
16AUDIO_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
28LISTEN_SETTINGS = {
29 "provider": {
30 "type": "deepgram",
31 "model": "nova-3",
32 }
33}
34
35THINK_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
45SPEAK_SETTINGS = {
46 "provider": {
47 "type": "deepgram",
48 "model": VOICE,
49 }
50}
51
52AGENT_SETTINGS = {
53 "language": "en",
54 "listen": LISTEN_SETTINGS,
55 "think": THINK_SETTINGS,
56 "speak": SPEAK_SETTINGS,
57 "greeting": FIRST_MESSAGE,
58}
59
60SETTINGS = {"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.

Python
1class 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.

Python
1settings = 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.