Р. Аллахвердиев
Оценка качестваLLM и моделиСерия «AI QA с нуля» · часть 6

Python-минимум для AI QA: что учить за 2–3 недели и что пропустить

Список того, что нужно знать на Python, чтобы писать проверки LLM и RAG: JSON, HTTP-клиент, CSV, pytest с параметризацией, переменные окружения. С примером первого теста на ответ модели.

опубликовано · 8 мин3707740
Обложка: Python-минимум для AI QA: что учить за 2–3 недели и что пропустить
Содержание

Коротко

  • Для 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: темы 1–5. Каждый день небольшой скрипт: прочитать CSV, отправить запрос, записать результат в новый CSV.
  2. Неделя 2: pytest и .env. Превратите скрипт в тесты с параметризацией.
  3. Неделя 3: закрепление на небольшом проекте — например, из портфолио-проекта AI QA.

Практикуйтесь на бесплатных локальных моделях через Ollama: так учёба не зависит от баланса на аккаунте провайдера.

Типичные ошибки новичков

  • Нет таймаута у запроса. Тест повисает на минуты, и вы не понимаете, где проблема.
  • Ключ в коде. Один случайный коммит, и ключ нужно перевыпускать. Читайте из окружения с первого дня.
  • Кодировка по умолчанию. Кириллица в CSV превращается в «кракозябры» на одной машине и нормальна на другой. Указывайте encoding="utf-8" явно.
  • Один тест на весь датасет. Падение на сотом вопросе скрывает результаты остальных. Параметризуйте: один вопрос — один тест.
  • Проверка точной строки. assert answer == "30 дней" ломается от любой перефразировки. Для первых проверок берите структурные признаки (формат, наличие поля, длина), а смысловые оценивайте метриками.
  • Глотание исключений. except: pass превращает ошибку сети в «тест прошёл». Пусть тест падает громко.
  • Нефиксированные зависимости. После обновления библиотеки метрик цифры меняются, а вы не знаете почему.

Упражнения на каждый день

  1. Прочитайте CSV из пяти вопросов и напечатайте длину каждого вопроса.
  2. Отправьте один вопрос в модель и сохраните полный JSON-ответ в файл. Найдите в нём поле с текстом и поле с числом токенов.
  3. Отправьте все пять вопросов и запишите результаты в новый CSV: вопрос, ответ, время запроса.
  4. Добавьте обработку ошибок: если запрос упал по таймауту, запишите это в колонку, а не прерывайте программу.
  5. Превратите скрипт в pytest-тест с параметризацией и тремя проверками (не пусто, не длиннее лимита, содержит ключевое слово).
  6. Вынесите адрес, ключ и модель в переменные окружения и добавьте .env.example.

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

Что дальше