IntermédiaireLLM
25 min de lecture20 vues

Prompt Engineering et APIs

Maîtrisez les techniques avancées de prompting (CoT, few-shot, JSON mode) et construisez des applications avec les APIs LLM et le function calling.

Au-delà du Prompt Basique

Dans le cours précédent, vous avez vu les bases du prompting. Ici, nous passons aux techniques qui font la différence entre un amateur et un professionnel.


Chain-of-Thought (CoT)

Le problème

Les LLMs se trompent souvent sur les problèmes qui nécessitent un raisonnement en plusieurs étapes.

Prompt : "Si j''ai 3 paniers de 7 pommes et que j''en mange 4, combien m''en reste-t-il ?"
GPT-4 (sans CoT) : "17" ✓ (parfois correct, parfois non)

La solution : forcer le raisonnement étape par étape

Prompt : "Si j''ai 3 paniers de 7 pommes et que j''en mange 4,
         combien m''en reste-t-il ?
         Réfléchis étape par étape."

Réponse :
1. 3 paniers × 7 pommes = 21 pommes au total
2. J''en mange 4
3. 21 - 4 = 17 pommes restantes

Pourquoi ça marche ? En forçant le modèle à "montrer son travail", chaque étape intermédiaire enrichit le contexte pour l''étape suivante. Le modèle a plus d''informations pour chaque calcul.

Variantes de CoT

TechniquePromptQuand l''utiliser
Zero-shot CoT"Réfléchis étape par étape"Questions simples
Few-shot CoTDonner des exemples avec le raisonnementProblèmes complexes
Self-consistencyGénérer N réponses et voterMaximiser la précision

Few-shot CoT en pratique

messages = [
    {"role": "system", "content": "Tu es un assistant logique. Raisonne toujours étape par étape."},
    {"role": "user", "content": "Marie a 2 fois plus de billes que Jean. Jean a 3 billes de plus que Paul. Paul a 5 billes. Combien Marie a-t-elle de billes ?"},
    {"role": "assistant", "content": """Raisonnons étape par étape :
1. Paul a 5 billes
2. Jean a 3 billes de plus que Paul → 5 + 3 = 8 billes
3. Marie a 2 fois plus que Jean → 8 × 2 = 16 billes

Marie a 16 billes."""},
    {"role": "user", "content": "Un train part à 14h de Paris à 300 km/h. Un autre part à 15h de Lyon (450 km) à 250 km/h vers Paris. À quelle heure se croisent-ils ?"}
]

Structured Outputs : Forcer le Format

Le problème

Quand on construit une application, on a besoin de réponses structurées (JSON, listes, tableaux) et pas de texte libre.

JSON Mode

La plupart des APIs proposent un mode JSON qui force le modèle à répondre en JSON valide.

from openai import OpenAI

client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key="sk-or-...")

response = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[
        {"role": "system", "content": "Tu extrais des informations de CV en JSON."},
        {"role": "user", "content": """Extrais les infos de ce CV :
Jean Dupont, 5 ans d''expérience en Python et React.
Diplômé de l''INSA Lyon en 2019. Parle français et anglais.

Retourne un JSON avec : name, experience_years, skills (array), school, languages (array)"""}
    ],
    response_format={"type": "json_object"},
    temperature=0
)

import json
data = json.loads(response.choices[0].message.content)
print(json.dumps(data, indent=2, ensure_ascii=False))

Résultat attendu :

{
  "name": "Jean Dupont",
  "experience_years": 5,
  "skills": ["Python", "React"],
  "school": "INSA Lyon",
  "languages": ["français", "anglais"]
}

Schéma strict avec Pydantic

Pour des applications production, validez les réponses avec Pydantic :

from pydantic import BaseModel
from typing import List

class CVInfo(BaseModel):
    name: str
    experience_years: int
    skills: List[str]
    school: str
    languages: List[str]

# Valider la réponse du LLM
cv = CVInfo(**data)
print(f"Candidat : {cv.name}, {cv.experience_years} ans d''exp.")
print(f"Compétences : {', '.join(cv.skills)}")

Même en JSON mode, le modèle peut inventer des champs ou omettre des valeurs. Validez toujours avec un schéma.


Function Calling (Tool Use)

Le concept

Le function calling permet au LLM d''appeler des fonctions de votre code. Au lieu de répondre directement, le modèle retourne un appel de fonction structuré que votre application exécute.

Implémentation

import json

# Définir les fonctions disponibles
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Obtenir la météo actuelle pour une ville",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "Nom de la ville"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "Unité de température"
                    }
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "Chercher des informations sur le web",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "La requête de recherche"
                    }
                },
                "required": ["query"]
            }
        }
    }
]

# Envoyer au LLM
response = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Quel temps fait-il à Toulouse ?"}
    ],
    tools=tools,
    tool_choice="auto"  # Le modèle décide s''il appelle une fonction
)

# Le modèle retourne un appel de fonction
message = response.choices[0].message
if message.tool_calls:
    call = message.tool_calls[0]
    print(f"Fonction : {call.function.name}")
    print(f"Arguments : {call.function.arguments}")
    # → Fonction : get_weather
    # → Arguments : {"city": "Toulouse", "unit": "celsius"}

Le flux complet

def get_weather(city, unit="celsius"):
    """Simule un appel API météo."""
    # En production, appelez une vraie API
    return {"temp": 18, "condition": "ensoleillé", "city": city}

