LangChain Prompts, AIPRM, Humanloop : Écosystème Outils 2025

tl;dr: Maîtrisez l'écosystème outils 2025 : LangChain pour gérer prompts programmatiquement, marketplaces (PromptBase, FlowGPT, AIPRM), platforms de versioning (Humanloop, PromptLayer), frameworks de testing, A/B testing et optimisation automatique (DSPy). De l'artisanat au mode industriel.

Écrire des prompts manuellement dans ChatGPT, c’est comme coder dans Notepad : ça fonctionne pour débuter, mais pas scalable pour la production.

Cet article présente l’écosystème professionnel du prompt engineering en 2025 : outils pour gérer, versionner, tester et optimiser vos prompts à l’échelle.


Exemples visuels de les outils et frameworks de prompt engineering pour optimiser les interactions avec les modèles de langage

Pourquoi des Outils Dédiés ?

Problèmes du Prompt Engineering “Artisanal”

ProblèmeImpactSolution Outillée
Copier-coller manuelErreurs, perte de tempsTemplates réutilisables (LangChain)
Pas de versioningImpossible de revenir en arrièreGit + platforms (Humanloop)
Qualité incertaineOutputs incohérentsTesting automatisé + métriques
Optimisation manuelleDes heures d’itérationsA/B testing + auto-optimization
Coûts invisiblesDépassements budgetsMonitoring intégré (tokens, latence)
Collaboration difficileSilos, duplicationHubs partagés, review process

Évolution : Artisanat → Industrialisation

Phase 1 : Artisanat (2022-2023)
└─ Prompts manuels dans ChatGPT/Claude
   └─ OK pour prototypes, pas scalable

Phase 2 : Semi-automatisé (2024)
└─ Templates réutilisables (LangChain)
   └─ Versioning basique (Git)
   └─ Testing manuel

Phase 3 : Industriel (2025) ← Nous sommes ici
└─ Platforms dédiées (Humanloop, PromptLayer)
   └─ CI/CD pour prompts
   └─ A/B testing automatisé
   └─ Optimisation via ML (DSPy)

LangChain : Gérer Prompts Programmatiquement

🔎 Tip
LangChain pour la scalabilité : Hard-coder vos prompts = dette technique. LangChain permet de gérer 100+ prompts avec versioning, tests et réutilisabilité. Une équipe Airbnb a réduit son temps de maintenance de 70% en migrant vers LangChain.

Installation

pip install langchain langchain-openai langchain-anthropic

Template de Base

Problème artisanal :

# ❌ Mauvaise approche : prompt en dur
prompt = f"Tu es un {role}. Tâche : {task}. Contexte : {context}."

❌ Problèmes :

  • Pas réutilisable
  • Difficile à modifier
  • Pas de validation

Solution LangChain :

from langchain.prompts import PromptTemplate

# ✅ Template réutilisable
template = """Tu es un {role} avec {experience} ans d'expérience.

Tâche : {task}

Contexte :
{context}

Contraintes :
- {constraint1}
- {constraint2}

Format de réponse : {format}
"""

prompt = PromptTemplate(
    input_variables=["role", "task", "context", "constraint1", "constraint2", "format", "experience"],
    template=template
)

# Utilisation
final_prompt = prompt.format(
    role="expert marketing digital",
    experience=10,
    task="Rédiger une accroche publicitaire",
    context="SaaS de gestion de projet pour startups tech",
    constraint1="Max 100 caractères",
    constraint2="Ton aspirationnel, pas corporate",
    format="Titre + sous-titre"
)

print(final_prompt)

Output :

Tu es un expert marketing digital avec 10 ans d'expérience.

Tâche : Rédiger une accroche publicitaire

Contexte :
SaaS de gestion de projet pour startups tech

Contraintes :
- Max 100 caractères
- Ton aspirationnel, pas corporate

Format de réponse : Titre + sous-titre

Chat Prompt Template

Pour les modèles de chat (GPT-4, Claude, Gemini) :

from langchain.prompts import ChatPromptTemplate

chat_template = ChatPromptTemplate.from_messages([
    ("system", "Tu es un {role}. {instructions}"),
    ("human", "Voici le code à analyser :\n\n{code}"),
    ("ai", "J'ai analysé le code. Voici mes observations :"),
    ("human", "Maintenant {task}")
])

messages = chat_template.format_messages(
    role="senior developer Python",
    instructions="Tu fais des code reviews constructives et pédagogiques.",
    code="def calculate(x, y):\n    return x + y",
    task="suggère des améliorations (type hints, docstrings, tests)"
)

