Optimizing LLMs: Fine-Tuning with Function Calling
Consider a healthcare appointment assistant that interacts with patients to:
- Confirm appointments
- Send follow-up reminders
- Schedules callbacks if patient is busy
Sample Conversation
Patient: Hello? Who is this?
Health Assistant: This is Health AI Assistant. I’m calling to confirm if you’d like to schedule your annual checkup. Would you like me to book an appointment for you?
Patient: Yes, I’ve been planning to get an eye checkup done at the clinic.
Health Assistant: I can help with that. When would you like to schedule your appointment?
Patient: Maybe this Thursday at 3 PM?
Health Assistant: Sounds good! Let me schedule that for you. Please hold on.
Function Call → schedule_appointment (Thursday, 3 PM, Ophthalmologist)
Structuring Fine-Tuning Data for GPT
Fine-tuning data should follow OpenAI’s structured format. When an appointment needs to be scheduled, the function call should be embedded as follows:
{
"role": "assistant",
"content": null,
"function_call": {
"name": "schedule_appointment",
"arguments":
"{ \"appointment_date\": \"This Thursday\", \"appointment_time\": \"3 PM\", \"doctor_specialty\": \"Ophthalmologist\"
}"
}
}
-
**role**
defines whether the speaker is the assistant or the user. -
**function_call**
contains the function nameschedule_appointment
and the required parameters “appointment_date
,appointment_time
,doctor_specialty"
For an official guide on fine-tuning (data validation, data preperation), check out OpenAI’s documentation: 🔗 Fine-Tuning Guide
Full Fine-Tuning Data Format for a Conversation
{
"messages": [
{ "role": "user", "content": "Hello? Who is this?" },
{ "role": "assistant", "content": "This is Health AI Assistant. I’m calling to confirm if you’d like to schedule your annual checkup. Would you like me to book an appointment for you?" },
{ "role": "user", "content": "Yes, I’ve been planning to get an eye checkup done at the clinic." },
{ "role": "assistant", "content": "I can help with that. When would you like to schedule your appointment?" },
{ "role": "user", "content": "Maybe this Thursday at 3 PM?" },
{ "role": "assistant", "content": "Sounds good! Let me schedule that for you. Please hold on." },
{ "role": "assistant", "content": null, "function_call": {
"name": "schedule_appointment",
"arguments":
"{ \"appointment_date\": \"This Thursday\", \"appointment_time\": \"3 PM\", \"doctor_specialty\": \"Ophthalmologist\"
}"
}
}
]
}
Defining Additional Function Calls
Follow-Up Reminder
{
"role": "assistant",
"content": null,
"function_call": {
"name": "follow_up_reminder",
"arguments":
"{ \"appointment_date\": \"Next Monday\", \"appointment_time\": \"10 AM\"
}"
}
}
Schedule Callback
{
"role": "assistant",
"content": null,
"function_call": {
"name": "schedule_callback",
"arguments":
"{ \"date\": \"Next Monday\", \"time\": \"10 AM\"
}"
}
}
Defining Functions for Fine-Tuning
To ensure function calling works seamlessly, functions must be defined with structured parameters. Below are the correct function definitions for a healthcare assistant scenario.
functions = [ {
"name": "schedule_appointment",
"description": "Schedules an appointment for the user.",
"parameters": {
"type": "object",
"properties": {
"appointment_date": {"type": "string", "description": "Date of the appointment (YYYY-MM-DD)"},
"appointment_time": {"type": "string", "description": "Time of the appointment (HH:MM AM/PM)"},
"doctor_specialty": {"type": "string", "description": "Specialty of the doctor"} },
"required": ["appointment_date", "appointment_time", "doctor_specialty"]
} }, {
"name": "follow_up_reminder",
"description": "Schedules a follow-up reminder for a user.",
"parameters": {
"type": "object",
"properties": {
"appointment_date": {"type": "string", "description": "Date of the follow-up (YYYY-MM-DD)"},
"appointment_time": {"type": "string", "description": "Time of the follow-up (HH:MM AM/PM)"} },
"required": ["appointment_date", "appointment_time"]
} }, {
"name": "schedule_callback",
"description": "Patient was busy on another call and has requested a callback.",
"parameters": {
"type": "object",
"properties": {
"date": {"type": "string", "description": "Date of the scheduled callback (YYYY-MM-DD)"},
"time": {"type": "string", "description": "Time of the scheduled callback (HH:MM AM/PM)"} },
"required": ["date", "time"]
} }
]
Using the Fine-Tuned Model for Function Calling
After fine-tuning, function calling must be explicitly handled at inference time. Below is an example using OpenAI’s API:
Inference Code
from openai import OpenAI
import json
client = OpenAI(api_key="your-api-key")
model_id = "your-finetuned-model-id"
def query_model(messages):
""" Sends messages to the fine-tuned GPT model and determines if a function should be called. """
try: response = client.chat.completions.create( model=model_id, messages=messages,
max_tokens=500,
temperature=0.5,
function_call="auto" )
response_message = response.choices[0].message
if response_message.function_call: function_name = response_message.function_call.name function_args = json.loads(response_message.function_call.arguments)
if function_name == "schedule_appointment":
return f"Appointment scheduled for {function_args['appointment_date']} at {function_args['appointment_time']} with {function_args['doctor_specialty']}."
if function_name == "follow_up_reminder":
return f"Follow-up scheduled for {function_args['appointment_date']} at {function_args['appointment_time']}."
if function_name == "schedule_callback":
return f"Scheduled call back for {function_args['date']} at {function_args['time']}."
return response_message.content.strip() if response_message.content else "I didn't quite catch that. Could you rephrase?"
except Exception as e:
return f"Error: {str(e)}"
Testing the Fine-Tuned Model
Run the following script to simulate a conversation with the fine-tuned model:
def run_conversation_flow():
print("Welcome to the AI Healthcare Assistant!")
messages = [{"role": "system", "content": "You are a healthcare assistant. Help users schedule and manage appointments."}]
while True:
user_input = input("User: ").strip()
if user_input.lower() in ["exit", "quit"]:
print("Assistant: Thank you for using the assistant. Goodbye!")
break
messages.append({"role": "user", "content": user_input})
assistant_response = query_model(messages)
messages.append({"role": "assistant", "content": assistant_response})
print(f"Assistant: {assistant_response}")
run_conversation_flow()
Conclusion
Fine-tuning LLMs for function calling enhances their ability to handle structured tasks within a conversation. By properly structuring training data and integrating function calling at inference, models can provide highly customized and reliable API interactions.