AI-тьютор для VR-навчання
VR-тренажери без адаптивного компонента — це дороге відео з контролем. Учень проходить один і той же сценарій незалежно від помилок: помилився на кроці 3, але сценарій продовжується далі. AI-тьютор змінює логіку: система відстежує кожну дію, виявляє паттерн помилок, адаптує наступний сценарій та надає персоналізований зворотний зв'язок у реальному часі.
Архітектура адаптивного тьютора
from langchain_openai import ChatOpenAI
from dataclasses import dataclass, field
from typing import Optional
import json
from datetime import datetime
@dataclass
class LearnerProfile:
learner_id: str
session_history: list[dict] = field(default_factory=list)
skill_scores: dict = field(default_factory=dict) # навичка → 0.0–1.0
common_errors: list[str] = field(default_factory=list)
learning_pace: float = 1.0 # коефіцієнт швидкості навчання
@dataclass
class VRAction:
action_type: str # step_completed, error, timeout, skip
step_id: str
timestamp: float
details: dict # конкретні параметри дії
correct: bool
class AdaptiveTutor:
FEEDBACK_PROMPT = """Ти — AI-тьютор у VR-тренажері. Дай коротку (1–2 речення) голосову зворотну інформацію.
Учень щойно: {action_description}
Виконано правильно: {is_correct}
{"Помилка: " + "{error_details}" if not "{is_correct}" else ""}
Історія помилок учня: {error_history}
Тон: підтримуючий, конкретний. Не хвали за очевидне.
Якщо помилка повторюється — поясни принцип, не просто скажи "неправильно"."""
def __init__(self, llm: ChatOpenAI):
self.llm = llm
def analyze_action(self, action: VRAction, profile: LearnerProfile) -> dict:
"""Аналізує дію та визначає наступний крок"""
# Оновлюємо скор навички
skill = self._get_skill_for_step(action.step_id)
if skill:
current = profile.skill_scores.get(skill, 0.5)
if action.correct:
profile.skill_scores[skill] = min(1.0, current + 0.05)
else:
profile.skill_scores[skill] = max(0.0, current - 0.1)
if action.action_type not in profile.common_errors:
profile.common_errors.append(action.step_id)
# Адаптація сценарію
next_scenario = self._select_next_scenario(profile)
return {
"feedback": self._generate_feedback(action, profile),
"next_scenario": next_scenario,
"skill_update": profile.skill_scores.get(skill, 0.5)
}
def _select_next_scenario(self, profile: LearnerProfile) -> dict:
"""Вибирає наступний сценарій на основі профілю учня"""
weak_skills = [
skill for skill, score in profile.skill_scores.items()
if score < 0.6
]
if weak_skills:
# Фокусуємо на слабких місцях
return {
"type": "remedial",
"target_skills": weak_skills[:2],
"difficulty": "easier",
"reason": f"Потребує практики: {', '.join(weak_skills[:2])}"
}
elif all(s > 0.8 for s in profile.skill_scores.values()):
return {
"type": "advancement",
"difficulty": "harder",
"reason": "Хороше вивчення базових навичок"
}
else:
return {"type": "standard", "difficulty": "normal"}
async def _generate_feedback(
self,
action: VRAction,
profile: LearnerProfile
) -> str:
repeated_error = action.step_id in profile.common_errors
prompt = f"""Дай зворотну інформацію учню у VR.
Дія: {action.action_type} на кроці {action.step_id}
Правильно: {action.correct}
Помилка, що повторюється: {repeated_error}
Деталі помилки: {json.dumps(action.details, ensure_ascii=False)}
{"Ця помилка повторюється. Поясни принцип, а не просто що це неправильно." if repeated_error else ""}
1 речення. Говори на "ти". Конкретно."""
result = await self.llm.ainvoke(prompt)
return result.content
Оцінка компетенцій та відстеження прогресу
class CompetencyTracker:
"""Відстежує опанування компетенцій через IRT (Item Response Theory)"""
def update_ability(
self,
learner_theta: float, # поточний рівень (-3 до +3)
item_difficulty: float, # складність завдання (-3 до +3)
correct: bool
) -> float:
"""Оновлює оцінку здібностей за 3PL моделлю IRT"""
# 3-parameter logistic model
a = 1.7 # discrimination
c = 0.25 # guessing parameter
# Ймовірність правильної відповіді
p = c + (1 - c) / (1 + math.exp(-a * (learner_theta - item_difficulty)))
# Оновлення за кроком градієнту
info = a**2 * (p - c)**2 * (1 - p) / ((1 - c)**2 * p)
delta = 0.3 * (1 if correct else -1) / (info + 0.01)
return max(-3, min(3, learner_theta + delta))
Unity: інтеграція тьютора у сцену
public class VRTutorController : MonoBehaviour
{
private AdaptiveTutorClient tutorClient;
private AudioSource feedbackAudio;
public async void OnActionCompleted(string stepId, bool isCorrect, Dictionary<string, object> details)
{
var action = new VRAction(
actionType: isCorrect ? "step_completed" : "error",
stepId: stepId,
timestamp: Time.time,
details: details,
correct: isCorrect
);
var result = await tutorClient.AnalyzeAction(action, currentLearnerId);
// Відтворюємо голосову зворотну інформацію
string feedbackText = result.feedback;
byte[] audio = await TTSService.Synthesize(feedbackText);
feedbackAudio.PlayOneShot(AudioService.BytesToClip(audio));
// Адаптуємо наступний сценарій
ScenarioManager.LoadScenario(result.nextScenario);
}
}
Кейс: навчання операторів нафтохімічного заводу роботі з аварійним обладнанням. 200 операторів, 12 необхідних компетенцій. До впровадження: фіксований сценарій, всі проходять однаково, середній балл підсумкового тесту — 71%. Після 3 місяців з AI-тьютором (персоналізовані повторення слабких зон, адаптивна складність): середній балл піднявся до 84%, час до освоєння рівня сертифікації скоротився з 8 до 5 занять.
Строки: базовий тьютор з зворотною інформацією та відстеженням прогресу: 6–8 тижнів; адаптивний движок з IRT та аналітикою: 3–4 місяці.







