Génération RAG : Choisir et optimiser son LLM

Guide complet pour sélectionner et configurer votre LLM dans un système RAG : prompting, température, tokens et optimisation des réponses.

Auteur
Équipe Ailog
Date de publication
Temps de lecture
20 min de lecture
Niveau
intermediate

Génération RAG : Choisir et optimiser son LLM

La phase de génération est le moment où votre système RAG transforme les documents récupérés en une réponse cohérente et utile. Le choix du LLM et son paramétrage déterminent la qualité finale de l'expérience utilisateur. Ce guide vous accompagne dans la sélection, la configuration et l'optimisation de votre modèle de génération.

Le rôle du LLM dans un système RAG

Contrairement à un LLM utilisé seul, le LLM dans un système RAG ne génère pas à partir de ses connaissances internes. Il synthétise, reformule et structure les informations issues du retrieval.

Ce que fait le LLM RAG Synthèse : Condenser plusieurs documents en une réponse concise Reformulation : Adapter le langage technique au niveau de l'utilisateur Structuration : Organiser l'information de manière logique Contextualisation : Relier la réponse à la question posée Détection d'insuffisance : Identifier quand les documents ne permettent pas de répondre

Ce que le LLM RAG ne devrait PAS faire • Inventer des informations absentes des documents (hallucination) • Contredire les sources fournies • Répondre à des questions hors scope sans le signaler

Comparatif des LLMs pour le RAG

Modèles propriétaires

| Modèle | Forces | Faiblesses | Coût (1M tokens) | Usage RAG | |--------|--------|------------|------------------|-----------| | GPT-4o | Polyvalent, raisonnement | Prix élevé | ~$5 input / $15 output | Production premium | | GPT-4o-mini | Bon rapport qualité/prix | Moins performant sur tâches complexes | ~$0.15 / $0.60 | Production standard | | Claude 3.5 Sonnet | Excellent suivi instructions | Contexte 200k parfois sous-utilisé | ~$3 / $15 | Production premium | | Claude 3 Haiku | Ultra rapide, économique | Moins nuancé | ~$0.25 / $1.25 | Volume élevé | | Gemini 1.5 Pro | Contexte 1M tokens | API parfois instable | ~$1.25 / $5 | Documents très longs |

Modèles open source

| Modèle | Paramètres | VRAM requise | Performance RAG | Auto-hébergeable | |--------|------------|--------------|-----------------|------------------| | Llama 3.1 70B | 70B | 48GB+ | Excellente | Oui (serveur dédié) | | Llama 3.1 8B | 8B | 8GB | Bonne | Oui (GPU grand public) | | Mistral 7B | 7B | 6GB | Bonne | Oui | | Mixtral 8x7B | 46.7B (MoE) | 32GB | Très bonne | Oui | | Qwen2 72B | 72B | 48GB+ | Excellente | Oui |

Critères de choix

``python def choisir_llm( budget_mensuel: float, volume_requetes: int, exigence_qualite: str, "standard", "premium" contrainte_hebergement: str, "cloud", "souverain", "on-premise" langues: list[str] ) -> str:

tokens_par_requete = 2000 estimation moyenne RAG tokens_mensuels = volume_requetes tokens_par_requete

if contrainte_hebergement == "on-premise": if exigence_qualite == "premium": return "Llama 3.1 70B ou Qwen2 72B" return "Llama 3.1 8B ou Mistral 7B"

if contrainte_hebergement == "souverain": return "Mistral Large via API Mistral (hébergé UE)"

cout_gpt4o_mini = tokens_mensuels 0.15 / 1_000_000 cout_claude_haiku = tokens_mensuels 0.25 / 1_000_000

if budget_mensuel < cout_gpt4o_mini: return "Modèle open source auto-hébergé"

if exigence_qualite == "premium": if "fr" in langues: return "Claude 3.5 Sonnet (excellent en français)" return "GPT-4o"

