0Pricing
AI Prompt Engineering · Leçon

Architecture d’un registre de prompts

Stockez les prompts comme des artefacts versionnés avec leurs métadonnées et leurs balises.

Architecture d’un registre de prompts est une leçon AI Prompt Engineering gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Prompt Engineering, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Prompt Engineering comprend 4 leçons au total.

Pourquoi un registre d’invites ?

Sans registre, les invites sont dispersées dans le code, les fichiers de configuration et la mémoire des développeurs. Un registre d’invites est un stockage centralisé qui traite chaque invite comme un artefact versionné et traçable — tout comme le code logiciel.

Ses avantages comprennent la reproductibilité, l’auditabilité, la possibilité de rollback et la collaboration en équipe.

Champs essentiels d’un artefact d’invite

Chaque artefact d’invite doit contenir les champs suivants :

  • prompt_id — identifiant unique et stable (par exemple : summarize-article)
  • version — chaîne de version sémantique (par exemple : 2.1.0)
  • template — texte réel de l’invite avec des espaces réservés {variable}
  • metadata — auteur, étiquettes, modèle cible, date de création, description

Conception du schéma de base de données

Un schéma relationnel pour un registre d’invites stocke les invites et leur historique des versions dans des tables distinctes, ce qui permet d’effectuer efficacement les recherches et les audits.

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

Conception d’un registre fondé sur des fichiers

Pour les équipes plus petites, un registre fondé sur des fichiers utilise une structure de répertoires organisée. Chaque invite reçoit un dossier ; chaque version est un fichier YAML ou JSON à l’intérieur de ce dossier.

# 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}

Classe Python PromptRegistry

Une classe Python simple encapsule l’accès à la base de données et expose des méthodes claires : register(), get_active() et 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]}

Analyse approfondie du schéma des métadonnées

Des métadonnées détaillées rendent le registre utile au-delà du simple stockage. Principaux champs de métadonnées :

  • auteur — responsabilité et point de contact
  • étiquettes — libellés interrogeables tels que ['production', 'summarization', 'v2']
  • modèle — modèle cible (l’invite peut ne pas être indépendante du modèle)
  • journal des modifications — description compréhensible par les humains de ce qui a changé
  • suite de tests — lien vers l’ensemble de données d’évaluation de cette invite
# 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
}

Rendu des modèles avec des variables

Les modèles d’invite utilisent une syntaxe avec espaces réservés. Le registre produit une invite finale en remplaçant les variables d’exécution dans le modèle. L’utilisation de str.format_map() en Python est sûre et simple.

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

Activation d’une version

Une seule version d’une invite doit être active à la fois en production. L’activation doit être atomique : désactiver la version actuelle, puis activer la nouvelle — le tout dans une seule transaction afin d’éviter toute interruption.

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

Liste et recherche d’invites

Un registre n’est utile que si vous pouvez en découvrir le contenu. Prenez en charge la recherche par étiquette et l’affichage de toutes les versions d’une invite donnée.

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

Points de terminaison de l’API du registre

Exposez le registre sous la forme d’une API REST afin que tous les services (serveur dorsal, chaînes de traitement d’apprentissage automatique, outils d’évaluation) partagent la même source de vérité. Principaux points de terminaison :

  • POST /prompts/{id}/versions — enregistrer une nouvelle version
  • GET /prompts/{id}/active — obtenir le modèle actif
  • PUT /prompts/{id}/activate/{version} — activer une version
  • GET /prompts — lister toutes les invites avec leurs métadonnées
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'}

Journal d’audit et historique des modifications

Chaque événement d’activation, de désactivation et d’enregistrement doit être consigné avec un horodatage et l’identité de son auteur. Cette piste d’audit est essentielle pour déboguer les incidents en production et satisfaire aux exigences de conformité.

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

Vérification rapide

Dans le schéma d’une base de données de registre d’invites, quel champ garantit qu’une seule version d’une invite est servie en production à un instant donné ?

Synthèse de l’architecture du registre

Un registre d’invites centralise la gestion des invites en les traitant comme des artefacts versionnés. Principales décisions de conception :

  • Séparer la table d’identité (prompt_id) de la table des versions (version, template, metadata)
  • Un indicateur is_active unique avec des échanges atomiques empêche les défauts liés à la double activation
  • Des métadonnées détaillées (auteur, étiquettes, modèle, journal des modifications) facilitent la découverte et l’audit
  • La couche d’API REST rend le registre accessible à tous les services
  • Le journal d’audit facilite la conformité et le débogage des incidents

Les registres fondés sur des fichiers conviennent aux petites équipes ; les registres adossés à une base de données sont préférables pour les systèmes de production réunissant plusieurs équipes et exigeant une haute disponibilité.

Questions Fréquemment Posées

La leçon « Architecture d’un registre de prompts » est-elle gratuite ?

Oui — le texte complet de « Architecture d’un registre de prompts » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Prompt Engineering, passe à CoddyKit PRO. Le cours AI Prompt Engineering comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Architecture d’un registre de prompts » ?

Stockez les prompts comme des artefacts versionnés avec leurs métadonnées et leurs balises. Tu pratiques AI Prompt Engineering avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer AI Prompt Engineering ?

Aucune expérience préalable n'est requise. AI Prompt Engineering sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Architecture d’un registre de prompts » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon AI Prompt Engineering ?

Oui. Chaque leçon AI Prompt Engineering inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Architecture d’un registre de prompts
  2. Contrôle de version des prompts
  3. Stratégies de déploiement et de restauration
  4. Surveiller les performances des prompts en production
← Retour à AI Prompt Engineering