Разработка Prompt Templates с переменными
Prompt Templates — параметризованные шаблоны промптов, где переменные подставляются в runtime. Позволяют переиспользовать структуру промпта для разных входных данных, управлять версиями шаблонов централизованно и тестировать вариации.
Базовые шаблоны
from string import Template
from jinja2 import Template as JinjaTemplate
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
# Вариант 1: Python f-strings (простой)
def create_analysis_prompt(document: str, analysis_type: str, language: str = "ru") -> str:
return f"""Проанализируй следующий документ.
Тип анализа: {analysis_type}
Язык ответа: {language}
Документ:
{document}
Предоставь структурированный анализ."""
# Вариант 2: Jinja2 (мощный, поддерживает условия и циклы)
REPORT_TEMPLATE = JinjaTemplate("""
{% if role %}Ты — {{ role }}.{% endif %}
Задача: {{ task }}
{% if context %}
Контекст:
{{ context }}
{% endif %}
{% if examples %}
Примеры:
{% for example in examples %}
Вход: {{ example.input }}
Выход: {{ example.output }}
---
{% endfor %}
{% endif %}
Входные данные:
{{ input_data }}
{% if output_format %}
Формат ответа:
{{ output_format }}
{% endif %}
""")
# Вариант 3: LangChain PromptTemplate
analysis_prompt = PromptTemplate(
template="""Ты — {role}.
Задача: Проанализируй {document_type}.
Документ: {document}
Критерии оценки:
{criteria}
Верни JSON: {{
"summary": "...",
"key_findings": [...],
"risk_level": "low|medium|high",
"recommendations": [...]
}}""",
input_variables=["role", "document_type", "document", "criteria"],
)
# Форматирование
prompt_text = analysis_prompt.format(
role="юридический аналитик",
document_type="договор поставки",
document=contract_text,
criteria="срок действия, ответственность сторон, условия расторжения",
)
Иерархические шаблоны
class PromptTemplateManager:
"""Управление библиотекой шаблонов промптов"""
BASE_TEMPLATES = {
"classifier": """Классифицируй следующий {input_type} по категориям: {categories}.
{input_type}: {input_text}
Верни JSON: {{"category": "...", "confidence": 0.0-1.0, "reasoning": "..."}}""",
"extractor": """Извлеки {entities} из следующего текста.
Текст: {text}
Верни JSON: {extracted_schema}""",
"summarizer": """Создай краткое резюме.
Стиль: {style}
Длина: {max_words} слов
Аудитория: {audience}
Текст:
{content}""",
"qa": """Ответь на вопрос используя только предоставленный контекст.
Контекст:
{context}
Вопрос: {question}
Если ответа нет в контексте, скажи "Нет данных в предоставленном контексте".""",
}
def get(self, template_name: str, **variables) -> str:
template = self.BASE_TEMPLATES.get(template_name)
if not template:
raise ValueError(f"Template '{template_name}' not found")
return template.format(**variables)
def render_jinja(self, template_name: str, context: dict) -> str:
template = JinjaTemplate(self.BASE_TEMPLATES[template_name])
return template.render(**context)
# Использование
manager = PromptTemplateManager()
# Классификатор поддержки
prompt = manager.get(
"classifier",
input_type="обращение в поддержку",
categories="billing, technical, account, general",
input_text=ticket_text,
)
# Экстрактор данных
extract_prompt = manager.get(
"extractor",
entities="ИНН, КПП, сумма, дата документа",
text=invoice_text,
extracted_schema='{"inn": "...", "kpp": "...", "amount": 0.0, "date": "YYYY-MM-DD"}',
)
Динамическое построение промптов
class DynamicPromptBuilder:
"""Строит промпты динамически на основе контекста запроса"""
def build(
self,
base_task: str,
context_docs: list[str] = None,
examples: list[dict] = None,
output_schema: dict = None,
constraints: list[str] = None,
) -> str:
parts = [f"Задача: {base_task}"]
if context_docs:
docs_text = "\n\n".join([f"[Документ {i+1}]: {doc}" for i, doc in enumerate(context_docs)])
parts.append(f"\nКонтекст:\n{docs_text}")
if examples:
examples_text = "\n".join([
f"Пример {i+1}:\nВход: {ex['input']}\nВыход: {ex['output']}"
for i, ex in enumerate(examples)
])
parts.append(f"\nПримеры:\n{examples_text}")
if constraints:
constraints_text = "\n".join(f"- {c}" for c in constraints)
parts.append(f"\nОграничения:\n{constraints_text}")
if output_schema:
parts.append(f"\nВерни результат в формате JSON:\n{json.dumps(output_schema, ensure_ascii=False, indent=2)}")
return "\n\n".join(parts)
Версионирование и хранение
# Хранение шаблонов в YAML (рекомендуется для командной работы)
# prompts/support_classifier.yaml
yaml_template = """
version: "2.1"
name: support_classifier
description: Классификатор обращений в поддержку
updated_at: "2025-03-15"
variables:
- ticket_text
- categories
template: |
Классифицируй обращение в техподдержку.
Категории: {{ categories }}
Обращение:
{{ ticket_text }}
Верни JSON: {"category": "...", "priority": "low|medium|high|critical", "confidence": 0.0-1.0}
eval_examples:
- input: "Я не могу войти в систему"
expected_category: "technical"
"""
Сроки
- Базовые шаблоны для одного use case: 1 день
- Библиотека шаблонов с версионированием: 3–5 дней
- Динамический builder с тестами: 1 неделя







