We are going to build a conversational language tutor that adapts to the learner's proficiency level, corrects mistakes in context, and accumulates vocabulary for later review. The whole thing runs against Oxlo.ai's request-based API (pricing), so long conversation histories do not inflate your bill.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK:
pip install openai
Step 1: Configure the Oxlo.ai client
I start by importing the OpenAI SDK and pointing it at Oxlo.ai. Because Oxlo.ai is fully OpenAI-compatible, this is the only client I need.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY")
)
Step 2: Define the tutor persona
The system prompt sets the rules: immerse the student in the target language, correct gently, and stay concise. I keep it in a module-level constant so I can tweak it without touching the rest of the code.
TARGET_LANGUAGE = "Spanish"
PROFICIENCY = "intermediate"
SYSTEM_PROMPT = (
"You are a patient, concise language tutor. The student is learning " + TARGET_LANGUAGE +
" at an " + PROFICIENCY + " level. Respond entirely in " + TARGET_LANGUAGE +
" to force immersion. When the student makes a grammar or vocabulary mistake, "
"briefly note the correction in English inside parentheses. Introduce one new word "
"naturally in each response. Keep sentences short and encouraging."
)
Step 3: Build the conversation engine
Next, a helper that appends the user's message to the running history and returns the reply from Llama 3.3 70B. I use Llama 3.3 70B because it follows instructions tightly and handles multilingual dialogue well.
def get_tutor_reply(messages):
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
*messages
],
temperature=0.7,
)
return response.choices[0].message.content
Step 4: Extract structured review data
I want to surface mistakes and new vocabulary at the end of a session. A second call with JSON mode turns the transcript into structured data. Oxlo.ai supports OpenAI-style JSON mode, so I set response_format and parse the result.
import json
def generate_session_review(transcript):
review_prompt = (
"Analyze this language tutoring transcript. Output valid JSON with exactly two keys: "
"'mistakes' (a list of strings in the format 'error -> correction') and "
"'vocabulary' (a list of objects with 'word' and 'translation')."
)
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": review_prompt},
{"role": "user", "content": transcript}
],
response_format={"type": "json_object"},
temperature=0.2,
)
return json.loads(response.choices[0].message.content)
Step 5: Wire up the CLI
Finally, I tie everything into a simple loop. Typing review prints a structured summary. Typing quit exits. The message list grows as the session continues, and because Oxlo.ai bills per request rather than per token, carrying that full history into every call does not change the price.
def main():
messages = []
print("Tutor: Hola. ¿Cómo estás hoy? (Type 'review' for summary, 'quit' to exit)")
while True:
user_input = input("You: ").strip()
if user_input.lower() == "quit":
break
if user_input.lower() == "review":
transcript = "\n".join(
f"{m['role']}: {m['content']}" for m in messages
)
review = generate_session_review(transcript)
print("\n--- Session Review ---")
print(json.dumps(review, indent=2, ensure_ascii=False))
print("----------------------\n")
continue
messages.append({"role": "user", "content": user_input})
reply = get_tutor_reply(messages)
messages.append({"role": "assistant", "content": reply})
print(f"Tutor: {reply}")
if __name__ == "__main__":
main()
Run it
Save the script as tutor.py, export your key, and start a session.
export OXLO_API_KEY="sk-oxlo.ai-..."
python tutor.py
Example interaction:
Tutor: Hola. ¿Cómo estás hoy? (Type 'review' for summary, 'quit' to exit)
You: Estoy bien, gracias. Yo fui a la biblioteca.
Tutor: ¡Muy bien! ¿Qué libro leíste? (Notice: native speakers often drop the pronoun and simply say 'Fui'.)
You: Leí un libro sobre historia.
Tutor: Excelente. ¿Te gustó? (gustó -> pleased/interested: here 'Te gustó' means 'Did you like it?')
You: review
--- Session Review ---
{
"mistakes": [
"Yo fui -> Fui (pronoun drop is more natural)"
],
"vocabulary": [
{"word": "leíste", "translation": "you read (past)"},
{"word": "gustó", "translation": "pleased / liked"}
]
}
----------------------
Next steps
Swap in kimi-k2.6 or deepseek-v3.2 if you want stronger reasoning for grammar explanations, or qwen-3-32b for multilingual scenarios beyond Spanish and English. To turn this into a production platform, persist the extracted review JSON to SQLite and schedule vocabulary drills using a spaced-repetition algorithm.
Top comments (0)