Prompt Slicing ADR

Table of Contents

1. Статус и назначение документа

Статус: принят и отражает текущее реализованное поведение.

Назначение: зафиксировать архитектурные решения для функции разбиения большого prompt-текста на пакет переиспользуемых блоков, включая режим обновления существующей композиции с сохранением структуры.

2. Контекст

В TextFoundry есть два близких, но разных AI-сценария:

  • генерация одного блока;

  • разбор большого prompt на набор reusable blocks.

Второй сценарий оказался существенно сложнее, потому что он работает не с одним draft, а сразу с пакетом будущих изменений. Пользователь ожидает от системы не просто "предложи несколько кусочков текста", а:

  • сохранить осмысленные границы секций;

  • по возможности переиспользовать существующие block_id;

  • не разрушить текущую композицию при обновлении;

  • опубликовать набор блоков и при необходимости собрать из них обновлённую композицию.

По коду это реализовано через BlockSliceViewModel, PromptSlicingRequest, Engine::GenerateBlockBatchData(…​) и отдельный workflow публикации пакета.

3. Проблема, которую нужно было решить

Нужно было решить, как встроить batch slicing в продукт так, чтобы он:

  • ускорял миграцию длинного prompt в библиотеку блоков;

  • не разрушал уже существующую структуру композиции;

  • не превращался в "слепую" массовую генерацию без review;

  • не зависел только от качества ответа модели;

  • позволял работать как с AI, так и с частично детерминированным разбором размеченных секций.

Именно здесь простой перенос single-block generation недостаточен:

  • у batch-сценария другие риски;

  • пакет нужно валидировать целиком;

  • ошибки в одном элементе могут испортить всю публикацию;

  • сохранение структуры становится требованием первого класса.

4. Рассмотренные варианты

Вариант A. Чисто детерминированный slicing без AI

Идея: поддерживать только прямой разбор текста по тегам или простым правилам.

Плюсы:

  • предсказуемость;

  • отсутствие внешней AI-зависимости;

  • упрощённая отладка.

Минусы:

  • работает только для уже хорошо размеченных исходников;

  • плохо переносит естественный текст без явных секций;

  • не помогает в реальных сценариях миграции сложных prompt-артефактов.

Вердикт:

  • отклонено как единственный путь, но сохранено как fast path для tagged sections.

Вариант B. Повторять single-block generation в цикле

Идея: разбить исходный текст на части вне контракта engine, а затем многократно вызывать генерацию одного блока.

Плюсы:

  • меньше новых интерфейсов;

  • можно переиспользовать существующий single-block API.

Минусы:

  • теряется целостное представление о наборе блоков;

  • нельзя задать требования по сохранению структуры на уровне всей пачки;

  • сложнее контролировать reuse existing ids и сохранение порядка;

  • валидация конфликтов между сгенерированными блоками становится разрозненной.

Вердикт:

  • отклонено, потому что batch-сценарий требует собственного контракта.

Вариант C. Batch generation с ручным review и публикацией

Идея: использовать отдельный PromptSlicingRequest, валидировать результат как набор, показывать пользователю preview и публиковать блоки только после review.

Плюсы:

  • можно передавать в модель контекст о текущей структуре;

  • возможно переиспользование существующих id;

  • есть единая точка batch validation;

  • пользователь сохраняет контроль до публикации.

Минусы:

  • workflow сложнее;

  • часть safety-checks лежит в UI workflow, а не только в engine;

  • публикация пакета может прерваться на середине при первой ошибке.

Вердикт:

  • выбранный вариант.

5. Принятое решение

Принято решение оформлять prompt slicing как отдельный batch authoring workflow с тремя уровнями обработки:

  • детерминированный fast path для уже размеченных секций;

  • AI-assisted batch generation через IBlockGenerator;

  • обязательный review и ручная публикация результатов.

Дополнительно зафиксированы правила:

  • slicing не публикуется автоматически;

  • при update-сценарии система старается сохранить существующие logical boundaries и block ids;

  • batch validation проверяет не только отдельные блоки, но и набор целиком;

  • режим обновления композиции отличается от режима первичного разбиения.

6. Детализация принятого решения

6.1. Для slicing используется отдельный batch contract

Причина: у пользователя есть не просто "текст для генерации", а источник, который надо декомпозировать с сохранением структуры.

Поэтому PromptSlicingRequest включает:

  • source_text;

  • preferred_language;

  • namespace_prefix;

  • existing_block_ids;

  • reusable_block_ids;

  • reusable_block_summaries;

  • preserve_reuse_percent;

  • preserve_order;

  • allow_id_collision.

