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

Настроить templating (Jinja2) для переменных {context} и {question}

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить templating (Jinja2) для переменных {context} и {question}

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

Научиться применять Jinja2 как систему шаблонизации для динамического формирования промптов в LLM-пайплайнах. Вы создадите шаблон, в который будут подставляться переменные {{ context }} и {{ question }} из внешних источников, и настроите его так, чтобы один и тот же шаблон порождал корректные промпты для разных запросов. Задача закладывает основу для production‑ready Prompt Management: отделение логики промпта от данных, централизованное хранение шаблонов, возможность A/B‑тестирования.

Ключевой результат Работающий Jinja2‑шаблон, который для любых корректных значений context и question генерирует валидный промпт, пригодный для передачи в LLM (например, OpenAI, YandexGPT). Шаблон поддерживает условную логику (например, пропуск пустого контекста) и подключается через Python‑скрипт.

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

Перед началом необходимо иметь:

Что нужноОткуда взять
Python 3.9+ с установленным jinja2Установить pip install jinja2
Текстовые примеры контекста и вопросаСоздать файл data.json с 5–10 парами (реальные или синтетические)
Базовый шаблон промпта (в черновике)Написать вручную, например: "Ответь на вопрос, используя контекст: {{ context }}. Вопрос: {{ question }}"
(Опционально) Доступ к LLM APIOpenAI / YandexGPT / GigaChat для финальной проверки

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

  1. Замените вызов LLM на заглушку: функция fake_llm(prompt) просто возвращает длину промпта и первые 100 символов.
  2. Все тесты на корректность генерации проводите без реального API.
  3. Убедитесь, что сгенерированный промпт соответствует ожидаемому формату (не содержит ошибок экранирования, пустых блоков).

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

КомпонентИнструментыНазначение
Язык программированияPython 3.9+Исполнение скриптов, интеграция
Библиотека шаблонизацииJinja2 (>=3.0)Рендеринг промптов с переменными
Формат данныхJSON / YAMLХранение тестовых пар context+question
Тестированиеpytest (опционально)Автоматическая проверка шаблона
(Опционально) LLM APIOpenAI Python SDK / YandexGPTФинальная валидация сгенерированного промпта

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

Этап 1: Инициализация проекта и установка Jinja2 (15 минут)

Действия

  1. Создайте структуру каталогов:
    prompt_templating/
    ├── templates/
    │   └── prompt.j2
    ├── data/
    │   └── examples.json
    ├── src/
    │   └── renderer.py
    ├── tests/
    │   └── test_template.py
    └── requirements.txt
    
  2. Установите зависимости: pip install jinja2 pyyaml pytest.
  3. Создайте базовый шаблон templates/prompt.j2 с содержимым:
    Используй следующий контекст для ответа:
    {{ context }}
    
    Вопрос: {{ question }}
    
    Ответь развёрнуто.
    

Ожидаемый результат этапа Структура проекта готова, Jinja2 установлен, шаблон существует на диске.

Этап 2: Подготовка тестовых данных и первого рендера (30 минут)

Действия

  1. Создайте data/examples.json с минимум 3 примерами:
    [
      {
        "context": "Квантовый компьютер использует кубиты для вычислений.",
        "question": "Что такое кубит?"
      },
      {
        "context": "",
        "question": "Какая сегодня погода?"
      },
      {
        "context": "Jinja2 — это мощный шаблонизатор для Python.",
        "question": "Как установить Jinja2?"
      }
    ]
    
  2. Напишите скрипт src/renderer.py, который:
    • Загружает шаблон через FileSystemLoader
    • Загружает данные из JSON
    • Рендерит шаблон для каждого примера
    • Выводит результат на экран
    from jinja2 import Environment, FileSystemLoader
    import json
    
    env = Environment(loader=FileSystemLoader('templates'))
    template = env.get_template('prompt.j2')
    
    with open('data/examples.json', 'r') as f:
        examples = json.load(f)
    
    for i, example in enumerate(examples, 1):
        rendered = template.render(example)
        print(f"=== Example {i} ===")
        print(rendered)
        print()
    
  3. Запустите скрипт и убедитесь, что все три примера рендерятся без ошибок.

Ожидаемый результат этапа Скрипт рендерит промпты, видны проблемы второго примера (пустой контекст создаёт пустую строку).

Этап 3: Добавление условной логики и фильтров (1 час)

Действия

  1. Избавьтесь от пустого контекста — добавьте условие в шаблон:

    {% if context %}
    Используй следующий контекст для ответа:
    {{ context }}
    {% else %}
    Ответь на вопрос без дополнительного контекста.
    {% endif %}
    
    Вопрос: {{ question }}
    
    Ответь развёрнуто.
    
  2. Добавьте фильтр trim для обрезки лишних пробелов в вопросе: {{ question | trim }}.

  3. Реализуйте безопасное экранирование — если в контексте или вопросе есть HTML/спецсимволы, используйте {{ context | e }} или примените autoescape в окружении:

    env = Environment(loader=..., autoescape=True)
    
  4. Добавьте цикл для списка документов — измените структуру данных на:

    {
      "documents": ["док1", "док2"],
      "question": "Резюмируй"
    }
    

    И шаблон:

    {% for doc in documents %}
    - {{ doc }}
    {% endfor %}
    

    (Опционально — если задание требует продвинутого использования).

  5. Протестируйте все модификации на трёх наборах:

    • с непустым контекстом
    • с пустым контекстом
    • с HTML в контексте (например, <script>alert(1)</script>)

Ожидаемый результат этапа Шаблон корректно обрабатывает пустой контекст, обрезает пробелы, экранирует вредоносные символы. Все примеры рендерятся без Jinja2‑ошибок.

