Генерация тестовых данных нейросетью: схема, валидация и фикстуры
Когда тестовые данные стоит генерировать нейросетью, а когда хватит Faker. Скрипт на Python с валидацией pydantic, батчами, фикстурами для pytest и расчётом стоимости.
5 мин · · разработка · автоматизация
Генерация тестовых данных нейросетью полезна там, где случайных строк мало: обращения в поддержку, отзывы, описания товаров, профили с согласованными полями. Ниже — скрипт на Python, который получает такие записи через API, проверяет каждую через pydantic, убирает дубликаты и сохраняет результат в фикстуру для тестов. Отдельно — как сделать данные повторяемыми и сколько это стоит.
Нейросеть или Faker
Faker и похожие библиотеки быстрые, бесплатные и детерминированные при фиксированном seed. Но они собирают значения независимо друг от друга: город не связан с именем, текст обращения — набор случайных слов.
| Задача | Чем лучше генерировать |
|---|---|
| ID, UUID, даты, номера, суммы | Faker или свой код |
| Поля с жёстким форматом (ИНН, телефоны) | Faker или свой код с проверкой контрольных сумм |
| Связный текст: обращения, отзывы, комментарии | нейросеть |
| Согласованные профили (возраст, профессия, тариф, история) | нейросеть |
| Краевые случаи для парсеров (опечатки, смешанные языки, эмодзи) | нейросеть по явному списку случаев |
Практичный вариант — гибрид: служебные поля (id, даты, суммы) генерирует ваш код, а нейросеть отвечает только за содержательные. Так ID гарантированно уникальны, а тексты выглядят естественно.
Схема → запрос → валидация → фикстура
- Описать запись моделью pydantic: типы, диапазоны, допустимые значения.
- Попросить модель вернуть JSON-массив с этими полями.
- Достать массив из ответа и проверить каждую запись; невалидные отбросить.
- Убрать дубликаты, назначить ID своим кодом, сохранить в файл.
Ключ fetch_... создайте в кабинете Zukko и задайте в переменной ZUKKO_API_KEY. Зависимости: pip install openai pydantic.
import json
import os
from typing import Literal
from openai import OpenAI
from pydantic import BaseModel, Field, ValidationError
client = OpenAI(base_url="https://api.zukko.pro/v1", api_key=os.environ["ZUKKO_API_KEY"])
MODEL = os.getenv("ZUKKO_MODEL", "glm-5.3-flash")
SEGMENTS = ["студенты", "пенсионеры", "предприниматели", "IT-специалисты", "родители с детьми"]
class Customer(BaseModel):
first_name: str = Field(min_length=2, max_length=50)Что важно в этом коде:
- Только зарезервированные домены. Адреса на
example.com,example.org,example.netзарезервированы для документации и примеров, поэтому тестовое письмо случайно не уйдёт реальному человеку. Регулярное выражение в модели отбрасывает всё остальное. - Устойчивый разбор. Модели иногда оборачивают JSON в markdown-блок или добавляют фразу перед ним.
extract_json_arrayберёт текст от первой[до последней]; если массива нет, партия пропускается. - Валидация каждой записи. Pydantic проверяет типы, длины, диапазон возраста и
Literalдля тарифа. Невалидные записи отбрасываются, остальные из партии сохраняются. - ID и уникальность — на стороне кода. Модель не знает, что она сгенерировала в прошлой партии, поэтому дубли email убираются по множеству
seen, аidназначается по порядку. - Сегменты. Разные сегменты в соседних запросах делают выборку разнообразнее, чем десять одинаковых запросов подряд.
- Ограничение попыток. Цикл не уйдёт в бесконечность, если модель раз за разом возвращает мусор.
Повторяемость данных
Ответ модели меняется от запуска к запуску, и слово «seed» в промпте этого не исправит. Не стоит полагаться и на параметры сэмплирования вроде temperature: они не делают ответ детерминированным, а новые модели Claude могут отклонить нестандартное значение temperature ошибкой 400, поэтому в примерах для claude-* его лучше не передавать вовсе.
Надёжный способ один — сгенерировать один раз и сохранить. Файл customers.json кладётся в репозиторий рядом с тестами, а тесты читают его как фикстуру:
import json
from pathlib import Path
import pytest
FIXTURE = Path(__file__).parent / "data" / "customers.json"
@pytest.fixture(scope="session")
def customers():
return json.loads(FIXTURE.read_text(encoding="utf-8"))
def test_every_customer_has_ticket(customers):
assert all(len(c["support_ticket"]) >= 20 for c in customers)Так тесты не зависят от сети и баланса, работают в CI без ключа, а перегенерация данных становится осознанным действием с понятным diff в ревью.
Если нужно повторять один и тот же запрос во время отладки, у Zukko есть кэш ответов по явному заголовку: запрос с X-Zukko-Cache: true и точно таким же телом в течение 7 дней вернёт сохранённый ответ, а в заголовке ответа будет X-Zukko-Cache: hit. В OpenAI SDK заголовок передаётся через extra_headers, а заголовки ответа видны через with_raw_response:
raw = client.chat.completions.with_raw_response.create(
model=MODEL,
max_tokens=4000,
messages=[{"role": "user", "content": PROMPT.format(count=10, segment="студенты")}],
extra_headers={"X-Zukko-Cache": "true"},
)
print(raw.headers.get("X-Zukko-Cache"))
response = raw.parse()Подробнее о кэше и лимитах ключей — в документации.
Валидация через jsonschema
Если схема уже описана в JSON Schema (например, это контракт API), можно проверять записи библиотекой jsonschema вместо pydantic:
import jsonschema
for record in records:
try:
jsonschema.validate(instance=record, schema=schema)
except jsonschema.ValidationError as e:
print("Запись отброшена:", e.message)Ту же схему полезно вставить в промпт: модели проще следовать явному описанию полей, чем пересказу словами.
Сколько стоит и какую модель взять
Цены в Zukko за 1M токенов (вход/выход): glm-5.3-flash — $0.04 / $0.04, gpt-5.6-luna — $0.10 / $0.10, claude-sonnet-5 — $0.30 / $0.30. Актуальный список — GET https://api.zukko.pro/v1/models или страница «Модели» в кабинете.
Пример: 1 000 записей партиями по 10 — это 100 запросов. Пусть промпт занимает 400 входных токенов, а ответ с десятью записями — 1 500 выходных.
glm-5.3-flash: 100 × (400 + 1 500) × $0.04 / 1 000 000 = $0.0076.claude-sonnet-5: 100 × (400 + 1 500) × $0.30 / 1 000 000 = $0.057.
Отброшенные записи и повторные партии добавят несколько процентов к этим суммам. Какая модель даёт достаточно разнообразные и корректные данные для ваших тестов, проверьте на своих задачах: сгенерируйте по 50 записей двумя моделями и посмотрите, сколько отброшено валидацией и насколько тексты похожи друг на друга.
Частые вопросы
Как не получить реальные персональные данные?
Пишите в промпте «вымышленные», запрещайте знаменитостей и используйте только зарезервированные домены example.*, как в примере. Для телефонов и документов генерируйте значения своим кодом в заведомо тестовых диапазонах, а не просите модель.
Модель возвращает меньше записей, чем просили
Это нормально: часть записей отбрасывает валидация, а иногда модель обрезает ответ по max_tokens. Цикл в generate() добирает недостающее следующими партиями. Если ответы регулярно обрываются, уменьшите batch_size или увеличьте max_tokens.
Можно ли генерировать картинки или PDF?
Моделей для генерации изображений в каталоге Zukko нет. Для PDF и документов используйте библиотеки вроде ReportLab, а нейросеть — только для текста, который в них попадёт.
Как генерировать данные для нескольких связанных таблиц?
Сначала сгенерируйте родительские записи (клиенты) и назначьте им ID, затем передавайте в промпт для дочерних (заказы, обращения) короткий список ID и ключевых полей родителя. Связи проверяйте кодом после генерации. Формат запросов описан в справочнике chat completions.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Перевод субтитров нейросетью: SRT без сбитых таймкодовГлавный риск при переводе SRT нейросетью — сломанная структура файла. Показываем схему, где таймкоды не попадают к модели, и скрипт на Python с проверкой.
- Редактирование текстов нейросетью: корректура, стиль и сокращениеРазные виды редактуры требуют разных промптов. Показываем формулировки для корректуры, стиля и сокращения, как получать правки с объяснением и не терять авторский голос.
- Нейросеть для написания скриптов: Bash, PowerShell и PythonМодель быстро пишет скрипты для рутины, но запускать их вслепую нельзя. Показываем, как ставить задачу, требовать безопасный режим dry-run и проверять результат до запуска.
- Dify в Docker: установка, первичная настройка и подключение моделейСтавим Dify через Docker Compose, создаём администратора и подключаем модели Claude, GPT и DeepSeek по одному ключу. Отдельно — что делать, если контейнеры не стартуют.