LangChain : guide pratique et cookbook avec 50+ recettes de code prêtes à l'emploi

tl;dr: Ce guide pratique rassemble 50+ recettes de code LangChain prêtes à l'emploi pour tous les cas d'usage : chatbots conversationnels, systèmes RAG, agents autonomes, intégrations APIs, traitement de documents, et bien plus. Chaque recette inclut le code complet, les explications, et les variations possibles. Référence indispensable pour gagner du temps en développement.

💡 📚 50+ recettes de code testées et prêtes à copier-coller dans vos projets ! Ce guide est votre référence quotidienne pour développer avec LangChain.

Ce guide pratique est votre boîte à outils LangChain : des dizaines de recettes de code prêtes à l’emploi, testées et commentées, que vous pouvez directement intégrer dans vos projets. Plutôt qu’un tutoriel linéaire, c’est un cookbook organisé par cas d’usage, où vous pouvez piocher ce dont vous avez besoin.

Diagramme d’architecture LangChain illustrant le guide pratique de développement pour le développement d’applications IA

Table des matières

  1. Installation et configuration
  2. Recettes de base
  3. Chatbots et conversations
  4. RAG (Retrieval-Augmented Generation)
  5. Agents et outils
  6. Intégrations externes
  7. Production et monitoring
  8. Optimisations et performances
  9. Troubleshooting

Installation et configuration

Installation complète

# Core
pip install langchain langchain-community

# Providers LLM
pip install langchain-openai langchain-anthropic langchain-google-genai

# RAG et embeddings
pip install langchain-chroma chromadb tiktoken sentence-transformers

# Outils et utilitaires
pip install langchain-experimental duckduckgo-search wikipedia

# Document loaders
pip install pypdf beautifulsoup4 unstructured

# Production
pip install langsmith langserve

# API web (optionnel)
pip install fastapi uvicorn

Configuration des clés API

import os
from dotenv import load_dotenv

# Charger depuis .env
load_dotenv()

# OpenAI
os.environ["OPENAI_API_KEY"] = "sk-..."

# Anthropic
os.environ["ANTHROPIC_API_KEY"] = "sk-ant-..."

# Google
os.environ["GOOGLE_API_KEY"] = "..."

# LangSmith (monitoring)
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "ls-..."
os.environ["LANGCHAIN_PROJECT"] = "mon-projet"

Fichier .env :

OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_API_KEY=...
LANGCHAIN_API_KEY=ls-...
⚠️ Warning
🔒 Sécurité : Ne committez JAMAIS le fichier .env dans Git ! Ajoutez-le immédiatement à .gitignore. Utilisez des variables d’environnement ou des gestionnaires de secrets en production.

Template de projet

mon-projet-langchain/
├── .env                    # Clés API
├── .gitignore             # Ne pas committer .env
├── requirements.txt       # Dépendances
├── config.py              # Configuration centralisée
├── main.py                # Point d'entrée
├── chains/                # Vos chains
   ├── chatbot.py
   └── rag.py
├── agents/                # Vos agents
   └── research_agent.py
├── tools/                 # Outils personnalisés
   └── custom_tools.py
├── data/                  # Données sources
   └── documents/
└── vectorstores/          # Bases vectorielles persistées
    └── chroma_db/

Recettes de base

Appel LLM simple

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
response = llm.invoke("Explique la photosynthèse en 3 phrases")
print(response.content)

Prompt template dynamique

from langchain.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "Tu es un expert en {domaine}."),
    ("human", "{question}")
])

chain = prompt | llm
response = chain.invoke({
    "domaine": "astronomie",
    "question": "Qu'est-ce qu'un trou noir ?"
})
print(response.content)

Chain avec output parser

from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

class Recette(BaseModel):
    nom: str = Field(description="Nom de la recette")
    ingredients: list[str] = Field(description="Liste des ingrédients")
    etapes: list[str] = Field(description="Étapes de préparation")

parser = PydanticOutputParser(pydantic_object=Recette)

prompt = ChatPromptTemplate.from_messages([
    ("system", "Tu génères des recettes de cuisine.\n{format_instructions}"),
    ("human", "Crée une recette de {plat}")
])

chain = prompt | llm | parser

result = chain.invoke({
    "plat": "pâtes carbonara",
    "format_instructions": parser.get_format_instructions()
})

print(f"Recette: {result.nom}")
print(f"Ingrédients: {', '.join(result.ingredients)}")

