← Назад

Параллельное тестирование 4 архитектурных подходов: как SuperSlide выбирал между LLM-стратегиями

2026-03-10 #ai#architecture#superslide#testing#llm

У тебя 4 способа решить задачу. Каждый звучит убедительно, но ни один нельзя отбросить без эксперимента. Классический подход — пробовать по одному. Но когда каждый вариант требует 3-6 часов подготовки данных, последовательное тестирование растягивается на недели. В SuperSlide я решил запустить всё параллельно — и делегировать каждый поток отдельному агенту.

Задача

SuperSlide делает презентации из текста. У нас 57 шаблонов — от cover_dark до roadmap_horizontal. LLM должна понимать, что «рост продаж на 30%» — это слайд с KPI-блоками, а не буллет-лист.

Первая версия работала через OpenRouter. Я давал модели текстовое описание каталога, она выбирала подходящий вариант. Результат — 60% точность. Остальные 40% — повторяла любимые лейауты или ошибалась с форматом.

Нужен был подход лучше. Какой именно — было неясно.

4 подхода, которые я тестировал

Вариант A — текущий baseline. LLM получает каталог шаблонов как текст, выбирает по описанию, заполняет плейсхолдеры. Просто, но модель «залипает» на 5-6 любимых лейаутах из 57.

Вариант B — примеры вместо описаний. Модель получает 57 заполненных примеров вместо пустых шаблонов с {{PLACEHOLDER}}. Гипотеза: конкретика учит лучше абстракций.

Вариант B2 — Qdrant + семантический поиск. Каждый шаблон получает semantic_description («3 числовых индикатора, KPI-метрики, квартальные результаты») и индексируется в Qdrant. Логика: POST /api/context/semantic → поиск ближайших шаблонов → фильтрация дубликатов. Гипотеза: пусть векторный поиск решает, а не LLM.

Вариант C — компоненты. Шаблоны разбиты на 48 атомарных блоков: фоны (bg_dark_rings, bg_gradient), заголовки (comp_title_hero), контент (comp_kpi_block, comp_bullets, comp_table). У каждого constraints, compatible_with[], grid_area. LLM собирает слайды из строительных блоков. Гипотеза: гибкая сборка даёт больше разнообразия.

Как я запустил это параллельно

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

Для варианта B2 я отправил такой промпт:

Prepare data for Qdrant indexing of 57 slide templates.
For each template create:
- semantic_description (2-3 sentences, visual and content description)
- best_for (3-5 use cases)
- never_for (limitations)
- visual_tags[] (filter tags)
Format: SQL INSERT into slide_templates table.
Reference HTML in /var/www/superslide/templates/

Для компонентного варианта — другой агент, другой промпт:

Decompose the 36 most complex templates into atomic components.
Each component: html_fragment, css_classes, description,
constraints (max_text, max_items, needs_number),
compatible_with[], grid_area.
Format: SQL INSERT into slide_components table.

Инфраструктура маршрутизации — воркфлоу в n8n с узлом Switch. Пользователь выбирает подход через радиокнопку, запрос идёт в нужную ветку.

Что я измерял

Логи пишутся в таблицу generation_log. Я отслеживаю:

  • Количество уникальных шаблонов в презентации
  • Разнообразие категорий (покрытие типов слайдов)
  • Чередование тем (тёмные/светлые фоны)
  • Время генерации
  • Использованный подход

5 тестовых генераций на вариант — 20 прогонов. Достаточно, чтобы увидеть паттерн.

Что я узнал

Семантический поиск (B2) дал лучшее разнообразие шаблонов. Qdrant не «залипает» на популярных лейаутах — в среднем 9-11 уникальных шаблонов на презентацию из 12 слайдов против 4-5 у baseline. Но требует точных описаний: если semantic_description написан плохо, ближайший вектор будет неправильным.

Примеры (B) работают лучше baseline, но модель начинает копировать контент из примеров вместо генерации нового. Пришлось явно добавить в промпт: «используй структуру, а не содержание».

Компоненты (C) дали максимальную гибкость, но и максимум ошибок сборки. LLM иногда комбинирует несовместимые блоки несмотря на compatible_with[].

Главный вывод — параллельное выполнение сэкономило 4-5 дней по сравнению с последовательным тестированием.

Когда НЕ стоит тестировать параллельно

Если у тебя 2 варианта и один очевидно проще — начни с простого. Параллельное тестирование оправдано когда:

  • Вариантов 3 или больше
  • Ни один нельзя отбросить без эксперимента
  • Подготовка данных для каждого занимает часы, а не минуты
  • Есть возможность делегировать (агенты, команда)

Можешь проверить гипотезу за 20 минут? Не строй инфраструктуру для параллельного запуска.

FAQ

Почему не добавил Function Calling (tools) как отдельный вариант?

Это был вариант D. Но он требует поддержки tools в API. claude -p не поддерживает tools напрямую, пришлось бы использовать OpenRouter. Это добавляло переменную, которая мешала чистому сравнению.

Сколько стоили 20 тестовых генераций?

Около 3-4 долларов через OpenRouter на модели Claude. Стоимость подготовки данных (токены агентов) — ещё 8-10 долларов. Итого менее 15 долларов за полную валидацию 4 архитектурных подходов.

Какой подход выбрал?

Гибрид B2 + элементы C. Семантический поиск для выбора шаблонов, ограничения компонентов для валидации совместимости. Чисто компонентный подход слишком хрупкий, чисто семантический не контролирует качество сборки.

Можно ли так тестировать без Claude Code?

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