# Prompt Management Strategy Дата: 2026-06-23 | Версия: v1.0 | Контекст: v1.0.109, обсуждение архитектуры промптов --- ## А. Несколько промптов — зачем и как Смешиваются **две разные потребности** — их нельзя путать: ### 1. Версионирование одного промпта (ОБЯЗАТЕЛЬНО) Это не «несколько промптов», а история эволюции одного. **Почему критично:** - `prompt_version` уже кладётся в `spec_events` (provenance, Opus раунд 2). - Значит промпт **обязан быть иммутабельным** — правка «на месте» сломает трассировку: старые события будут ссылаться на текст, которого больше нет. - **Правка = новая версия**, а не перезапись. Откат, аудит «какая версия породила какой результат», сравнение версий — бесплатно. ### 2. Несколько РАЗНЫХ промптов одновременно | Сценарий | Вердикт | |----------|---------| | **По роли в пайплайне** — разные LLM-вызовы (извлечение услуг vs сравнение vs резолв имён) | ✅ У каждого свой промпт. Настоящая причина «несколько» — по **задаче**. | | **Варианты для эксперимента** — форкнул активный, сделал строже, прогнал на тестах, сравнил | ✅ Loop «дублировать → изменить → протестировать → активировать» — правильно. | | **Каталог из 20 промптов «на всякий случай»** | ❌ Ловушка. Для узкого домена (colocation/ЦОД) нужен **ОДИН хороший** промпт на задачу. | ### Рекомендуемая модель: prompt-as-version (не prompt-as-document) Одна таблица, один активный на `role`, вся история — строки: | Поле | Тип | Смысл | |------|-----|-------| | `id` | UUID PK | Версия (иммутабельная) | | `role` | VARCHAR | Шаг пайплайна: `extract`, `diff` | | `name` | VARCHAR | Человеческое имя («default-v3», «strict-prices») | | `body` | TEXT | Тело промпта с плейсхолдерами | | `parent_id` | UUID FK→prompts.id | От какой версии форкнут | | `is_active` | BOOLEAN | UNIQUE(role, is_active) с частичным индексом WHERE is_active | | `created_at` | TIMESTAMP | | | `created_by` | VARCHAR | Мульти-юзер | | `notes` | TEXT | Что изменили и зачем | **Операции:** - **Править** = `INSERT` новой строки с `parent_id` на предыдущую. Не `UPDATE`. - **Активировать** = переключить `is_active` (старая теряет флаг). - **Дублировать** = копия под новым `name` (форк). - **Откат** = активировать старую версию. **Никогда не UPDATE текста на месте.** --- ## Б. Как составлять промпт ### Стартовый шаблон — ОБЯЗАТЕЛЕН Пустое поле ввода — катастрофа для качества. Всегда форкать от выверенного дефолта, не с нуля. ### Структура (8 секций, порядок важен) Для доменной задачи **без structural output** (gpt-oss-120b): ``` ┌─────────────────────────────────────────────┐ │ 1. РОЛЬ / КОНТЕКСТ │ │ «ты эксперт по договорам colocation │ │ и облачных услуг ЦОД» │ ├─────────────────────────────────────────────┤ │ 2. ЗАДАЧА │ │ «сравни текущую спецификацию с документом,│ │ верни операции изменений» │ ├─────────────────────────────────────────────┤ │ 3. ДОМЕННЫЙ ГЛОССАРИЙ │ │ стойко-место, кВт мощности, colocation, │ │ единицы измерения, типы услуг. │ │ Без этого модель путает домен. │ ├─────────────────────────────────────────────┤ │ 4. ФОРМАТ ВХОДА │ │ Как подаётся spec_current (с ID r1..rN), │ │ как подаётся текст документа. │ ├─────────────────────────────────────────────┤ │ 5. КОНТРАКТ ВЫВОДА │ │ Строгая JSON-схема ops: поля, типы, │ │ обязательность. КРИТИЧНО — structural │ │ output нет, схема держится промптом. │ ├─────────────────────────────────────────────┤ │ 6. ПРАВИЛА / ОГРАНИЧЕНИЯ │ │ «ссылайся только на id из spec_current», │ │ «верни source_quote», «верни confidence», │ │ «name существующих строк не переписывай» │ ├─────────────────────────────────────────────┤ │ 7. FEW-SHOT ПРИМЕРЫ (2-3) │ │ ⭐ САМЫЙ МОЩНЫЙ РЫЧАГ для бесплатной │ │ модели без fine-tune. Примеры учат и │ │ формату, и поведению лучше инструкций. │ │ Вход→Выход на ВАШЕМ домене (ЦОД). │ ├─────────────────────────────────────────────┤ │ 8. EDGE-CASES │ │ Как помечать неоднозначность, что делать │ │ при low-confidence. │ └─────────────────────────────────────────────┘ ``` ### Принцип разделения: статика vs рантайм ``` [версионируемая часть — в БД] [рантайм-инъекция — в коде] роль + глоссарий + правила + {spec_current} + {document_text} + few-shot + контракт вывода ``` - Статическая инструкция (секции 1-8) → **версионируется** в `prompts.body`. - Динамические данные (`{spec_current}`, `{document_text}`, `{date}`) → **подставляются в рантайме** через плейсхолдеры. - В БД хранится тело промпта **с плейсхолдерами**, не с конкретными данными. --- ## В. Prompt CI — как с этим работать ``` ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ │ Дублировать │ → │ Изменить │ → │ Прогнать на │ → │ Активировать │ │ (форк) │ │ (новая v) │ │ golden-наборе│ │ (is_active) │ └──────────┘ └──────────┘ └───────────┘ └──────────┘ ``` 1. Форкнуть активный промпт → новый `id`, `is_active=false` 2. Изменить тело 3. Прогнать на golden-наборе (3-5 реальных ДС с известным результатом) 4. Сравнить метрики (precision/recall по ops) 5. Если лучше — активировать. Если хуже — оставить как эксперимент или удалить. --- ## Г. Текущее состояние (v1.0.109) Промпты жёстко зашиты в `llm_prompt.py`: - `_build_initial()` — для первого документа - `_build_diff()` — для сравнения (основной) **Что уже хорошо:** - JSON-контракт вывода описан - `target_id` (r1..rN) вместо `target_hash` - Правила: mode full_replace, UPDATE только изменённые поля, UNRESOLVED для неоднозначного **Чего не хватает (по приоритету):** 1. Few-shot примеры на домене ЦОД — самый большой рычаг качества 2. Доменный глоссарий — чтобы модель понимала единицы измерения и термины 3. `source_quote` в контракте вывода — для provenance 4. `confidence` в контракте вывода — самооценка модели 5. Edge-cases инструкция — как вести себя при неоднозначности --- ## Д. План миграции (если делать) | Шаг | Что | Сложность | |-----|-----|-----------| | 1 | Таблица `prompts` в PostgreSQL (Lucee datasource `baza`) | Низкая | | 2 | CRUD в `api.cfm` для prompts (list, get, create, set_active) | Средняя | | 3 | `llm_prompt.py` → читает активный промпт из Lucee API вместо хардкода | Средняя | | 4 | `prompt_version` в `spec_events` — ссылка на `prompts.id` | Низкая | | 5 | UI для prompts в `index.cfm` (список версий, редактор, активация) | Высокая | | 6 | Golden-набор: 3-5 ДС + эталонные ops | Ручная работа | | 7 | Prompt CI: скрипт прогона на golden-наборе + сравнение метрик | Средняя | **Первый практический шаг** (максимум пользы, минимум кода): добавить few-shot примеры в текущие промпты прямо в `llm_prompt.py`, не дожидаясь таблицы `prompts`.