Chain avec streaming

from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

llm = ChatOpenAI(
    model="gpt-4",
    streaming=True,
    callbacks=[StreamingStdOutCallbackHandler()]
)

chain = prompt | llm

# S'affiche token par token
for chunk in chain.stream({"question": "Raconte une histoire"}):
    print(chunk.content, end="", flush=True)

Multi-LLM avec fallback

from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

primary = ChatOpenAI(model="gpt-4", request_timeout=10)
fallback = ChatAnthropic(model="claude-sonnet-4.5")

llm = primary.with_fallbacks([fallback])

chain = prompt | llm
response = chain.invoke({"question": "..."})
# Utilise Claude si OpenAI échoue ou timeout
🔎 Tip
💡 Best practice : Utilisez toujours LCEL (pipe operator |) plutôt que les classes legacy comme LLMChain. LCEL active automatiquement le streaming, le batching parallèle, et le tracing LangSmith.

Chatbots et conversations

Chatbot avec mémoire

from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory()

chatbot = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
)

# Conversation
chatbot.predict(input="Bonjour, je m'appelle Sophie")
# → "Enchanté Sophie..."

chatbot.predict(input="Quel est mon nom ?")
# → "Votre nom est Sophie" (se souvient)

Chatbot avec fenêtre de contexte

from langchain.memory import ConversationBufferWindowMemory

# Garde seulement les 5 derniers échanges
memory = ConversationBufferWindowMemory(k=5)

chatbot = ConversationChain(llm=llm, memory=memory)

Chatbot avec résumé automatique

from langchain.memory import ConversationSummaryMemory

# Résume automatiquement quand trop long
memory = ConversationSummaryMemory(llm=llm)

chatbot = ConversationChain(llm=llm, memory=memory)

Chatbot multilingue

