Agents
LearnPanta's intelligence layer is a coordinated multi-agent system. Each agent has a specific role, distinct prompt logic, and defined input/output contracts.
Agent Overview
| Agent | Role | Model | File |
|---|---|---|---|
| Curator | Content generation | Gemini Pro + Search | curator.py |
| Analyzer | Behavioral analysis | Gemini Flash | llm.py |
| Feedback Provider | Performance synthesis | Gemini Pro | activities.py |
| Debrief Orchestrator | Beat-synced review script | Gemini Flash | routers/debrief.py |
| Brief Explainer | Per-question paragraph (review sync) | Gemini Flash | routers/debrief.py |
| Interviewer | Oral debrief (legacy) | Gemini Pro | llm.py |
Current UI Note: The AI Debrief Review/Explore tabs use the TLDraw scaffold agent in the frontend (ScaffoldDebriefTab.tsx) plus the /debrief/orchestrate script and /debrief/brief paragraph endpoints.
1. The Curator (Content Generation)
Role: Content Strategist & Fact-Finder
Model: Gemini Pro with Google Search grounding
Location: backend/app/agent/curator.py
Process
- Research Syllabus: Uses Google Search to find official exam specifications
- Extract Topics: Parses syllabus into weighted topic list
- Generate Questions: Creates MCQs per topic with explanations
Prompt Structure
ROLE: Senior Exam Content Developer for {exam_name}
TASK: Generate {count} MCQs for topic "{topic}"
MCQ QUALITY STANDARDS:
- Stem: Clear, single concept, no negatives
- Options: One correct, three plausible distractors
- Difficulty: Calibrated to exam level
OUTPUT SCHEMA:
{
"questions": [{
"question_text": "...",
"options": ["A", "B", "C", "D"],
"correct_answer": "B",
"explanation": "...",
"difficulty": "medium",
"cognitive_level": "application"
}]
}
ANTI-HALLUCINATION:
- Only generate questions for topics in official syllabus
- If unsure about facts, omit rather than fabricate
Key Methods
async def curate_exam(self, exam_id: int) -> Paper:
"""Full curation: research → topics → questions → paper"""
async def research_syllabus(self, exam_name: str) -> dict:
"""Google Search for official exam topics"""
async def generate_questions_for_topic(self, topic: str, count: int) -> list:
"""Generate MCQs for single topic"""
2. The Analyzer (Behavioral Analysis)
Role: Behavioral Analytics Engine
Model: Gemini Flash (speed-optimized)
Location: backend/app/services/llm.py → analyze_telemetry()
Input Metrics
| Metric | Type | Description |
|---|---|---|
avg_time_per_question_ms | number | Average question duration |
total_answer_changes | number | Sum of answer modifications |
tab_blur_count | number | Window focus losses |
idle_periods | number | Periods >30s without interaction |
face_detection_rate | number | % time face detected (if camera) |
Output Schema
{
"focus_score": 85,
"fatigue_detected": false,
"anomalies": ["High answer change rate on Q5-Q10"],
"summary": "Candidate maintained good focus with minor hesitation mid-exam"
}
Scoring Rules (Deterministic)
focus_score: computed by Gemini Flash from behavioral + biometric signals
fatigue_detected: inferred from time patterns + focus drift signals
3. The Holistic Feedback Provider
Role: Performance Coach
Model: Gemini Pro (deep reasoning)
Location: backend/app/agent/activities.py → feedback_synthesis_agent()
Input Data
- Exam Results: Score, per-question correctness
- Behavioral Metrics: Time patterns, answer changes, focus data
- Scratchpad Images: Visual evidence of reasoning (if captured)
- Answer History: Full change log per question
Output Schema
{
"readiness_score": 72,
"accuracy_percent": 78.5,
"behavior_score": 64,
"behavior_penalty": 10,
"summary": "Strong conceptual understanding with time management challenges",
"strengths": [
"Consistent performance in {Topic A}",
"Good use of process of elimination"
],
"improvement_areas": [
"Review {Topic B} fundamentals",
"Practice timed conditions"
],
"recommendations": [
"Focus 60% study time on {Topic B}",
"Take practice exams under time pressure"
],
"domain_accuracy": [
{"tag": "risk-management", "score": 30, "question_count": 10},
{"tag": "scheduling", "score": 80, "question_count": 10}
],
"study_priority": "Topic B > Topic C > Topic A",
"encouragement": "Your careful approach shows strong analytical skills..."
}
Prompt Framework
ROLE: Senior Exam Performance Analyst
ANALYSIS FRAMEWORK:
1. Score Context: Interpret percentage against exam pass rate
2. Behavioral Correlation: Link time patterns to performance
3. Scratchpad Analysis: Infer reasoning from visual evidence
CONSTRAINTS:
- Base all observations on provided data
- Specific recommendations, not generic advice
- Encouraging but honest tone
4. Debrief Orchestrator (Review Script Generator)
Role: Script Writer for beat-synced review
Model: Gemini Flash (speed-optimized)
Location: backend/app/routers/debrief.py
Purpose
Generates timed beat scripts for the guided review experience (speech, cursor actions, optional canvas instructions).
Output Schema
{
"totalDurationMs": 45000,
"beats": [
{
"id": "q1_explain",
"startMs": 0,
"speech": { "text": "Let's review..." },
"cursor": { "action": "highlight", "target": { "type": "option", "id": "A" }, "color": "red" },
"canvas": { "instruction": "Draw a simple diagram..." }
}
]
}
5. Brief Explainer (Per-Question Paragraph)
Role: Generate a concise paragraph explanation per question for review sync.
Model: Gemini Flash
Location: backend/app/routers/debrief.py
Purpose
Provides a paragraph explanation (why correct is right, why others are wrong). This paragraph is passed as the message to the scaffold agent for drawing + narration sync.
6. The Interviewer (Oral Examiner) - Legacy
Role: Expert Oral Examiner
Model: Gemini Pro (conversational reasoning)
Location: backend/app/services/llm.py → conduct_interview_turn()
Purpose
Conducts voice-based post-exam debrief:
- Listens to candidate's explanation (transcribed)
- Evaluates clarity, accuracy, and confidence
- Asks probing follow-up questions
Evaluation Criteria
| Dimension | Weight | Indicators |
|---|---|---|
| Clarity | 25% | Structured explanation, no rambling |
| Accuracy | 35% | Factually correct statements |
| Depth | 25% | Beyond surface-level understanding |
| Confidence | 15% | Conviction without arrogance |
Response Patterns
If correct + confident → "Good explanation. Can you elaborate on..."
If correct + uncertain → "You're right. Let's build your confidence..."
If incorrect → "Interesting approach. Consider that..."
Prompt Engineering Standards
All agent prompts follow these conventions:
1. Structured Format
ROLE: [Professional persona with expertise]
TASK: [Specific action required]
CONTEXT:
- [Labeled data sections]
OUTPUT SCHEMA:
{
"field": "type and description"
}
CONSTRAINTS:
- [Hard rules]
ANTI-HALLUCINATION:
- [Grounding requirements]
2. JSON Enforcement
All prompts request structured JSON with explicit types:
response = await client.generate_content(
prompt,
generation_config=GenerationConfig(
response_mime_type="application/json",
response_schema=OutputSchema
)
)
3. Anti-Hallucination Rules
Every content-generating prompt includes:
- "Only use information from provided context"
- "If uncertain, state 'Unable to determine' rather than fabricate"
- "Do not invent exam topics, statistics, or pass rates"
4. Deterministic Fallbacks
For critical calculations (scores, thresholds), use code-based logic rather than AI:
# Don't ask AI: "What's the focus score?"
# Do calculate: focus_score = 100 - (blurs * 5) - (idles * 3)
Adding New Agents
To add a new agent:
- Define the role in this handbook
- Create the activity in
activities.py:@activity.defn async def new_agent_activity(input: NewAgentInput) -> NewAgentOutput: ... - Add the prompt in
llm.pyor dedicated file - Wire into workflow in
workflows.py - Document the prompt structure and I/O schema here
Next Steps
- Agent Architecture - Deep dive into marathon agents
- Architecture - System overview
- Development - Local setup guide