Розробка AI-системи автогенерації тестів та екзаменів
AI-генерація тестових завдань створює унікальні питання за навчальним матеріалом, різних рівнів складності (таксономія Блума), з кількома варіантами виконання — исключает списування при масовому тестуванні.
Багаторівневе генерування питань
from openai import AsyncOpenAI
from enum import Enum
import json
client = AsyncOpenAI()
class BloomLevel(Enum):
REMEMBER = "remember" # запам'ятати факти
UNDERSTAND = "understand" # пояснити концепції
APPLY = "apply" # застосувати в новій ситуації
ANALYZE = "analyze" # розкласти на частини
EVALUATE = "evaluate" # оцінити критично
CREATE = "create" # створити нове
BLOOM_PROMPTS = {
BloomLevel.REMEMBER: "Створи питання на запам'ятовування фактів, дат, визначень",
BloomLevel.UNDERSTAND: "Створи питання на розуміння: пояснення, перефразування, приклади",
BloomLevel.APPLY: "Створи практичне завдання: застосування знань в новій ситуації",
BloomLevel.ANALYZE: "Створи питання на аналіз: порівняння, виявлення причин, структурування",
BloomLevel.EVALUATE: "Створи питання на оцінку: обґрунтування судження, критика підходу",
BloomLevel.CREATE: "Створи завдання на синтез: розробка рішення, створення продукту",
}
async def generate_question(
topic: str,
source_text: str,
question_type: str, # multiple_choice, true_false, open_answer, case_study
bloom_level: BloomLevel = BloomLevel.UNDERSTAND,
difficulty: str = "medium"
) -> dict:
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": f"""Створи тестове питання.
Тип: {question_type}.
Рівень таксономії Блума: {bloom_level.value}. {BLOOM_PROMPTS[bloom_level]}.
Складність: {difficulty}.
Для multiple_choice: 4 варіанти, 1 правильний, 3 правдоподібні дистрактори.
Для open_answer: еталонна відповідь + критерії оцінювання.
Для case_study: ситуація + 3-5 питань різних рівнів.
Поверни JSON: {{
question: "текст питання",
type: "{question_type}",
bloom_level: "{bloom_level.value}",
options: ["A...", "B...", ...], // лише для MC
correct_answer: "...",
explanation: "чому саме ця відповідь правильна",
scoring_rubric: {{...}} // для open_answer
}}"""
}, {
"role": "user",
"content": f"Тема: {topic}\n\nМатеріал:\n{source_text[:2000]}"
}],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
Генерування повного варіанта екзамену
async def generate_exam_variant(
course_topics: list[str],
total_questions: int = 30,
time_limit_min: int = 60,
bloom_distribution: dict = None
) -> dict:
"""
bloom_distribution: {BloomLevel.REMEMBER: 0.3, BloomLevel.APPLY: 0.4, ...}
За замовчуванням: 20% Remember, 30% Understand, 30% Apply, 20% Analyze
"""
if not bloom_distribution:
bloom_distribution = {
BloomLevel.REMEMBER: 0.2,
BloomLevel.UNDERSTAND: 0.3,
BloomLevel.APPLY: 0.3,
BloomLevel.ANALYZE: 0.2
}
questions_by_level = {
level: int(total_questions * fraction)
for level, fraction in bloom_distribution.items()
}
all_questions = []
tasks = []
for level, count in questions_by_level.items():
for i in range(count):
topic = course_topics[i % len(course_topics)]
q_type = "multiple_choice" if level in [BloomLevel.REMEMBER, BloomLevel.UNDERSTAND] else "open_answer"
tasks.append(generate_question(
topic=topic,
source_text="",
question_type=q_type,
bloom_level=level
))
all_questions = await asyncio.gather(*tasks)
return {
"variant_id": f"V{random.randint(1000, 9999)}",
"time_limit_min": time_limit_min,
"total_points": sum(q.get("points", 1) for q in all_questions),
"questions": list(all_questions),
"bloom_distribution": {l.value: c for l, c in questions_by_level.items()}
}
Автоматична перевірка відкритих відповідей
async def auto_grade_open_answer(
question: str,
correct_answer: str,
rubric: dict,
student_answer: str
) -> dict:
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": f"""Перевір відповідь студента за рубрикою.
Питання: {question}
Еталонна відповідь: {correct_answer}
Критерії оцінювання: {json.dumps(rubric, ensure_ascii=False)}
Оціни відповідь і поверни JSON:
{{score: 0-100, feedback: "детальна зворотна зв'язок", strengths: [], weaknesses: []}}"""
}, {
"role": "user",
"content": f"Відповідь студента: {student_answer}"
}],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
Антиплагіат — унікальні варіанти
async def generate_unique_variants(
base_question: str,
n_variants: int = 30,
maintain_difficulty: bool = True
) -> list[dict]:
"""Генеруємо N унікальних версій питання"""
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "system",
"content": f"""Створи {n_variants} унікальних версій питання.
Варіюй: цифри, імена, контекст, порядок варіантів відповіді.
Складність {'повинна залишатися однаковою' if maintain_difficulty else 'може варіюватися'}.
Поверни JSON масив."""
}, {
"role": "user",
"content": f"Вихідне питання: {base_question}"
}],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)["variants"]
Терміни: генератор тестів із текстового матеріалу — 1–2 тижні. Повнофункціональна платформа з автоперевіркою, аналітикою та інтеграцією в LMS (Moodle/iSpring) — 2–3 місяці.







