# Тесты по учебным материалам через API

> Пять вопросов с вариантами ответа и пояснением к каждому уроку курса. Вторая модель решает тест без ключа и находит ошибки, готовый файл импортируется в Moodle. Ключ Polza.ai, оплата в рублях.

- Тесты к 1 000 уроков — от 257 ₽, оценка по ценам каталога
- Проверка решением без ключа
- Пояснение к каждому ответу
- Импорт в Moodle

## Охрана труда · Первая помощь при термическом ожоге

**Вопрос 2 из 5**

> Как правильно поступить с одеждой, прилипшей к термическому ожогу?
>
> ○ Аккуратно оторвать её от кожи
> ● Обрезать одежду вокруг прилипшего участка
> ○ Оставить до осмотра врачом
> ○ Смазать маслом и снять

**Пояснение:** Верно. Текст прямо указывает: прилипшую к коже одежду не отрывают — её обрезают вокруг.

Реальный вопрос из теста. [Как тестировали](#test)

## Задача

В курсе 200 уроков, тест есть у трети. Методист пишет пять вопросов за полчаса, и ещё столько же уходит на проверку. Обновили урок — тест устарел.

Через API тест к каждому уроку пишется по его тексту, а вторая модель решает его, не видя ключа. Методист читает только вопросы, где ответы разошлись, — в нашем тесте таких было 2 из 60.

## Для кого

Везде, где уроков больше, чем методистов.

- **Онлайн-школы.** Тест к каждому уроку курса и новый тест после обновления урока. Банк вопросов растёт вместе с курсом. Сотни уроков за вечер.
- **Учителя и репетиторы.** Проверочные по параграфу учебника или своему конспекту: пять вопросов с пояснениями для разбора. Тест за минуту, а не за час.
- **Корпоративное обучение.** Охрана труда, регламенты, продукт компании. Тест проверяет, что сотрудник прочитал документ. Вопросы только по тексту регламента.
- **Авторы курсов и платформы.** Генерация тестов как функция платформы: автор загружает урок — получает черновик теста. Через API, под своим интерфейсом.

## Как тест попадает в курс

Четыре шага: уроки, генерация, проверка, импорт.

- **Шаг 1. Уроки.** Тексты уроков из курса: таблица, выгрузка из LMS или папка с файлами. (lessons.csv)
- **Шаг 2. Генерация.** Модель пишет 5 вопросов к уроку, скрипт перемешивает варианты. (python make_quiz.py)
- **Шаг 3. Проверка.** Вторая модель решает тест без ключа. Расхождения уходят методисту. (60 вопросов · 2 на проверку)
- **Шаг 4. Курс.** Файл GIFT импортируется в банк вопросов Moodle, по категории на урок. (quizzes.gift)

### Формат GIFT для Moodle

GIFT — текстовый формат банка вопросов Moodle. Знак `=` отмечает верный вариант, `~` — неверные, после `####` идёт пояснение, которое ученик видит после ответа. Каждый урок ложится в свою категорию. Для GetCourse и любой другой LMS с импортом вопросов скрипт отдаёт JSON: из него собирается CSV или XML под формат импорта платформы.

quizzes.gift · реальный фрагмент:

```
$CATEGORY: Первая помощь при термическом ожоге

::L06-1:: Сколько минут рекомендуется охлаждать обожжённое место проточной водой? {
=20 минут
~30 минут
~10 минут
~5 минут
####В тексте указано\: «Обожжённое место охлаждают прохладной проточной водой около 20 минут».
}
```

## Как это выглядит в курсе

Реальные вопросы из теста: до ответа, после ответа с пояснением и в банке вопросов после импорта.

### Охрана труда · Первая помощь при термическом ожоге

**Вопрос 5 из 5**

> Взрослый получил ожог предплечья горячим паром. Ожог поверхностный, без пузырей, размером примерно с ладонь. Какие действия будут правильными?
>
> ○ Смазать обожжённое место маслом, наложить повязку и вызвать врача
> ○ Охладить прохладной водой около 20 минут, закрыть чистой неплотной повязкой, скорую не вызывать
> ○ Приложить лёд на 10 минут, нанести антибактериальный крем и вскрыть пузыри
> ○ Нанести мазь от ожогов, охладить водой и обрезать одежду вокруг раны

Ученик видит вопрос и варианты

### Охрана труда · Первая помощь при термическом ожоге

**Вопрос 3 из 5**

> Почему при термическом ожоге нельзя прикладывать лёд?
>
> ○ Лёд вызывает сильную боль
> ○ Холод не помогает при термических ожогах
> ● Лёд может повредить ткани
> ○ Лёд замедляет образование пузырей

**Пояснение:** Верно. Прямая причина указана в тексте: лёд может повредить ткани.

После ответа — пояснение из урока

### Банк вопросов · импорт GIFT

**Импортировано 60 вопросов**

> 12 категорий по темам уроков
>
> Фотосинтез — 5 вопросов
> Закон Ома для участка цепи — 5 вопросов
> Списки — 5 вопросов
> Первая помощь при термическом ожоге — 5 вопросов
> Коды ответа HTTP — 5 вопросов
> …ещё 7 категорий

Вопросы в банке разложены по темам

## Сколько стоят тесты к 1 000 уроков

Замер — фактический расход по полю `cost_rub` на трёх самых трудных уроках, пересчитанный на 1 000 уроков по 5 вопросов. Короткое рассуждение включено у всех моделей. Стоимость «сейчас» Polza.ai оценивает по текущим ценам [каталога](https://polza.ai/models).

| Модель | 1 000 уроков, замер 6 октября | Один урок | Флаги проверки | Верный — первым | 1 000 уроков, оценка сейчас |
| --- | --- | --- | --- | --- | --- |
| [GPT-5 Mini](https://polza.ai/models/openai/gpt-5-mini.md) | 257 ₽ | 11,8 с | 0 из 15 | 11 из 15 | 257 ₽ |
| [Gemini 2.5 Flash](https://polza.ai/models/google/gemini-2.5-flash.md) | 780 ₽ | 17,6 с | 2 из 15 | 0 из 15 | 320 ₽ |
| [DeepSeek V4 Pro](https://polza.ai/models/deepseek/deepseek-v4-pro.md) | 189 ₽ | 88,0 с | 1 из 15 | 2 из 15 | 601 ₽ |
| [Grok 4.3](https://polza.ai/models/x-ai/grok-4.3.md) | 502 ₽ | 13,6 с | 1 из 15 | 1 из 15 | 786 ₽ |
| [Claude Sonnet 5](https://polza.ai/models/anthropic/claude-sonnet-5.md) | 1 204 ₽ | 10,1 с | 1 из 15 | 3 из 15 | 2 681 ₽ |

Замер — 6 октября 2026, по ценам того дня.

«Оценка сейчас» — по текущим ценам каталога для объёмов, которые оценила редакция, а не замерил тест: 1 300 токенов на входе (промпт и текст урока) и 2 000 на выходе (тест в JSON вместе с рассуждением; у моделей, которые рассуждают дольше, выход больше) на один урок.

Проверка решением на Gemini 2.5 Flash стоила 0,7 ₽ на 12 уроков по ценам 6 октября. Последняя колонка — сколько раз верный ответ стоял первым до перемешивания: у GPT-5 Mini 11 из 15, поэтому скрипт перемешивает варианты сам. Как не платить за лишнее — в сценарии про SEO-тексты: [как не переплатить за рассуждение и провайдера](https://polza.ai/use-cases/seo-content#stoimost).

## Готовый скрипт на Python

Читает уроки из таблицы, пишет тесты параллельно, перемешивает варианты и печатает расход. Второй скрипт собирает файл GIFT. Нужен пакет `openai` и ключ в `POLZA_API_KEY`.

### Вход: lessons.csv

Курс, тема и текст урока. Чем точнее текст, тем точнее вопросы: модель спрашивает только то, что в нём есть.

lessons.csv:

```
id,course,topic,text
L10,Веб-разработка,Коды ответа HTTP,"Сервер отвечает на каждый HTTP-запрос трёхзначным кодом состояния. Первая цифра показывает класс ответа: 2xx — успех, 3x…"
```

### Выход: один вопрос

Вопрос, варианты, номер верного, пояснение и уровень. Реальный ответ из теста.

quizzes.jsonl · вопрос:

```
{
  "question": "Как правильно поступить с одеждой, прилипшей к термическому ожогу?",
  "options": [
    "Аккуратно оторвать её от кожи",
    "Обрезать одежду вокруг прилипшего участка",
    "Оставить до осмотра врачом",
    "Смазать маслом и снять"
  ],
  "correct": 1,
  "explanation": "Текст прямо указывает: прилипшую к коже одежду не отрывают — её обрезают вокруг.",
  "level": "запоминание"
}
```

Python · make_quiz.py:

```
# make_quiz.py — тесты по урокам из CSV через Polza
import asyncio, csv, json, os, random
from openai import AsyncOpenAI, APIStatusError

MODEL = "deepseek/deepseek-v4-pro"
PROVIDER = "streamlake/fp8"  # самый дешёвый провайдер модели: top_provider.name в каталоге
CONCURRENCY = 10

ai = AsyncOpenAI(base_url="https://polza.ai/api/v1", api_key=os.environ["POLZA_API_KEY"])
SYSTEM = open("prompt.txt", encoding="utf-8").read()

QUESTION = {
    "type": "object",
    "properties": {
        "question": {"type": "string"},
        "options": {"type": "array", "items": {"type": "string"}},
        "correct": {"type": "integer"},
        "explanation": {"type": "string"},
        "level": {"type": "string", "enum": ["запоминание", "понимание", "применение"]},
    },
    "required": ["question", "options", "correct", "explanation", "level"],
    "additionalProperties": False,
}
SCHEMA = {"name": "quiz", "strict": True, "schema": {
    "type": "object", "properties": {"questions": {"type": "array", "items": QUESTION}},
    "required": ["questions"], "additionalProperties": False}}

async def make(row, sem, stats):
    prompt = f"Курс: {row['course']}\nТема: {row['topic']}\n\nТекст урока:\n{row['text']}"
    async with sem:
        for attempt in range(5):
            try:
                r = await ai.chat.completions.create(
                    model=MODEL,
                    messages=[{"role": "system", "content": SYSTEM},
                              {"role": "user", "content": prompt}],
                    response_format={"type": "json_schema", "json_schema": SCHEMA},
                    extra_body={"reasoning": {"effort": "low"},  # короткое рассуждение: в тесте без него было 5 неверных ключей на 60 вопросов, с ним — ни одного
                                "provider": {"only": [PROVIDER], "allow_fallbacks": False}},
                )
                break
            except APIStatusError as e:
                if e.status_code in (429, 500, 502, 503) and attempt < 4:
                    await asyncio.sleep(2 ** attempt)
                    continue
                raise
    stats["rub"] += r.usage.model_extra.get("cost_rub", 0)
    quiz = json.loads(r.choices[0].message.content)
    rnd = random.Random(row["id"])  # перемешиваем варианты: модели ставят верный ответ в одни и те же позиции
    for q in quiz["questions"]:
        right = q["options"][q["correct"]]
        rnd.shuffle(q["options"])
        q["correct"] = q["options"].index(right)
    return {"id": row["id"], "topic": row["topic"], **quiz}

async def main():
    rows = list(csv.DictReader(open("lessons.csv", encoding="utf-8")))
    sem, stats = asyncio.Semaphore(CONCURRENCY), {"rub": 0}
    results = await asyncio.gather(*(make(r, sem, stats) for r in rows), return_exceptions=True)
    ok = 0
    with open("quizzes.jsonl", "w", encoding="utf-8") as out, open("errors.txt", "w", encoding="utf-8") as err:
        for row, res in zip(rows, results):
            if isinstance(res, Exception):
                err.write(f"{row['id']}\t{res}\n")
            else:
                out.write(json.dumps(res, ensure_ascii=False) + "\n")
                ok += 1
    print(f"Готово {ok} из {len(rows)}, расход {stats['rub']:.2f} ₽")

asyncio.run(main())
```

Python · to_gift.py:

```
# to_gift.py — выгрузка тестов в формат GIFT для импорта в банк вопросов Moodle
import json

def esc(s):
    # служебные символы GIFT экранируются обратной косой чертой
    for ch in '\\~=#{}:':
        s = s.replace(ch, '\\' + ch)
    return s

with open("quizzes.gift", "w", encoding="utf-8") as out:
    for line in open("quizzes.jsonl", encoding="utf-8"):
        quiz = json.loads(line)
        out.write(f"$CATEGORY: {esc(quiz['topic'])}\n\n")
        for i, q in enumerate(quiz["questions"], 1):
            opts = "\n".join(("=" if k == q["correct"] else "~") + esc(o) for k, o in enumerate(q["options"]))
            out.write(f"::{quiz['id']}-{i}:: {esc(q['question'])} {{\n{opts}\n####{esc(q['explanation'])}\n}}\n\n")

print("quizzes.gift готов")
```

Для DeepSeek V4 Pro каталог перечисляет уровни рассуждения `high` и `xhigh`; в тесте передавали `low`.

## Промпт для тестов

Промпт задаёт состав теста — два вопроса на запоминание, два на понимание, один на применение — и правила для вариантов. Главное правило: ответ однозначно следует из текста урока.

Вторая версия добавила четыре запрета по итогам первого прогона: варианты не повторяются, отвечают на сам вопрос, нет вопросов «что НЕ…», а задачу модель сначала решает сама. В первом прогоне были повторяющиеся варианты в тесте по английскому и вопрос «почему», в котором варианты были следствиями.

prompt.txt:

```
Ты составляешь тест по учебному тексту для онлайн-
курса.

Сделай 5 вопросов:
- 2 на запоминание факта из текста,
- 2 на понимание: объяснить, сравнить, найти
  причину,
- 1 на применение: задача или ситуация, которую
  решают по правилу из текста.

Правила:
- Ответ на каждый вопрос однозначно следует из
  текста. Не спрашивай того, чего в тексте нет.
- У каждого вопроса 4 разных варианта и ровно один
  верный. Варианты не повторяются.
- Варианты отвечают на сам вопрос: на «почему» —
  причины, на «сколько» — числа, на «какой код» —
  код.
- Не задавай вопросов «что НЕ…» и вопросов, где
  подходят несколько вариантов.
- В задачах на применение сначала реши задачу сам и
  проверь, что верный вариант совпадает с решением.
- Неверные варианты правдоподобные: той же длины и
  формы, что верный, из той же темы.
- Не используй варианты «все ответы верны», «нет
  верного ответа», «оба варианта».
- Верный вариант ставь в разные позиции, не всегда
  первым.
- Пояснение — одно-два предложения: почему ответ
  верный, со ссылкой на мысль из текста.
- Формулировки короткие, на «ты» не обращайся.

Верни JSON: questions — список из 5 вопросов, у
каждого:
question — текст вопроса, options — 4 варианта,
correct — номер верного варианта от 0 до 3,
explanation — пояснение, level — «запоминание»,
«понимание» или «применение».
```

## Проверка теста

Модель-автор ошибается в ключах. Поэтому тест проверяет вторая модель — решает его так же, как ученик: [проверка по эталону, как в протоколах](https://polza.ai/use-cases/protokoly-vstrech).

- **Решение без ключа.** Gemini 2.5 Flash получает текст урока и вопросы без ответов. Если её ответ не совпал с ключом или она считает вопрос двусмысленным — флаг. В первом прогоне так нашлись 9 из 11 ошибок, без единого ложного флага.
- **Опасные ошибки.** В первом прогоне к уроку о первой помощи верным был отмечен вариант «вскрыть пузыри и наложить повязку». Проверка решением его поймала. Тесты по охране труда и медицине методист читает целиком.
- **Повторы вариантов.** Одинаковые варианты внутри вопроса ловит одна строка кода. В первом прогоне их было 5 вопросов, во втором — ни одного.
- **Позиции верных ответов.** Модели ставят верный ответ в одни и те же места: Claude Sonnet ни разу не поставила его четвёртым, GPT-5 Mini в 11 из 15 ставила первым. Скрипт перемешивает варианты.
- **Самый длинный — верный.** Верный вариант часто длиннее и подробнее остальных: так было в 25 из 60 вопросов при 25% случайных. Перемешивание это не исправит — смотрите на длину при вычитке.
- **Методист читает флаги.** После проверки на человека остаются вопросы с флагами и выборка остальных. Это минуты на урок вместо получаса на написание теста.

## Через Claude, OpenAI и Grok — или без кода

Скрипт генерации, проверку и файл для Moodle соберёт ИИ-агент. Модели — в том же каталоге Polza.ai.

- **Claude Code и Claude Desktop.** Положите уроки и промпт в папку и отдайте Claude задание ниже: тесты, проверка и GIFT за один заход. Claude Sonnet 5: тесты к 1 000 уроков — 2 681 ₽, оценка по ценам каталога.
- **Codex и ChatGPT Desktop.** То же задание выполняет Codex CLI. Модели GPT подключаются тем же ключом Polza. GPT-5 Mini: тесты к 1 000 уроков — 257 ₽, оценка по ценам каталога.
- **Grok.** Модели xAI в том же API: `MODEL = "x-ai/grok-4.3"` в скрипте. Grok 4.3: тесты к 1 000 уроков — 786 ₽, оценка по ценам каталога.

### Задание для агента

Подходит для Claude Code, Codex и других агентов из [интеграций](https://polza.ai/integrations).

задание для Claude Code или Codex:

```
В папке лежат lessons.csv и prompt.txt.
Напиши и запусти скрипт на Python:
для каждого урока запрос к https://polza.ai/api/v1
через OpenAI SDK, ключ — в переменной POLZA_API_KEY,
модель deepseek/deepseek-v4-pro
с коротким рассуждением (reasoning: {effort: low}),
системный промпт — prompt.txt, ответ — JSON
с полями question, options, correct, explanation, level.
Перемешай варианты и пересчитай correct.
Потом проверь тест: google/gemini-2.5-flash отвечает
на вопросы по тексту урока без ключа,
расхождения выведи списком.
В конце собери quizzes.gift для Moodle.
```

### Без кода: n8n и Dify

Новый урок в таблице или CMS — нода OpenAI Chat Model с адресом `https://polza.ai/api/v1` — тест в таблицу методисту на проверку.

- **n8n.** Обновили урок — сценарий пересобрал тест и прислал методисту ссылку. Нода OpenAI Chat Model с адресом Polza.
- **Dify.** Workflow: генерация, проверка решением, выгрузка. Облако или self-hosted.

## Тест редакции: 12 уроков, 60 вопросов

Мы написали 12 коротких уроков: от фотосинтеза и закона Ома до списков в Python и первой помощи при ожоге. Редактор прочитал все вопросы каждого прогона, где это было нужно для оценки. Замер 6 октября 2026: весь тест, включая сравнение пяти моделей, стоил 16 ₽ по ценам того дня.

- Уроков: 12
- Вопросов: 60
- Неверных ключей: 0
- На проверку методисту: 2

### Три прогона DeepSeek V4 Pro

| Прогон | Расход | Время | Ошибки по вычитке | Флаги проверки | Без повторов |
| --- | --- | --- | --- | --- | --- |
| v1: без рассуждения | 0,51 ₽ | 72 с | 11 из 60 | 9 | 55 из 60 |
| v2: новый промпт, без рассуждения | 0,52 ₽ | 188 с | ≥5 | 6 | 60 из 60 |
| v2: новый промпт, короткое рассуждение | 2,59 ₽ | 207 с | 0 ключей, 3 спорных | 2 | 60 из 60 |

Во втором прогоне редактор прочитал только вопросы с флагами — из 6 настоящими ошибками оказались 5. Третий прочитан целиком: неверных ключей нет, в 3 вопросах неудачные варианты. Расход — по ценам 6 октября 2026.

- **Опасный ключ.** К уроку о первой помощи верным отмечен вариант «вскрыть пузыри и наложить повязку», хотя в тексте прямо сказано: пузыри не вскрывают.
- **Неверные ответы.** Для среза `[5, 10, 15][1:3]` верным отмечено «1, 2» вместо `[10, 15]`. В тесте по английскому — повторяющиеся варианты и неверная форма глагола.
- **Вопрос и ответы не сходятся.** На «почему увеличение сопротивления уменьшает ток» варианты: «уменьшение силы тока», «увеличение напряжения».

### Пять моделей на трёх трудных уроках

| Модель | 1 000 уроков, замер | Флаги проверки | Что увидел редактор |
| --- | --- | --- | --- |
| DeepSeek V4 Pro | 189 ₽ | 1 из 15 | Ключи верные. Медленная с рассуждением: полторы минуты на урок. |
| GPT-5 Mini | 257 ₽ | 0 из 15 | Ни одного флага, быстрая. Верный ответ почти всегда ставит первым — без перемешивания не обойтись. |
| Gemini 2.5 Flash | 780 ₽ | 2 из 15 | Ключи верные, но задачи перегружены лишними условиями. |
| Grok 4.3 | 502 ₽ | 1 из 15 | Ключи верные, вопросы короткие и чёткие. Один вопрос «почему» с ответом, которого нет в тексте. |
| Claude Sonnet 5 | 1 204 ₽ | 1 из 15 | Аккуратные формулировки. Ни разу не ставит верный ответ последним. |

Уроки: списки в Python, Present Perfect, первая помощь при ожоге. Промпт v2, короткое рассуждение. Неверных ключей не было ни у одной модели. Стоимость — замер 6 октября 2026 по ценам того дня, текущая — в [разделе «Стоимость»](#stoimost).

**Вывод.** Для тестов рассуждение окупается: без него неверных ключей в разы больше, с ним — ни одного на 60 вопросах. Генерация на DeepSeek V4 Pro или GPT-5 Mini — по оценке на текущих ценах каталога 601 ₽ и 257 ₽ за 1 000 уроков, проверка решением на Gemini 2.5 Flash, перемешивание вариантов в коде. Методист читает флаги и тесты по безопасности целиком.

## Вопросы

### Можно ли выдавать тесты ученикам без проверки?

Нет. Даже с рассуждением и проверкой решением методист читает вопросы с флагами, а тесты по охране труда и медицине — целиком. В первом прогоне модель отметила верным опасный совет при ожоге.

### Почему проверяет другая модель?

Модель, которая написала вопрос, склонна соглашаться со своим ключом. Вторая модель решает тест как ученик: по тексту урока и без ответов.

### Сколько вопросов делать к уроку?

Пять — хватает, чтобы проверить ключевые мысли короткого урока. Для длинного урока разбейте текст на части и делайте тест к каждой.

### Можно ли загрузить тесты в Moodle и другие LMS?

В Moodle — через импорт в формате GIFT: скрипт со страницы собирает файл, каждый урок — отдельная категория банка вопросов. Для GetCourse и других LMS с импортом вопросов соберите из JSON файл в формате импорта платформы.

### Подойдут ли тесты для школьной программы?

Да, если в запросе текст параграфа или конспекта. Модель спрашивает только то, что есть в тексте, поэтому качество теста зависит от качества материала.

### Можно ли платить юрлицом?

Да. Polza.ai работает по договору: счёт, УПД и НДС. Расход виден в кабинете по ключам и моделям.

## Ссылки

- Сценарий «SEO-тексты»: https://polza.ai/use-cases/seo-content.md
- Сценарий «Ответы на отзывы»: https://polza.ai/use-cases/otvety-na-otzyvy.md
- Сценарий «Объявления для Авито»: https://polza.ai/use-cases/obyavleniya-avito.md
- Сценарий «Письма клиентам»: https://polza.ai/use-cases/pisma-klientam.md
- Сценарий «Протоколы встреч»: https://polza.ai/use-cases/protokoly-vstrech.md
- Документация: https://polza.ai/docs
- Каталог моделей: https://polza.ai/models/llms.txt
- Страница: https://polza.ai/use-cases/testy-po-urokam
- Обновлено: 2026-10-14; замер теста — 6 октября 2026