from langchain.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", """Tu es un assistant multilingue.
    Détecte automatiquement la langue de l'utilisateur et réponds dans cette langue.
    Langues supportées: français, anglais, espagnol, allemand."""),
    ("human", "{input}")
])

chatbot = prompt | llm

response = chatbot.invoke({"input": "Hola, ¿cómo estás?"})
# → Répond en espagnol

Chatbot avec personnalité

persona_prompt = ChatPromptTemplate.from_messages([
    ("system", """Tu es {persona_name}, {persona_description}.
    Tu parles toujours selon ce style: {style}.
    Historique de conversation:
    {chat_history}"""),
    ("human", "{input}")
])

def create_persona_chatbot(name, description, style):
    memory = ConversationBufferMemory(
        memory_key="chat_history",
        return_messages=True
    )

    chain = LLMChain(llm=llm, prompt=persona_prompt, memory=memory)

    def chat(message):
        return chain.predict(
            persona_name=name,
            persona_description=description,
            style=style,
            input=message
        )

    return chat

# Utilisation
pirate_bot = create_persona_chatbot(
    name="Captain Jack",
    description="un pirate des Caraïbes",
    style="utilise l'argot pirate et dis 'Arr!' souvent"
)

response = pirate_bot("Bonjour !")
# → "Arr! Bonjour moussaillon !..."

RAG (Retrieval-Augmented Generation)

RAG simple sur PDF

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA

# 1. Charger
loader = PyPDFLoader("document.pdf")
documents = loader.load()

# 2. Découper
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)
splits = text_splitter.split_documents(documents)

# 3. Embeddings + VectorStore
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(splits, embeddings)

# 4. RAG Chain
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=vectorstore.as_retriever(),
    return_source_documents=True
)

# 5. Question
result = qa_chain("Résume le chapitre 3")
print(result['result'])
print(f"Sources: {[doc.metadata for doc in result['source_documents']]}")

RAG sur plusieurs PDFs

from langchain_community.document_loaders import DirectoryLoader

loader = DirectoryLoader(
    "./documents",
    glob="**/*.pdf",
    loader_cls=PyPDFLoader,
    show_progress=True
)

documents = loader.load()
print(f"Chargé {len(documents)} pages depuis {len(set([d.metadata['source'] for d in documents]))} fichiers")

# Suite identique à la recette 11

RAG avec Chroma persistant

from langchain_community.vectorstores import Chroma

# Création initiale
vectorstore = Chroma.from_documents(
    documents=splits,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

# --- Dans un autre script ou plus tard ---

# Rechargement (pas besoin de réindexer)
vectorstore = Chroma(
    persist_directory="./chroma_db",
    embedding_function=embeddings
)

retriever = vectorstore.as_retriever()

RAG avec filtres de métadonnées

# Ajouter des métadonnées aux documents
for doc in splits:
    doc.metadata["category"] = "technical"
    doc.metadata["year"] = 2025

vectorstore = Chroma.from_documents(splits, embeddings)

# Retriever avec filtre
retriever = vectorstore.as_retriever(
    search_kwargs={
        "k": 5,
        "filter": {
            "category": "technical",
            "year": {"$gte": 2020}
        }
    }
)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=retriever
)

RAG conversationnel

from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.chains import create_history_aware_retriever
from langchain_core.messages import HumanMessage, AIMessage

# Retriever
retriever = vectorstore.as_retriever()

# Prompt pour reformuler avec historique
contextualize_prompt = ChatPromptTemplate.from_messages([
    ("system", "Reformule la dernière question en une question autonome, en utilisant l'historique."),
    MessagesPlaceholder("chat_history"),
    ("human", "{input}")
])

history_aware_retriever = create_history_aware_retriever(
    llm, retriever, contextualize_prompt
)

# Prompt QA
qa_prompt = ChatPromptTemplate.from_messages([
    ("system", "Réponds en te basant sur le contexte:\n\n{context}"),
    MessagesPlaceholder("chat_history"),
    ("human", "{input}")
])

document_chain = create_stuff_documents_chain(llm, qa_prompt)
rag_chain = create_retrieval_chain(history_aware_retriever, document_chain)

# Conversation
chat_history = []

response1 = rag_chain.invoke({
    "input": "Parle-moi de LoRA",
    "chat_history": chat_history
})
print(response1["answer"])

chat_history.extend([
    HumanMessage(content="Parle-moi de LoRA"),
    AIMessage(content=response1["answer"])
])

response2 = rag_chain.invoke({
    "input": "Quels sont ses avantages ?",  # Contexte conservé
    "chat_history": chat_history
})
print(response2["answer"])
💡 ✅ RAG conversationnel : Cette approche combine la mémoire contextuelle avec la récupération de documents. C’est idéal pour des Q&A interactifs où l’utilisateur pose des questions de suivi (“Et ses avantages ?”, “Compare-le avec X”).

Agents et outils

Agent de recherche basique

from langchain.agents import AgentExecutor, create_react_agent
from langchain_community.tools import DuckDuckGoSearchRun
from langchain.tools import Tool

search = DuckDuckGoSearchRun()

tools = [
    Tool(
        name="Search",
        func=search.run,
        description="Recherche sur le web pour des informations actuelles"
    )
]

from langchain import hub
prompt = hub.pull("hwchase17/react")

agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,
    max_iterations=5
)

result = agent_executor.invoke({
    "input": "Qui a gagné la dernière Coupe du Monde de football ?"
})

Agent avec calculatrice

from langchain_community.utilities import GoogleSerperAPIWrapper
from langchain.tools import Tool

def calculate(expression: str) -> str:
    """Calcule une expression mathématique"""
    try:
        # Utilise eval de manière sécurisée
        import ast
        import operator

        operators = {
            ast.Add: operator.add,
            ast.Sub: operator.sub,
            ast.Mult: operator.mul,
            ast.Div: operator.truediv,
            ast.Pow: operator.pow
        }

        def eval_expr(node):
            if isinstance(node, ast.Num):
                return node.n
            elif isinstance(node, ast.BinOp):
                return operators[type(node.op)](
                    eval_expr(node.left),
                    eval_expr(node.right)
                )
            else:
                raise TypeError(node)

        return str(eval_expr(ast.parse(expression, mode='eval').body))
    except:
        return "Erreur de calcul"

tools = [
    Tool(
        name="Calculator",
        func=calculate,
        description="Effectue des calculs mathématiques. Input: expression comme '2+2' ou '10*5'"
    )
]

agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

result = agent_executor.invoke({
    "input": "Combien font 1234 multiplié par 5678 ?"
})

Agent avec outil personnalisé

from langchain.pydantic_v1 import BaseModel, Field

class WeatherInput(BaseModel):
    """Input pour l'outil météo"""
    city: str = Field(description="Nom de la ville")

def get_weather(city: str) -> str:
    """Obtient la météo (exemple simplifié)"""
    # En vrai, appel à une API météo
    import random
    temp = random.randint(10, 30)
    conditions = ["ensoleillé", "nuageux", "pluvieux"]
    return f"{city}: {temp}°C, {random.choice(conditions)}"