return "GPT-4o-mini ou Claude 3 Haiku" `

Configurer le prompt système

Le prompt système définit le comportement du LLM dans votre application RAG. C'est l'élément le plus critique de la configuration.

Structure d'un prompt RAG efficace

`python SYSTEM_PROMPT = """Tu es un assistant IA pour {nom_entreprise}, spécialisé dans {domaine}.

RÈGLES STRICTES : Réponds UNIQUEMENT à partir des documents fournis dans le contexte Si l'information n'est pas dans les documents, dis "Je n'ai pas cette information dans ma base de connaissances" Ne jamais inventer d'informations Cite tes sources quand c'est pertinent

STYLE DE RÉPONSE : • Ton : {ton} (professionnel/amical/technique) • Longueur : {longueur} (concis/détaillé) • Format : Utilise des listes à puces pour plus de 3 éléments • Langue : Réponds dans la langue de la question

CONTEXTE MÉTIER : {contexte_specifique}

DOCUMENTS DISPONIBLES : {documents_retrieves}

QUESTION DE L'UTILISATEUR : {question} """ `

Exemples de prompts par cas d'usage

Support client e-commerce

`python ECOMMERCE_PROMPT = """Tu es l'assistant virtuel de la boutique {nom_boutique}.

OBJECTIFS : • Aider les clients avec leurs commandes, retours et questions produits • Maximiser la satisfaction client • Orienter vers le support humain si nécessaire

RÈGLES : Base tes réponses UNIQUEMENT sur les documents fournis Pour les questions sur une commande spécifique, demande le numéro de commande Ne communique jamais d'informations personnelles d'autres clients Si une demande dépasse tes capacités, propose de contacter le service client

TON : Amical et serviable, comme un vendeur en boutique

DOCUMENTS : {context}

QUESTION : {question} """ `

Base de connaissances technique

`python TECH_KB_PROMPT = """Tu es un expert technique pour {produit}.

OBJECTIFS : • Fournir des réponses techniques précises • Inclure des exemples de code quand pertinent • Guider vers la documentation officielle

RÈGLES : Réponds uniquement à partir de la documentation fournie Précise la version du produit concernée si mentionnée Signale les limitations connues ou bugs documentés Propose des alternatives si la solution demandée n'existe pas

FORMAT : • Commence par une réponse directe • Puis détaille si nécessaire • Termine par un exemple de code si applicable

DOCUMENTATION : {context}

QUESTION : {question} """ `

Paramètres de génération

Température

La température contrôle la créativité vs la cohérence des réponses.

`python Basse température (0.0 - 0.3) : Réponses déterministes, factuelles Idéal pour : Support client, FAQ, documentation technique temperature = 0.1

Température moyenne (0.4 - 0.7) : Équilibre créativité/cohérence Idéal pour : Chat général, reformulation temperature = 0.5

