LangChain
Le framework Python le plus populaire pour construire des applications autour des LLMs : chaînes de traitement, agents, RAG, intégrations avec des dizaines de services. Une boîte à outils complète pour transformer un appel à un LLM en application réelle.
À quoi ça sert
Appeler un LLM en Python, c'est trois lignes : on envoie un prompt, on récupère du texte. Construire une application autour, c'est beaucoup plus : gérer la mémoire d'une conversation, aller chercher de l'info dans des documents, appeler des outils externes, enchaîner plusieurs étapes, gérer les erreurs, switcher entre LLMs sans tout réécrire.
LangChain fournit les briques standardisées pour tout ça :
- Wrappers de LLMs — API uniforme pour OpenAI, Anthropic, Ollama, Mistral, HuggingFace… Tu changes une ligne pour switcher de modèle.
- Chains — enchaîner prompt → LLM → parser → traitement, le tout déclaratif avec la syntaxe LCEL (LangChain Expression Language).
- Retrievers et RAG — charger des documents, les découper en chunks, les indexer dans un vector store, et les retrouver par similarité au moment de répondre.
- Tools et Agents — donner au LLM la capacité d'utiliser des outils (calculatrice, recherche web, API maison) et de décider lequel appeler.
- Memory — garder le fil d'une conversation multi-tours sans tout renvoyer manuellement à chaque appel.
- Intégrations — connecteurs prêts à l'emploi pour des centaines de services (Notion, GitHub, Slack, S3, PostgreSQL…).
Les deux frameworks dominent l'écosystème, mais avec des angles différents. LangChain est généraliste : RAG + agents + chains + dizaines d'intégrations. Plus large, plus puissant, plus complexe. LlamaIndex est focalisé sur le RAG : indexer et requêter des documents, c'est sa raison d'être. Plus simple à démarrer si c'est ton seul besoin. Pour un pur RAG, prends LlamaIndex. Pour des agents, des pipelines multi-étapes ou plusieurs sources mélangées, prends LangChain. Et les deux peuvent cohabiter — beaucoup d'applis utilisent LlamaIndex pour le RAG dans une chaîne LangChain plus large.
Un exemple d'usage
Construire un mini-RAG sur quelques fichiers texte : charger les documents, indexer, poser une question, obtenir une réponse avec les sources. Avec Ollama en local (pas besoin de clé OpenAI) :
from langchain_community.document_loaders import DirectoryLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_ollama import OllamaEmbeddings, ChatOllama
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
# 1. Charger des fichiers .txt depuis un dossier
docs = DirectoryLoader("./notes", glob="*.txt").load()
# 2. Découper en chunks (les LLMs ont une fenêtre limitée)
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)
# 3. Embeddings + vector store en mémoire
embeddings = OllamaEmbeddings(model="nomic-embed-text")
store = FAISS.from_documents(chunks, embeddings)
# 4. Prompt + LLM + chaîne RAG
prompt = ChatPromptTemplate.from_template(
"Réponds à la question en t'appuyant sur le contexte.\n"
"Contexte: {context}\nQuestion: {input}"
)
llm = ChatOllama(model="llama3.2")
chain = create_retrieval_chain(
store.as_retriever(),
create_stuff_documents_chain(llm, prompt),
)
# 5. Question → réponse contextuelle
result = chain.invoke({"input": "Quelle est la date du dernier sprint ?"})
print(result["answer"])
En ~25 lignes, un RAG complet : ingestion → indexation → recherche → réponse contextualisée. Changer Ollama pour OpenAI = 2 imports à modifier. Changer le format des documents (PDF, HTML, Notion…) = changer le loader, tout le reste reste identique.
How-to : installer et utiliser LangChain
-
Installer le bon set de paquets
LangChain est modulaire : un paquet « core » + un paquet par intégration. On installe au minimum :
bashuv add langchain langchain-community # + au moins un fournisseur de LLM : uv add langchain-ollama # local (recommandé pour démarrer) uv add langchain-openai # API OpenAI uv add langchain-anthropic # API Claude # + utilitaires courants uv add langchain-text-splitters faiss-cpuPourquoi autant de paquets ?LangChain a éclaté son monorepo en 2024 pour découpler les releases. Du coup, tu n'installes que les intégrations dont tu as besoin. Le revers : faut savoir où trouver quoi — la doc indique pour chaque import le paquet à installer.
-
Connecter un LLM
Tous les LLMs ont la même interface :
.invoke()pour une requête simple,.stream()pour le mot par mot,.batch()pour plusieurs en parallèle.pythonfrom langchain_ollama import ChatOllama llm = ChatOllama(model="llama3.2", temperature=0.7) print(llm.invoke("Capitale du Pérou ?").content) # > "La capitale du Pérou est Lima." for chunk in llm.stream("Liste 5 fruits."): print(chunk.content, end="", flush=True) -
Composer une chaîne avec LCEL
LCEL (LangChain Expression Language) compose les étapes avec l'opérateur
|à la manière d'un pipe Unix :pythonfrom langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser prompt = ChatPromptTemplate.from_messages([ ("system", "Tu es un assistant concis."), ("user", "Explique {sujet} en 2 phrases."), ]) chain = prompt | llm | StrOutputParser() print(chain.invoke({"sujet": "l'overfitting"}))Cette chaîne se lit : un prompt structuré, envoyé au LLM, dont la sortie est parsée en string brute. Chaque étape est interchangeable.
-
Charger et découper des documents
Pour le RAG, on commence toujours par charger des sources :
pythonfrom langchain_community.document_loaders import ( PyPDFLoader, WebBaseLoader, TextLoader, DirectoryLoader, ) from langchain_text_splitters import RecursiveCharacterTextSplitter docs = PyPDFLoader("manuel.pdf").load() docs += WebBaseLoader(["https://example.com/doc"]).load() splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=100, ) chunks = splitter.split_documents(docs)Le bon chunk_size ?Règle empirique : 500-1500 tokens (≈ 300-1000 mots). Trop petit, on perd le contexte ; trop grand, le LLM se noie ou dépasse sa fenêtre.
chunk_overlapévite de couper une phrase en deux entre deux chunks. -
Vector store et retriever
Le vector store stocke les embeddings des chunks et sait retrouver les plus proches d'une question :
pythonfrom langchain_community.vectorstores import FAISS from langchain_ollama import OllamaEmbeddings embeddings = OllamaEmbeddings(model="nomic-embed-text") store = FAISS.from_documents(chunks, embeddings) # Sauver / recharger store.save_local("./faiss_index") store = FAISS.load_local("./faiss_index", embeddings, allow_dangerous_deserialization=True) retriever = store.as_retriever(search_kwargs={"k": 4}) docs_pertinents = retriever.invoke("Sujet de ma question")FAISS est l'option locale la plus simple. En production on utilise plutôt Qdrant, Chroma, Weaviate ou Postgres + pgvector (cf. PostgreSQL).
-
Chaîne RAG complète
pythonfrom langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain prompt = ChatPromptTemplate.from_template( "Contexte : {context}\n\nQuestion : {input}\n\n" "Si l'info n'est pas dans le contexte, dis-le." ) doc_chain = create_stuff_documents_chain(llm, prompt) rag_chain = create_retrieval_chain(retriever, doc_chain) ans = rag_chain.invoke({"input": "Quelle est la procédure pour …"}) print(ans["answer"]) print([d.metadata for d in ans["context"]]) # sources -
Tools et agents (aperçu)
Un tool est une fonction Python qu'on expose au LLM. Un agent décide lui-même quel tool appeler.
pythonfrom langchain_core.tools import tool from langgraph.prebuilt import create_react_agent @tool def meteo(ville: str) -> str: """Renvoie la météo d'une ville.""" return f"À {ville} il fait 18°C." agent = create_react_agent(llm, tools=[meteo]) result = agent.invoke({"messages": [("user", "Quel temps à Liège ?")]}) print(result["messages"][-1].content)Le LLM lit la docstring du tool, décide qu'il en a besoin, l'appelle avec les bons paramètres, intègre le résultat dans sa réponse finale. Sous-projet LangGraph du même éditeur pour les agents complexes.
-
Debugger avec LangSmith ou des callbacks
Une chaîne LangChain de 5 étapes devient opaque à debugger. Activer les logs verbose ou brancher LangSmith (service payant de l'éditeur) donne la trace complète.
pythonimport langchain langchain.debug = True # logs locaux # LangSmith via variable d'environnement # LANGCHAIN_TRACING_V2=true # LANGCHAIN_API_KEY=…
Aide-mémoire
from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama3.2")
llm.invoke("…"); llm.stream("…"); llm.batch(["…", "…"])
chain = prompt | llm | StrOutputParser()
chain.invoke({"var": "…"})
docs = PyPDFLoader("…").load()
chunks = RecursiveCharacterTextSplitter(...).split_documents(docs)
store = FAISS.from_documents(chunks, embeddings)
chain = create_retrieval_chain(store.as_retriever(), doc_chain)
chain.invoke({"input": "…"})
@tool
def my_tool(x: str) -> str: """docstring vue par le LLM"""; return ...
agent = create_react_agent(llm, tools=[my_tool])
agent.invoke({"messages": [("user", "…")]})
LangChain et le reste de l'écosystème
- LlamaIndex — l'autre framework majeur. Plus simple pour un pur cas RAG. LangChain est plus complet (agents, tools, multi-step). Les deux peuvent coexister.
-
Ollama /
Hugging Face —
fournisseurs de LLMs locaux.
langchain-ollamaetlangchain-huggingfaceexposent la même API que les intégrations cloud. -
FastAPI — pattern
classique : ton API FastAPI expose un endpoint
/chatqui appelle une chaîne LangChain. LangChain gère même nativement le streaming pour FastAPI. -
Pydantic — LangChain
utilise Pydantic en interne pour valider les inputs/outputs des
chaînes. Tu déclares un
BaseModelet un parser le force comme structure de sortie du LLM. -
PostgreSQL — avec
l'extension pgvector, Postgres devient un vector store production
intégrable à LangChain via
langchain-postgres. Alternative aux vector stores spécialisés (FAISS, Qdrant…). -
Streamlit — prototyper
un chatbot LangChain en quelques dizaines de lignes :
st.chat_input+ appel à la chaîne +st.write_stream. -
MLflow — sait logger
et servir une chaîne LangChain comme un modèle classique
(
mlflow.langchain.log_model), ce qui permet de versionner tes RAG comme tu versionnes tes modèles ML.
LangChain encourage la composition de chaînes complexes. Pour un
besoin simple (« appelle Ollama avec ce prompt »), un simple
httpx.post(...) sur l'API Ollama suffit. Avant
d'ajouter LangChain, demande-toi si tu as vraiment
besoin de RAG, d'agents ou de multi-LLM. Si non, reste sur
httpx direct — moins de magie, moins de
dépendances, plus facile à debugger.
Pour aller plus loin
- Site officiel : langchain.com
- Documentation Python : python.langchain.com
- Tutoriels « build a RAG » : python.langchain.com/docs/tutorials/rag
- LangGraph (agents) : langchain-ai.github.io/langgraph