# Envoi à l'API
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4", temperature=0)
response = llm(messages)
print(response.content)

Few-Shot Prompts (Exemples Dynamiques)

from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts import PromptTemplate

# Base d'exemples
examples = [
    {"input": "heureux", "output": "joyeux, content, ravi, enchanté"},
    {"input": "triste", "output": "malheureux, mélancolique, affligé, morose"},
    {"input": "rapide", "output": "véloce, prompt, agile, leste"},
    {"input": "intelligent", "output": "brillant, perspicace, sagace, érudit"}
]

# Template pour chaque exemple
example_template = """
Mot : {input}
Synonymes : {output}
"""

example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template=example_template
)

# Combiner dans un few-shot prompt
few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="Tu es un expert linguiste. Trouve 4 synonymes précis pour chaque mot.",
    suffix="\nMot : {input}\nSynonymes :",
    input_variables=["input"],
)

# Utilisation
print(few_shot_prompt.format(input="courageux"))

Output :

Tu es un expert linguiste. Trouve 4 synonymes précis pour chaque mot.

Mot : heureux
Synonymes : joyeux, content, ravi, enchanté

Mot : triste
Synonymes : malheureux, mélancolique, affligé, morose

Mot : rapide
Synonymes : véloce, prompt, agile, leste

Mot : intelligent
Synonymes : brillant, perspicace, sagace, érudit

Mot : courageux
Synonymes :

Conditional Logic (Prompts Dynamiques)

from langchain.prompts import PromptTemplate

def create_prompt(task_type: str, include_examples: bool = True):
    """Génère un prompt selon le type de tâche"""

    base = "Tu es un assistant IA expert.\n\n"

    if task_type == "code":
        base += "Spécialité : Génération et review de code.\n"
        constraints = "- Inclure type hints\n- Gestion erreurs\n- Tests unitaires"
    elif task_type == "marketing":
        base += "Spécialité : Copywriting et stratégie marketing.\n"
        constraints = "- Accrocheur\n- Call-to-action clair\n- Preuve sociale"
    else:
        constraints = "- Clair et concis"

    if include_examples:
        base += "\nExemples de sorties attendues :\n{examples}\n"

    base += f"\nContraintes :\n{constraints}\n\nTâche : {{task}}"

    variables = ["task"]
    if include_examples:
        variables.append("examples")

    return PromptTemplate(input_variables=variables, template=base)

# Utilisation
code_prompt = create_prompt("code", include_examples=False)
marketing_prompt = create_prompt("marketing", include_examples=True)

print(marketing_prompt.format(
    task="Créer un slogan pour app de méditation",
    examples="- Nike : Just Do It\n- Apple : Think Different"
))

Prompt Hubs et Marketplaces

LangChain Hub (Gratuit)

Repository communautaire de prompts versionnés.

💡 Communauté vs Payant : LangChain Hub (gratuit) contient 4000+ prompts open-source de qualité variable. PromptBase (payant) offre des prompts premium testés avec support. Pour démarrer, utilisez le Hub. Pour la production, investissez dans des prompts premium qui économisent 10-20h de développement.

URL : smith.langchain.com/hub

from langchain import hub

# Charger un prompt depuis le Hub
rag_prompt = hub.pull("rlm/rag-prompt")

# Voir le contenu
print(rag_prompt.template)

# Utiliser
response = rag_prompt.format(context="...", question="...")

Prompts populaires :

  • rlm/rag-prompt : RAG (Retrieval-Augmented Generation)
  • jacob/chain-of-thought : CoT optimisé
  • hwchase17/react-agent : Agent ReAct

Publier vos prompts :

from langchain import hub

# Pousser votre prompt
hub.push("username/my-awesome-prompt", my_prompt)

PromptBase (Marketplace Premium)

URL : promptbase.com

Concept : Marketplace de prompts payants créés par experts.

Catégories :

  • Marketing (Facebook Ads, SEO, emails) : 2-5$
  • Code (debugging, génération, review) : 3-7$
  • Art (Midjourney, DALL-E, Stable Diffusion) : 2-10$
  • Business (business plans, pitchs, analyses) : 5-10$

Avantages :

  • ✅ Prompts testés et optimisés
  • ✅ Ratings/reviews
  • ✅ Support du créateur

Inconvénients :

  • ❌ Payant (vs gratuit communautaire)
  • ❌ Qualité variable
  • ❌ Pas toujours à jour avec nouveaux modèles

