中文翻译暂不可用,显示俄语原文。

Настроить version tagging для промптов (latest, stable, canary)

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить version tagging для промптов (latest, stable, canary)

1. Цель задачи

Научиться управлять версиями промптов в production через механизм тегов (tags). Разработать и реализовать систему, в которой каждый промпт можно получить по семантическому тегу :latest, :stable, :canary, а при обновлении версий теги автоматически обновляются в соответствии со стратегией развёртывания. Это позволит безопасно проводить A/B-тесты, быстро откатываться и чётко понимать, какой промпт используется в каждом окружении.

Ключевой результат Рабочая система тегирования промптов, где по тегам :latest, :stable, :canary возвращается соответствующая версия промпта, а перемещение тегов выполняется контролируемо (через скрипт или pipeline).


2. Исходные данные

Что нужноОткуда взять
Репозиторий с промптами (например, prompts/ директория с YAML/JSON файлами)Создать новый или использовать существующий проект
Git (установлен и настроен)Локальная среда
Инструмент для хранения тегов (git-tag или собственный registry)Git / Python + SQLite (опционально)
Тестовое окружение (Python 3.10+)virtualenv / conda

Если нет реального инструмента — симулируем:

  1. Создайте директорию prompts/ с тремя файлами: greeting-v1.yaml, greeting-v2.yaml, greeting-v3.yaml.
  2. Инициализируйте Git-репозиторий в этой директории.
  3. Каждый файл содержит простой промпт с полями name, template, version.
  4. Будем использовать Git-теги как механизм хранения тегов (это достаточно для симуляции production-системы).

3. Технологический стек

КомпонентИнструментыНазначение
Управление версиямиGit + Git tagsХранение и метки версий промптов
Язык скриптовPython 3.10+Автоматизация перемещения тегов
Формат промптовYAML (PyYAML)Структурированное хранение промптов
CI (опционально)GitHub Actions / GitLab CIАвтоматическое обновление тегов при пуше
Мониторинг теговGit log + скриптыАудит истории перемещения тегов

4. Этапы выполнения

Этап 1: Проектирование стратегии тегирования (30 минут)

Действия

  1. Определить семантику тегов

    • latest — последняя подтверждённая версия (обновляется при каждом мерже в main)
    • stable — версия, прошедшая полное тестирование и утверждённая для продакшна
    • canary — версия, развёрнутая на небольшой процент трафика для экспериментов
  2. Описать правила перемещения тегов

    СобытиеЧто происходит с тегами
    Новый коммит в mainlatest → новая версия
    Ручное утверждение (через скрипт)stable → текущая latest
    Запуск canary-пайплайнаcanary → выбранная версия (не обязательно latest)
    Откат (rollback)Любой тег можно переместить на предыдущую версию командой
  3. Задокументировать схему создать файл PROMPT_VERSIONING.md с описанием.

Ожидаемый результат этапа Документ со стратегией тегирования (Markdown).


Этап 2: Реализация механизма тегирования (1 час)

