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# For EU data processing, use: "wss://api.eu.deepgram.com/v1/agent/converse"
16
17AUDIO_SETTINGS = {
18 "input": {
19 "encoding": "linear16",
20 "sample_rate": USER_AUDIO_SAMPLE_RATE,
21 },
22 "output": {
23 "encoding": "linear16",
24 "sample_rate": AGENT_AUDIO_SAMPLE_RATE,
25 "container": "none",
26 },
27}
28
29LISTEN_SETTINGS = {
30 "provider": {
31 "type": "deepgram",
32 "model": "nova-3",
33 }
34}
35
36THINK_SETTINGS = {
37 "provider": {
38 "type": "open_ai",
39 "model": "gpt-4o-mini",
40 "temperature": 0.7,
41 },
42 "prompt": PROMPT_TEMPLATE,
43 "functions": FUNCTION_DEFINITIONS,
44}
45
46SPEAK_SETTINGS = {
47 "provider": {
48 "type": "deepgram",
49 "model": VOICE,
50 }
51}
52
53AGENT_SETTINGS = {
54 "language": "en",
55 "listen": LISTEN_SETTINGS,
56 "think": THINK_SETTINGS,
57 "speak": SPEAK_SETTINGS,
58 "greeting": FIRST_MESSAGE,
59}
60
61SETTINGS = {"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