Exemple : Prompt “Email Cold Outreach B2B” à 4.99$ avec 4.8★ (127 reviews)

FlowGPT (Gratuit)

URL : flowgpt.com

Concept : Reddit des prompts - communautaire, gratuit, voting system.

Catégories populaires :

  • Productivity (15k+ prompts)
  • Coding (12k+)
  • Writing (18k+)
  • Marketing (8k+)

Exemple : “Ultimate Code Reviewer” (8.2k upvotes)

Tu es un senior developer avec 15 ans d'expérience faisant une code review.

[... prompt détaillé de 500 mots ...]

Code à reviewer :
{CODE}

Avantages :

  • ✅ Gratuit
  • ✅ Grande diversité
  • ✅ Système de voting (meilleurs prompts en top)

Inconvénients :

  • ❌ Qualité très variable
  • ❌ Pas de versioning
  • ❌ Parfois obsolètes

AIPRM (Extension Chrome)

URL : aiprm.com

Concept : Extension Chrome avec 4000+ prompts pré-faits s’intégrant directement dans ChatGPT.

Installation :

  1. Installer extension Chrome
  2. Ouvrir ChatGPT
  3. Accéder bibliothèque AIPRM (menu déroulant)

Catégories :

  • SEO (meta descriptions, articles, mots-clés)
  • Marketing (ads, social media, emails)
  • Copywriting (landing pages, sales pages)
  • Productivité (résumés, traductions, reformulations)

Modèle : Freemium

  • Gratuit : 20 prompts publics/mois
  • Pro (9$/mois) : Illimité + prompts privés + custom lists

Exemple : Prompt “Human-Written Article | 100% Unique” → 1 clic, remplir champs (mot-clé, ton, longueur) → article généré

Avantages :

  • ✅ Intégration native ChatGPT (UX fluide)
  • ✅ Filtres avancés (topic, activity, tone)
  • ✅ Mis à jour régulièrement

Inconvénients :

  • ❌ Seulement ChatGPT (pas Claude, Gemini)
  • ❌ Prompts anglais majoritairement

Versioning et Gestion de Prompts

Fichiers YAML/JSON (Approche Simple)

Structure : prompts.yaml

# prompts.yaml
marketing_facebook_ad:
  version: "2.1"
  description: "Generate Facebook ad copy (PAS framework)"
  model: "gpt-4"
  temperature: 0.7
  template: |
    Tu es un copywriter expert en publicités Facebook.

    Produit : {{product}}
    Audience : {{audience}}
    Objectif : {{objective}}

    Crée 3 variantes de publicité suivant le framework PAS (Problem-Agitate-Solve).

    Format :
    **Variante 1**
    Titre : [...]
    Corps : [...]
    CTA : [...]
  variables:
    - product
    - audience
    - objective
  metadata:
    author: "Marie Dupont"
    created: "2024-11-15"
    last_updated: "2025-01-10"
    tested: true
    avg_performance: 0.87  # CTR moyen
    cost_per_run: 0.024  # USD

code_review:
  version: "1.5"
  description: "Python code review with security focus"
  model: "gpt-4"
  temperature: 0.2
  template: |
    Tu es un senior developer Python faisant une code review.

    [... template ...]
  variables:
    - code
    - language
  metadata:
    author: "Jean Martin"
    created: "2024-09-20"
    tested: true

Charger en Python :

import yaml
from langchain.prompts import PromptTemplate

# Charger prompts
with open("prompts.yaml", "r") as f:
    prompts = yaml.safe_load(f)

# Utiliser
ad_config = prompts["marketing_facebook_ad"]
ad_prompt = PromptTemplate(
    input_variables=ad_config["variables"],
    template=ad_config["template"]
)

# Formatter
final = ad_prompt.format(
    product="App de méditation",
    audience="Femmes 30-45 ans, stress professionnel",
    objective="Installations app (7j gratuits)"
)

Git pour Prompts (Approche Pro)

Structure de repository :

prompts-repo/
├── README.md
├── prompts/
│   ├── marketing/
│   │   ├── facebook_ad_v1.txt
│   │   ├── facebook_ad_v2.txt
│   │   ├── facebook_ad_v3.txt  ← Version actuelle
│   │   ├── email_cold_b2b_v1.txt
│   │   └── seo_meta_v2.txt
│   ├── code/
│   │   ├── code_review_v1.txt
│   │   ├── code_review_v2.txt
│   │   ├── debugging_v1.txt
│   │   └── generation_python_v1.txt
│   └── data/
│       ├── sql_query_v1.txt
│       └── pandas_eda_v1.txt
├── tests/
│   ├── test_marketing.py
│   └── test_code.py
├── benchmarks/
│   └── results.json
└── CHANGELOG.md