Действия

  1. Создать скрипт tag_prompt.py с командами:

    # tag_prompt.py
    import subprocess, argparse, re, os
    
    PROMPTS_DIR = "prompts"
    
    def get_current_tags(prompt_name):
        result = subprocess.run(
            ["git", "tag", "-l", f"{prompt_name}:*"],
            capture_output=True, text=True, cwd=PROMPTS_DIR
        )
        return result.stdout.strip().split("\n") if result.stdout else []
    
    def set_tag(prompt_name, tag_type, version):
        # tag_type: latest, stable, canary
        tag = f"{prompt_name}:{tag_type}"
        # перемещаем тег (force, так как тег уже может существовать)
        subprocess.run(["git", "tag", "-f", tag, version], cwd=PROMPTS_DIR, check=True)
        print(f"Tag {tag} moved to {version}")
    
    def get_version_by_tag(prompt_name, tag_type):
        result = subprocess.run(
            ["git", "rev-list", "-n", "1", f"refs/tags/{prompt_name}:{tag_type}"],
            capture_output=True, text=True, cwd=PROMPTS_DIR
        )
        if result.returncode != 0:
            return None
        # вернуть коммит (в реальности можно хранить маппинг тег -> версия в файле)
        return result.stdout.strip()
    
    if __name__ == "__main__":
        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")
        # команда set
        set_parser = subparsers.add_parser("set")
        set_parser.add_argument("prompt_name")
        set_parser.add_argument("tag_type", choices=["latest","stable","canary"])
        set_parser.add_argument("version")
        # команда get
        get_parser = subparsers.add_parser("get")
        get_parser.add_argument("prompt_name")
        get_parser.add_argument("tag_type", choices=["latest","stable","canary"])
        args = parser.parse_args()
        if args.command == "set":
            set_tag(args.prompt_name, args.tag_type, args.version)
        elif args.command == "get":
            print(get_version_by_tag(args.prompt_name, args.tag_type))
    
  2. Интегрировать в CI (Actions) — пример пайплайна:

    # .github/workflows/prompt-tagging.yml
    name: Prompt Tagging
    on:
      push:
        branches: [main]
        paths: ['prompts/**']
    jobs:
      tag-latest:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - name: Update latest tag
            run: |
              git config user.email "ci@example.com"
              git config user.name "CI"
              git tag -f greeting:latest HEAD
              git push origin --tags --force
    
  3. Добавить команду для ручного утверждения stable:

    python tag_prompt.py set greeting stable v2
    # git push origin --tags --force
    
  4. Реализовать fallback: если тега нет — использовать latest.

Ожидаемый результат этапа Скрипты управления тегами и базовый CI-пайплайн.


Этап 3: Создание API для получения промпта по тегу (1 час)

Действия

  1. Написать функцию get_prompt(prompt_name, tag='latest'):

    import yaml, subprocess, tempfile, os
    
    def get_prompt(prompt_name, tag='latest'):
        tag_ref = f"refs/tags/{prompt_name}:{tag}"
        # получить содержимое файла из коммита тега
        result = subprocess.run(
            ["git", "show", f"{tag_ref}:prompts/{prompt_name}.yaml"],
            capture_output=True, text=True, cwd="."
        )
        if result.returncode != 0:
            raise FileNotFoundError(f"Prompt {prompt_name}:{tag} not found")
        return yaml.safe_load(result.stdout)
    
  2. Создать тестовый Flask / FastAPI эндпоинт (опционально):

    from fastapi import FastAPI, Query
    app = FastAPI()
    
    @app.get("/prompt/{name}")
    def get(name: str, tag: str = Query("latest")):
        return get_prompt(name, tag)
    
  3. Проверить на тестовых данных

    • Создать в репозитории три версии одного промпта.
    • Проставить теги:
      python tag_prompt.py set greeting latest v3
      python tag_prompt.py set greeting stable v1
      python tag_prompt.py set greeting canary v2
      
    • Проверить, что get_prompt("greeting", "latest") возвращает v3, а get_prompt("greeting", "stable") — v1.

Ожидаемый результат этапа Рабочая функция get_prompt + опциональный REST-сервер.


Этап 4: Тестирование и документирование (30 минут)

Действия

  1. Написать unit-тесты (pytest):

    def test_latest_tag():
        prompt = get_prompt("greeting", "latest")
        assert prompt['version'] == 3
    
    def test_stable_tag():
        prompt = get_prompt("greeting", "stable")
        assert prompt['version'] == 1
    
    def test_canary_tag():
        prompt = get_prompt("greeting", "canary")
        assert prompt['version'] == 2
    
    def test_move_stable():
        set_tag("greeting", "stable", "v2")
        prompt = get_prompt("greeting", "stable")
        assert prompt['version'] == 2
        # откатить
        set_tag("greeting", "stable", "v1")
    
  2. Запустить тесты и убедиться в прохождении.

  3. Задокументировать команды в README

    • python tag_prompt.py set <prompt_name> <tag_type> <version> — переместить тег
    • python tag_prompt.py get <prompt_name> <tag_type> — получить версию
    • curl http://localhost:8000/prompt/greeting?tag=stable — получение через API

