Архитектура реестра запросов
Хранение запросов как версионируемых артефактов с метаданными и тегами.
«Архитектура реестра запросов» — бесплатный урок AI Prompt Engineering на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Prompt Engineering, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Prompt Engineering содержит 4 уроков всего.
Зачем нужен реестр промптов?
Без реестра промпты хранятся разрозненно в коде, конфигурационных файлах и памяти разработчиков. Реестр промптов — это централизованное хранилище, в котором каждый промпт рассматривается как версионируемый и отслеживаемый артефакт — так же, как программный код.
К преимуществам относятся воспроизводимость, возможность аудита, возможность отката и совместная работа команды.
Основные поля артефакта промпта
Каждый артефакт промпта должен содержать следующие поля:
prompt_id— уникальный стабильный идентификатор (например,summarize-article)version— строка семантической версии (например,2.1.0)template— фактический текст промпта с заполнителями{variable}metadata— автор, теги, целевая модель, дата создания, описание
Проектирование схемы базы данных
Реляционная схема для реестра промптов хранит промпты и историю их версий в отдельных таблицах, обеспечивая эффективный поиск и аудит.
-- prompts table: one row per unique prompt identity
CREATE TABLE prompts (
prompt_id VARCHAR(100) PRIMARY KEY,
description TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- prompt_versions table: one row per versioned artifact
CREATE TABLE prompt_versions (
id SERIAL PRIMARY KEY,
prompt_id VARCHAR(100) REFERENCES prompts(prompt_id),
version VARCHAR(20) NOT NULL,
template TEXT NOT NULL,
author VARCHAR(100),
tags TEXT[],
model VARCHAR(50),
is_active BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(prompt_id, version)
);Проектирование реестра на основе файлов
Для небольших команд реестр на основе файлов использует организованную структуру каталогов. Для каждого промпта создаётся папка, а каждая версия представлена YAML- или JSON-файлом внутри неё.
# Directory structure
prompts/
summarize-article/
1.0.0.yaml
1.1.0.yaml
latest -> 1.1.0.yaml # symlink
classify-sentiment/
1.0.0.yaml
# Example: summarize-article/1.1.0.yaml
prompt_id: summarize-article
version: '1.1.0'
model: gpt-4o-mini
author: alice@company.com
tags: [summarization, articles, english]
created_at: '2024-06-01T10:00:00Z'
template: |
Summarize the following article in {num_sentences} sentences.
Focus on: {focus_area}.
Article:
{article_text}Класс PromptRegistry на Python
Простой класс на Python инкапсулирует доступ к базе данных и предоставляет понятные методы: register(), get_active() и list_versions().
import psycopg2
import json
from datetime import datetime
class PromptRegistry:
def __init__(self, dsn):
self.conn = psycopg2.connect(dsn)
def register(self, prompt_id, version, template, author, tags, model):
with self.conn.cursor() as cur:
# Ensure prompt identity exists
cur.execute(
'INSERT INTO prompts (prompt_id) VALUES (%s) ON CONFLICT DO NOTHING',
(prompt_id,)
)
cur.execute(
'''INSERT INTO prompt_versions
(prompt_id, version, template, author, tags, model)
VALUES (%s, %s, %s, %s, %s, %s)''',
(prompt_id, version, template, author, tags, model)
)
self.conn.commit()
print(f'Registered {prompt_id}@{version}')
def get_active(self, prompt_id):
with self.conn.cursor() as cur:
cur.execute(
'SELECT template, version FROM prompt_versions '
'WHERE prompt_id=%s AND is_active=TRUE LIMIT 1',
(prompt_id,)
)
row = cur.fetchone()
if not row:
raise ValueError(f'No active version for {prompt_id}')
return {'template': row[0], 'version': row[1]}Подробный разбор схемы метаданных
Богатые метаданные делают реестр полезным не только для простого хранения. Основные поля метаданных:
- автор — ответственное лицо и контактная информация
- теги — доступные для поиска метки, такие как
['production', 'summarization', 'v2'] - модель — целевая модель (промпт может зависеть от конкретной модели)
- журнал изменений — понятное человеку описание того, что изменилось
- набор_проверок — ссылка на набор данных для оценки этого промпта
# Extended metadata example
prompt_metadata = {
'prompt_id': 'extract-key-dates',
'version': '2.0.0',
'author': 'bob@company.com',
'tags': ['extraction', 'dates', 'contracts', 'production'],
'model': 'gpt-4o',
'changelog': 'Added support for relative dates (next quarter, end of year)',
'test_suite': 's3://company-evals/extract-key-dates/v2-testset.jsonl',
'created_at': '2024-07-15T09:30:00Z',
'is_active': True
}Подстановка переменных в шаблон
В шаблонах промптов используется синтаксис заполнителей. Реестр формирует итоговый промпт, подставляя в шаблон переменные времени выполнения. Использование Python-выражения str.format_map() безопасно и просто.
class PromptRegistry:
# ... (previous methods)
def render(self, prompt_id, variables: dict) -> str:
artifact = self.get_active(prompt_id)
template = artifact['template']
try:
rendered = template.format_map(variables)
except KeyError as e:
raise ValueError(f'Missing variable {e} for prompt {prompt_id}')
return rendered
# Usage
registry = PromptRegistry(dsn='postgresql://...')
prompt = registry.render(
'summarize-article',
{
'num_sentences': 3,
'focus_area': 'financial impact',
'article_text': 'Apple reported record revenue of $119B...'
}
)
print(prompt)
# Output: Summarize the following article in 3 sentences.
# Focus on: financial impact. ...Активация версии
В рабочей среде одновременно должна быть активной только одна версия промпта. Активация должна выполняться атомарно: деактивировать текущую версию и активировать новую — всё в одной транзакции, чтобы не возникало промежутков без активной версии.
def activate_version(self, prompt_id, version):
with self.conn.cursor() as cur:
# Deactivate all current versions
cur.execute(
'UPDATE prompt_versions SET is_active=FALSE '
'WHERE prompt_id=%s AND is_active=TRUE',
(prompt_id,)
)
# Activate target version
cur.execute(
'UPDATE prompt_versions SET is_active=TRUE '
'WHERE prompt_id=%s AND version=%s',
(prompt_id, version)
)
if cur.rowcount == 0:
self.conn.rollback()
raise ValueError(f'Version {version} not found for {prompt_id}')
self.conn.commit()
print(f'Activated {prompt_id}@{version}')Вывод списка и поиск промптов
Реестр полезен только в том случае, если вы можете находить его содержимое. Поддерживайте поиск по тегам и вывод списка всех версий заданного промпта.
def list_versions(self, prompt_id):
with self.conn.cursor() as cur:
cur.execute(
'SELECT version, author, is_active, created_at '
'FROM prompt_versions WHERE prompt_id=%s '
'ORDER BY created_at DESC',
(prompt_id,)
)
return cur.fetchall()
def search_by_tag(self, tag):
with self.conn.cursor() as cur:
cur.execute(
'SELECT prompt_id, version, tags FROM prompt_versions '
'WHERE %s = ANY(tags)',
(tag,)
)
return cur.fetchall()
# Usage
for v in registry.list_versions('summarize-article'):
print(v) # ('1.1.0', 'alice', True, datetime(...))
for p in registry.search_by_tag('production'):
print(p) # ('summarize-article', '1.1.0', ['production', 'summarization'])Конечные точки API реестра
Предоставьте доступ к реестру через REST API, чтобы все сервисы (серверная часть, конвейеры машинного обучения, инструменты оценки) использовали единый источник достоверных данных. Основные конечные точки:
POST /prompts/{id}/versions— зарегистрировать новую версиюGET /prompts/{id}/active— получить активный шаблонPUT /prompts/{id}/activate/{version}— активировать версиюGET /prompts— вывести список всех промптов с метаданными
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
registry = PromptRegistry(dsn='postgresql://user:pass@localhost/prompts')
class VersionPayload(BaseModel):
version: str
template: str
author: str
tags: list
model: str
@app.post('/prompts/{prompt_id}/versions')
def register_version(prompt_id: str, payload: VersionPayload):
registry.register(
prompt_id, payload.version, payload.template,
payload.author, payload.tags, payload.model
)
return {'status': 'registered'}
@app.get('/prompts/{prompt_id}/active')
def get_active(prompt_id: str):
try:
return registry.get_active(prompt_id)
except ValueError as e:
raise HTTPException(404, str(e))
@app.put('/prompts/{prompt_id}/activate/{version}')
def activate(prompt_id: str, version: str):
registry.activate_version(prompt_id, version)
return {'status': 'activated'}Журнал аудита и история изменений
Каждое событие активации, деактивации и регистрации должно регистрироваться с отметкой времени и указанием исполнителя. Этот журнал аудита необходим для отладки инцидентов в рабочей среде и соблюдения нормативных требований.
CREATE TABLE prompt_audit_log (
id SERIAL PRIMARY KEY,
prompt_id VARCHAR(100),
version VARCHAR(20),
action VARCHAR(50), -- 'registered', 'activated', 'deactivated'
actor VARCHAR(100), -- user or service that performed the action
reason TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Trigger to auto-log activations
CREATE OR REPLACE FUNCTION log_activation()
RETURNS TRIGGER AS $func$
BEGIN
IF NEW.is_active != OLD.is_active THEN
INSERT INTO prompt_audit_log (prompt_id, version, action)
VALUES (NEW.prompt_id, NEW.version,
CASE WHEN NEW.is_active THEN 'activated' ELSE 'deactivated' END);
END IF;
RETURN NEW;
END;
$func$ LANGUAGE plpgsql;
CREATE TRIGGER trg_activation
AFTER UPDATE ON prompt_versions
FOR EACH ROW EXECUTE FUNCTION log_activation();Быстрая проверка
В схеме базы данных реестра промптов какое поле гарантирует, что в каждый момент в рабочей среде обслуживается только одна версия промпта?
Краткий обзор архитектуры реестра
Реестр промптов централизует управление промптами, рассматривая их как артефакты с версиями. Основные проектные решения:
- Отдельная таблица идентификаторов (prompt_id) и таблица версий (версия, шаблон, метаданные)
- Единый флаг
is_activeс атомарным переключением предотвращает ошибки с двумя активными версиями - Богатые метаданные (автор, теги, модель, журнал изменений) поддерживают поиск и аудит
- Слой REST API делает реестр доступным для всех сервисов
- Журнал аудита помогает соблюдать нормативные требования и разбирать инциденты
Реестры на основе файлов подходят для небольших команд; для рабочих систем с несколькими командами и высокой доступностью предпочтительны реестры на основе БД.
Часто задаваемые вопросы
Урок «Архитектура реестра запросов» бесплатный?
Да — полный текст урока «Архитектура реестра запросов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Prompt Engineering, подпишись на CoddyKit PRO. Курс AI Prompt Engineering содержит 4 уроков всего.
Чему я научусь в уроке «Архитектура реестра запросов»?
Хранение запросов как версионируемых артефактов с метаданными и тегами. Ты практикуешь AI Prompt Engineering с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать AI Prompt Engineering?
Предыдущий опыт не требуется. AI Prompt Engineering на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Архитектура реестра запросов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке AI Prompt Engineering?
Да. Каждый урок AI Prompt Engineering включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Архитектура реестра запросов
- Контроль версий запросов
- Стратегии развёртывания и отката
- Мониторинг производительности запросов в рабочей среде