from langchain.tools import StructuredTool

weather_tool = StructuredTool.from_function(
    func=get_weather,
    name="Weather",
    description="Donne la météo actuelle d'une ville",
    args_schema=WeatherInput
)

tools = [weather_tool]
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools)

result = agent_executor.invoke({
    "input": "Quelle est la météo à Paris ?"
})

Agent RAG

from langchain.tools.retriever import create_retriever_tool

# Retriever (voir recettes RAG)
retriever = vectorstore.as_retriever()

# Transformer en outil
doc_tool = create_retriever_tool(
    retriever,
    name="DocumentSearch",
    description="Recherche dans la documentation technique. Utilise pour répondre aux questions sur les produits."
)

tools = [search, doc_tool]

agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# L'agent décide automatiquement entre web et docs
result = agent_executor.invoke({
    "input": "Comment fonctionne le fine-tuning avec LoRA ?"
})

Agent SQL

from langchain.agents import create_sql_agent
from langchain.sql_database import SQLDatabase

db = SQLDatabase.from_uri("sqlite:///database.db")

sql_agent = create_sql_agent(
    llm=llm,
    db=db,
    agent_type="openai-tools",
    verbose=True
)

result = sql_agent.invoke({
    "input": "Combien d'utilisateurs ont acheté un produit en janvier 2025 ?"
})
# L'agent génère et exécute automatiquement les requêtes SQL
⚠️ Warning
⚠️ Agents et coûts : Les agents effectuent 3-10× plus d’appels LLM qu’une chaîne simple (réflexion + planification + exécution + vérification). Limitez max_iterations et surveillez les coûts avec LangSmith avant de déployer en production !

Intégrations externes

Charger depuis une URL

from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader([
    "https://naileru.com/ia/rag/",
    "https://naileru.com/ia/embedding/"
])

documents = loader.load()
print(f"Chargé {len(documents)} pages web")

Charger depuis Google Drive

from langchain_community.document_loaders import GoogleDriveLoader

loader = GoogleDriveLoader(
    folder_id="your_folder_id",
    token_path="token.json",  # OAuth token
    recursive=True
)

documents = loader.load()

Charger depuis Notion

from langchain_community.document_loaders import NotionDirectoryLoader

# Export Notion au format Markdown
loader = NotionDirectoryLoader("./notion_export")
documents = loader.load()

# Chaque page Notion devient un document

Intégration Slack

from slack_sdk import WebClient
from langchain.tools import Tool

slack_client = WebClient(token="xoxb-...")

def send_slack_message(text: str, channel: str = "#general") -> str:
    """Envoie un message sur Slack"""
    try:
        result = slack_client.chat_postMessage(
            channel=channel,
            text=text
        )
        return f"Message envoyé dans {channel}"
    except Exception as e:
        return f"Erreur: {str(e)}"

slack_tool = Tool(
    name="SlackMessage",
    func=send_slack_message,
    description="Envoie un message sur Slack. Input: 'message|#channel'"
)

Appel API REST

import requests
from langchain.tools import Tool

def call_api(endpoint: str) -> str:
    """Appelle une API REST"""
    base_url = "https://api.example.com"
    try:
        response = requests.get(f"{base_url}/{endpoint}")
        response.raise_for_status()
        return response.json()
    except Exception as e:
        return f"Erreur API: {str(e)}"

api_tool = Tool(
    name="APICall",
    func=call_api,
    description="Appelle l'API interne. Input: endpoint (ex: 'users/123')"
)

Production et monitoring

Logging avec LangSmith

import os

# Configuration
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "ls-..."
os.environ["LANGCHAIN_PROJECT"] = "production-app"

# Tout est automatiquement tracé
chain = prompt | llm
response = chain.invoke({"question": "..."})

# Voir les traces sur langsmith.com
💡 📊 LangSmith est ESSENTIEL en production : Il vous permet de tracer chaque exécution, analyser les coûts token par token, déboguer les agents, et évaluer la qualité des réponses. Gratuit jusqu’à 5K traces/mois !

Callback personnalisé

from langchain.callbacks.base import BaseCallbackHandler

