Feature Flags LLM

Механизм отдельно от политики: роутинг живёт в коде, решения — в конфиге. Код нового варианта вливается в main выключенным, а включает его продуктовая команда правкой флага. Для LLM-сервиса флаг маппится не на булево «включено», а на полную связку провайдер + модель + промпт + параметры.

Суть

Без флагов любое изменение поведения агента — это деплой. Значит, эксперимент требует релиза, откат требует релиза, а во время инцидента вы ждёте сборку, пока пользователи получают сломанные ответы.

Флаг разрывает эту связь. Вариант уже в проде, просто выключен; переключение занимает секунды и не трогает код.

Флаг = объект конфигурации, а не переключатель

Главное отличие от обычных фича-флагов. Строка model_version = "v3.2" бесполезна: поведение агента определяется связкой целиком, и промпт под одну модель на другой работает иначе.

flags:
  support_agent:
    stable:
      provider: anthropic
      model: claude-sonnet-5
      prompt_id: support_v3.1
      temperature: 0.2
    candidate:
      provider: anthropic
      model: claude-haiku-4-5
      prompt_id: support_v3.2
      temperature: 0.0
    rollout: { candidate: 5 }        # процент трафика; sticky по user_id

Такой флаг переключает всё сразу и откатывает тоже всё сразу — рассинхрона «новая модель со старым промптом» не возникает.

Что это даёт команде

Эксперименты без релизов. Несколько моделей и промптов работают параллельно; смена конфигурации — правка флага, а не выкатка. Аудитория расширяется ступенями: сотрудники → 10% пользователей → все.

Инструмент митигации. Во время инцидента флаг выключает сломанную фичу быстрее любого отката деплоя. Kill switch по умолчанию — обязательная часть конфигурации, а не опция: именно он спасает в сценариях вроде «бот пообещал внедорожник за доллар».

Динамическое распределение. Продвинутый вариант — multi-armed bandit сам сдвигает трафик в сторону выигрывающего варианта, без ручных ступеней.

Где хранить сам текст промпта. Оба варианта рабочие, и выбор между реестром и git-ссылкой второстепенен — принципиально то, что флаг хранит идентификатор версии, а не текст. Копия текста внутри флага гарантированно разъедется с оригиналом. Реестр удобнее, когда промпты меняют не только разработчики и нужна история правок вне репозитория; git-ссылка проще, когда промпты живут рядом с кодом и выкатываются вместе с ним.

Отдельная оговорка, которую легко пропустить: идентификатор версии, вставленный в начало промпта, ломает кэширование префикса для всего, что за ним следует (Prompt Caching). Версия должна быть в конфигурации и в трейсе, а не внутри текста, который уходит в модель.

Комбинаторика флагов не тестируется полным перебором — при пяти флагах это 32 конфигурации, при десяти уже больше тысячи, и большинство из них никогда не встретится в проде. Работают три ограничения вместо перебора.

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

Тестируются только реально включённые сочетания. Флаг существует ради конкретного эксперимента, поэтому в проде одновременно живут единицы комбинаций, а не все возможные — их и покрывают, взяв список из конфигурации, а не из математики.

Флаг имеет срок жизни. Комбинаторика растёт потому, что флаги не удаляют после завершения эксперимента. Удаление отработавшего флага — часть выкатки, а не уборка на потом; без этого дисциплина из раздела ниже перестаёт работать за пару месяцев.

Снимаемость — критерий выбора механизма, а не следствие

Срок жизни объявить легко, а вот выполнить его мешает то, как флаг вставлен. Отсюда правило, действующее в момент заведения, а не в момент уборки: из двух работающих способов выбирается тот, который потом дешевле убрать.

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

Удаление выполнимо ровно настолько, насколько перечислены точки вставки. «Убрать флаг» — не одно действие, а обход списка мест, где он живёт, и список этот пишется при заведении, а не вспоминается через полгода:

Где живёт Что остаётся, если пропустить
объявление в перечислении флагов мёртвое имя, которое ещё кто-то прочитает как живое
списки аудиторий: сотрудники, превью, релиз флага нет, а он в чьём-то списке — расхождение конфигурации с кодом
проверки в рантайме по всей кодовой базе ветка условия, у которой один исход
предикаты доступности в UI и горячих клавишах пункт, который включается и выключается ничем
ветки «иначе» — поведение при выключенном мёртвый код, который следующий агент воспроизведёт как образец (AI Tech Debt)

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

Это тот же обратный ход, что у правил в файле инструкций (Agent First Repository): у операции добавления обязана быть парная операция снятия, и записаны они вместе, иначе снятие не выполняется никогда.

Дисциплина

  • Флаг — временная конструкция. Каждый оставленный флаг удваивает число возможных состояний системы; через полгода никто не помнит, какая комбинация тестируется. У флага должен быть владелец и срок жизни.
  • Флаг не заменяет гейт. Он даёт возможность переключить, но решение переключать принимается по порогам (Canary Release LLM).
  • Kill switch проверяется заранее. Механизм, который впервые дёргают в момент аварии, — это не механизм, а надежда.

Связано с

  • Canary Release LLM — флаги как исполнительный механизм ступенчатой выкатки
  • Shadow Mode — включение зеркалирования тем же способом
  • Incident Management AI — kill switch как первый шаг митигации
  • Agent Deployment Cloud — почему конфигурация отделена от образа
  • Agent First Repository — тот же обратный ход для правил в файле инструкций