Это принципиально богаче single-block request и отражает именно batch-задачу.

6.2. Tagged sections разбираются без AI, если это возможно

Причина: если исходный текст уже содержит явные секции вида <Section>…​</Section>, вызов внешней модели не нужен.

В текущем коде GUI сначала пытается:

  • выделить секции по тегам;

  • угадать тип блока;

  • собрать description;

  • сформировать candidate ids;

  • переиспользовать подходящие существующие id.

Если такой разбор удался и дал достаточно секций, AI не вызывается вообще.

Это решение важно, потому что:

  • снижает стоимость и latency;

  • уменьшает риск лишнего переписывания;

  • лучше сохраняет исходную структуру там, где она уже явно задана.

6.3. AI slicing не является источником истины без дополнительной проверки

Причина: даже после engine-level validation batch может быть плохим по product-смыслу:

  • дублировать секции;

  • ломать expected namespace;

  • чрезмерно схлопывать структуру;

  • использовать неудобные или конфликтующие id.

Поэтому поверх результата провайдера есть дополнительная workflow-валидация в BlockSliceViewModel, которая проверяет пригодность набора к публикации.

Это сознательный выбор: не считать provider response достаточным основанием для массового изменения библиотеки.

6.4. Режим обновления композиции отличается от первичного slicing

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

В update mode система:

  • загружает текущую композицию;

  • пытается взять её текущий render как источник для редактирования;

  • вычисляет namespace по composition id;

  • передаёт reusable_block_ids и summaries текущей структуры;

  • включает preserve_order;

  • управляет силой сохранения через preserve_reuse_percent.

Это фиксирует архитектурный приоритет: при обновлении важнее сохранить структуру и идентичность частей, чем "красиво переизобрести" prompt заново.

6.5. Публикация идёт блок за блоком через обычный block lifecycle

Причина: slicing не создаёт отдельный тип сущности. Его выходом становятся обычные блоки, которые должны пройти тот же lifecycle, что и вручную созданные блоки.

Поэтому публикация batch-результата реализована через:

  • PublishBlock(…​) для новых блоков;

  • UpdateBlock(…​) для reuse existing ids.

Это сохраняет единый storage contract и не вводит отдельное "batch-хранилище".

6.6. Prompt Slicing документируется отдельно от Block Generation

Причина: технически они используют один и тот же generator abstraction, но продуктово это разные функции.

Block Generation отвечает на вопрос: "как получить один хороший reusable block".

Prompt Slicing отвечает на вопрос: "как преобразовать большой prompt в набор блоков, не потеряв структуру".

Отдельный ADR нужен, потому что здесь главные решения связаны не с одним draft, а с preservation, reuse и batch safety.

7. Последствия решения

Положительные:

  • миграция длинных prompt-артефактов в библиотеку блоков сильно ускоряется;

  • update workflow может сохранять значительную часть существующей структуры;

  • tagged input часто обрабатывается без лишнего AI-вмешательства;

  • batch contract делает ограничения и намерения более явными.

Компромиссы:

  • часть correctness-проверок находится в GUI workflow, а не только в engine;

  • публикация набора требует большего числа шагов и больше UI-состояния;

  • логика update mode заметно сложнее, чем create mode.

Отрицательные:

  • качество результата чувствительно к качеству исходного prompt и summaries;

  • AI всё ещё может выдать structurally weak batch;

  • массовая публикация повышает стоимость ошибки по сравнению с single draft.

8. Риски и меры снижения

Риск: destructive update разрушит текущую композицию

Снижение:

  • режим сохранения структуры;

  • reuse existing ids;

  • preserve_reuse_percent;

  • ручной review до публикации.

Риск: конфликтующие или плохие block_id

Снижение:

  • engine-level validation;

  • GUI batch validation;

  • явная работа со списком существующих и переиспользуемых id.

Риск: модель схлопнет несколько важных секций в один общий блок

Снижение:

  • отдельные prompt constraints на сохранение структуры;

  • summaries текущих reusable blocks;

  • консервативный update mode.

Риск: пользователь воспримет slicing как полностью автоматическую миграцию

Снижение:

  • явные стадии generate → review → publish;

  • отсутствие auto-apply;

  • статусные сообщения о количестве сгенерированных предложений.

9. Что сознательно не покрывается

Данный ADR не фиксирует:

  • автоматическую транзакционную публикацию всей пачки как одной atomic unit;

  • серверный orchestrator для удалённого slicing;

  • полноценный semantic diff между старой и новой структурой;

  • автоматический выбор оптимального preserve_reuse_percent.

10. Связанные документы