Version1 / agents /teacher.py
Prerit018's picture
Upload 26 files
6bc3db2 verified
Raw
History Blame Contribute Delete
10.6 kB
# agents/teacher.py
import os
import json
import time
from dotenv import load_dotenv
import openai
from .base_agent import BaseAgent
load_dotenv()
class TeacherAgent(BaseAgent):
def __init__(self, level):
super().__init__(f"{level.capitalize()}TeacherAgent")
api_key = os.getenv("OPENAI_API_KEY")
self.client = openai.OpenAI(api_key=api_key)
self.level = level.lower()
def teach_module(self, module):
"""
Returns a rich, k-shot based explanation string for the given module.
Will attempt a small re-prompt if the output is too short.
"""
system_prompt = (
"You are an engaging and adaptive AI Tutor. Produce a thorough, structured explanation "
"of the requested module tuned to the user's learning level. Use the structure below."
"\n\nTeaching style differences by level:\n"
"- Novice: Simple language, relatable analogies, many concrete examples.\n"
"- Intermediate: Explain 'how' and 'why', connect to related concepts, include practical examples.\n"
"- Advanced: Discuss nuances, edge-cases, performance, comparative methods and deeper insights.\n\n"
"Explanation structure (MANDATORY):\n"
"1) Core Concept — clear, precise description (several sentences)\n"
"2) Worked Example or Analogy — at least one detailed example that illustrates application\n"
"4) Key Takeaway — one concise sentence\n\n"
"### Few-shot examples (follow style):\n\n"
"Novice Example:\n"
"Module: Variables\n"
"Core Concept: Variables are containers that store values like numbers or text. Example: x = 5.\n"
"Analogy/Example: Think of a labeled jar.\n"
"Intermediate Example:\n"
"Module: For loops\n"
"Core Concept: For loops iterate over a collection. Example: for item in collection: process(item)\n"
"Application: Useful for batch-processing and iteration in algorithms.\n\n"
"Advanced Example:\n"
"Module: Tail recursion\n"
"Core Concept: Tail recursion preserves state for compiler optimizations; consider stack usage.\n\n"
"Produce detailed output (minimum ~130 words). Do NOT output JSON — just plain text explanation."
)
user_prompt = (
f"Module: {module.name}\n"
f"Learning objective: {getattr(module, 'learning_objective', '')}\n\n"
"Please produce the explanation now."
)
resp = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
# you can tune temperature if needed
)
explanation = resp.choices[0].message.content.strip()
# If too short, ask for expansion once
if len(explanation.split()) < 120:
followup = (
"The previous explanation was too short. Please expand the explanation, add another worked example "
"and a short code or pseudo-code snippet where appropriate. Keep same style & level."
)
resp2 = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
{"role": "user", "content": followup}
],
)
extra = resp2.choices[0].message.content.strip()
# concatenate but keep readable
explanation = explanation + "\n\n" + extra
# return explanation string (do not print in agent; app will show it)
return explanation
def evaluate_example(self, module, student_example):
"""
Evaluate the student's example for the given module.
Returns a dict: { "is_correct": bool, "feedback": str, "confidence": float (0-1) }
The model MUST output JSON only; we robustly parse it and fallback if needed.
"""
system_prompt = (
"You are an expert educational assessor. Evaluate the student's example strictly with respect "
"to the module's learning objective. Respond with JSON ONLY (no extra text). The JSON object MUST contain:\n"
" - is_correct: true/false\n"
" - feedback: short one-sentence constructive feedback\n"
" - confidence: numeric between 0 and 1\n\n"
f"Evaluation sensitivity is based on learner level: {self.level}."
)
user_prompt = (
f"Module: {module.name}\n"
f"Learning objective: {getattr(module, 'learning_objective', '')}\n\n"
f"Student example: {student_example}\n\n"
"Evaluate and return JSON only."
)
resp = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
# lower temperature can reduce hallucinations
)
raw = resp.choices[0].message.content.strip()
# Try to parse JSON; be forgiving (extract first {...})
try:
parsed = json.loads(raw)
except Exception:
import re
m = re.search(r'(\{.*\})', raw, re.DOTALL)
if m:
try:
parsed = json.loads(m.group(1))
except Exception:
parsed = None
else:
parsed = None
if not parsed:
# fallback: simple heuristics (very conservative)
is_correct = len(student_example.strip()) > 20
feedback = "Could not parse evaluator output; using conservative heuristic. Provide a more concrete example." \
if not is_correct else "Example seems plausible but automatic evaluation failed to parse."
confidence = 0.45 if not is_correct else 0.6
return {"is_correct": bool(is_correct), "feedback": feedback, "confidence": confidence, "raw": raw}
# normalize fields
is_correct = bool(parsed.get("is_correct", parsed.get("correct", False)))
feedback = str(parsed.get("feedback", parsed.get("explanation", "")))
confidence = float(parsed.get("confidence", parsed.get("score", 0))) if parsed.get("confidence") is not None else 0.9
return {"is_correct": is_correct, "feedback": feedback, "confidence": confidence, "raw": raw}
def check_example(self, module):
"""
Interactive method to check if student understands the module by asking for an example.
Returns True if the student provides a satisfactory example, False otherwise.
"""
print(f"\n🎯 Let's test your understanding of '{module.name}'!")
print("Please provide a specific example or application that demonstrates this concept.")
learning_objective = getattr(module, 'learning_objective', '')
if learning_objective:
print(f"Learning Objective: {learning_objective}")
print("\nYour example should be:")
print("• Specific and concrete (not just a definition)")
print("• Relevant to the module content")
print("• Show your understanding of how to apply the concept")
print("• At least 2-3 sentences with clear reasoning")
while True: # Allow multiple attempts
student_example = input("\nYour example: ").strip()
if not student_example:
print("❌ Please provide an example to demonstrate your understanding.")
continue
# Check for minimum length and specificity
if len(student_example.split()) < 10:
print("❌ Your example is too brief. Please provide a more detailed example with specific details.")
continue
# Evaluate the example
evaluation = self.evaluate_example(module, student_example)
if evaluation['is_correct']:
print("✅ Correct! Your example demonstrates good understanding.")
return True
else:
print("❌ Incorrect. Your example doesn't demonstrate sufficient understanding.")
# Provide a simple hint
hint = self.get_simple_hint(module)
if hint:
print(f"💡 Hint: {hint}")
retry = input("\nWould you like to try again with a different example? (y/n): ").lower().strip()
if retry == 'y':
continue
else:
print("📚 Let's review the concept again and then try the example.")
return False
def get_simple_hint(self, module):
"""Generate a simple hint to guide the student toward a better example."""
system_prompt = (
"You are an expert tutor providing a simple hint. Give a brief, helpful suggestion (1-2 sentences) "
"to guide the student toward providing a better example. Don't give away the answer, just nudge them in the right direction."
)
user_prompt = (
f"Module: {module.name}\n"
f"Learning Objective: {getattr(module, 'learning_objective', '')}\n\n"
"Provide a simple hint to help the student think of a better example."
)
try:
response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
)
return response.choices[0].message.content.strip()
except Exception:
return "Think about how this concept applies in real-world situations or practical scenarios."
# convenience subclasses (optional)
class NoviceTeacherAgent(TeacherAgent):
def __init__(self):
super().__init__("novice")
class IntermediateTeacherAgent(TeacherAgent):
def __init__(self):
super().__init__("intermediate")
class AdvancedTeacherAgent(TeacherAgent):
def __init__(self):
super().__init__("advanced")