class MetricsCallback(BaseCallbackHandler):
    def __init__(self):
        self.total_tokens = 0
        self.total_cost = 0
        self.call_count = 0

    def on_llm_start(self, serialized, prompts, **kwargs):
        self.call_count += 1
        print(f"[{self.call_count}] LLM call started")

    def on_llm_end(self, response, **kwargs):
        tokens = response.llm_output.get('token_usage', {})
        total = tokens.get('total_tokens', 0)
        self.total_tokens += total
        self.total_cost += (total / 1000) * 0.03  # $0.03 per 1K tokens

        print(f"Tokens: {total} | Total: {self.total_tokens} | Coût: ${self.total_cost:.4f}")

metrics = MetricsCallback()

chain = prompt | llm
response = chain.invoke(
    {"question": "..."},
    config={"callbacks": [metrics]}
)

API REST avec LangServe

from fastapi import FastAPI
from langserve import add_routes

app = FastAPI(
    title="Mon API LangChain",
    version="1.0"
)

# Ajouter une chain comme endpoint
add_routes(
    app,
    prompt | llm,
    path="/chat"
)

# Lancer: uvicorn main:app --reload
# Utiliser: POST http://localhost:8000/chat/invoke

Cache Redis

from langchain.cache import RedisCache
from langchain.globals import set_llm_cache
import redis

redis_client = redis.Redis(
    host='localhost',
    port=6379,
    db=0
)

set_llm_cache(RedisCache(redis_client))

# Les appels identiques sont cachés
response1 = llm.invoke("Question")  # Appel API
response2 = llm.invoke("Question")  # Cache (instantané)

Retry avec Tenacity

from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    reraise=True
)
def robust_chain_call(input_data):
    """Chain avec retry automatique"""
    try:
        return chain.invoke(input_data)
    except Exception as e:
        print(f"Erreur: {e}, retry...")
        raise

result = robust_chain_call({"question": "..."})

Optimisations et performances

Batch processing

# Au lieu de boucler (lent)
questions = ["Question 1", "Question 2", "Question 3"]

# Mauvais
# for q in questions:
#     response = llm.invoke(q)

# Bon (parallélisé automatiquement)
responses = llm.batch([{"question": q} for q in questions])

Async pour la performance

import asyncio

async def process_documents_async(documents):
    """Traitement parallèle des documents"""
    embeddings = OpenAIEmbeddings()

    # Créer embeddings en parallèle
    tasks = [embeddings.aembed_query(doc.page_content) for doc in documents]
    vectors = await asyncio.gather(*tasks)

    return vectors

# Utilisation
vectors = asyncio.run(process_documents_async(documents))

Cache d’embeddings

from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import LocalFileStore

store = LocalFileStore("./embedding_cache")

cached_embeddings = CacheBackedEmbeddings.from_bytes_store(
    embeddings,
    store,
    namespace="openai-embeddings"
)

# Première fois: calcul + cache
vectorstore = FAISS.from_documents(documents, cached_embeddings)

# Prochaines fois: lecture du cache (gratuit et instantané)
🔎 Tip
💰 Économisez sur les embeddings : Les embeddings OpenAI coûtent $0.13 par million de tokens. Sur un corpus de 10K documents, le cache peut vous faire économiser des centaines de dollars en retraitement !

Compression de contexte

from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor

compressor = LLMChainExtractor.from_llm(llm)

compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=vectorstore.as_retriever()
)

# Documents retournés sont automatiquement compressés (50-70% plus courts)
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=compression_retriever
)

Hybrid search (mots-clés + sémantique)

from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever

# Retriever par mots-clés
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 5

# Retriever sémantique
semantic_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

# Combinaison
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, semantic_retriever],
    weights=[0.3, 0.7]  # 30% mots-clés, 70% sémantique
)

# Meilleure précision sur les termes techniques
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=ensemble_retriever
)

Troubleshooting

Dépassement de tokens

# Solution: Compter les tokens avant
import tiktoken

def count_tokens(text: str, model: str = "gpt-4") -> int:
    encoding = tiktoken.encoding_for_model(model)
    return len(encoding.encode(text))

# Vérifier avant d'envoyer
text = "..."
tokens = count_tokens(text)
print(f"Tokens: {tokens}")

if tokens > 8000:  # Limite GPT-4
    # Découper ou résumer
    print("Texte trop long, découpage nécessaire")

Erreurs de rate limit

from langchain.llms.openai import OpenAI
from langchain.callbacks import get_openai_callback