Этап 4: Интеграция с LLM‑пайплайном и тестирование (30 минут)

Действия

  1. Создайте симуляцию LLM (если нет реального API):
    def fake_llm(prompt: str) -> str:
        # симуляция: возвращаем длину и первые символы
        return f"[LLM RSP] len={len(prompt)}: {prompt[:60]}..."
    
  2. Допишите renderer.py — после рендеринга вызывайте fake_llm и выводите ответ.
  3. Напишите тест tests/test_template.py (pytest):
    import json, pytest
    from jinja2 import Environment, FileSystemLoader
    
    @pytest.fixture
    def env():
        return Environment(loader=FileSystemLoader('templates'))
    
    def test_renders_with_context(env):
        template = env.get_template('prompt.j2')
        out = template.render(context="test", question="q")
        assert "test" in out
        assert "q" in out
    
    def test_handles_empty_context(env):
        template = env.get_template('prompt.j2')
        out = template.render(context="", question="q")
        assert "без дополнительного контекста" in out
    
    def test_trim_filter(env):
        template = env.get_template('prompt.j2')
        out = template.render(context=" c ", question=" q ")
        assert "c" in out  # лишние пробелы убраны
    
  4. Запустите тесты командой pytest tests/ -v.

Ожидаемый результат этапа Все тесты проходят. Промпты успешно подаются в симулятор LLM.

Этап 5: Документирование и финальная упаковка (15 минут)

Действия

  1. Добавьте README.md в корень проекта:
    • Описание шаблона, поддерживаемые переменные
    • Инструкция по запуску
    • Примеры вывода
  2. Закрепите версию Jinja2 в requirements.txt: jinja2>=3.0,<4.0
  3. Создайте Makefile (опционально) для удобных команд: make render, make test.

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

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

  • Jinja2 установлен и работает в виртуальном окружении.
  • Создан шаблон prompt.j2 с переменными {{ context }} и {{ question }}.
  • Шаблон содержит условный блок для обработки пустого контекста.
  • Использован хотя бы один встроенный фильтр (trim, e или другой).
  • Написаны 3 pytest‑теста (на корректный рендер, пустой контекст, фильтр).
  • Скрипт renderer.py принимает путь к данным и шаблону, выводит результат.
  • Все тесты проходят (pytest tests/ -v — зелёный).
  • В README описаны назначение шаблона и пример запуска.
  • Данные в examples.json содержат как минимум один пример с пустым контекстом.
  • Код соответствует PEP 8 (проверено flake8 или подобным).

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

  • Основной артефакт Каталог prompt_templating/ со следующей структурой:

    • templates/prompt.j2 — финальный шаблон
    • src/renderer.py — скрипт рендеринга
    • data/examples.json — тестовые данные
    • tests/test_template.py — автоматические тесты
    • requirements.txt — зависимости
    • README.md — документация
  • Содержимое шаблона (пример финальной версии):

    {% if context | trim %}
    Используй следующий контекст для ответа:
    {{ context }}
    {% else %}
    Ответь на вопрос без дополнительного контекста.
    {% endif %}
    
    Вопрос: {{ question | trim }}
    
    Ответь развёрнуто.
    
  • Дополнительно (по желанию): Makefile, скрипт для A/B‑тестирования двух версий шаблона, поддержка вложенных структур (например, список документов).

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

СложностьРешение
Jinja2 выкидывает ошибку из‑за неэкранированных символов { в данныхИспользовать raw‑блок в шаблоне либо экранировать через {% raw %}...{% endraw %}
Пустой контекст приводит к висящей пустой строке в промптеДобавить {% if context %}...{% endif %} и фильтр trim
HTML/JavaScript в контексте попадает в промпт и может сломать логикуВключить autoescape=True в окружении или применить `{{ context
Вопрос содержит перевод строкиФильтр replace('\n', ' ') или `{{ question
Шаблон слишком большой, сложно поддерживатьВынести повторяющиеся части в {% macro %} и подключать через {% import %}

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

ЭтапВремя
Этап 1: Инициализация проекта и установка Jinja215 мин
Этап 2: Подготовка тестовых данных и первый рендер30 мин
Этап 3: Добавление условной логики и фильтров1 час
Этап 4: Интеграция с LLM‑пайплайном и тестирование30 мин
Этап 5: Документирование и упаковка15 мин
Итого2,5 часа

Примечание Для первого раза с учётом изучения документации Jinja2 заложите дополнительно 30–60 минут.

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

ВопросТема
42Как безопасно экранировать пользовательский ввод в промптах?
57Лучшие практики хранения шаблонов промптов в production
89Использование Jinja2 для A/B‑тестирования инструкций
131Управление версиями промптов через Git
204Интеграция шаблонизации с LangChain / LlamaIndex
315Динамическая подстановка {{ few_shot_examples }}
444Фильтры Jinja2 для форматирования дат и чисел в промптах
567Обработка ошибок рендеринга: что делать, если не хватает переменной
689Нагрузочное тестирование шаблонов: производительность рендеринга
777Переход от f‑строк к Jinja2: миграция легаси‑кода

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

  • Я создал виртуальное окружение и установил Jinja2.
  • Я написал хотя бы один тест, который проверяет подстановку context и question.
  • Я проверил, что шаблон корректно обрабатывает пустой контекст (выводит альтернативный текст).
  • Я добавил фильтр trim и убедился, что лишние пробелы удаляются из вопроса.
  • Я запустил pytest tests/ и получил passed для всех тестов.
  • README содержит команду для запуска рендера: python src/renderer.py.