# 1. Premier appel : le LLM décide d''appeler get_weather
response = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[{"role": "user", "content": "Météo à Toulouse ?"}],
    tools=tools,
)

# 2. Exécuter la fonction
call = response.choices[0].message.tool_calls[0]
args = json.loads(call.function.arguments)
result = get_weather(**args)

# 3. Renvoyer le résultat au LLM pour qu''il formule la réponse
messages = [
    {"role": "user", "content": "Météo à Toulouse ?"},
    response.choices[0].message,  # Le message avec l''appel de fonction
    {
        "role": "tool",
        "tool_call_id": call.id,
        "content": json.dumps(result)
    }
]

final = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=messages,
)
print(final.choices[0].message.content)
# → "Il fait 18°C et ensoleillé à Toulouse."

Le function calling est la base des agents IA. Un agent est un LLM qui peut appeler des outils (recherche web, exécution de code, accès base de données) en boucle jusqu''à résoudre un problème.


Techniques Avancées

System Prompt Engineering

Un bon system prompt est précis, structuré et contient des contraintes explicites.

system_prompt = """Tu es un assistant expert en droit du travail français.

RÈGLES :
- Réponds UNIQUEMENT aux questions de droit du travail français
- Cite les articles de loi pertinents (Code du travail)
- Si tu n''es pas sûr, dis-le explicitement
- Format : commence par un résumé en 1 phrase, puis développe
- Langue : français, registre professionnel

INTERDICTIONS :
- Ne donne jamais de conseil juridique définitif
- Ne réponds pas aux questions hors sujet
- Ajoute toujours : "Consultez un avocat pour votre situation spécifique."
"""

Multi-turn Conversations

Les LLMs sont stateless : ils n''ont pas de mémoire. C''est à vous de renvoyer l''historique complet.

conversation = [
    {"role": "system", "content": "Tu es un tuteur Python patient et pédagogue."},
]

def chat(user_message):
    conversation.append({"role": "user", "content": user_message})

    response = client.chat.completions.create(
        model="openai/gpt-4o-mini",
        messages=conversation,
        temperature=0.5
    )

    assistant_message = response.choices[0].message.content
    conversation.append({"role": "assistant", "content": assistant_message})

    return assistant_message

# Utilisation
print(chat("C''est quoi une liste en Python ?"))
print(chat("Comment en ajouter un élément ?"))  # Se souvient du contexte
print(chat("Et pour en supprimer ?"))            # Historique complet envoyé

Attention au coût : Chaque message de l''historique est recompté à chaque appel. Une conversation de 50 messages coûte beaucoup plus qu''une seule question. Pensez à résumer ou tronquer l''historique quand il devient trop long.

Prompt Chaining

Décomposer une tâche complexe en plusieurs appels LLM successifs.

# Étape 1 : Extraire les données
extract_response = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[{"role": "user", "content": f"Extrais les noms et dates de ce texte en JSON :\n{texte}"}],
    response_format={"type": "json_object"},
    temperature=0
)
data = json.loads(extract_response.choices[0].message.content)

# Étape 2 : Analyser avec les données extraites
analysis_response = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[{"role": "user", "content": f"Analyse ces événements et identifie les tendances :\n{json.dumps(data)}"}],
    temperature=0.3
)
print(analysis_response.choices[0].message.content)

Exercice : Construire un Assistant Spécialisé

Créez un assistant qui extrait des informations de fiches produit et les structure en JSON.

import json
from openai import OpenAI

client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key="sk-or-...")

system = """Tu es un expert en extraction de données produit.
Pour chaque fiche produit, retourne un JSON avec :
- name (string)
- price (number, en euros)
- category (string)
- features (array de strings)
- rating (number, sur 5)
- in_stock (boolean)

Si une information est absente, utilise null."""

fiches = [
    "iPhone 15 Pro - 1229€ - Smartphone Apple. Puce A17 Pro, 256Go, titane. Note 4.7/5. En stock.",
    "Casque Sony WH-1000XM5 - Réduction de bruit active, 30h autonomie, Bluetooth 5.2. 349€. Rupture de stock. 4.8/5.",
    "Samsung Galaxy Tab S9 - Tablette 11 pouces, 128Go, S Pen inclus. Prix : 799€."
]

for fiche in fiches:
    response = client.chat.completions.create(
        model="openai/gpt-4o-mini",
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": fiche}
        ],
        response_format={"type": "json_object"},
        temperature=0
    )
    data = json.loads(response.choices[0].message.content)
    print(json.dumps(data, indent=2, ensure_ascii=False))
    print("---")

Résultat : Un pipeline d''extraction automatique qui transforme du texte libre en données structurées exploitables par votre application.


Pour Aller Plus Loin

  • Exercice bonus : ajoutez du function calling à l''assistant pour qu''il puisse rechercher un produit dans une base de données
  • Explorez le Cookbook OpenAI pour des patterns avancés
  • Prochain cours : fine-tuning et exécution de modèles en local avec Ollama

Specialiste IA — Master Intelligence Artificielle

Diplome d'un Master en Intelligence Artificielle, je travaille au quotidien sur des projets IA en entreprise. J'ai cree IwanttolearnAI pour rendre l'apprentissage de l'IA accessible a tous, gratuitement.