Building a personalized tutoring agent that adapts explanations to a student's knowledge level and maintains memory across sessions. This helps teachers scale one-on-one instruction and lets self-learners get feedback without managing token budgets. We will wire it to Oxlo.ai so each tutoring round costs one flat request, which matters when student profiles grow long.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
- A topic you want to teach. I will use middle-school algebra as the running example.
1. Scaffold the student profile
We start with a small JSON profile that stores the student's grade, known concepts, and struggling areas. We also instantiate the Oxlo.ai client so every subsequent script block is copy-paste runnable.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
student_profile = {
"name": "Alex",
"grade_level": 7,
"known_concepts": ["addition", "subtraction", "multiplication"],
"struggling_concepts": ["division", "fractions"],
"learning_style": "step-by-step with visual examples"
}
# Quick connectivity check
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": "You are a helpful tutor."},
{"role": "user", "content": f"Greet {student_profile['name']} and confirm you are ready to teach fractions."},
],
)
print(response.choices[0].message.content)
2. Design the adaptive system prompt
The system prompt injects the student profile and instructs the model to adjust its difficulty and examples accordingly. Keeping this in a dedicated string makes it easy to iterate without touching business logic.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
student_profile = {
"name": "Alex",
"grade_level": 7,
"known_concepts": ["addition", "subtraction", "multiplication"],
"struggling_concepts": ["division", "fractions"],
"learning_style": "step-by-step with visual examples"
}
SYSTEM_PROMPT = f"""You are a personalized math tutor. Adapt every response using the following student profile:
- Name: {student_profile['name']}
- Grade level: {student_profile['grade_level']}
- Known concepts: {', '.join(student_profile['known_concepts'])}
- Struggling concepts: {', '.join(student_profile['struggling_concepts'])}
- Learning style: {student_profile['learning_style']}
Rules:
1. Only teach concepts the student does not already know.
2. Use the learning style to shape examples.
3. End each message with one practice question.
4. Keep responses under 150 words."""
user_message = "I want to learn fractions. Start with the basics."
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
print(response.choices[0].message.content)
3. Evaluate answers and update the profile
After the student replies, we send their answer to the model with a second system instruction that asks for an assessment and an updated profile. This creates a closed feedback loop.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
student_profile = {
"name": "Alex",
"grade_level": 7,
"known_concepts": ["addition", "subtraction", "multiplication"],
"struggling_concepts": ["division", "fractions"],
"learning_style": "step-by-step with visual examples"
}
student_answer = "I think 1/2 plus 1/4 is 2/6 because you add the top and bottom."
eval_prompt = f"""You are an assessment engine. Given the student profile and their answer, return ONLY a JSON object with two keys:
- "assessment": a brief, encouraging correction or confirmation.
- "updated_profile": the full student profile dict, but move any mastered concept from struggling_concepts to known_concepts if the answer shows mastery, or leave it if not.
Current profile: {json.dumps(student_profile)}
Student answer: {student_answer}"""
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": eval_prompt},
{"role": "user", "content": "Evaluate and return JSON."},
],
)
print(response.choices[0].message.content)
4. Maintain multi-turn conversation memory
Real tutoring requires context. We append each exchange to a messages list so the model remembers what was already covered. Because Oxlo.ai uses request-based pricing, growing the context window does not inflate cost, which makes long tutoring sessions predictable.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
student_profile = {
"name": "Alex",
"grade_level": 7,
"known_concepts": ["addition", "subtraction", "multiplication"],
"struggling_concepts": ["division", "fractions"],
"learning_style": "step-by-step with visual examples"
}
SYSTEM_PROMPT = f"""You are a personalized math tutor. Adapt every response using the following student profile:
- Name: {student_profile['name']}
- Grade level: {student_profile['grade_level']}
- Known concepts: {', '.join(student_profile['known_concepts'])}
- Struggling concepts: {', '.join(student_profile['struggling_concepts'])}
- Learning style: {student_profile['learning_style']}
Rules:
1. Only teach concepts the student does not already know.
2. Use the learning style to shape examples.
3. End each message with one practice question.
4. Keep responses under 150 words."""
history = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "I want to learn fractions. Start with the basics."},
]
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=history,
)
assistant_msg = response.choices[0].message.content
history.append({"role": "assistant", "content": assistant_msg})
# Student answers
history.append({"role": "user", "content": "Is 1/2 bigger than 1/3?"})
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=history,
)
print(response.choices[0].message.content)
Run it
Here is a single script that wires the profile, the system prompt, and the conversation loop together. Save it as tutor.py, set your YOUR_OXLO_API_KEY, and run python tutor.py.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
student_profile = {
"name": "Alex",
"grade_level": 7,
"known_concepts": ["addition", "subtraction", "multiplication"],
"struggling_concepts": ["division", "fractions"],
"learning_style": "step-by-step with visual examples"
}
SYSTEM_PROMPT = f"""You are a personalized math tutor. Adapt every response using the following student profile:
- Name: {student_profile['name']}
- Grade level: {student_profile['grade_level']}
- Known concepts: {', '.join(student_profile['known_concepts'])}
- Struggling concepts: {', '.join(student_profile['struggling_concepts'])}
- Learning style: {student_profile['learning_style']}
Rules:
1. Only teach concepts the student does not already know.
2. Use the learning style to shape examples.
3. End each message with one practice question.
4. Keep responses under 150 words."""
history = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "I want to learn fractions. Start with the basics."},
]
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=history,
)
assistant_msg = response.choices[0].message.content
history.append({"role": "assistant", "content": assistant_msg})
print("Tutor:", assistant_msg)
# Simulate student reply
student_reply = "I think 1/2 plus 1/4 is 2/6 because you add the top and bottom."
history.append({"role": "user", "content": student_reply})
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=history,
)
print("Tutor:", response.choices[0].message.content)
Example output:
Tutor: Hi Alex! Let's tackle fractions together. A fraction has two parts: the top number (numerator) tells you how many pieces you have, and the bottom number (denominator) tells you how many equal pieces make up one whole. Imagine a pizza cut into 4 slices. If you eat 1 slice, you ate 1/4 of the pizza. Ready for your first question? What fraction of the pizza is left if you eat 1 slice from a 4-slice pizza?
Tutor: Not quite, but great try! When adding fractions, the denominators must be the same. Think of it like this: a pizza cut into 2 large slices and another cut into 4 small slices. To add 1/2 and 1/4, you need both pizzas cut into the same number of slices. 1/2 is the same as 2/4. So 2/4 plus 1/4 equals 3/4. You add the numerators, but keep the denominator the same. Here's your next question: what is 1/3 plus 1/3?
Wrap-up and next steps
You now have a working personalized tutor on Oxlo.ai that adapts to a student profile and remembers context across turns. Because Oxlo.ai charges per request rather than per token, you can stuff detailed student histories and long system prompts into every call without watching metered costs climb.
Two concrete ways to extend this: first, add a tool-calling step that quizzes the student with auto-graded multiple choice by defining a submit_answer function. Second, swap the model to qwen-3-32b if you need to support multilingual students, or to deepseek-v3.2 if you pivot the curriculum toward coding. You can explore flat request-based pricing for these workloads at https://oxlo.ai/pricing.
Top comments (0)