Trois workflows IA opérationnels que vous pouvez déployer cette semaine — sans abonnement API, sans dépendance à un fournisseur cloud, sans que vos données ne quittent votre machine. Chaque workflow utilise une stack open-source différente pour couvrir les trois demandes IA les plus fréquentes des équipes non-techniques : synthétiser les réunions, automatiser les réponses FAQ, et interroger les documents internes.
Ces tutoriels utilisent Whisper (le modèle de transcription vocale open-source d’OpenAI) pour la transcription, LangChain + Ollama pour le bot FAQ (Python, prêt à copier), et ChromaDB pour la recherche dans les PDFs. Ils complètent — sans les répéter — les approches n8n JSON et BART couvertes dans notre guide précédent.
brew install ollama sur Mac ou l’installeur Linux). 8 Go de RAM recommandés ; 4 Go minimum.Workflow 1 — Transcription de réunions avec Whisper + n8n
Cas d’usage : Votre équipe enregistre les stand-ups, les réunions clients ou les sessions de formation. Vous voulez des transcriptions automatiques et un résumé en un paragraphe envoyé aux participants — sans uploader l’audio sur Otter.ai ou Zoom AI (qui envoient les données vers des serveurs américains).
Stack : Whisper (serveur HTTP local via whisper.cpp ou le package Python) + n8n pour l’orchestration + Ollama pour l’étape de synthèse.
Temps de déploiement : 25 minutes.
Étape 1 Démarrer un serveur Whisper HTTP local
L’approche la plus rapide est le serveur officiel whisper.cpp, qui expose un endpoint REST compatible avec le format OpenAI Audio API :
# Installer whisper.cpp (Mac/Linux)
brew install whisper-cpp # Mac avec Homebrew
# OU sur Linux :
git clone https://github.com/ggerganov/whisper.cpp
cd whisper.cpp && make
# Télécharger le modèle 'base' (~142 Mo, rapide sur CPU)
./models/download-ggml-model.sh base
# Démarrer le serveur HTTP sur le port 8080
./whisper-server -m models/ggml-base.bin --host 0.0.0.0 --port 8080
# Tester (uploader un fichier .wav ou .mp3)
curl http://localhost:8080/inference \
-F file="@reunion.mp3" \
-F temperature="0" \
-F response_format="json"Sortie attendue : un objet JSON avec un champ text contenant la transcription complète. Une réunion de 30 minutes avec un audio clair prend environ 90 secondes sur CPU (modèle base).
Étape 2 Construire le workflow n8n
Dans n8n, créez un workflow avec quatre nœuds. Importez le JSON ci-dessous via “Importer depuis JSON” dans le menu du canvas n8n :
{
"name": "Transcripteur + Synthèse de Réunions",
"nodes": [
{
"name": "Surveiller Dossier",
"type": "n8n-nodes-base.localFileTrigger",
"parameters": {
"path": "/home/utilisateur/reunions",
"events": ["add"],
"filter": "*.mp3,*.wav,*.m4a"
}
},
{
"name": "Transcrire avec Whisper",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "http://localhost:8080/inference",
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{ "name": "file", "value": "={{ $binary.data }}", "parameterType": "formBinaryData" },
{ "name": "response_format", "value": "json" },
{ "name": "temperature", "value": "0" }
]
}
}
},
{
"name": "Synthèse avec Ollama",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "http://localhost:11434/api/generate",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"model\": \"mistral:7b\", \"prompt\": \"Résume cette transcription de réunion en 3 points clés, puis liste les actions à suivre avec le nom du responsable :\\n\\n{{ $json.text }}\", \"stream\": false}"
}
},
{
"name": "Envoyer Email de Synthèse",
"type": "n8n-nodes-base.emailSend",
"parameters": {
"toEmail": "equipe@votreentreprise.com",
"subject": "=Synthèse de réunion — {{ $now.format('DD/MM/YYYY') }}",
"text": "={{ $json.response }}"
}
}
]
}localFileTrigger par un nœud emailReadImap pour traiter automatiquement les enregistrements de réunions reçus en pièce jointe par email. Configurez le nœud IMAP pour surveiller les emails avec l’objet “enregistrement réunion” et le type de pièce jointe audio/*.Étape 3 Tester avec un vrai enregistrement
Déposez n’importe quel fichier .mp3 ou .wav dans le dossier surveillé. En moins de 2 minutes (pour un enregistrement de 30 minutes), vous recevez un email avec un résumé en 3 points et une liste numérotée des actions à suivre. Précision sur un audio clair : 96 à 98%. Pour les accents prononcés (français d’Afrique de l’Ouest, arabe maghrébin), passez au modèle ggml-medium.bin — téléchargement ~1,5 Go, gain de précision ~12%.
Workflow 2 — Bot FAQ avec LangChain + Ollama (script Python de 50 lignes)
Cas d’usage : Votre équipe support répond aux mêmes 40 questions chaque semaine. Vous voulez un chatbot qui lit vos documents de politique interne et répond avec précision — sans halluciner des réponses non documentées.
Stack : Ollama (llama3.1:8b) + LangChain LCEL + ChromaDB (en mémoire pour les petites bases FAQ). Cette approche diffère de la configuration JSON n8n en vous donnant un contrôle total sur le template de prompt et le comportement de repli “je ne sais pas”.
Étape 1 Installer les dépendances et télécharger le modèle
# Créer un environnement virtuel
python3 -m venv faq-env && source faq-env/bin/activate
# Installer LangChain + intégration Ollama
pip install langchain-ollama langchain-chroma langchain-community
# Télécharger le modèle (4,7 Go, une seule fois)
ollama pull llama3.1:8b
# Vérifier qu'Ollama tourne
curl http://localhost:11434/api/tagsÉtape 2 Préparer votre document FAQ
Créez un fichier texte brut faq.txt avec vos paires Q&R. Le format n’a pas d’importance — LangChain le découpera et l’encodera automatiquement :
Q: Quelle est votre politique de retour ?
R: Nous acceptons les retours dans les 30 jours suivant l'achat. Les articles doivent être non utilisés et dans leur emballage d'origine. Contactez support@entreprise.com avec votre numéro de commande pour initier un retour.
Q: Livrez-vous en Afrique de l'Ouest ?
R: Oui. Nous livrons au Sénégal, en Côte d'Ivoire, au Ghana, au Nigeria et au Cameroun. La livraison prend 7 à 14 jours ouvrables. Les frais de douane sont à la charge de l'acheteur.
Q: Quels modes de paiement acceptez-vous ?
R: Nous acceptons Visa, Mastercard, Orange Money, Wave et virement bancaire (SEPA pour les clients UE). PayPal n'est pas disponible dans notre région.Étape 3 Le script complet du bot FAQ
# bot_faq.py — copiez et lancez : python bot_faq.py
from langchain_ollama import OllamaLLM, OllamaEmbeddings
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
# 1. Charger et découper le document FAQ
loader = TextLoader("faq.txt", encoding="utf-8")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)
# 2. Créer un index vectoriel en mémoire avec les embeddings Ollama
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(chunks, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 3. Définir le prompt — critique : inclure l'instruction de repli
PROMPT = ChatPromptTemplate.from_template("""
Vous êtes un assistant support utile. Répondez à la question du client
EN UTILISANT UNIQUEMENT les informations ci-dessous. Si la réponse
n'est pas dans le contexte, répondez exactement :
"Je n'ai pas cette information. Veuillez contacter support@entreprise.com."
Contexte :
{context}
Question : {question}
Réponse :""")
# 4. Construire la chaîne LCEL
llm = OllamaLLM(model="llama3.1:8b", temperature=0)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| PROMPT
| llm
| StrOutputParser()
)
# 5. Boucle interactive
print("Bot FAQ prêt. Tapez 'quitter' pour arrêter.\n")
while True:
question = input("Client : ").strip()
if question.lower() == "quitter":
break
response = chain.invoke(question)
print(f"Bot : {response}\n")nomic-embed-text : Il convertit vos chunks FAQ en vecteurs numériques pour que le retriever trouve les 3 chunks les plus pertinents pour chaque question client. Téléchargez-le une fois : ollama pull nomic-embed-text (274 Mo).temperature=0 est essentiel pour les bots FAQ — cela élimine la tendance du modèle à élaborer au-delà du document source. Des températures plus élevées génèrent des réponses créatives qui semblent plausibles mais contredisent vos politiques.Exemple de sortie
Client : Livrez-vous à Abidjan ?
Bot : Oui. Nous livrons en Côte d'Ivoire. La livraison prend 7 à 14 jours ouvrables.
Les frais de douane sont à la charge de l'acheteur.
Client : Puis-je payer en crypto-monnaie ?
Bot : Je n'ai pas cette information. Veuillez contacter support@entreprise.com.Workflow 3 — Assistant de connaissance PDF avec RAG
Cas d’usage : Votre équipe dispose de 30+ PDFs — contrats, procédures, spécifications techniques, politiques RH. Vous voulez poser des questions en langage naturel et obtenir des réponses avec les références de pages. Plus besoin de relire des documents entiers.
Stack : PyMuPDF (extraction de texte PDF) + LangChain + ChromaDB (persistant, survit aux redémarrages) + Ollama.
Étape 1 Installer et indexer vos PDFs
pip install pymupdf langchain-ollama langchain-chroma langchain-community
# indexer_pdfs.py — à lancer UNE SEULE FOIS pour construire la base de connaissance
import os
from langchain_community.document_loaders import PyMuPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_ollama import OllamaEmbeddings
from langchain_chroma import Chroma
DOSSIER_PDF = "./documents" # Placez vos PDFs ici
CHEMIN_DB = "./chroma_db" # Index vectoriel persistant
# Charger tous les PDFs du dossier
docs = []
for filename in os.listdir(DOSSIER_PDF):
if filename.endswith(".pdf"):
loader = PyMuPDFLoader(os.path.join(DOSSIER_PDF, filename))
docs.extend(loader.load())
print(f"Chargé {len(docs)} pages depuis {DOSSIER_PDF}")
# Découper avec chevauchement pour préserver le contexte entre les pages
splitter = RecursiveCharacterTextSplitter(chunk_size=600, chunk_overlap=80)
chunks = splitter.split_documents(docs)
print(f"Découpé en {len(chunks)} chunks")
# Encoder et persister (2 à 5 min pour 30 PDFs sur CPU)
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(
chunks,
embeddings,
persist_directory=CHEMIN_DB,
collection_name="docs_entreprise"
)
print(f"Indexé {len(chunks)} chunks dans {CHEMIN_DB}")Étape 2 Interroger la base de connaissance
# interroger_docs.py — à lancer pour poser des questions
from langchain_ollama import OllamaLLM, OllamaEmbeddings
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
CHEMIN_DB = "./chroma_db"
# Charger l'index persisté (pas de ré-indexation nécessaire)
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma(
persist_directory=CHEMIN_DB,
embedding_function=embeddings,
collection_name="docs_entreprise"
)
# Retourner 4 chunks avec leur fichier source et numéro de page
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
def formater_docs(docs):
parties = []
for d in docs:
source = d.metadata.get("source", "inconnu")
page = d.metadata.get("page", "?")
parties.append(f"[Source : {source}, Page {page}]\n{d.page_content}")
return "\n\n".join(parties)
PROMPT = ChatPromptTemplate.from_template("""
Vous êtes un assistant documentaire précis. Utilisez UNIQUEMENT les extraits
ci-dessous pour répondre. Citez toujours le fichier source et le numéro de page.
Si la réponse n'est pas dans les extraits, dites "Non trouvé dans les documents indexés."
Extraits :
{context}
Question : {question}
Réponse (avec citations des sources) :""")
llm = OllamaLLM(model="llama3.1:8b", temperature=0)
chain = (
{"context": retriever | formater_docs, "question": RunnablePassthrough()}
| PROMPT
| llm
| StrOutputParser()
)
print("Assistant de connaissance prêt. Tapez 'quitter' pour arrêter.\n")
while True:
question = input("Vous : ").strip()
if question.lower() == "quitter":
break
print(f"\nAssistant : {chain.invoke(question)}\n")Exemple de sortie
Vous : Quel est le délai de préavis pour la résiliation de contrat ?
Assistant : Le délai de préavis pour la résiliation de contrat est de
30 jours calendaires pour les personnels de catégorie A à C
et de 60 jours pour la catégorie D et au-dessus.
[Source : politique-rh-2026.pdf, Page 14]
Si l'une des parties ne respecte pas le préavis, une indemnité
compensatrice égale au salaire de base pour la durée du préavis
est due.
[Source : politique-rh-2026.pdf, Page 15]
Vous : Quelles sont les exigences de sécurité informatique pour le télétravail ?
Assistant : Les employés en télétravail doivent utiliser le VPN de l'entreprise
à tout moment pour accéder aux systèmes internes. L'authentification
à deux facteurs est obligatoire. Les appareils personnels nécessitent
une inscription MDM avant d'accéder à la messagerie professionnelle.
[Source : politique-securite-it.pdf, Page 3]Dépannage : 5 erreurs fréquentes et leurs solutions
1. Ollama retourne "connection refused"
Ollama ne tourne pas. Démarrez-le avec ollama serve dans un terminal (Mac/Linux) ou via l’icône dans la barre des tâches (Windows). Sur les serveurs Linux, activez le service systemd : sudo systemctl enable --now ollama.
2. Serveur Whisper : "model file not found"
Vous avez démarré le serveur en pointant vers un mauvais chemin de modèle. Le modèle doit se trouver dans le répertoire whisper.cpp/models/. Vérifiez avec : ls whisper.cpp/models/*.bin. Si vide, relancez le script de téléchargement : ./models/download-ggml-model.sh base.
3. ChromaDB "Embedding dimension mismatch"
Vous avez changé de modèle d’embedding après avoir créé l’index. Les vecteurs stockés ne correspondent plus aux dimensions du nouveau modèle. Solution : supprimez le dossier ./chroma_db et relancez indexer_pdfs.py avec le nouveau modèle.
4. LangChain retourne des réponses hallucinées absentes de vos documents
Le template de prompt manque de l’instruction de contrainte. Assurez-vous que votre prompt dit explicitement “Utilisez UNIQUEMENT les informations ci-dessous” et inclut l’instruction de repli. Vérifiez également que temperature=0 est défini sur le LLM — même des valeurs faibles (0,3) causent des dérives factuelles.
5. Le workflow n8n s’arrête après le nœud Whisper
Le fichier audio est envoyé comme URL au lieu de données binaires. Dans le nœud HTTP Request, activez “Envoyer des données binaires” et mappez le nom de la propriété binaire sur la sortie du nœud de déclenchement de fichier (par défaut : data). Consultez le journal d’exécution n8n pour l’erreur exacte — il affiche généralement la réponse HTTP 400 du serveur Whisper.
FAQ
Whisper a-t-il besoin d'un GPU pour transcrire les réunions en local ?
Non. Les modèles 'base' et 'small' de Whisper fonctionnent sur CPU. Une réunion de 30 minutes se transcrit en environ 4 minutes sur un laptop de 2020. Utilisez 'medium' ou 'large-v3' seulement si vous avez besoin d'une haute précision pour des accents prononcés — ces modèles nécessitent 6 à 8 Go de RAM et bénéficient d'un GPU.
Quel modèle Ollama fonctionne le mieux pour un bot FAQ en français ou en arabe ?
Pour le français, utilisez 'mistral:7b' ou 'llama3.1:8b' — les deux obtiennent plus de 85% sur les benchmarks de compréhension française. Pour l'arabe, 'aya:8b' (le modèle multilingue de Cohere) est la meilleure option open-source disponible via Ollama. Téléchargez-le avec : ollama pull aya:8b.
Comment gérer les PDFs scannés (images) dans le pipeline RAG ?
PyMuPDF n'extrait que le texte des PDFs numériques. Pour les documents scannés, ajoutez une étape OCR : installez 'pytesseract' et 'pdf2image', convertissez chaque page en image, puis lancez Tesseract OCR avant de passer le texte à LangChain. Autre option : 'marker-pdf' (open-source, GPU optionnel) gère les deux types de PDFs en une seule commande.
Puis-je déployer le workflow de synthèse de réunions n8n sur un serveur d'équipe partagé ?
Oui. Déployez n8n via Docker sur n'importe quel serveur avec 2 Go de RAM. Les trois composants (n8n, serveur HTTP Whisper, Ollama) tournent dans des conteneurs séparés sur la même machine. Utilisez le gestionnaire de credentials intégré à n8n pour sécuriser les clés. Un VPS à 20 EUR/mois gère 5 à 10 synthèses de réunions par jour sans problème de performance.
Quelle est la différence entre ce tutoriel et le bot FAQ avec configuration JSON n8n ?
L'approche JSON n8n est purement visuelle — aucun code requis, tout configuré dans le navigateur. L'approche LangChain Python de cet article donne plus de contrôle : templates de prompts personnalisés, mémoire de conversation, re-ranking des chunks récupérés, et possibilité d'ajouter des filtres (par exemple, répondre uniquement depuis les documents d'un département spécifique). Utilisez n8n pour la simplicité ; utilisez LangChain pour la personnalisation.
Combien de PDFs l'assistant ChromaDB peut-il gérer avant que les performances se dégradent ?
ChromaDB avec les embeddings 'all-MiniLM-L6-v2' gère 50 000 chunks de documents sans problème sur 8 Go de RAM. Un PDF typique de 200 pages génère environ 400 chunks (500 caractères chacun avec un chevauchement de 50 caractères). Vous pouvez donc indexer environ 125 PDFs avant de devoir passer à une installation serveur. Pour de plus grands corpus, passez à Qdrant avec ses capacités de filtrage.