Workflow Git :

# Créer nouvelle version
cp prompts/marketing/facebook_ad_v2.txt prompts/marketing/facebook_ad_v3.txt
# Modifier v3

# Committer
git add prompts/marketing/facebook_ad_v3.txt
git commit -m "Improve facebook_ad prompt: +15% CTR (A/B test 500 samples)"

# Tagger version
git tag marketing/facebook_ad/v3.0
git push origin marketing/facebook_ad/v3.0

# Revenir à version précédente si problème
git checkout marketing/facebook_ad/v2.0 prompts/marketing/facebook_ad_v2.txt

CHANGELOG.md :

# Changelog

## [3.0] - 2025-01-15 {#30---2025-01-15}
### Marketing / Facebook Ad
- **Changed** : Ajout framework PAS explicite
- **Improved** : CTR +15% vs v2.0 (A/B test, n=500)
- **Fixed** : Génération CTA trop générique

## [2.0] - 2024-12-10 {#20---2024-12-10}
### Marketing / Facebook Ad
- **Added** : Support multi-langues (FR, EN, ES)
- **Improved** : Ton ajustable (urgent/aspirationnel/éducatif)

Platforms de Gestion (Humanloop, PromptLayer)

Humanloop

URL : humanloop.com

Fonctionnalités :

  • Versioning automatique : Chaque modification = nouvelle version trackée
  • A/B testing intégré : Split traffic entre versions, analytics temps réel
  • Monitoring : Coûts (tokens), latence, taux erreurs
  • Collaboration : Review process, commentaires, approval workflow
  • Rollback 1-click : Revenir à version précédente instantanément
  • Intégrations : OpenAI, Anthropic, Cohere, custom models

Exemple d’utilisation :

from humanloop import Humanloop

hl = Humanloop(api_key="your_api_key")

# Créer/updater un prompt
hl.prompts.upsert(
    name="marketing-facebook-ad",
    version="3.0",
    template="Tu es un copywriter...",
    model="gpt-4",
    temperature=0.7,
    metadata={
        "category": "marketing",
        "tested": True,
        "performance": 0.87
    }
)

# Appeler le prompt
response = hl.chat(
    prompt_name="marketing-facebook-ad",
    inputs={
        "product": "App de méditation",
        "audience": "Femmes 30-45 ans"
    }
)

print(response.output)

# Dashboard : voir analytics (coût, latence, outputs)

Tarifs :

  • Free : 1k calls/mois
  • Pro : 50$/mois (50k calls)
  • Enterprise : Custom

PromptLayer

URL : promptlayer.com

Concept : Logging + versioning de tous vos appels LLM.

Installation :

pip install promptlayer

Usage :

import promptlayer
from openai import OpenAI

# Wrapper OpenAI avec logging
promptlayer.api_key = "pl_xxxxx"
OpenAI = promptlayer.openai.OpenAI
client = OpenAI()

# Tous les appels sont automatiquement loggés
response = client.chat.completions.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": "Tu es un expert marketing."},
        {"role": "user", "content": "Crée une accroche pour app méditation."}
    ],
    pl_tags=["marketing", "facebook-ad", "v3.0"]  # Tags custom
)

print(response.choices[0].message.content)

# Dashboard PromptLayer : voir tous les logs, filtrer par tag, replayer

Fonctionnalités :

  • Logging automatique : Input, output, metadata (modèle, tokens, latence, coût)
  • Replay : Re-exécuter un appel passé
  • Search : Filtrer par tag, date, modèle, coût
  • Analytics : Graphiques coûts, latence, volume
  • Templates : Créer templates depuis logs réussis

Tarifs : Gratuit jusqu’à 1k requests/mois, puis 29$/mois.


Testing et Évaluation de Prompts

Framework de Testing (Python)

import openai
from typing import List, Dict, Callable
from dataclasses import dataclass

@dataclass
class TestCase:
    """Un cas de test"""
    input: Dict[str, str]
    expected_criteria: Dict[str, bool]  # Critères à vérifier
    description: str

