Назад в блог

Версионирование промптов: одна строка двигает поведение как смена модели

Промпты правятся строками в коде мимо ревью — а деградация после «мелкой правки» неатрибутируема. Workflow как для кода: файлы, версии, PR-ревью, eval-gating в CI, откат за секунды.

Иллюстрация к материалу: Версионирование промптов: одна строка двигает поведение как смена модели

Огромная доля поведения LLM-приложения живёт в промпте — и однострочная правка сдвигает выходы так же сильно, как замена модели. При этом промпты лежат строками в коде, правятся «по-быстрому» в проде и нигде не версионируются. Итог известен каждому, кто эксплуатировал агентов: качество просело, никто не знает, какая правка виновата, воспроизвести прошлое поведение нельзя, откат — это панический редеплой. В демо вопрос звучит «промпт хороший?». В проде — «он версионирован, протестирован и откатываем, и можем ли мы привязать изменение качества к конкретной правке?». Разберём workflow, переводящий промпты из черновиков в управляемые артефакты — вплоть до голого GitHub без единой покупки.

Четыре болезни неверсионированных промптов

По разбору LLMOps.si, картина стандартная. Mystery regressions: качество упало, а какая правка виновата — неизвестно, потому что истории, по которой строить diff, нет; это самая частая причина необъяснимых потерь качества. Невоспроизводимость: поведение прошлой недели не повторить — промпт, который его давал, исчез. Нет отката: плохая правка лечится суетливым редеплоем вместо указания на предыдущую версию. Нет ревью: промпты меняются прямо в проде мимо второй пары глаз — мимо доменного эксперта, который заметил бы проблему. Каждая болезнь лечится одним и тем же лекарством: относиться к промптам как к коду.

Файлы, версии, реестр

Первый шаг — вытащить промпты из inline-строк в версионированные файлы: Markdown-тело плюс маленький metadata.yaml (модель, параметры, владелец, changelog). Структура по GitHub-практике: prompts/rag-answer/v4.md — текущий промпт, metadata.yaml — параметры, evals/rag-answer.jsonl — eval-датасет этого промпта. Теперь у каждого изменения есть diff, автор и история — три вещи, теряемые в строковых литералах. Два слоя версий дополняют друг друга: история git даёт коммит на изменение автоматически, а семантическая версия в имени или frontmatter (v4) маркирует значимые релизы, на которые ссылаются код и трейсы. Семантика как у софта: PATCH — только текст шаблона, MINOR — новые обратно совместимые переменные, MAJOR — убранные required-переменные. Инструменты класса promptctl/promptvc дают тот же git-опыт без инфраструктуры: commit, diff, log, show, rollback поверх локального стора.

Ревью как PR

Изменения промптов идут через pull request — и это привычка с максимальной отдачей. Diff показывает ровно, что изменилось, — бесценно, когда качество поплыло. Ревьювер (часто доменный эксперт, а не только инженер) утверждает. Описание PR фиксирует зачем — будущее «я» скажет спасибо. Один этот ритуал убивает главную причину mystery regressions: тихое редактирование живого промпта. Переменные шаблона ({user_goal}) отделяют статику от инстанса: ревью смотрит на скелет, а не на конкретные подстановки. Тон и роль — в system, детали задачи и примеры — в user: структурированный промпт ревьюится быстрее и точнее.

Гейт eval в CI

Здесь LLMOps становится реальным: eval-датасет в CI на каждый промпт-PR. Скетч workflow: триггер по путям prompts/** и evals/**, шаг прогона eval с фейлом при просадке pass rate или регрессе критических кейсов. Теперь изменение промпта не мержится, если роняет качество, — проверка до продакшена, а не разбор после. Eval-датасет живёт рядом с промптом и версионируется вместе с ним: новые кейсы из прод-инцидентов добавляются тем же PR, что и фикс. Отдельно — side-by-side сравнение выходов двух версий до шипа и привязка eval к Prompt ID для повторяемых запусков (так делает Playground-интеграция).

Откат за секунды

Откат — смена указателя, а не редеплой. Активная версия грузится по имени (rag-answer-v4), смена на v3 — одна строка конфига или перенос production-метки в UI (модель Langfuse). Некритично — но важно: откат недеструктивен (создаёт новую версию поверх, история не переписывается), код резолвит версию через единый реестр (в dev — из git, в проде — из CI-снапшота вроде snapshot.json), каждый запрос логирует точную версию промпта. Тогда просадка на дашборде привязывается к версии — и «откатить» означает «вернуть метку», а не «собрать и выкатить».

Blame в день инцидента

Герой-сценарий инструментов класса promptops: «прод сломался в 10:00 UTC — что работало?» Ответ собирается из журнала деплоев (append-only deploys.jsonl с provenance: env, commit, actor) плюс истории git: blame --at <timestamp> показывает точный текст промпта на момент. Три команды — один доказуемый ответ. Для этого нужны: deploy event log, коммитящийся рядом с промптами; снапшот сборки на CI, едущий в Docker-образ вместо .git/; pre-commit хуки с автобампом semver по сигнатуре переменных. Инцидент-археология из роскоши превращается в рутину — а MTTR падает, потому что исчезает фаза «а что вообще менялось».

Canary и A/B

Между eval-гейтом и полным роллаутом — постепенность: canary на долю трафика с мониторингом качества, A/B двух версий с выбором победителя по метрикам, маршрутизация по сегментам. Трафик делят по version ID, сравнение идёт на тех же eval-метриках, что и CI-гейт, — консистентность критериев от PR до прода. Отдельная практика — drift detection после обновления модели вендором: выходы меняются при том же промпте, и это тоже ловится сравнением версий, а не жалобами пользователей.

Когда вырастать в платформу

Голый GitHub закрывает 80% потребностей команды. Сигналы к платформе (Langfuse, Playground prompts и аналоги): неинженерам нужно править промпты без PR; версий десятки и нужен UI-поиск; eval-прогоны нужны по кнопке с историей; метки окружений (dev/staging/prod) на версиях; оптимизация-ассистенты для детекта противоречий и нечётких инструкций. Правило: платформа покупается ради collaboration и observability, а не ради версионирования — версионирование даёт git бесплатно с первого дня.

Чеклист

  • Промпты — файлами вне кода, с metadata (модель, параметры, владелец, changelog).
  • Семантические версии на значимые релизы; каждое изменение — с автором и причиной.
  • Изменения — через PR с доменным ревьювером; тихие правки в проде запрещены.
  • CI eval-gating на промпт-PR; датасет версионируется рядом.
  • Откат — сменой метки/конфига за секунды, недеструктивно.
  • Каждый запрос логирует prompt_version; deploy-лог с provenance; blame —at работает.
  • Canary/A/B перед полным роллаутом; drift-детект после обновлений модели вендором.

Где Codenik

Конфиги агентов в Codenik — версионированные артефакты того же класса: политики и промпты с историей, авторами и причинами; изменения через ревью; eval-прогон как гейт; canary и откат сменой активной версии. Каждый вызов в журнале несёт точную версию конфига — деградация атрибутируется до правки за минуты, а не за спринт. Промпт перестаёт быть «магией, которую никто не трогает» и становится кодом: diffable, reviewable, rollbackable.

Короткий вывод

Промпт — production-артефакт: версионируйте как код, ревьюйте как код, тестируйте в CI как код, откатывайте за секунды. Начните с файлов в git и eval-гейта — это закроет mystery regressions уже на этой неделе. Платформу купите позже, когда упрётесь в collaboration, а не раньше.

Источники и дальнейшее чтение