0Pricing
AI Prompt Engineering · Lekcja

Architektura rejestru promptów

Przechowywanie promptów jako wersjonowanych artefaktów z metadanymi i tagami.

Architektura rejestru promptów to bezpłatna lekcja AI Prompt Engineering na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Prompt Engineering, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.

Dlaczego rejestr promptów?

Bez rejestru prompty są rozproszone w kodzie, plikach konfiguracyjnych i pamięci programistów. Rejestr promptów to scentralizowany magazyn, który traktuje każdy prompt jako wersjonowany i możliwy do śledzenia artefakt — podobnie jak kod oprogramowania.

Do korzyści należą powtarzalność, możliwość przeprowadzania audytów, możliwość wycofywania zmian oraz współpraca zespołowa.

Podstawowe pola artefaktu promptu

Każdy artefakt promptu powinien zawierać następujące pola:

  • prompt_id — unikalny, stabilny identyfikator (np. summarize-article)
  • version — ciąg znaków oznaczający wersję semantyczną (np. 2.1.0)
  • template — właściwy tekst promptu z symbolami zastępczymi {variable}
  • metadata — autor, tagi, docelowy model, created_at, opis

Projektowanie schematu bazy danych

Relacyjny schemat rejestru promptów przechowuje prompty i historię ich wersji w oddzielnych tabelach, umożliwiając wydajne wyszukiwanie i przeprowadzanie audytów.

-- 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)
);

Projekt rejestru opartego na plikach

W przypadku mniejszych zespołów rejestr oparty na plikach wykorzystuje uporządkowany układ katalogów. Każdy prompt otrzymuje własny folder, a każda wersja jest przechowywana w osobnym pliku YAML lub 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}

Klasa Python PromptRegistry

Prosta klasa języka Python opakowuje dostęp do bazy danych i udostępnia przejrzyste metody: register(), get_active() oraz 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]}

Szczegółowe omówienie schematu metadanych

Bogate metadane sprawiają, że rejestr jest przydatny nie tylko do prostego przechowywania danych. Najważniejsze pola metadanych:

  • author — odpowiedzialność i osoba kontaktowa
  • tags — umożliwiające wyszukiwanie etykiety, takie jak ['production', 'summarization', 'v2']
  • model — docelowy model (prompt może nie być niezależny od modelu)
  • changelog — zrozumiały dla człowieka opis wprowadzonych zmian
  • test_suite — odsyłacz do zbioru danych ewaluacyjnych dla tego promptu
# 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
}

Renderowanie szablonów ze zmiennymi

Szablony promptów używają składni symboli zastępczych. Rejestr tworzy końcowy prompt, podstawiając zmienne z czasu wykonywania do szablonu. Użycie języka Python i metody str.format_map() jest bezpieczne i proste.

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. ...

Aktywowanie wersji

W środowisku produkcyjnym tylko jedna wersja promptu powinna być jednocześnie aktywna. Aktywowanie powinno być atomowe: dezaktywacja bieżącej wersji i aktywacja nowej powinny odbywać się w ramach jednej transakcji, aby uniknąć przerw.

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}')

Wyświetlanie i wyszukiwanie promptów

Rejestr jest przydatny tylko wtedy, gdy można odnaleźć jego zawartość. Należy obsługiwać wyszukiwanie według tagów oraz wyświetlanie wszystkich wersji danego promptu.

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'])

Punkty końcowe API rejestru

Rejestr należy udostępnić jako API REST, aby wszystkie usługi (backend, potoki ML i narzędzia ewaluacyjne) korzystały z tego samego źródła prawdy. Najważniejsze punkty końcowe:

  • POST /prompts/{id}/versions — rejestruje nową wersję
  • GET /prompts/{id}/active — pobiera aktywny szablon
  • PUT /prompts/{id}/activate/{version} — aktywuje wersję
  • GET /prompts — wyświetla wszystkie prompty wraz z metadanymi
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'}

Dziennik audytu i historia zmian

Każde zdarzenie aktywacji, dezaktywacji i rejestracji powinno być rejestrowane wraz ze znacznikiem czasu i wykonawcą. Ta ścieżka audytu jest niezbędna do debugowania incydentów produkcyjnych i spełniania wymagań zgodności.

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();

Szybkie sprawdzenie

W schemacie bazy danych rejestru promptów które pole gwarantuje, że w danym momencie w środowisku produkcyjnym udostępniana jest tylko jedna wersja promptu?

Podsumowanie architektury rejestru

Rejestr promptów centralizuje zarządzanie promptami, traktując je jako wersjonowane artefakty. Najważniejsze decyzje projektowe:

  • Oddzielna tabela tożsamości (prompt_id) i tabela wersji (version, template, metadata)
  • Pojedyncza flaga is_active i atomowe przełączanie zapobiegają błędom związanym z jednoczesną aktywnością wielu wersji
  • Bogate metadane (autor, tagi, model, changelog) ułatwiają wyszukiwanie i przeprowadzanie audytów
  • Warstwa API REST udostępnia rejestr wszystkim usługom
  • Dziennik audytu wspiera zapewnienie zgodności i debugowanie incydentów

Rejestry oparte na plikach sprawdzają się w małych zespołach, natomiast rejestry oparte na bazach danych są preferowane w produkcyjnych systemach obsługujących wiele zespołów i wymagających wysokiej dostępności.

Często zadawane pytania

Czy lekcja „Architektura rejestru promptów” jest bezpłatna?

Tak — pełny tekst „Architektura rejestru promptów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Prompt Engineering, przejdź na CoddyKit PRO. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.

Co nauczysz się w „Architektura rejestru promptów”?

Przechowywanie promptów jako wersjonowanych artefaktów z metadanymi i tagami. Ćwiczysz AI Prompt Engineering z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć AI Prompt Engineering?

Nie wymagamy żadnego doświadczenia. AI Prompt Engineering w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Architektura rejestru promptów”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji AI Prompt Engineering?

Tak. Każda lekcja AI Prompt Engineering zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Architektura rejestru promptów
  2. Kontrola wersji promptów
  3. Strategie wdrażania i wycofywania zmian
  4. Monitorowanie wydajności promptów na produkcji
← Powrót do AI Prompt Engineering