def test_prompt(
    prompt_template: str,
    test_cases: List[TestCase],
    evaluator: Callable,
    model: str = "gpt-4"
) -> Dict:
    """
    Teste un prompt sur plusieurs cas.

    Args:
        prompt_template: Template avec {variables}
        test_cases: Liste de TestCase
        evaluator: Fonction qui évalue la réponse
        model: Modèle LLM

    Returns:
        Résultats agrégés avec scores
    """
    results = []
    total_tokens = 0
    total_cost = 0

    for i, case in enumerate(test_cases):
        print(f"\n🧪 Test {i+1}/{len(test_cases)}: {case.description}")

        # Formatter prompt
        prompt = prompt_template.format(**case.input)

        # Appel API
        response = openai.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": prompt}]
        )

        output = response.choices[0].message.content
        tokens = response.usage.total_tokens
        cost = calculate_cost(tokens, model)

        # Évaluation
        evaluation = evaluator(output, case.expected_criteria)

        # Stocker résultat
        results.append({
            'test_id': i + 1,
            'description': case.description,
            'input': case.input,
            'output': output,
            'expected_criteria': case.expected_criteria,
            'evaluation': evaluation,
            'passed': all(evaluation.values()),
            'tokens': tokens,
            'cost': cost
        })

        total_tokens += tokens
        total_cost += cost

        # Affichage
        status = "✅ PASS" if results[-1]['passed'] else "❌ FAIL"
        print(f"{status} | Tokens: {tokens} | Cost: ${cost:.4f}")
        if not results[-1]['passed']:
            print(f"   Critères non respectés : {[k for k, v in evaluation.items() if not v]}")

    # Agrégation
    pass_rate = sum(r['passed'] for r in results) / len(results)

    summary = {
        'total_tests': len(test_cases),
        'passed': sum(r['passed'] for r in results),
        'failed': len(test_cases) - sum(r['passed'] for r in results),
        'pass_rate': pass_rate,
        'total_tokens': total_tokens,
        'total_cost': total_cost,
        'avg_cost_per_test': total_cost / len(test_cases),
        'results': results
    }

    return summary

def calculate_cost(tokens: int, model: str) -> float:
    """Calcule coût en USD"""
    pricing = {
        "gpt-4": {"input": 0.03/1000, "output": 0.06/1000},
        "gpt-3.5-turbo": {"input": 0.0005/1000, "output": 0.0015/1000}
    }
    # Simplification : assume 50/50 input/output
    return tokens * ((pricing[model]["input"] + pricing[model]["output"]) / 2)

# Evaluator example : Facebook Ad
def evaluate_facebook_ad(output: str, criteria: Dict[str, bool]) -> Dict[str, bool]:
    """Évalue si output respecte critères"""
    evaluation = {}

    # Critère : Contient CTA
    evaluation['has_cta'] = any(word in output.lower() for word in ['télécharger', 'essayer', 'découvrir', 'profiter', 'commencer'])

    # Critère : Longueur appropriée (corps < 125 car)
    lines = output.split('\n')
    corps_lines = [l for l in lines if l.startswith('Corps :')]
    if corps_lines:
        corps = corps_lines[0].replace('Corps :', '').strip()
        evaluation['length_ok'] = len(corps) <= 125
    else:
        evaluation['length_ok'] = False

    # Critère : Contient chiffre/stat (preuve sociale)
    evaluation['has_social_proof'] = any(char.isdigit() for char in output)

    # Critère : 3 variantes
    evaluation['three_variants'] = output.count('Variante') >= 3

    return evaluation

# Utilisation
test_cases = [
    TestCase(
        input={
            "product": "App de méditation",
            "audience": "Femmes 30-45 ans, stress",
            "objective": "Installations"
        },
        expected_criteria={
            "has_cta": True,
            "length_ok": True,
            "has_social_proof": True,
            "three_variants": True
        },
        description="Cas nominal : app méditation"
    ),
    TestCase(
        input={
            "product": "SaaS CRM B2B",
            "audience": "Sales managers PME",
            "objective": "Démo gratuite"
        },
        expected_criteria={
            "has_cta": True,
            "length_ok": True,
            "has_social_proof": True,
            "three_variants": True
        },
        description="Cas B2B : CRM"
    )
]

prompt_template = """Tu es un copywriter expert Facebook Ads.

Produit : {product}
Audience : {audience}
Objectif : {objective}

Crée 3 variantes (PAS framework, corps max 125 car).
"""

summary = test_prompt(prompt_template, test_cases, evaluate_facebook_ad)