Ожидаемый результат этапа Тесты проходят, README с инструкциями.


Этап 5: Валидация признака успеха (15 минут)

Действия

  1. На чистом клоне репозитория выполнить

    git clone ... ; cd prompts-repo
    git fetch --tags
    git checkout refs/tags/greeting:latest  # должно переключиться на v3
    git checkout refs/tags/greeting:stable  # на v1
    git checkout refs/tags/greeting:canary  # на v2
    
  2. Убедиться, что обращение по тегу работает без знания номера версии.

  3. Зафиксировать результат скриншот или вывод git log --oneline refs/tags/greeting:latest.

Ожидаемый результат этапа Подтверждение, что теги можно использовать как идентификаторы версий.


5. Критерии приемки (Definition of Done)

  • В Git-репозитории присутствуют три семантических тега (prompt:latest, prompt:stable, prompt:canary) для хотя бы одного промпта.
  • По каждому тегу можно получить соответствующую версию промпта (файл YAML) с помощью git show.
  • Написан и работает скрипт tag_prompt.py с командами set и get.
  • Реализована функция get_prompt(prompt_name, tag) без ошибок.
  • Написаны и успешно проходят минимум 3 unit-теста (latest, stable, canary).
  • Разработан документ PROMPT_VERSIONING.md с описанием стратегии.
  • В CI (или локально) демонстрируется автоматическое обновление тега latest при пуше в main.
  • Возможен ручной откат тега (git tag -f prompt:stable <old-commit>).

6. Ожидаемый результат

АртефактСодержание
PROMPT_VERSIONING.mdДокумент со стратегией и правилами перемещения тегов
tag_prompt.pyPython-скрипт с CLI для управления тегами
.github/workflows/prompt-tagging.ymlCI-пайплайн обновления latest
test_tagging.pyUnit-тесты для проверки корректности тегов
(Опционально) api/main.pyFastAPI-сервер для выполнения запросов по тегу

Дополнительно Убедиться, что команда:

python -c "import yaml; print(yaml.safe_load(open('prompts/greeting-v1.yaml')))"

работает и возвращает корректный словарь.


7. Возможные сложности и их решение

СложностьРешение
Git-теги не переносятся при push (force не разрешён)Настроить в CI права на force-push тегов или использовать отдельный branch references.
Конфликт имён тегов (одинаковые для разных промптов)Использовать префикс prompt_name:tag_type (например, greeting:latest).
При перемещении тега старая версия теряетсяХранить историю тегов в отдельном файле tags_history.json или в Git-notes.
Разные промпты имеют разный тег stableДопустимо – каждый промпт управляется независимо.
Необходимость атомарного обновления нескольких теговИспользовать скрипт, который создаёт одну фиксацию с несколькими тегами.

8. Бюджет времени (оценка)

ЭтапВремя
Этап 1: Проектирование стратегии30 мин
Этап 2: Реализация механизма тегирования1 ч
Этап 3: Создание API для получения промпта по тегу1 ч
Этап 4: Тестирование и документирование30 мин
Этап 5: Валидация признака успеха15 мин
Итого3 ч 15 мин

Примечание Для первого раза рекомендуется выделить 4 часа с учётом возможных задержек.


9. Связанные вопросы из базы знаний

ВопросТема
15Основы prompt management
42CI/CD для промптов
58Rollback стратегии
73Canary deployments
89Семантическое версионирование
102Prompt registries
155Теги и метки в Git
210Git hooks для управления версиями
330Python subprocess и автоматизация
415A/B тестирование промптов

10. Чек-лист самопроверки

  • Я создал Git-тэги greeting:latest, greeting:stable, greeting:canary и проверил, что git show refs/tags/greeting:latest возвращает корректный YAML.
  • Я написал скрипт tag_prompt.py и выполнил команды set и get без ошибок.
  • Я запустил unit-тесты (pytest) и все прошли зелёным.
  • Я задокументировал стратегию в PROMPT_VERSIONING.md и добавил инструкцию в README.
  • Я убедился, что при клоне репозитория с --tags теги доступны, и можно переключиться на любой из них через git checkout refs/tags/prompt:tag.