Огромная доля поведения 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, а не раньше.