# Rapport
print(f"\n{'='*50}")
print(f"📊 RÉSUMÉ")
print(f"{'='*50}")
print(f"Tests réussis : {summary['passed']}/{summary['total_tests']} ({summary['pass_rate']:.0%})")
print(f"Coût total : ${summary['total_cost']:.4f}")
print(f"Coût moyen/test : ${summary['avg_cost_per_test']:.4f}")

Métriques d’Évaluation

MétriqueDescriptionImplémentationUse Case
ExactitudeMatch exactoutput == expectedClassification, extraction données
Similarité sémantiqueCosine similarity embeddingscosine(embed(output), embed(expected))Génération texte, paraphrase
LLM-as-JudgeGPT-4 évalue qualitégpt4("Note /10 : {output}")Créativité, copywriting
BLEU/ROUGEMétriques NLPnltk.translate.bleu_scoreTraduction, résumé
Human EvalNotation humaineInterface customGold standard (coûteux)
CoûtTokens × prixtotal_tokens * rateOptimisation budget
LatenceTemps réponsetime.time()Apps temps réel
Pass@k% succès sur k essaissum(passed) / kCode generation

Exemple : Similarité Sémantique

from openai import OpenAI
import numpy as np

client = OpenAI()

def semantic_similarity(text1: str, text2: str) -> float:
    """Calcule similarité cosine entre 2 textes"""

    # Embeddings
    emb1 = client.embeddings.create(input=text1, model="text-embedding-3-small").data[0].embedding
    emb2 = client.embeddings.create(input=text2, model="text-embedding-3-small").data[0].embedding

    # Cosine similarity
    dot_product = np.dot(emb1, emb2)
    norm1 = np.linalg.norm(emb1)
    norm2 = np.linalg.norm(emb2)

    return dot_product / (norm1 * norm2)

# Test
output = "Notre app vous aide à réduire le stress quotidien."
expected = "L'application diminue votre anxiété au travail."

score = semantic_similarity(output, expected)
print(f"Similarité : {score:.2f}")  # 0.85+ = très similaire

A/B Testing de Prompts

⚠️ Warning
Signification statistique requise : Ne déployez jamais une variante sans au moins 100 samples et p-value <0.05. Une startup a perdu 15k$ en déployant une ‘amélioration’ testée sur 20 samples qui s’est révélée 12% moins performante à l’échelle.
import random
from collections import defaultdict
from datetime import datetime
from typing import Dict, List

class PromptABTest:
    """A/B testing framework pour prompts"""

    def __init__(self, prompts: Dict[str, str], split: Dict[str, float] = None):
        """
        Args:
            prompts: {"A": prompt_a, "B": prompt_b, "C": prompt_c}
            split: {"A": 0.5, "B": 0.3, "C": 0.2} (défaut: équitable)
        """
        self.prompts = prompts
        self.split = split or {k: 1/len(prompts) for k in prompts}
        self.results = defaultdict(list)

    def assign_variant(self) -> str:
        """Assigne variant selon split ratio"""
        rand = random.random()
        cumulative = 0
        for variant, ratio in self.split.items():
            cumulative += ratio
            if rand <= cumulative:
                return variant
        return list(self.prompts.keys())[-1]

    def run(self, user_input: str, model: str = "gpt-4") -> Dict:
        """Exécute A/B test pour 1 requête"""

        # Assignment
        variant = self.assign_variant()

        # Appel LLM
        prompt = self.prompts[variant].format(input=user_input)
        start = datetime.now()

        response = openai.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": prompt}]
        )

        latency = (datetime.now() - start).total_seconds()
        output = response.choices[0].message.content
        tokens = response.usage.total_tokens

        # Track result
        self.results[variant].append({
            'timestamp': datetime.now(),
            'input': user_input,
            'output': output,
            'latency': latency,
            'tokens': tokens,
            'cost': calculate_cost(tokens, model)
        })

        return {
            'variant': variant,
            'output': output
        }

    def analyze(self, metric: str = "all") -> Dict:
        """Analyse résultats A/B test"""

        analysis = {}

        for variant, results in self.results.items():
            n = len(results)
            if n == 0:
                continue

            avg_latency = sum(r['latency'] for r in results) / n
            avg_tokens = sum(r['tokens'] for r in results) / n
            total_cost = sum(r['cost'] for r in results)
            avg_output_length = sum(len(r['output']) for r in results) / n

            analysis[variant] = {
                'sample_size': n,
                'avg_latency': avg_latency,
                'avg_tokens': avg_tokens,
                'total_cost': total_cost,
                'avg_cost': total_cost / n,
                'avg_output_length': avg_output_length
            }

        return analysis

    def compare(self, baseline: str = "A"):
        """Compare variants vs baseline"""
        analysis = self.analyze()
        baseline_data = analysis[baseline]

        print(f"\n📊 A/B Test Results (Baseline: {baseline})")
        print("=" * 80)

        for variant, data in analysis.items():
            if variant == baseline:
                print(f"\n{variant} (BASELINE)")
            else:
                print(f"\n{variant}")

            print(f"  Sample size: {data['sample_size']}")
            print(f"  Avg latency: {data['avg_latency']:.3f}s", end="")
            if variant != baseline:
                diff = ((data['avg_latency'] - baseline_data['avg_latency']) / baseline_data['avg_latency']) * 100
                print(f" ({diff:+.1f}%)")
            else:
                print()

            print(f"  Avg tokens: {data['avg_tokens']:.0f}", end="")
            if variant != baseline:
                diff = ((data['avg_tokens'] - baseline_data['avg_tokens']) / baseline_data['avg_tokens']) * 100
                print(f" ({diff:+.1f}%)")
            else:
                print()

            print(f"  Avg cost: ${data['avg_cost']:.4f}", end="")
            if variant != baseline:
                diff = ((data['avg_cost'] - baseline_data['avg_cost']) / baseline_data['avg_cost']) * 100
                print(f" ({diff:+.1f}%)")
            else:
                print()

