Qu'est-ce que LangChain ?
LangChain est un framework open-source Python (et TypeScript) conçu pour simplifier la construction d'applications alimentées par des Large Language Models (LLM). Au lieu d'écrire des appels d'API bas niveau et de gérer manuellement les templates de prompts, LangChain fournit des abstractions composables pour des patterns courants : récupération de documents, maintien de la mémoire conversationnelle, appels d'outils externes et chaînage de plusieurs appels LLM ensemble.
Lancé en octobre 2022 par Harrison Chase, LangChain est rapidement devenu le framework LLM le plus populaire, avec plus de 85 000 étoiles GitHub et un écosystème d'intégrations florissant (50+ bases de données vectorielles, 100+ chargeurs de documents, 20+ fournisseurs LLM).
Concepts Fondamentaux
LangChain repose sur cinq abstractions clés :
- Models : Wrappers pour les LLM (OpenAI, Claude, Llama) et les embeddings (text-embedding-3-small, nomic-embed-text)
- Prompts : Templates pour structurer les entrées aux LLM avec substitution de variables
- Chains : Séquences d'appels (ex : récupération documents → formatage prompt → génération réponse)
- Memory : Gestion de l'état pour les conversations multi-tours
- Agents : LLM qui décident quels outils appeler et quand
Pourquoi Utiliser LangChain ?
| Bénéfice | Sans LangChain | Avec LangChain |
|---|
| Système RAG | 200+ lignes de boilerplate (vector DB, embeddings, récupération, formatage prompt) | 30 lignes avec RetrievalQA ou LCEL |
| Mémoire conversation | Stockage session manuel, gestion fenêtre contexte, logique de résumé | ConversationBufferMemory ou ConversationSummaryMemory (5 lignes) |
| Agent avec outils | Boucle ReAct custom, parsing function calling, gestion erreurs, logique retry | create_react_agent() + décorateurs d'outils (20 lignes) |
| Changement fournisseur LLM | Réécriture appels API, adaptation aux différents formats de réponse | Changer une ligne : ChatOpenAI() → ChatAnthropic() |
| Observabilité | Logging custom, métriques, infrastructure de tracing | Intégration LangSmith (2 variables d'env) |
Cas d'Usage Courants et Exemples de Code
Cas d'Usage 1 : Chatbot Q&A Simple
L'application LangChain la plus simple : envoyer une question, obtenir une réponse. Utile pour les applications sans état comme les requêtes ponctuelles ou les endpoints API.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# 1. Initialiser le LLM
llm = ChatOpenAI(
model="gpt-4o-mini",
temperature=0.7,
api_key="votre-cle-api"
)
# 2. Créer un template de prompt
prompt = ChatPromptTemplate.from_messages([
("system", "Tu es un assistant utile qui répond aux questions de façon concise."),
("human", "{question}")
])
# 3. Créer une chaîne avec LCEL (LangChain Expression Language)
chain = prompt | llm | StrOutputParser()
# 4. Invoquer
response = chain.invoke({"question": "Quelle est la capitale de la France ?"})
print(response) # "Paris est la capitale de la France."
# Pour le streaming des réponses :
for chunk in chain.stream({"question": "Explique l'informatique quantique en 3 phrases"}):
print(chunk, end="", flush=True)
Concepts clés :
- L'opérateur
| crée une chaîne (syntaxe LCEL) StrOutputParser() extrait le texte de la réponse LLMchain.stream() active le streaming token par token (crucial pour l'UX)
Cas d'Usage 2 : Chatbot avec Mémoire Conversationnelle
La plupart des chatbots doivent se souvenir des messages précédents. LangChain gère cela avec des composants Memory.
from langchain_openai import ChatOpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
# Initialiser le LLM
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
# Créer la mémoire (stocke l'historique complet de conversation)
memory = ConversationBufferMemory()
# Créer la chaîne de conversation
conversation = ConversationChain(
llm=llm,
memory=memory,
verbose=True # Affiche le prompt envoyé au LLM
)
# Conversation multi-tours
response1 = conversation.predict(input="Je m'appelle Alice et j'adore Python.")
print(response1) # "Ravi de te rencontrer, Alice ! Python est un super langage..."
response2 = conversation.predict(input="Quel est mon nom ?")
print(response2) # "Ton nom est Alice."
response3 = conversation.predict(input="Quel langage de programmation j'aime ?")
print(response3) # "Tu adores Python."
# Inspecter la mémoire
print(conversation.memory.buffer)
# Affiche l'historique complet de conversation
Astuce production : Pour les longues conversations, utilisez ConversationBufferWindowMemory(k=10) pour garder seulement les 10 derniers messages, ou ConversationSummaryMemory pour que le LLM résume les vieux messages (réduit les coûts en tokens).
Cas d'Usage 3 : RAG (Retrieval-Augmented Generation)
Le RAG permet d'interroger des documents privés sans fine-tuning. Voici un exemple complet : chargement de PDF, création d'embeddings, stockage dans une base vectorielle et réponse aux questions.
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
# Étape 1 : Charger les documents
loader = PyPDFLoader("documentation_entreprise.pdf")
documents = loader.load()
print(f"Chargé {len(documents)} pages")
# Étape 2 : Découper en chunks
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # Caractères par chunk
chunk_overlap=200, # Chevauchement pour préserver le contexte
separators=["\n\n", "\n", " ", ""]
)
chunks = text_splitter.split_documents(documents)
print(f"Découpé en {len(chunks)} chunks")
# Étape 3 : Créer les embeddings et stocker dans la vector DB
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db" # Sauvegarder sur disque
)
# Étape 4 : Créer le retriever
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 4} # Récupérer les 4 chunks les plus pertinents
)
# Étape 5 : Créer la chaîne RAG
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # "stuff" = insérer tous les docs dans un seul prompt
retriever=retriever,
return_source_documents=True
)
# Étape 6 : Interroger
query = "Quelle est la politique de retour de l'entreprise ?"
result = qa_chain.invoke({"query": query})
print(f"Réponse : {result['result']}")
print(f"\nSources ({len(result['source_documents'])} documents) :")
for i, doc in enumerate(result['source_documents']):
print(f" [{i+1}] Page {doc.metadata.get('page', 'N/A')}")
print(f" {doc.page_content[:150]}...")
# Sortie attendue :
# Réponse : L'entreprise propose une politique de retour de 30 jours pour les produits non utilisés...
# Sources (4 documents) :
# [1] Page 12
# Les retours doivent être initiés dans les 30 jours suivant l'achat...
Alternative : Syntaxe LCEL moderne
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
# Prompt personnalisé pour un meilleur contrôle
template = """Réponds à la question en te basant sur le contexte suivant.
Si tu ne sais pas, dis "Je ne sais pas" - n'invente pas d'information.
Contexte :
{context}
Question : {question}
Réponse :"""
prompt = ChatPromptTemplate.from_template(template)
# Créer la chaîne RAG avec LCEL
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# Interroger
answer = rag_chain.invoke("Quelle est la politique de retour de l'entreprise ?")
print(answer)
Cas d'Usage 4 : Agent avec Outils (Recherche Web + Calculatrice)
Les agents permettent au LLM de décider quels outils utiliser et quand. Cet exemple crée un agent qui peut rechercher sur le web et effectuer des calculs.
from langchain_openai import ChatOpenAI
from langchain.agents import Tool, create_react_agent, AgentExecutor
from langchain_community.tools import DuckDuckGoSearchRun
from langchain_core.prompts import PromptTemplate
import math
# Initialiser le LLM
llm = ChatOpenAI(model="gpt-4o", temperature=0) # gpt-4o pour meilleur raisonnement
# Définir les outils
search_tool = DuckDuckGoSearchRun()
def calculator(expression: str) -> str:
"""Évalue une expression mathématique. Exemple : '2 + 2' ou 'sqrt(16)'"""
try:
# Eval sécurisé avec fonctions math
result = eval(expression, {"__builtins__": {}}, vars(math))
return str(result)
except Exception as e:
return f"Erreur : {str(e)}"
tools = [
Tool(
name="Recherche",
func=search_tool.run,
description="Utile pour trouver des informations actuelles sur internet. L'entrée doit être une requête de recherche."
),
Tool(
name="Calculatrice",
func=calculator,
description="Utile pour les calculs mathématiques. L'entrée doit être une expression Python valide comme '2 + 2' ou 'sqrt(16) * 3'."
)
]
# Créer l'agent ReAct
prompt = PromptTemplate.from_template("""Réponds à la question suivante du mieux que tu peux. Tu as accès aux outils suivants :
{tools}
Utilise le format suivant :
Question : la question d'entrée à laquelle tu dois répondre
Pensée : réfléchis à ce qu'il faut faire
Action : l'action à prendre, doit être l'un de [{tool_names}]
Entrée Action : l'entrée de l'action
Observation : le résultat de l'action
... (cette Pensée/Action/Entrée Action/Observation peut se répéter N fois)
Pensée : Je connais maintenant la réponse finale
Réponse Finale : la réponse finale à la question d'entrée originale
Commence !
Question : {input}
Pensée : {agent_scratchpad}""")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # Afficher les étapes de raisonnement
max_iterations=10,
handle_parsing_errors=True
)
# Test de requêtes
query1 = "Quel est le prix actuel du Bitcoin en EUR ?"
result1 = agent_executor.invoke({"input": query1})
print(result1["output"])
query2 = "Si le Bitcoin est à 42 000 € et j'achète 0,5 BTC, combien je paie ?"
result2 = agent_executor.invoke({"input": query2})
print(result2["output"])
# Raisonnement attendu :
# Pensée : Je dois rechercher le prix actuel du Bitcoin
# Action : Recherche
# Entrée Action : prix actuel bitcoin EUR
# Observation : Le Bitcoin se négocie à 42 123 €...
# Pensée : Maintenant je dois calculer 42000 * 0,5
# Action : Calculatrice
# Entrée Action : 42000 * 0.5
# Observation : 21000.0
# Pensée : Je connais maintenant la réponse finale
# Réponse Finale : Vous paieriez 21 000 € pour 0,5 BTC à 42 000 € par coin.
Qu'est-ce que LangGraph ?
LangGraph est une bibliothèque construite au-dessus de LangChain pour créer des workflows d'agents stateful multi-étapes avec des graphes cycliques. Lancé en 2024, il résout une limitation clé des chaînes LangChain basiques : elles sont acycliques (flux à sens unique). LangGraph vous permet de construire des workflows où les agents peuvent boucler, réessayer, se brancher conditionnellement et maintenir un état persistant.
Pourquoi LangGraph ?
Les chaînes LangChain basiques sont linéaires : entrée → étape1 → étape2 → sortie. Mais beaucoup de cas d'usage réels nécessitent :
- Workflows cycliques : L'agent essaie, évalue le résultat, réessaie si nécessaire
- Branchement conditionnel : Router vers différents sous-agents selon le type d'entrée
- Human-in-the-loop : Pause pour approbation avant exécution d'actions
- État persistant : Sauvegarder l'état de conversation pour reprendre plus tard
- Coordination multi-agents : Plusieurs agents spécialisés collaborent
LangGraph représente les workflows comme des graphes dirigés où les nœuds sont des fonctions (agents, outils, prompts) et les arêtes définissent les transitions. Il supporte le checkpointing (sauvegarder/reprendre l'état) et le débogage time travel.
LangChain vs LangGraph : Quand Utiliser Chacun
| Cas d'Usage | LangChain (Chains/Agents) | LangGraph |
|---|
| RAG Q&A simple | ✅ Parfait | Surdimensionné |
| Workflow linéaire (récupération → génération) | ✅ Utiliser chaînes LCEL | Complexité inutile |
| Agent avec logique de retry | ❌ Difficile à implémenter | ✅ Support natif |
| Recherche multi-étapes (recherche → analyse → résumé → affinage) | ⚠️ Possible mais compliqué | ✅ Structure de graphe claire |
| Approbation humaine avant action | ❌ Pas de support natif | ✅ Nœuds interrupt |
| Conversation qui doit se mettre en pause/reprendre | ⚠️ Gestion d'état manuelle | ✅ Checkpointing |
| Routing entre agents spécialisés | ⚠️ Logique custom requise | ✅ Arêtes conditionnelles |
Exemples de Code LangGraph
Exemple 1 : Agent de Recherche avec Auto-Réflexion
Cet agent recherche sur le web, analyse les résultats et réfléchit pour savoir si la réponse est suffisamment bonne. Sinon, il recherche à nouveau avec une requête affinée.
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_community.tools import DuckDuckGoSearchRun
from typing import TypedDict, List
# Définir l'état
class AgentState(TypedDict):
question: str
search_query: str
search_results: str
answer: str
confidence: str # "high" ou "low"
iteration: int
# Initialiser les outils et le LLM
search_tool = DuckDuckGoSearchRun()
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# Nœud 1 : Générer la requête de recherche
def generate_query(state: AgentState) -> AgentState:
question = state["question"]
iteration = state.get("iteration", 0)
if iteration == 0:
query = question
else:
# Affiner la requête basée sur la tentative précédente
prompt = f"""La recherche précédente pour "{state['search_query']}" n'a pas donné une réponse confiante.
Génère une requête de recherche plus spécifique pour : {question}"""
query = llm.invoke(prompt).content
return {**state, "search_query": query, "iteration": iteration + 1}
# Nœud 2 : Exécuter la recherche
def search(state: AgentState) -> AgentState:
results = search_tool.run(state["search_query"])
return {**state, "search_results": results}
# Nœud 3 : Générer la réponse et auto-évaluer
def generate_answer(state: AgentState) -> AgentState:
prompt = f"""Basé sur ces résultats de recherche, réponds à la question.
Puis évalue ta confiance (high/low).
Question : {state['question']}
Résultats de Recherche : {state['search_results']}
Format :
Réponse : [ta réponse]
Confiance : [high ou low]"""
response = llm.invoke(prompt).content
# Parser la réponse
lines = response.split("\n")
answer = next((l.replace("Réponse:", "").strip() for l in lines if "Réponse:" in l), "")
confidence = next((l.replace("Confiance:", "").strip().lower() for l in lines if "Confiance:" in l), "low")
return {**state, "answer": answer, "confidence": confidence}
# Fonction de décision : réessayer ou terminer ?
def should_retry(state: AgentState) -> str:
if state["confidence"] == "high" or state["iteration"] >= 3:
return "finish"
return "retry"
# Construire le graphe
workflow = StateGraph(AgentState)
# Ajouter les nœuds
workflow.add_node("generate_query", generate_query)
workflow.add_node("search", search)
workflow.add_node("generate_answer", generate_answer)
# Ajouter les arêtes
workflow.set_entry_point("generate_query")
workflow.add_edge("generate_query", "search")
workflow.add_edge("search", "generate_answer")
workflow.add_conditional_edges(
"generate_answer",
should_retry,
{
"retry": "generate_query", # Boucler en arrière
"finish": END
}
)
# Compiler le graphe
app = workflow.compile()
# Exécuter
result = app.invoke({
"question": "Quelle est la dernière version de Python en 2026 ?",
"iteration": 0
})
print(f"Réponse Finale : {result['answer']}")
print(f"Confiance : {result['confidence']}")
print(f"Itérations : {result['iteration']}")
# Flux attendu :
# 1. Générer requête : "dernière version Python 2026"
# 2. Recherche → résultats
# 3. Générer réponse → confiance : low (résultats vagues)
# 4. Retry : Générer requête affinée : "Python 3.13 date sortie 2026"
# 5. Recherche → meilleurs résultats
# 6. Générer réponse → confiance : high
# 7. Terminer
Exemple 2 : Workflow d'Approbation Human-in-the-Loop
Cet agent rédige un email, demande l'approbation humaine, et envoie seulement si approuvé.
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver # Pour les interrupts
from langchain_openai import ChatOpenAI
from typing import TypedDict
class EmailState(TypedDict):
recipient: str
topic: str
draft: str
approved: bool
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
# Nœud 1 : Rédiger l'email
def draft_email(state: EmailState) -> EmailState:
prompt = f"Écris un email professionnel à {state['recipient']} concernant {state['topic']}."
draft = llm.invoke(prompt).content
return {**state, "draft": draft}
# Nœud 2 : Envoyer l'email (seulement si approuvé)
def send_email(state: EmailState) -> EmailState:
print(f"📧 Envoi de l'email à {state['recipient']} :")
print(state['draft'])
return state
# Décision : vérifier l'approbation
def check_approval(state: EmailState) -> str:
return "send" if state.get("approved", False) else END
# Construire le graphe avec checkpointing
workflow = StateGraph(EmailState)
workflow.add_node("draft", draft_email)
workflow.add_node("send", send_email)
workflow.set_entry_point("draft")
workflow.add_conditional_edges(
"draft",
check_approval,
{"send": "send", END: END}
)
workflow.add_edge("send", END)
# Compiler avec mémoire (requis pour les interrupts)
memory = MemorySaver()
app = workflow.compile(checkpointer=memory, interrupt_before=["send"])
# Exécuter avec un thread_id (requis pour l'exécution stateful)
config = {"configurable": {"thread_id": "email-123"}}
# Étape 1 : Rédiger l'email
result1 = app.invoke({
"recipient": "jean@exemple.fr",
"topic": "feuille de route produit Q1 2026"
}, config)
print("Brouillon créé :")
print(result1["draft"])
print("\n⏸️ Workflow en pause. Réviser et approuver.")
# --- L'humain révise le brouillon ici ---
# Étape 2 : Approuver et continuer
result2 = app.invoke({
**result1,
"approved": True # Approbation humaine
}, config)
# Sortie :
# Brouillon créé :
# Objet : Feuille de Route Produit Q1 2026
#
# Cher Jean,
#
# Je souhaitais partager notre feuille de route produit pour le Q1 2026...
#
# ⏸️ Workflow en pause. Réviser et approuver.
# 📧 Envoi de l'email à jean@exemple.fr :
# [contenu email]
Exemple 3 : Collaboration Multi-Agents (Chercheur + Rédacteur)
Deux agents spécialisés collaborent : l'un fait de la recherche, l'autre rédige un rapport.
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_community.tools import DuckDuckGoSearchRun
from typing import TypedDict, List
class ResearchState(TypedDict):
topic: str
research_notes: str
article: str
search_tool = DuckDuckGoSearchRun()
llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
# Agent 1 : Chercheur
def research(state: ResearchState) -> ResearchState:
topic = state["topic"]
# Rechercher des informations
search_results = search_tool.run(f"{topic} derniers développements 2026")
# Analyser et résumer
prompt = f"""Analyse ces résultats de recherche et extrais les faits clés sur {topic}.
Focus sur : définitions, développements récents, avis d'experts, statistiques.
Résultats de Recherche :
{search_results}
Format de sortie :
- Fait clé 1
- Fait clé 2
..."""
notes = llm.invoke(prompt).content
return {**state, "research_notes": notes}
# Agent 2 : Rédacteur
def write_article(state: ResearchState) -> ResearchState:
prompt = f"""Écris un article de 300 mots sur {state['topic']}.
Utilise ces notes de recherche comme source :
{state['research_notes']}
Écris dans un style professionnel et engageant. Inclus une introduction, des points clés et une conclusion."""
article = llm.invoke(prompt).content
return {**state, "article": article}
# Construire le graphe
workflow = StateGraph(ResearchState)
workflow.add_node("researcher", research)
workflow.add_node("writer", write_article)
workflow.set_entry_point("researcher")
workflow.add_edge("researcher", "writer")
workflow.add_edge("writer", END)
app = workflow.compile()
# Exécuter
result = app.invoke({"topic": "Impact des régulations AI Act sur les startups européennes"})
print("Notes de Recherche :")
print(result["research_notes"])
print("\n" + "="*50 + "\n")
print("Article :")
print(result["article"])
Bonnes Pratiques de Production
1. Optimisation des Coûts
- Utiliser des modèles moins chers pour les tâches simples : gpt-4o-mini (0,15 €/1M tokens) au lieu de gpt-4o (5 €/1M tokens) pour la génération RAG
- Cacher les embeddings : Stocker les embeddings pendant 30 jours pour éviter de recalculer pour les mêmes requêtes
- Grouper les appels API : Utiliser l'API batch OpenAI pour les tâches non urgentes (50% de réduction)
- Limiter la fenêtre de contexte : Utiliser ConversationBufferWindowMemory au lieu de l'historique complet
- Considérer les LLM locaux : Llama 3.3 70B via Ollama coûte 0 € par requête (nécessite GPU)
2. Monitoring avec LangSmith
LangSmith est la plateforme d'observabilité de LangChain. Activez-la avec 2 variables d'environnement :
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "votre-cle-api-langsmith"
# Maintenant toutes les chaînes/agents loguent automatiquement vers LangSmith
# Voir les traces sur : https://smith.langchain.com/
Ce que vous obtenez :
- Trace complète de chaque exécution de chaîne (entrées, sorties, latences)
- Suivi de l'utilisation des tokens et des coûts par appel
- Analyse des erreurs et patterns d'échec
- Tests A/B de prompts et modèles
- Création de datasets depuis les logs de production
3. Gestion d'Erreurs et Retries
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnableRetry
llm = ChatOpenAI(model="gpt-4o-mini")
# Ajouter des retries automatiques (jusqu'à 3 tentatives)
llm_with_retry = RunnableRetry(
bound=llm,
max_attempts=3,
wait_exponential_jitter=True # Backoff exponentiel
)
# Utiliser dans une chaîne
chain = prompt | llm_with_retry | output_parser
# Pour les agents : ajouter un LLM de secours
from langchain_anthropic import ChatAnthropic
llm_primary = ChatOpenAI(model="gpt-4o")
llm_fallback = ChatAnthropic(model="claude-3-5-sonnet-20241022")
llm = llm_primary.with_fallbacks([llm_fallback])
# Si OpenAI échoue, essaie automatiquement Claude
4. Streaming pour une Meilleure UX
Toujours streamer les réponses dans les applications face utilisateur :
# Exemple d'endpoint FastAPI
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
app = FastAPI()
@app.post("/chat")
async def chat(question: str):
llm = ChatOpenAI(model="gpt-4o-mini", streaming=True)
prompt = ChatPromptTemplate.from_messages([
("system", "Tu es un assistant utile."),
("human", "{question}")
])
chain = prompt | llm
async def generate():
async for chunk in chain.astream({"question": question}):
yield chunk.content
return StreamingResponse(generate(), media_type="text/plain")
# Le client reçoit les tokens au fur et à mesure de leur génération (sensation instantanée)
5. Bonnes Pratiques de Sécurité
- Ne jamais mettre les clés API dans le code : Utiliser des variables d'environnement ou des gestionnaires de secrets
- Valider les entrées utilisateur : Nettoyer les requêtes avant de les passer aux LLM (prévenir l'injection de prompts)
- Limiter les itérations des agents : Définir max_iterations pour éviter les boucles infinies
- Restreindre l'accès aux outils : Donner aux agents accès uniquement aux outils nécessaires (principe du moindre privilège)
- Utiliser l'IA constitutionnelle : Ajouter une couche de modération pour filtrer les sorties nuisibles
Ressources d'Apprentissage
Pour maîtriser LangChain et LangGraph, nous recommandons :
- Documentation officielle LangChain : python.langchain.com/docs (référence API complète)
- Documentation LangGraph : langchain-ai.github.io/langgraph (tutoriels et exemples)
- LangChain Academy : Cours gratuit par Harrison Chase (créateur) couvrant les fondamentaux aux agents avancés
- LangSmith Cookbook : Patterns de production et bonnes pratiques
Pour une formation pratique professionnelle, Talki Academy propose :
- RAG et Agents en Production (3 jours intensifs) : Construire des systèmes RAG de production avec LangChain, LlamaIndex et LangGraph. Inclut des projets réels et déploiement sur AWS.
- Claude API pour Développeurs (2 jours) : Maîtriser Claude 4.5 avec intégration LangChain. Prompt engineering avancé, function calling et optimisation des coûts.
Questions Fréquemment Posées
Quand dois-je utiliser LangGraph plutôt que LangChain basique ?
Utilisez LangGraph quand vous avez besoin de : (1) Workflows multi-étapes complexes avec branchement conditionnel, (2) Des agents qui doivent réviser leur travail selon les retours, (3) État persistant entre les tours de conversation, (4) Approbations humaines avant action, ou (5) Workflows cycliques (l'agent essaie, évalue, réessaie). Pour des chaînes linéaires simples (récupération → génération), LangChain basique suffit.
Puis-je utiliser LangChain avec des LLM open-source comme Llama ou Mistral ?
Oui, absolument. LangChain a des intégrations natives avec Ollama (inférence locale), vLLM (serving accéléré GPU), HuggingFace Transformers, et les serveurs d'API compatibles OpenAI. Exemple : ChatOllama(model='llama3.3:70b') fonctionne de façon identique à ChatOpenAI. Idem pour les embeddings : OllamaEmbeddings(model='nomic-embed-text') remplace OpenAIEmbeddings. Vous pouvez tout faire tourner en local avec zéro coût API.
Quel est le coût réel d'une application RAG LangChain en production ?
Pour un support client RAG typique avec 50k requêtes/mois : ~400-600 €/mois (OpenAI GPT-4o mini + embeddings + Pinecone vector DB + compute). Vous pouvez réduire cela de 60% en utilisant Llama 3.3 70B local (0 € d'appels LLM, +200 €/mois GPU) et ChromaDB auto-hébergé (0 € vector DB). Coût total optimisé : ~250 €/mois. Économies clés : cache des embeddings (TTL 30 jours), utiliser gpt-4o-mini pas gpt-4, grouper les requêtes quand possible.
Comment ajouter de la mémoire à un chatbot LangChain ?
LangChain offre 4 stratégies de mémoire : (1) ConversationBufferMemory (stocke tous les messages, simple mais la mémoire grandit), (2) ConversationBufferWindowMemory (derniers N messages, bon pour longues conversations), (3) ConversationSummaryMemory (le LLM résume les vieux messages, idéal pour la production), (4) ConversationKGMemory (graphe de connaissances des faits). Pour la plupart des applications : commencez avec BufferWindowMemory(k=10), passez à SummaryMemory quand les limites de contexte sont atteintes. Avec LangGraph, utilisez les checkpoints pour un état persistant entre sessions.
Quelle est la différence entre LangChain Expression Language (LCEL) et l'ancienne API Chain ?
LCEL (introduit en 2023) est la façon moderne de construire des chaînes en utilisant l'opérateur pipe (|). Avantages : (1) streaming par défaut, (2) async/sync auto-géré, (3) meilleur débogage, (4) intégration LangSmith. L'ancienne API Chain (RetrievalQA, etc.) fonctionne toujours mais est en mode maintenance. Exemple : retriever | prompt | llm | output_parser (LCEL) vs RetrievalQA.from_chain_type() (ancien). Recommandation : utilisez LCEL pour les nouveaux projets, migrez les anciennes chaînes progressivement.