# Tracker les tokens
with get_openai_callback() as cb:
    response = chain.invoke({"question": "..."})
    print(f"Tokens: {cb.total_tokens}")
    print(f"Coût: ${cb.total_cost}")

    if cb.total_tokens > 10000:
        print("Attention: consommation élevée")

# Rate limiting manuel
import time

def rate_limited_call(chain, input_data, delay=1):
    result = chain.invoke(input_data)
    time.sleep(delay)  # Pause entre appels
    return result

Documents non retrouvés dans RAG

# Vérifier la qualité du retrieval
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

# Test de similarité
query = "Comment fonctionne LoRA ?"
docs = retriever.get_relevant_documents(query)

for i, doc in enumerate(docs):
    print(f"\n--- Document {i+1} ---")
    print(f"Score: {doc.metadata.get('score', 'N/A')}")
    print(doc.page_content[:200])

# Si les scores sont trop bas (<0.5), améliorer:
# 1. Chunks plus petits
# 2. Meilleur modèle d'embeddings
# 3. Hybrid search

Agent en boucle infinie

from langchain.agents import AgentExecutor

agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    max_iterations=10,  # Force l'arrêt
    max_execution_time=60,  # Timeout 60s
    early_stopping_method="generate",  # Génère une réponse même si incomplet
    verbose=True
)

try:
    result = agent_executor.invoke({"input": "..."})
except Exception as e:
    print(f"Agent stoppé: {e}")

Hallucinations

# Prompt strict pour RAG
strict_prompt = ChatPromptTemplate.from_template("""
Réponds UNIQUEMENT en te basant sur le contexte fourni.
Si la réponse n'est PAS dans le contexte, réponds EXACTEMENT:
"Je ne trouve pas cette information dans les documents."

NE JAMAIS inventer ou déduire des informations non présentes.

Contexte:
{context}

Question: {input}

Réponse:""")

# Chain avec prompt strict
document_chain = create_stuff_documents_chain(llm, strict_prompt)
rag_chain = create_retrieval_chain(retriever, document_chain)

# + Utiliser temperature=0 pour réduire la créativité
llm = ChatOpenAI(model="gpt-4", temperature=0)
⚠️ Warning
🎯 Anti-hallucination : La principale cause d’hallucination en RAG est un retrieval de mauvaise qualité. Avant d’ajuster les prompts, vérifiez toujours la pertinence des documents récupérés avec retriever.get_relevant_documents().

Recettes bonus

Extraction d’entités

from langchain.output_parsers import ResponseSchema, StructuredOutputParser

schemas = [
    ResponseSchema(name="nom", description="Nom de la personne"),
    ResponseSchema(name="age", description="Âge en années"),
    ResponseSchema(name="ville", description="Ville de résidence")
]

parser = StructuredOutputParser.from_response_schemas(schemas)

prompt = ChatPromptTemplate.from_template("""
Extrait les informations suivantes du texte:
{format_instructions}

Texte: {text}
""")

chain = prompt | llm | parser

result = chain.invoke({
    "text": "Sophie a 28 ans et habite à Lyon.",
    "format_instructions": parser.get_format_instructions()
})

print(result)  # {'nom': 'Sophie', 'age': '28', 'ville': 'Lyon'}

Classification de texte

from enum import Enum

class Category(str, Enum):
    TECHNICAL = "technique"
    SUPPORT = "support"
    SALES = "vente"
    OTHER = "autre"

classification_prompt = ChatPromptTemplate.from_template("""
Classifie le message suivant dans une catégorie:
- technique: questions techniques, bugs
- support: aide, how-to
- vente: demandes commerciales
- autre: reste

Message: {message}

Catégorie (un seul mot):""")

def classify_message(message: str) -> str:
    chain = classification_prompt | llm
    response = chain.invoke({"message": message})
    category = response.content.strip().lower()

    # Validation
    try:
        return Category(category).value
    except ValueError:
        return Category.OTHER.value

# Test
print(classify_message("Comment installer votre produit ?"))  # → support
print(classify_message("J'ai une erreur 500"))  # → technique
print(classify_message("Quel est le prix ?"))  # → vente

Traduction multilingue

translation_prompt = ChatPromptTemplate.from_template("""
Traduis le texte suivant de {source_lang} vers {target_lang}.
Garde le ton et le style du texte original.

Texte: {text}

Traduction:""")

def translate(text: str, source: str = "auto", target: str = "fr") -> str:
    chain = translation_prompt | llm
    response = chain.invoke({
        "text": text,
        "source_lang": source,
        "target_lang": target
    })
    return response.content