# Utilisation
prompts = {
    "A": "Explique {input} simplement.",
    "B": "Tu es un professeur. Explique {input} à un élève de 10 ans.",
    "C": "Explique {input} en 3 points clés avec analogies."
}

ab_test = PromptABTest(prompts, split={"A": 0.33, "B": 0.33, "C": 0.34})

# Simuler 100 requêtes
questions = [
    "la photosynthèse",
    "les trous noirs",
    "la blockchain",
    # ... 97 autres
]

for q in questions:
    ab_test.run(q)

# Analyser
ab_test.compare(baseline="A")

Output exemple :

📊 A/B Test Results (Baseline: A)
================================================================================

A (BASELINE)
  Sample size: 33
  Avg latency: 1.245s
  Avg tokens: 287
  Avg cost: $0.0172

B
  Sample size: 33
  Avg latency: 1.512s (+21.4%)
  Avg tokens: 356 (+24.0%)
  Avg cost: $0.0213 (+23.8%)

C
  Sample size: 34
  Avg latency: 1.103s (-11.4%)  ← MEILLEUR
  Avg tokens: 245 (-14.6%)  ← MEILLEUR
  Avg cost: $0.0147 (-14.5%)  ← MEILLEUR

Conclusion : Variant C est meilleur (plus rapide, moins cher, plus concis).


Optimisation Automatique

DSPy (Stanford) : Auto-optimization

Concept : Au lieu d’écrire prompts manuellement, décrire la tâche et laisser DSPy optimiser le prompt automatiquement.

Installation :

pip install dspy-ai

Exemple : Classification de Sentiment

import dspy
from dspy.datasets import DataLoader

# Configurer LLM
lm = dspy.OpenAI(model="gpt-3.5-turbo")
dspy.settings.configure(lm=lm)

# Définir la tâche (signature)
class SentimentClassifier(dspy.Signature):
    """Classifier le sentiment d'un texte"""
    text = dspy.InputField(desc="Le texte à analyser")
    sentiment = dspy.OutputField(desc="positive, negative, ou neutral")

# Créer module
classifier = dspy.Predict(SentimentClassifier)

# Test AVANT optimisation
print(classifier(text="J'adore ce produit !"))
# Output: sentiment='positive'

# Données d'entraînement
train_data = [
    dspy.Example(text="J'adore ce film !", sentiment="positive").with_inputs("text"),
    dspy.Example(text="C'est horrible.", sentiment="negative").with_inputs("text"),
    dspy.Example(text="Pas mal.", sentiment="neutral").with_inputs("text"),
    dspy.Example(text="Incroyable expérience !", sentiment="positive").with_inputs("text"),
    dspy.Example(text="Décevant.", sentiment="negative").with_inputs("text"),
    # ... 20-50 exemples
]

# Métrique d'évaluation
def accuracy(example, prediction, trace=None):
    return example.sentiment.lower() == prediction.sentiment.lower()