Haute température (0.8 - 1.0) : Réponses variées, créatives Idéal pour : Brainstorming, génération de contenu À ÉVITER en RAG (risque d'hallucination) temperature = 0.9 `

Top-p (Nucleus Sampling)

Limite les tokens considérés à ceux représentant une probabilité cumulée.

`python top_p = 0.9 : Considère les tokens jusqu'à 90% de probabilité cumulée Plus restrictif = plus cohérent Plus large = plus varié

from openai import OpenAI client = OpenAI()

response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], temperature=0.2, top_p=0.9, Combiné avec température basse pour RAG ) `

Max tokens

Limite la longueur de la réponse générée.

`python Calcul du budget tokens def calculer_max_tokens( context_length: int, model_limit: int = 128000, GPT-4o reserve_output: int = 2000 ) -> int: """ Assure qu'on laisse assez de place pour la réponse """ prompt_tokens = context_length + 500 + instructions available = model_limit - prompt_tokens return min(available, reserve_output) `

Frequency et Presence Penalty

Contrôlent la répétition dans les réponses.

`python response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, frequency_penalty=0.3, Pénalise les tokens déjà utilisés presence_penalty=0.1, Encourage les nouveaux sujets ) `

Optimiser le contexte fourni au LLM

Formatage des documents récupérés

`python def format_context(documents: list[dict], max_tokens: int = 4000) -> str: """ Formate les documents pour le contexte LLM """ formatted_docs = [] total_tokens = 0

for i, doc in enumerate(documents): Estimation tokens (1 token ≈ 4 caractères en français) doc_tokens = len(doc["text"]) // 4

if total_tokens + doc_tokens > max_tokens: break

formatted = f""" --- SOURCE {i+1}: {doc.get("source", "Document")} SCORE DE PERTINENCE: {doc.get("score", "N/A")}

{doc["text"]} --- """ formatted_docs.append(formatted) total_tokens += doc_tokens

return "\n".join(formatted_docs) `

Ordre des documents

L'ordre impacte l'attention du LLM. Deux stratégies principales :

`python def order_documents(documents: list[dict], strategy: str = "best_first") -> list: """ Ordonne les documents selon la stratégie choisie """ if strategy == "best_first": Le plus pertinent en premier return sorted(documents, key=lambda x: x["score"], reverse=True)

elif strategy == "lost_in_middle": Les meilleurs au début et à la fin (évite le "lost in the middle") sorted_docs = sorted(documents, key=lambda x: x["score"], reverse=True) n = len(sorted_docs) reordered = [] for i in range(n): if i % 2 == 0: reordered.insert(0, sorted_docs[i]) else: reordered.append(sorted_docs[i]) return reordered

return documents `

Compression du contexte

Pour les documents longs, résumer avant d'envoyer au LLM final :

`python async def compress_context( documents: list[str], query: str, llm_compressor ) -> str: """ Compresse les documents en gardant l'info pertinente """ compression_prompt = f""" Extrais les informations pertinentes pour répondre à cette question : Question : {query}

Documents : {chr(10).join(documents)}

Résumé des informations pertinentes : """

compressed = await llm_compressor.generate(compression_prompt) return compressed `

Gestion des hallucinations

Les hallucinations sont le risque principal en RAG. Voici comment les minimiser.

Détection d'hallucination

`python def detect_hallucination( response: str, context: str, query: str, verifier_llm ) -> dict: """ Vérifie si la réponse contient des hallucinations """ verification_prompt = f""" Analyse cette réponse et vérifie si elle est fidèle au contexte fourni.

CONTEXTE FOURNI : {context}

QUESTION : {query}

RÉPONSE À VÉRIFIER : {response}

ANALYSE : La réponse contient-elle des affirmations non présentes dans le contexte ? La réponse contredit-elle le contexte ? Score de fidélité (0-100) :

Réponds en JSON : {{"hallucinations": [...], "contradictions": [...], "score": X}} """

result = verifier_llm.generate(verification_prompt) return json.loads(result) `

Stratégies anti-hallucination

`python class RAGGenerator: def __init__(self, llm, verifier_llm=None): self.llm = llm self.verifier = verifier_llm

async def generate_with_verification( self, query: str, context: str, max_retries: int = 2 ) -> dict: """ Génère une réponse avec vérification anti-hallucination """ for attempt in range(max_retries + 1): Génération response = await self.llm.generate( self._build_prompt(query, context), temperature=0.1 Basse pour réduire hallucinations )

Vérification si verifier disponible if self.verifier: check = detect_hallucination(response, context, query, self.verifier)

if check["score"] >= 80: return { "response": response, "confidence": check["score"], "verified": True }

Retry avec instruction plus stricte context = self._add_anti_hallucination_instruction(context, check) else: return {"response": response, "verified": False}

Fallback : réponse prudente return { "response": "Je ne suis pas certain de pouvoir répondre précisément à cette question avec les informations disponibles.", "confidence": 0, "verified": True } `

Streaming et latence

Pour une expérience utilisateur fluide, le streaming est essentiel.

Implémentation du streaming

`python from openai import OpenAI

client = OpenAI()

async def stream_response(prompt: str): """ Stream la réponse token par token """ stream = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], stream=True )

for chunk in stream: if chunk.choices[0].delta.content: yield chunk.choices[0].delta.content

Utilisation avec FastAPI from fastapi import FastAPI from fastapi.responses import StreamingResponse

app = FastAPI()

@app.post("/chat") async def chat(request: ChatRequest): prompt = build_rag_prompt(request.query, request.context)

return StreamingResponse( stream_response(prompt), media_type="text/event-stream" ) `

Optimisation de la latence

`python import asyncio from functools import lru_cache

class OptimizedRAG: def __init__(self): self.retriever = Retriever() self.llm = LLM()

async def query(self, question: str) -> str: Paralléliser retrieval et préparation prompt retrieval_task = asyncio.create_task( self.retriever.search(question) )

Pré-calculer les parties statiques du prompt base_prompt = self._get_cached_prompt()

Attendre le retrieval documents = await retrieval_task

Construire et envoyer au LLM full_prompt = base_prompt.format( context=format_context(documents), question=question )

return await self.llm.generate(full_prompt)

@lru_cache(maxsize=1) def _get_cached_prompt(self) -> str: return self._load_system_prompt() `

Métriques de qualité de génération

Faithfulness (Fidélité)

Mesure si la réponse est fidèle au contexte fourni.

`python def calculate_faithfulness( response: str, context: str, evaluator_llm ) -> float: """ Score de fidélité entre 0 et 1 """ prompt = f""" Évalue la fidélité de cette réponse par rapport au contexte.

Contexte : {context} Réponse : {response}

Pour chaque affirmation dans la réponse, vérifie si elle est : • Supportée par le contexte (1 point) • Non mentionnée dans le contexte (0 point) • Contredite par le contexte (-1 point)

Score final (0-1) : """

result = evaluator_llm.generate(prompt) return float(result) `

Answer Relevancy (Pertinence)

Mesure si la réponse répond bien à la question.

`python def calculate_relevancy( question: str, response: str, evaluator_llm ) -> float: """ Score de pertinence entre 0 et 1 """ prompt = f""" Évalue si cette réponse répond bien à la question posée.

Question : {question} Réponse : {response}

Critères : • La réponse adresse-t-elle directement la question ? (0-0.4) • La réponse est-elle complète ? (0-0.3) • La réponse est-elle concise et claire ? (0-0.3)

Score final (0-1) : """

result = evaluator_llm.generate(prompt) return float(result) `

Intégration avec différents fournisseurs

OpenAI

`python from openai import OpenAI

class OpenAIGenerator: def __init__(self, model: str = "gpt-4o-mini"): self.client = OpenAI() self.model = model

async def generate(self, prompt: str, kwargs) -> str: response = self.client.chat.completions.create( model=self.model, messages=[{"role": "user", "content": prompt}], temperature=kwargs.get("temperature", 0.2), max_tokens=kwargs.get("max_tokens", 2000) ) return response.choices[0].message.content `

Anthropic Claude

`python from anthropic import Anthropic

class ClaudeGenerator: def __init__(self, model: str = "claude-3-5-sonnet-20241022"): self.client = Anthropic() self.model = model

async def generate(self, prompt: str, system: str = None, kwargs) -> str: messages = [{"role": "user", "content": prompt}]

response = self.client.messages.create( model=self.model, max_tokens=kwargs.get("max_tokens", 2000), system=system or "Tu es un assistant RAG précis et factuel.", messages=messages ) return response.content[0].text `

Modèle local avec Ollama

`python import httpx

class OllamaGenerator: def __init__(self, model: str = "llama3.1:8b", base_url: str = "http://localhost:11434"): self.model = model self.base_url = base_url

async def generate(self, prompt: str, kwargs) -> str: async with httpx.AsyncClient() as client: response = await client.post( f"{self.base_url}/api/generate", json={ "model": self.model, "prompt": prompt, "stream": False, "options": { "temperature": kwargs.get("temperature", 0.2) } } ) return response.json()["response"] ``

Prochaines étapes

Maintenant que vous maîtrisez la génération RAG, explorez ces sujets avancés : • RAG Conversationnel : Mémoire et contexte - Gérer les conversations multi-tours • Agents RAG : Orchestration multi-agents - Aller au-delà du RAG simple • Évaluer un système RAG - Métriques et méthodologies complètes

Pour une vue d'ensemble complète, consultez notre Introduction au RAG.

---

Simplifiez-vous la vie avec Ailog

Configurer et optimiser un LLM pour le RAG demande beaucoup d'itérations. Avec Ailog, bénéficiez d'une configuration optimisée clé en main : • Prompts pré-optimisés pour chaque cas d'usage (support, e-commerce, KB interne) • Anti-hallucination intégré avec vérification automatique • Streaming natif pour une expérience utilisateur fluide • Multi-LLM* : Basculez entre GPT-4, Claude, ou modèles souverains sans changer votre code

Démarrez gratuitement avec Ailog et déployez un assistant RAG optimisé en quelques minutes.

Tags

  • RAG
  • LLM
  • génération
  • prompting
  • GPT
  • Claude
GuideIntermédiaire

Génération RAG : Choisir et optimiser son LLM

13 janvier 2026
20 min de lecture
Équipe Ailog

Guide complet pour sélectionner et configurer votre LLM dans un système RAG : prompting, température, tokens et optimisation des réponses.

Génération RAG : Choisir et optimiser son LLM

La phase de génération est le moment où votre système RAG transforme les documents récupérés en une réponse cohérente et utile. Le choix du LLM et son paramétrage déterminent la qualité finale de l'expérience utilisateur. Ce guide vous accompagne dans la sélection, la configuration et l'optimisation de votre modèle de génération.

Le rôle du LLM dans un système RAG

Contrairement à un LLM utilisé seul, le LLM dans un système RAG ne génère pas à partir de ses connaissances internes. Il synthétise, reformule et structure les informations issues du retrieval.

Ce que fait le LLM RAG

  1. Synthèse : Condenser plusieurs documents en une réponse concise
  2. Reformulation : Adapter le langage technique au niveau de l'utilisateur
  3. Structuration : Organiser l'information de manière logique
  4. Contextualisation : Relier la réponse à la question posée
  5. Détection d'insuffisance : Identifier quand les documents ne permettent pas de répondre

Ce que le LLM RAG ne devrait PAS faire

  • Inventer des informations absentes des documents (hallucination)
  • Contredire les sources fournies
  • Répondre à des questions hors scope sans le signaler

Comparatif des LLMs pour le RAG

Modèles propriétaires

ModèleForcesFaiblessesCoût (1M tokens)Usage RAG
GPT-4oPolyvalent, raisonnementPrix élevé~$5 input / $15 outputProduction premium
GPT-4o-miniBon rapport qualité/prixMoins performant sur tâches complexes~$0.15 / $0.60Production standard
Claude 3.5 SonnetExcellent suivi instructionsContexte 200k parfois sous-utilisé~$3 / $15Production premium
Claude 3 HaikuUltra rapide, économiqueMoins nuancé~$0.25 / $1.25Volume élevé
Gemini 1.5 ProContexte 1M tokensAPI parfois instable~$1.25 / $5Documents très longs

Modèles open source

ModèleParamètresVRAM requisePerformance RAGAuto-hébergeable
Llama 3.1 70B70B48GB+ExcellenteOui (serveur dédié)
Llama 3.1 8B8B8GBBonneOui (GPU grand public)
Mistral 7B7B6GBBonneOui
Mixtral 8x7B46.7B (MoE)32GBTrès bonneOui
Qwen2 72B72B48GB+ExcellenteOui

Critères de choix

DEVELOPERpython
def choisir_llm( budget_mensuel: float, volume_requetes: int, exigence_qualite: str, # "standard", "premium" contrainte_hebergement: str, # "cloud", "souverain", "on-premise" langues: list[str] ) -> str: tokens_par_requete = 2000 # estimation moyenne RAG tokens_mensuels = volume_requetes * tokens_par_requete if contrainte_hebergement == "on-premise": if exigence_qualite == "premium": return "Llama 3.1 70B ou Qwen2 72B" return "Llama 3.1 8B ou Mistral 7B" if contrainte_hebergement == "souverain": return "Mistral Large via API Mistral (hébergé UE)" cout_gpt4o_mini = tokens_mensuels * 0.15 / 1_000_000 cout_claude_haiku = tokens_mensuels * 0.25 / 1_000_000 if budget_mensuel < cout_gpt4o_mini: return "Modèle open source auto-hébergé" if exigence_qualite == "premium": if "fr" in langues: return "Claude 3.5 Sonnet (excellent en français)" return "GPT-4o" return "GPT-4o-mini ou Claude 3 Haiku"

Configurer le prompt système

Le prompt système définit le comportement du LLM dans votre application RAG. C'est l'élément le plus critique de la configuration.

Structure d'un prompt RAG efficace

DEVELOPERpython
SYSTEM_PROMPT = """Tu es un assistant IA pour {nom_entreprise}, spécialisé dans {domaine}. RÈGLES STRICTES : 1. Réponds UNIQUEMENT à partir des documents fournis dans le contexte 2. Si l'information n'est pas dans les documents, dis "Je n'ai pas cette information dans ma base de connaissances" 3. Ne jamais inventer d'informations 4. Cite tes sources quand c'est pertinent STYLE DE RÉPONSE : - Ton : {ton} (professionnel/amical/technique) - Longueur : {longueur} (concis/détaillé) - Format : Utilise des listes à puces pour plus de 3 éléments - Langue : Réponds dans la langue de la question CONTEXTE MÉTIER : {contexte_specifique} DOCUMENTS DISPONIBLES : {documents_retrieves} QUESTION DE L'UTILISATEUR : {question} """

Exemples de prompts par cas d'usage

Support client e-commerce

DEVELOPERpython
ECOMMERCE_PROMPT = """Tu es l'assistant virtuel de la boutique {nom_boutique}. OBJECTIFS : - Aider les clients avec leurs commandes, retours et questions produits - Maximiser la satisfaction client - Orienter vers le support humain si nécessaire RÈGLES : 1. Base tes réponses UNIQUEMENT sur les documents fournis 2. Pour les questions sur une commande spécifique, demande le numéro de commande 3. Ne communique jamais d'informations personnelles d'autres clients 4. Si une demande dépasse tes capacités, propose de contacter le service client TON : Amical et serviable, comme un vendeur en boutique DOCUMENTS : {context} QUESTION : {question} """

Base de connaissances technique

DEVELOPERpython
TECH_KB_PROMPT = """Tu es un expert technique pour {produit}. OBJECTIFS : - Fournir des réponses techniques précises - Inclure des exemples de code quand pertinent - Guider vers la documentation officielle RÈGLES : 1. Réponds uniquement à partir de la documentation fournie 2. Précise la version du produit concernée si mentionnée 3. Signale les limitations connues ou bugs documentés 4. Propose des alternatives si la solution demandée n'existe pas FORMAT : - Commence par une réponse directe - Puis détaille si nécessaire - Termine par un exemple de code si applicable DOCUMENTATION : {context} QUESTION : {question} """

Paramètres de génération

Température

La température contrôle la créativité vs la cohérence des réponses.

DEVELOPERpython
# Basse température (0.0 - 0.3) : Réponses déterministes, factuelles # Idéal pour : Support client, FAQ, documentation technique temperature = 0.1 # Température moyenne (0.4 - 0.7) : Équilibre créativité/cohérence # Idéal pour : Chat général, reformulation temperature = 0.5 # Haute température (0.8 - 1.0) : Réponses variées, créatives # Idéal pour : Brainstorming, génération de contenu # À ÉVITER en RAG (risque d'hallucination) temperature = 0.9

Top-p (Nucleus Sampling)

Limite les tokens considérés à ceux représentant une probabilité cumulée.

DEVELOPERpython
# top_p = 0.9 : Considère les tokens jusqu'à 90% de probabilité cumulée # Plus restrictif = plus cohérent # Plus large = plus varié from openai import OpenAI client = OpenAI() response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], temperature=0.2, top_p=0.9, # Combiné avec température basse pour RAG )

Max tokens

Limite la longueur de la réponse générée.

DEVELOPERpython
# Calcul du budget tokens def calculer_max_tokens( context_length: int, model_limit: int = 128000, # GPT-4o reserve_output: int = 2000 ) -> int: """ Assure qu'on laisse assez de place pour la réponse """ prompt_tokens = context_length + 500 # + instructions available = model_limit - prompt_tokens return min(available, reserve_output)

Frequency et Presence Penalty

Contrôlent la répétition dans les réponses.

DEVELOPERpython
response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, frequency_penalty=0.3, # Pénalise les tokens déjà utilisés presence_penalty=0.1, # Encourage les nouveaux sujets )

Optimiser le contexte fourni au LLM

Formatage des documents récupérés

DEVELOPERpython
def format_context(documents: list[dict], max_tokens: int = 4000) -> str: """ Formate les documents pour le contexte LLM """ formatted_docs = [] total_tokens = 0 for i, doc in enumerate(documents): # Estimation tokens (1 token ≈ 4 caractères en français) doc_tokens = len(doc["text"]) // 4 if total_tokens + doc_tokens > max_tokens: break formatted = f""" --- SOURCE {i+1}: {doc.get("source", "Document")} SCORE DE PERTINENCE: {doc.get("score", "N/A")} {doc["text"]} --- """ formatted_docs.append(formatted) total_tokens += doc_tokens return "\n".join(formatted_docs)

Ordre des documents

L'ordre impacte l'attention du LLM. Deux stratégies principales :

DEVELOPERpython
def order_documents(documents: list[dict], strategy: str = "best_first") -> list: """ Ordonne les documents selon la stratégie choisie """ if strategy == "best_first": # Le plus pertinent en premier return sorted(documents, key=lambda x: x["score"], reverse=True) elif strategy == "lost_in_middle": # Les meilleurs au début et à la fin (évite le "lost in the middle") sorted_docs = sorted(documents, key=lambda x: x["score"], reverse=True) n = len(sorted_docs) reordered = [] for i in range(n): if i % 2 == 0: reordered.insert(0, sorted_docs[i]) else: reordered.append(sorted_docs[i]) return reordered return documents

Compression du contexte

Pour les documents longs, résumer avant d'envoyer au LLM final :

DEVELOPERpython
async def compress_context( documents: list[str], query: str, llm_compressor ) -> str: """ Compresse les documents en gardant l'info pertinente """ compression_prompt = f""" Extrais les informations pertinentes pour répondre à cette question : Question : {query} Documents : {chr(10).join(documents)} Résumé des informations pertinentes : """ compressed = await llm_compressor.generate(compression_prompt) return compressed

Gestion des hallucinations

Les hallucinations sont le risque principal en RAG. Voici comment les minimiser.

Détection d'hallucination

DEVELOPERpython
def detect_hallucination( response: str, context: str, query: str, verifier_llm ) -> dict: """ Vérifie si la réponse contient des hallucinations """ verification_prompt = f""" Analyse cette réponse et vérifie si elle est fidèle au contexte fourni. CONTEXTE FOURNI : {context} QUESTION : {query} RÉPONSE À VÉRIFIER : {response} ANALYSE : 1. La réponse contient-elle des affirmations non présentes dans le contexte ? 2. La réponse contredit-elle le contexte ? 3. Score de fidélité (0-100) : Réponds en JSON : {{"hallucinations": [...], "contradictions": [...], "score": X}} """ result = verifier_llm.generate(verification_prompt) return json.loads(result)

Stratégies anti-hallucination

DEVELOPERpython
class RAGGenerator: def __init__(self, llm, verifier_llm=None): self.llm = llm self.verifier = verifier_llm async def generate_with_verification( self, query: str, context: str, max_retries: int = 2 ) -> dict: """ Génère une réponse avec vérification anti-hallucination """ for attempt in range(max_retries + 1): # Génération response = await self.llm.generate( self._build_prompt(query, context), temperature=0.1 # Basse pour réduire hallucinations ) # Vérification si verifier disponible if self.verifier: check = detect_hallucination(response, context, query, self.verifier) if check["score"] >= 80: return { "response": response, "confidence": check["score"], "verified": True } # Retry avec instruction plus stricte context = self._add_anti_hallucination_instruction(context, check) else: return {"response": response, "verified": False} # Fallback : réponse prudente return { "response": "Je ne suis pas certain de pouvoir répondre précisément à cette question avec les informations disponibles.", "confidence": 0, "verified": True }

Streaming et latence

Pour une expérience utilisateur fluide, le streaming est essentiel.

Implémentation du streaming

DEVELOPERpython
from openai import OpenAI client = OpenAI() async def stream_response(prompt: str): """ Stream la réponse token par token """ stream = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], stream=True ) for chunk in stream: if chunk.choices[0].delta.content: yield chunk.choices[0].delta.content # Utilisation avec FastAPI from fastapi import FastAPI from fastapi.responses import StreamingResponse app = FastAPI() @app.post("/chat") async def chat(request: ChatRequest): prompt = build_rag_prompt(request.query, request.context) return StreamingResponse( stream_response(prompt), media_type="text/event-stream" )

Optimisation de la latence

DEVELOPERpython
import asyncio from functools import lru_cache class OptimizedRAG: def __init__(self): self.retriever = Retriever() self.llm = LLM() async def query(self, question: str) -> str: # Paralléliser retrieval et préparation prompt retrieval_task = asyncio.create_task( self.retriever.search(question) ) # Pré-calculer les parties statiques du prompt base_prompt = self._get_cached_prompt() # Attendre le retrieval documents = await retrieval_task # Construire et envoyer au LLM full_prompt = base_prompt.format( context=format_context(documents), question=question ) return await self.llm.generate(full_prompt) @lru_cache(maxsize=1) def _get_cached_prompt(self) -> str: return self._load_system_prompt()

Métriques de qualité de génération

Faithfulness (Fidélité)

Mesure si la réponse est fidèle au contexte fourni.

DEVELOPERpython
def calculate_faithfulness( response: str, context: str, evaluator_llm ) -> float: """ Score de fidélité entre 0 et 1 """ prompt = f""" Évalue la fidélité de cette réponse par rapport au contexte. Contexte : {context} Réponse : {response} Pour chaque affirmation dans la réponse, vérifie si elle est : - Supportée par le contexte (1 point) - Non mentionnée dans le contexte (0 point) - Contredite par le contexte (-1 point) Score final (0-1) : """ result = evaluator_llm.generate(prompt) return float(result)

Answer Relevancy (Pertinence)

Mesure si la réponse répond bien à la question.

DEVELOPERpython
def calculate_relevancy( question: str, response: str, evaluator_llm ) -> float: """ Score de pertinence entre 0 et 1 """ prompt = f""" Évalue si cette réponse répond bien à la question posée. Question : {question} Réponse : {response} Critères : - La réponse adresse-t-elle directement la question ? (0-0.4) - La réponse est-elle complète ? (0-0.3) - La réponse est-elle concise et claire ? (0-0.3) Score final (0-1) : """ result = evaluator_llm.generate(prompt) return float(result)

Intégration avec différents fournisseurs

OpenAI

DEVELOPERpython
from openai import OpenAI class OpenAIGenerator: def __init__(self, model: str = "gpt-4o-mini"): self.client = OpenAI() self.model = model async def generate(self, prompt: str, **kwargs) -> str: response = self.client.chat.completions.create( model=self.model, messages=[{"role": "user", "content": prompt}], temperature=kwargs.get("temperature", 0.2), max_tokens=kwargs.get("max_tokens", 2000) ) return response.choices[0].message.content

Anthropic Claude

DEVELOPERpython
from anthropic import Anthropic class ClaudeGenerator: def __init__(self, model: str = "claude-3-5-sonnet-20241022"): self.client = Anthropic() self.model = model async def generate(self, prompt: str, system: str = None, **kwargs) -> str: messages = [{"role": "user", "content": prompt}] response = self.client.messages.create( model=self.model, max_tokens=kwargs.get("max_tokens", 2000), system=system or "Tu es un assistant RAG précis et factuel.", messages=messages ) return response.content[0].text

Modèle local avec Ollama

DEVELOPERpython
import httpx class OllamaGenerator: def __init__(self, model: str = "llama3.1:8b", base_url: str = "http://localhost:11434"): self.model = model self.base_url = base_url async def generate(self, prompt: str, **kwargs) -> str: async with httpx.AsyncClient() as client: response = await client.post( f"{self.base_url}/api/generate", json={ "model": self.model, "prompt": prompt, "stream": False, "options": { "temperature": kwargs.get("temperature", 0.2) } } ) return response.json()["response"]

Prochaines étapes

Maintenant que vous maîtrisez la génération RAG, explorez ces sujets avancés :

Pour une vue d'ensemble complète, consultez notre Introduction au RAG.


Simplifiez-vous la vie avec Ailog

Configurer et optimiser un LLM pour le RAG demande beaucoup d'itérations. Avec Ailog, bénéficiez d'une configuration optimisée clé en main :

  • Prompts pré-optimisés pour chaque cas d'usage (support, e-commerce, KB interne)
  • Anti-hallucination intégré avec vérification automatique
  • Streaming natif pour une expérience utilisateur fluide
  • Multi-LLM : Basculez entre GPT-4, Claude, ou modèles souverains sans changer votre code

Démarrez gratuitement avec Ailog et déployez un assistant RAG optimisé en quelques minutes.

Tags

RAGLLMgénérationpromptingGPTClaude

Articles connexes

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !