Python-минимум для AI QA: что учить за 2–3 недели и что пропустить
Список того, что нужно знать на Python, чтобы писать проверки LLM и RAG: JSON, HTTP-клиент, CSV, pytest с параметризацией, переменные окружения. С примером первого теста на ответ модели.
3707740
Содержание
Коротко
- Для AI QA не нужен весь Python. Хватает восьми тем: типы данных, словари и JSON, функции, чтение CSV, HTTP-запросы, pytest, переменные окружения и виртуальное окружение.
- Главный навык — склеить цепочку: прочитать датасет, вызвать систему, получить ответ, посчитать результат, записать отчёт.
- Асинхронность, декораторы, классы и ООП вы освоите по мере необходимости. На старте они тормозят.
- Секреты хранятся в
.env, который не попадает в репозиторий. Это правило безопасности, а не стиль. - Проверка готовности: вы можете за вечер написать pytest-тест, который читает вопросы из CSV, вызывает модель и падает при пустом или некорректном ответе.
Почему именно минимум
Ручной QA часто откладывает код «на потом», потому что учебники Python огромные. Но задачи AI QA очень однотипны: взять набор вопросов, отправить их в систему, разобрать JSON-ответ, применить проверки. Под эти задачи нужен узкий срез языка. Остальное дорабатывается уже на реальных задачах.
Если вы автоматизатор и пишете на Java или JavaScript, весь Python-блок сводится к синтаксису и экосистеме: pytest вместо JUnit, httpx вместо вашего HTTP-клиента. Фреймворки оценки качества (DeepEval, RAGAS) написаны на Python, поэтому для этой работы язык лучше выучить.
Восемь тем
1. Типы данных и f-строки
Строки, числа, списки, словари, множества, None. F-строки нужны для шаблонов промптов и отчётов:
question = "Сколько дней на возврат?"
prompt = f"Ответь по правилам магазина. Вопрос: {question}"
2. Словари и JSON
Ответ любого LLM API — JSON. Вы должны уверенно доставать вложенные поля и обрабатывать случай, когда поля нет:
data = {"choices": [{"message": {"content": "30 дней"}}]}
text = data["choices"][0]["message"]["content"]
missing = data.get("error", {}).get("message") # не упадёт, вернёт None
3. Функции
Оборачивайте каждое обращение к системе в функцию ask(question) -> str. Тогда замена модели или сервиса правит одно место.
4. Чтение и запись CSV
Датасет почти всегда лежит в таблице. Модуль csv из стандартной библиотеки хватает:
import csv
def load_dataset(path: str) -> list[dict]:
with open(path, encoding="utf-8", newline="") as f:
return list(csv.DictReader(f))
Кодировку utf-8 указывайте явно: на Windows умолчание бывает другим, и кириллица превращается в мусор.
5. HTTP-запросы
Библиотеки httpx или requests: POST с JSON, заголовки, таймаут, проверка статуса. Таймаут обязателен: LLM может «зависнуть», и тест без таймаута повиснет вместе с ним.
import httpx
def call_api(url: str, payload: dict, key: str) -> dict:
r = httpx.post(url, json=payload, headers={"Authorization": f"Bearer {key}"}, timeout=60)
r.raise_for_status()
return r.json()
6. pytest: тест, фикстура, параметризация, маркеры
Это самая важная тема. Параметризация превращает датасет в набор тестов:
import pytest
from dataset import load_dataset
from client import ask
CASES = load_dataset("golden.csv")
@pytest.mark.parametrize("case", CASES, ids=[c["id"] for c in CASES])
def test_answer_not_empty_and_short(case):
answer = ask(case["question"])
assert answer.strip(), "пустой ответ"
assert len(answer) < 1500, "ответ слишком длинный"
Фикстуры пригодятся для общего клиента, маркеры — чтобы делить дешёвые и дорогие проверки (@pytest.mark.slow).
7. Переменные окружения и .env
Ключи API никогда не пишутся в код и не коммитятся. Читайте их из окружения:
import os
API_KEY = os.environ["LLM_KEY"] # упадёт сразу, если ключ не задан, и это хорошо
Файл .env добавьте в .gitignore до первого коммита. Если ключ однажды попал в историю репозитория, считайте его скомпрометированным и перевыпустите.
8. Виртуальное окружение и зависимости
Отдельное окружение на проект (python -m venv .venv или uv) и файл зависимостей с зафиксированными версиями. Для оценки качества это критично: обновление библиотеки метрик может сдвинуть оценки.
Что можно отложить
- Классы и ООП — функций и словарей хватает.
- Асинхронный код (
asyncio) — понадобится для нагрузочных и параллельных прогонов, но не в первые недели. - Декораторы и метаклассы — пока вы лишь пользуетесь чужими декораторами (
@pytest.mark...). - Типизация и линтеры — полезны, подключайте после первых рабочих скриптов.
- Фреймворки веб-разработки — для проверки не нужны.
Первый тест на ответ модели
Это финальное задание блока: связать всё вместе. Вот скелет, который можно запустить на любой модели через OpenAI-совместимый API.
# test_smoke.py
import os, httpx, pytest
URL = os.environ.get("LLM_URL", "http://localhost:11434/v1/chat/completions")
KEY = os.environ.get("LLM_KEY", "")
MODEL = os.environ.get("LLM_MODEL", "your-model")
def ask(question: str) -> str:
r = httpx.post(
URL,
headers={"Authorization": f"Bearer {KEY}"},
json={"model": MODEL, "temperature": 0,
"messages": [{"role": "user", "content": question}]},
timeout=60,
)
r.raise_for_status()
return r.json()["choices"][0]["message"]["content"]
@pytest.mark.parametrize("question,must_contain", [
("Сколько будет 2+2? Ответь одним числом.", "4"),
("Назови столицу Франции одним словом.", "Париж"),
])
def test_contains_expected(question, must_contain):
assert must_contain in ask(question)
Запуск: pytest -v. Этот тест нарочито примитивен. Он показывает механику, а для настоящих ответов LLM строгое in обычно слишком хрупко: ответы можно проверять метриками, о которых говорится дальше по карте навыков.
Как учить: порядок на 2–3 недели
- Неделя 1: темы 1–5. Каждый день небольшой скрипт: прочитать CSV, отправить запрос, записать результат в новый CSV.
- Неделя 2: pytest и
.env. Превратите скрипт в тесты с параметризацией. - Неделя 3: закрепление на небольшом проекте — например, из портфолио-проекта AI QA.
Практикуйтесь на бесплатных локальных моделях через Ollama: так учёба не зависит от баланса на аккаунте провайдера.
Типичные ошибки новичков
- Нет таймаута у запроса. Тест повисает на минуты, и вы не понимаете, где проблема.
- Ключ в коде. Один случайный коммит, и ключ нужно перевыпускать. Читайте из окружения с первого дня.
- Кодировка по умолчанию. Кириллица в CSV превращается в «кракозябры» на одной машине и нормальна на другой. Указывайте
encoding="utf-8"явно. - Один тест на весь датасет. Падение на сотом вопросе скрывает результаты остальных. Параметризуйте: один вопрос — один тест.
- Проверка точной строки.
assert answer == "30 дней"ломается от любой перефразировки. Для первых проверок берите структурные признаки (формат, наличие поля, длина), а смысловые оценивайте метриками. - Глотание исключений.
except: passпревращает ошибку сети в «тест прошёл». Пусть тест падает громко. - Нефиксированные зависимости. После обновления библиотеки метрик цифры меняются, а вы не знаете почему.
Упражнения на каждый день
- Прочитайте CSV из пяти вопросов и напечатайте длину каждого вопроса.
- Отправьте один вопрос в модель и сохраните полный JSON-ответ в файл. Найдите в нём поле с текстом и поле с числом токенов.
- Отправьте все пять вопросов и запишите результаты в новый CSV: вопрос, ответ, время запроса.
- Добавьте обработку ошибок: если запрос упал по таймауту, запишите это в колонку, а не прерывайте программу.
- Превратите скрипт в pytest-тест с параметризацией и тремя проверками (не пусто, не длиннее лимита, содержит ключевое слово).
- Вынесите адрес, ключ и модель в переменные окружения и добавьте
.env.example.
Если все шесть пунктов выполнены без подсказок, вы готовы к задачам из карты навыков: к датасетам и метрикам.
Что дальше
- Поставьте Python, создайте виртуальное окружение и запустите тест выше на своей модели.
- Вернитесь к карте навыков и отметьте закрытые блоки.
- Следующая статья серии — как собрать портфолио-проект AI QA.