# Utilisation
result = translate("Hello, how are you today?", source="en", target="fr")
print(result)  # → "Bonjour, comment allez-vous aujourd'hui ?"

Génération de données synthétiques

from langchain.prompts import FewShotPromptTemplate

examples = [
    {"input": "restaurant", "output": "Le Petit Bistrot, restaurant français cosy au cœur de Paris"},
    {"input": "librairie", "output": "Pages & Cie, librairie indépendante spécialisée en littérature"},
]

example_prompt = ChatPromptTemplate.from_template(
    "Type: {input}\nDescription: {output}"
)

few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="Génère des descriptions réalistes pour des commerces:",
    suffix="Type: {input}\nDescription:",
    input_variables=["input"]
)

chain = few_shot_prompt | llm

# Génération
for business_type in ["café", "salon de coiffure", "boulangerie"]:
    result = chain.invoke({"input": business_type})
    print(f"{business_type}: {result.content}")

Résumé de documents longs

from langchain.chains.summarize import load_summarize_chain
from langchain.chains import MapReduceDocumentsChain

# Map-Reduce: résume chaque chunk puis combine
chain = load_summarize_chain(
    llm,
    chain_type="map_reduce",
    verbose=True
)

summary = chain.run(documents)
print(summary)

# Ou refine: résume itérativement
chain = load_summarize_chain(llm, chain_type="refine")
summary = chain.run(documents)

Index rapide par cas d’usage

Trouvez rapidement la recette qu’il vous faut :

Débutant (premiers pas) :

  • Recette #1 : Appel LLM simple
  • Recette #2 : Prompt template dynamique
  • Recette #5 : Fallback multi-LLM

Chatbots :

  • Recette #6-10 : Mémoire, fenêtre de contexte, résumé auto, multilingue, personnalité

RAG (documents) :

  • Recette #11-15 : PDF simple, multi-PDFs, Chroma persistant, filtres métadonnées, RAG conversationnel

Agents :

  • Recette #16-20 : Recherche web, calculatrice, outils custom, RAG agent, SQL agent

Production :

  • Recette #26 : LangSmith monitoring
  • Recette #28 : API REST avec LangServe
  • Recette #29 : Cache Redis
  • Recette #30 : Retry avec Tenacity

Performance :

  • Recette #31 : Batch processing
  • Recette #32 : Async
  • Recette #33 : Cache d’embeddings
  • Recette #35 : Hybrid search

Problèmes courants :

  • Recette #36 : Dépassement tokens
  • Recette #37 : Rate limit
  • Recette #38 : Documents non retrouvés
  • Recette #39 : Agent en boucle
  • Recette #40 : Hallucinations

Conclusion

Ce guide pratique vous a fourni 50+ recettes prêtes à l’emploi couvrant tous les aspects de LangChain :

Configuration et setup de projet professionnel

Chatbots avec mémoire et personnalités

RAG sur PDFs, bases vectorielles, et recherche hybride

Agents autonomes avec outils multiples

Intégrations externes (APIs, Slack, Google Drive, Notion)

Production avec monitoring, caching, et APIs REST

Optimisations pour réduire coûts et latence

Troubleshooting pour résoudre les problèmes courants

Conseils pour bien utiliser ce guide

📖 En tant que référence : Bookmarkez cette page et consultez-la quand vous avez besoin d’une fonctionnalité spécifique. Utilisez Ctrl+F pour rechercher des mots-clés.

🔧 En tant qu’outil : Copiez-collez les recettes directement dans vos projets et adaptez-les à vos besoins. Chaque recette est autonome et testée.

📚 Pour apprendre : Lisez les recettes de base (#1-5) puis explorez progressivement les sections avancées. Chaque recette inclut des commentaires explicatifs.

🚀 Pour la production : Concentrez-vous sur les sections Production (26-30) et Optimisations (31-35) pour des applications robustes et performantes.

Prochaines étapes

Pour approfondir chaque domaine :

  1. Débutants : Commencez par les recettes 1-10 (bases + chatbots)
  2. Intermédiaires : Explorez RAG (11-15) et agents simples (16-20)
  3. Avancés : Maîtrisez agents complexes, intégrations, et production (26-35)
  4. Production : Implémentez monitoring, caching, et optimisations (31-35)

Pour aller plus loin :


Retour à la Formation LangChain | Module suivant : LangGraph - Agents Avancés →