# OPTIMISER automatiquement le prompt
from dspy.teleprompt import BootstrapFewShot

optimizer = BootstrapFewShot(metric=accuracy, max_bootstrapped_demos=3)
optimized_classifier = optimizer.compile(classifier, trainset=train_data)

# Test APRÈS optimisation
print(optimized_classifier(text="J'adore ce produit !"))
# Même output, mais prompt interne optimisé automatiquement

# Voir le prompt optimisé
print(lm.inspect_history(n=1))

Résultat : DSPy a automatiquement :

  1. Sélectionné meilleurs exemples (few-shot)
  2. Ordonné exemples optimalement
  3. Ajouté instructions de raisonnement (CoT si bénéfique)
  4. Testé variantes et gardé la meilleure

Gain : +15-30% précision vs prompt manuel.

PromptPerfect (No-code)

URL : promptperfect.jina.ai

Concept : Outil en ligne qui optimise vos prompts automatiquement.

Utilisation :

  1. Collez votre prompt initial
  2. Sélectionnez modèle cible (GPT-4, Claude, Gemini, Midjourney, etc.)
  3. Cliquez “Optimize”
  4. Récupérez prompt optimisé

Exemple :

Input :

Write a product description for a meditation app.

Output optimisé (par PromptPerfect) :

You are an expert copywriter specializing in wellness and mindfulness products.

Task: Write a compelling product description for a meditation mobile app.

Target audience: Busy professionals aged 25-45 seeking stress relief and better sleep.

Description must include:
- Hook (emotional pain point)
- 3 key benefits (specific, measurable)
- Social proof element
- Clear call-to-action

Tone: Calm, aspirational, science-backed (not woo-woo)
Length: 150-200 words

Format:
[Hook paragraph]
[Benefits paragraph with bullet points]
[Social proof + CTA paragraph]

Résultat : Prompt 5x plus détaillé → output 2-3x meilleur.

Tarifs : Freemium (10 optimizations/mois gratuit), Pro 9.99$/mois.


Best Practices Production

Checklist : Prompts en Production

  • Versioning : Git ou platform (Humanloop/PromptLayer)
  • Testing : Suite de tests (min 10 cas par prompt)
  • Monitoring : Coûts, latence, taux erreurs (dashboard)
  • Fallback : Si échec → retry avec backoff OU prompt alternatif
  • Logging : Inputs/outputs (attention RGPD/privacy)
  • Documentation : Quand utiliser, limitations connues, exemples
  • Review process : Validation par pairs avant deploy
  • Rollback plan : Retour version N-1 en < 5 min
  • Cost alerts : Notification si dépassement budget
  • Rate limiting : Protection contre abus

Architecture Recommandée

┌─────────────────┐
│   Application   │
└────────┬────────┘
┌─────────────────┐
│ Prompt Registry │  ← Charge prompts depuis YAML/DB/Platform
└────────┬────────┘
┌─────────────────┐
│  Prompt Cache   │  ← Cache résultats identiques (économies)
└────────┬────────┘
┌─────────────────┐
│   LLM Router    │  ← Choisit modèle optimal (coût/qualité)
└────────┬────────┘
┌─────────────────┐
│  LLM Provider   │  ← OpenAI, Anthropic, etc.
└────────┬────────┘
┌─────────────────┐
│  Logger/Monitor │  ← PromptLayer, Humanloop, custom
└─────────────────┘

Points Clés à Retenir

  1. LangChain : Templates réutilisables, few-shot dynamique, intégration facile

  2. Marketplaces :

    • Gratuit : LangChain Hub, FlowGPT
    • Payant : PromptBase (2-10$/prompt)
    • Extension : AIPRM (intégration ChatGPT native)
  3. Versioning :

    • Simple : YAML + Git
    • Pro : Humanloop, PromptLayer (versioning auto, A/B testing, analytics)
  4. Testing : Framework custom (Python), métriques (exactitude, similarité, LLM-as-judge), A/B testing

  5. Optimisation auto : DSPy (ML-based), PromptPerfect (no-code)

  6. Production : Monitoring, fallbacks, logging, documentation, review process


Suite de la Série

Article 6 : Sécurité et Robustesse : Prompt Injection, Jailbreaking, Guardrails Protéger vos prompts contre attaques et outputs inappropriés

Article 7 : Mesurer et Optimiser Performance : KPIs, A/B Testing, Coûts Métriques clés, optimisation coûts, amélioration continue

Retour : Prompting par Cas d’Usage (Templates)