Industrialiser l'IA : pgvector, Évaluation Ragas et RAG Agentique en Production

Dans le paysage actuel de l'intelligence artificielle, on entend souvent dire que "les données sont le nouveau pétrole". Mais pour un Data Scientist ou un MLOps Engineer, cette métaphore est incomplète. Si les données sont le pétrole, les embeddings sont le carburant raffiné qui permet aux moteurs des Large Language Models (LLM) de fonctionner. Pour comprendre pourquoi l'IA générative révolutionne nos industries, il faut descendre d'un étage et explorer la "langue maternelle" des algorithmes : le vecteur.

1.1 L'Ontologie du Vecteur : Traduire le monde en coordonnées

Un ordinateur, par nature, est une machine déterministe qui excelle dans le traitement des nombres mais échoue lamentablement face à l'ambiguïté du langage humain ou à la complexité d'une image brute. Pour combler ce fossé, nous utilisons les vecteurs. En apprentissage automatique, un vecteur est une collection ordonnée de valeurs numériques qui servent de coordonnées dans un espace multidimensionnel.

Prenons un exemple simple pour illustrer cette abstraction. Si vous deviez décrire un fruit à un algorithme, vous pourriez définir un vecteur à trois dimensions : [poids, taux_de_sucre, acidite]. Dans cet espace, une pomme Granny Smith pourrait être représentée par le vecteur [150, 10, 25], tandis qu'un citron serait [100, 2, 45]. La puissance de cette approche réside dans la géométrie. En calculant la distance entre ces deux points, l'algorithme peut quantifier mathématiquement à quel point ces deux objets sont "proches" ou "différents".

Cependant, pour les LLM, nous ne travaillons pas avec 3 dimensions, mais avec des milliers (par exemple, 1536 dimensions pour les modèles d'OpenAI). Chaque dimension capture une nuance subtile, souvent imperceptible pour l'homme, mais cruciale pour la machine.

1.2 La Forge des Embeddings : Du texte brut au sens profond

Il est crucial de faire une distinction technique : si tout embedding est un vecteur, tout vecteur n'est pas un embedding. Un vecteur peut être une simple liste de statistiques (comme notre exemple de fruit). Un embedding, en revanche, est le résultat d'un processus d'apprentissage profond (Deep Learning).

C'est ici qu'intervient la notion de similarité sémantique. Contrairement à un encodage classique (comme l'ASCII ou l'UTF-8) qui se contente de mapper un caractère à un code, l'embedding capture l'essence et la relation entre les objets. Lors de l'entraînement d'un modèle, ce dernier apprend à placer les mots ou les images qui partagent un contexte similaire dans des zones proches de son espace latent.

Voici comment nous extrayons ces représentations en Python en utilisant une bibliothèque standard :

from sentence_transformers import SentenceTransformer

# Chargement d'un modèle pré-entraîné sur HuggingFace
model = SentenceTransformer('all-MiniLM-L6-v2')

# Nos phrases à transformer
sentences = [
    "Le chat dort sur le canapé",
    "Un félin se repose sur le sofa",
    "Le processeur de l'ordinateur surchauffe"
]

# Génération des embeddings
embeddings = model.encode(sentences)

for i, embedding in enumerate(embeddings):
    print(f"Vecteur {i} (extrait) : {embedding[:5]}...")
    

Dans cet exemple, bien que les phrases 1 et 2 n'utilisent pas les mêmes mots ("chat" vs "félin", "dort" vs "se repose"), leurs embeddings seront extrêmement proches géométriquement car le modèle a appris que ces concepts sont sémantiquement interchangeables.

1.3 L'Espace Latent et l'Arithmétique Sémantique

L'une des propriétés les plus fascinantes des embeddings, découverte avec les travaux sur Word2Vec, est la capacité à effectuer des opérations algébriques sur le sens. Dans un espace d'embedding bien structuré, les relations entre les concepts sont préservées sous forme de vecteurs de translation.

L'exemple canonique est l'équation suivante :
Vecteur("Roi") - Vecteur("Homme") + Vecteur("Femme") ≈ Vecteur("Reine").

Cela démontre que le modèle a isolé la dimension "genre" et la dimension "royauté" de manière indépendante. Pour un Data Product Manager, comprendre cela est vital : cela signifie que votre système de recherche ou votre agent IA ne fait pas que du "matching" de texte, il manipule des concepts abstraits.

1.4 Ingénierie des caractéristiques et LLM

Pour les LLM modernes, le modèle d'embedding sert de couche d'entrée et de sortie. Lorsque vous posez une question, le LLM convertit votre texte en un flux d'embeddings. Ces représentations sont ensuite passées à travers des couches d'attention qui calculent l'importance relative de chaque concept par rapport aux autres.

Pourquoi est-ce une révolution pour le MLOps ? Auparavant, nous devions faire du "Feature Engineering" manuel (extraire des mots-clés, compter les fréquences avec TF-IDF). Aujourd'hui, nous déléguons cette extraction de caractéristiques au modèle d'embedding. Cependant, cela déplace le problème vers la gestion de l'infrastructure : comment stocker ces vecteurs ? Comment garantir que le modèle d'embedding utilisé pour l'indexation est le même que celui utilisé pour la requête ?

Ces questions nous amènent directement à la nécessité d'une infrastructure dédiée. Le simple stockage en mémoire ou dans une base de données relationnelle ne suffit plus dès lors que l'on dépasse le stade du prototype.

Nous avons vu que le vecteur est l'unité fondamentale de compréhension de l'IA. L'embedding est une représentation apprise qui capture la sémantique et permet une recherche basée sur le sens plutôt que sur les caractères. Mais manipuler ces vecteurs de haute dimension nécessite des outils spécifiques.

L'Infrastructure de Stockage — Vector Databases Deep Dive

Si la partie 1 nous a permis de comprendre la nature mathématique des données, la partie 2 s'attaque au défi de l'ingénierie : comment passer d'un simple tableau de nombres à une infrastructure capable de servir des millions d'utilisateurs avec une latence milliseconde ? Bienvenue dans le monde des Vector Databases (VDB).

2.1 La Rupture Technologique : Pourquoi vos bases SQL sont obsolètes ici

Une question revient souvent en comité d'architecture : "Pourquoi ne pas simplement ajouter une colonne 'vector' dans ma base PostgreSQL ?". La réponse tient en deux mots : Malédiction de la Dimensionnalité.

Dans une base de données relationnelle classique, l'indexation (B-Tree) fonctionne sur un ordre linéaire. Pour trouver une valeur, on divise l'espace de recherche en deux de manière récursive. Mais dans un espace à 1536 dimensions, la notion de "proximité" change radicalement. La recherche exacte du "plus proche voisin" (k-Nearest Neighbors) nécessite de calculer la distance entre votre vecteur de requête et chaque vecteur stocké. Sur 1 million de documents, c'est un suicide computationnel.

Les bases vectorielles ont été conçues pour résoudre ce problème en abandonnant la précision absolue au profit de la rapidité via les algorithmes ANN (Approximate Nearest Neighbors).

2.2 L'Indexation HNSW : Le cerveau des bases vectorielles

L'algorithme le plus performant aujourd'hui est le HNSW (Hierarchical Navigable Small World). Imaginez une structure de graphe en couches successives. La couche supérieure contient peu de points (les "autoroutes"). On y trouve rapidement la zone globale de notre vecteur. Puis, on descend dans les couches inférieures pour affiner la recherche parmi des points plus denses.

Voici comment on configure un index HNSW (exemple conceptuel sur Qdrant) :

# Configuration d'une collection avec index HNSW
import qdrant_client
from qdrant_client.http import models

client = qdrant_client.QdrantClient(host="localhost", port=6333)

client.recreate_collection(
    collection_name="articles_blog",
    vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
    hnsw_config=models.HnswConfigDiff(
        m=16, # Nombre de liens par nœud
        ef_construct=100, # Précision lors de la création
        full_scan_threshold=10000
    )
)
    

Concrètement, l'implémentation de HNSW s'est tellement démocratisée qu'il n'est plus nécessaire d'utiliser des outils de niche. Sous PostgreSQL (via l'extension pgvector), la création d'un index HNSW pour optimiser les requêtes sur vos embeddings se fait avec une simple instruction SQL :

-- Création d'un index HNSW utilisant la distance Cosinus
CREATE INDEX ma_table_hnsw_idx 
ON ma_table 
USING hnsw (embedding vector_cosine_ops) 
WITH (m = 16, ef_construction = 64);

Les paramètres m (nombre de connexions par nœud) et ef_construction (taille de la file d'attente lors de la création) illustrent parfaitement le compromis entre la précision du rappel (recall) et l'empreinte mémoire, une préoccupation quotidienne en MLOps.

Excellente initiative. Pour boucler la boucle et illustrer concrètement le pipeline d'ingestion et de recherche sémantique, voici un script Python complet prêt pour la production (ou presque).

Ce script fait le pont entre le monde de la Data Science (Génération d'embeddings avec `sentence_transformers`) et le monde du Data Engineering (Stockage et indexation HNSW dans PostgreSQL via `psycopg2` et la surcouche `pgvector`).

Prérequis d'environnement

Avant de lancer le script, assurez-vous d'avoir installé les librairies requises dans votre environnement virtuel :

pip install sentence-transformers psycopg2-binary pgvector

Le Code d'Intégration

Voici comment orchestrer l'ensemble. Notez la dimension 384 de notre colonne vectorielle : c'est la taille de sortie exacte du modèle all-MiniLM-L6-v2.

import psycopg2
from pgvector.psycopg2 import register_vector
from sentence_transformers import SentenceTransformer

# ---------------------------------------------------------
# 1. Modélisation et génération des Embeddings (Data Science)
# ---------------------------------------------------------
model = SentenceTransformer('all-MiniLM-L6-v2')

# Nos documents textuels bruts
sentences = [
    "Le chat dort sur le canapé",
    "Un félin se repose sur le sofa",
    "Le processeur de l'ordinateur surchauffe"
]

print("Génération des embeddings en cours...")
embeddings = model.encode(sentences)

# ---------------------------------------------------------
# 2. Connexion à PostgreSQL (Data Engineering / MLOps)
# ---------------------------------------------------------
# Remplacez les credentials par ceux de votre base de données locale ou distante
conn = psycopg2.connect(dbname="postgres", user="postgres", password="votre_mot_de_passe", host="localhost")
cur = conn.cursor()

# Activation de l'extension et enregistrement du type vectoriel pour psycopg2
cur.execute("CREATE EXTENSION IF NOT EXISTS vector;")
register_vector(conn)

# ---------------------------------------------------------
# 3. Préparation du Schéma (DDL)
# ---------------------------------------------------------
cur.execute("DROP TABLE IF EXISTS documents;")

# Le modèle all-MiniLM-L6-v2 génère des vecteurs de dimension 384
cur.execute("""
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    content TEXT,
    embedding VECTOR(384)
);
""")

# ---------------------------------------------------------
# 4. Ingestion des données (ETL)
# ---------------------------------------------------------
# Insertion par lots (batch) dans un scénario réel, ici itératif pour l'exemple
for sentence, embedding in zip(sentences, embeddings):
    cur.execute(
        "INSERT INTO documents (content, embedding) VALUES (%s, %s);",
        (sentence, embedding) # psycopg2 convertit automatiquement l'array numpy grâce à register_vector
    )

# ---------------------------------------------------------
# 5. Construction de l'Index HNSW
# ---------------------------------------------------------
print("Construction du graphe HNSW en base...")
cur.execute("""
CREATE INDEX documents_hnsw_idx ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
""")
conn.commit()

# ---------------------------------------------------------
# 6. Cas d'usage : Requête de Recherche Sémantique
# ---------------------------------------------------------
# Une requête utilisateur qui n'a aucun mot en commun avec nos documents
query = "Mon animal de compagnie fait la sieste"
query_embedding = model.encode(query)

print(f"\n--- Recherche Sémantique pour : '{query}' ---")

# Requête SQL calculant la similarité cosinus (1 - distance)
# Le moteur Postgres utilisera automatiquement notre index HNSW
cur.execute("""
SELECT content, 1 - (embedding <=> %s) AS similarity
FROM documents
ORDER BY embedding <=> %s
LIMIT 2;
""", (query_embedding, query_embedding))

for row in cur.fetchall():
    print(f"Document trouvé : '{row[0]}' | Similarité : {row[1]:.4f}")

# Clôture propre des connexions
cur.close()
conn.close()

Que se passe-t-il concrètement lors de l'exécution ?

  1. Vectorisation transparente : La librairie Python `pgvector` s'interface avec `psycopg2` via `register_vector()`. Cela permet d'envoyer directement les arrays Numpy générés par HuggingFace vers PostgreSQL, sans avoir à les transformer manuellement en chaînes de caractères.
  2. Distance Cosinus : Dans la requête SQL finale, l'opérateur `<=>` calcule la distance Cosinus. En soustrayant ce résultat à 1 (`1 - distance`), on obtient un score de similarité intuitif (plus il est proche de 1, plus les concepts sont sémantiquement liés).
  3. Magie Sémantique : Bien que la phrase "Mon animal de compagnie fait la sieste" ne partage presque aucun mot-clé avec "Le chat dort sur le canapé", le modèle d'embedding capture le contexte, et l'index HNSW de PostgreSQL nous remonte le bon résultat instantanément.

2.3 Benchmarking : Choisir sa stack selon le profil MLOps

Le marché est saturé, mais quatre solutions se détachent pour un profil Data Product Manager soucieux du ROI et de la maintenabilité :

  • Pinecone : Le choix "Serverless". Idéal si vous n'avez pas d'équipe DevOps dédiée. Vous payez à l'usage, et Pinecone gère toute la complexité de l'indexation et du passage à l'échelle.
  • Weaviate : L'approche "Data Object". Elle stocke les vecteurs mais aussi les objets JSON associés. Son grand point fort est la recherche hybride (Vecteurs + Texte classique).
  • PostgreSQL (pgvector) : L'approche "Tout-en-un" et pragmatique. Elle permet de stocker vos embeddings directement à côté de vos données relationnelles existantes sans ajouter de nouvelle brique d'infrastructure. Son grand point fort est de garantir les transactions ACID et d'offrir un filtrage hybride natif redoutable (requêtes SQL classiques combinées à la recherche vectorielle).
  • Chroma DB : Le roi du prototypage. Open-source, elle s'intègre en deux lignes de code. Parfaite pour valider un MVP avant de migrer vers une solution plus robuste.
  • Qdrant / Milvus : Les solutions haute performance. Écrites en Rust ou Go, elles sont destinées aux environnements où la latence et l'optimisation de la mémoire vive (RAM) sont critiques.

Analyse comparative : pgvector vs Bases Vectorielles Natives

En production, le choix du moteur de recherche vectoriel déclenche souvent un débat passionné entre l'équipe Data Science et les Data Engineers. Faut-il déployer un moteur spécialisé ou faire évoluer le socle relationnel existant ? Confrontons PostgreSQL (via pgvector) aux bases vectorielles natives (Milvus, Qdrant).

Critère (KPIs MLOps) PostgreSQL (pgvector) Vector DBs Natives (Milvus, Qdrant)
Simplicité d'Architecture Maximale. Pas de nouvelle brique infra. Transactions ACID garanties. Complexe. Nécessite de maintenir un cluster séparé et de synchroniser les données.
Filtrage Hybride Natif et parfait. Jointures SQL classiques (JOIN, WHERE) avec la recherche vectorielle. Souvent géré via des métadonnées dupliquées (payloads). Risque de désynchronisation.
Scalabilité & RAM Limitée par les ressources du serveur Postgres (Scale-up vertical). Idéal jusqu'à ~10-20 millions de vecteurs. Conçues pour le Sharding et le calcul distribué (Scale-out horizontal). Taillées pour les milliards de vecteurs.
Optimisation Hardware Standard (dépend du CPU général). Ultra-optimisée (Rust/Go/C++), instructions SIMD, accélération GPU native.

Le verdict du terrain :

  • Choisissez PostgreSQL (pgvector) si votre application (catalogue e-commerce, base documentaire interne) traite quelques millions de vecteurs et que vous avez besoin d'appliquer des règles de gestion métiers strictes (stocks, droits d'accès) en temps réel. Le gain de temps sur la maintenance de l'infrastructure (Time-to-Market) compense largement la légère différence de performance brute.
  • Passez sur une base native (Milvus, Qdrant) si la recherche sémantique est le cœur absolu de votre produit (ex: moteur de recherche IA massif, reconnaissance d'images à l'échelle mondiale) et que votre volumétrie dépasse les dizaines de millions d'embeddings. L'empreinte RAM de l'algorithme HNSW imposera alors de distribuer la charge sur plusieurs nœuds.

2.4 Scalabilité et "Product Management" des Vecteurs

En production, stocker des vecteurs coûte cher car les index ANN doivent souvent résider en RAM pour être performants. Un DPM doit anticiper ces coûts :

  1. Quantification : Technique consistant à réduire la précision des nombres (de Float32 à Int8) pour diviser par 4 l'empreinte mémoire.
  2. Multitenancy : Comment isoler les données de vos clients dans une même base vectorielle sans risquer de fuite d'information.
  3. Persistance : S'assurer que votre base peut reconstruire ses index rapidement après un crash.
Nous avons quitté le monde du SQL pour entrer dans celui de la recherche de proximité. Choisir une VDB n'est pas qu'une affaire de performance brute, c'est un arbitrage entre coût opérationnel (Ops) et flexibilité de recherche. Maintenant que notre "mémoire" est installée, il est temps de lui apprendre à discuter avec un LLM.

Le Workflow RAG — Donner une mémoire vive à l'IA

Après avoir compris la nature des vecteurs (partie 1) et l'infrastructure nécessaire pour les stocker (Partie 2), nous arrivons au cœur de l'application pratique : le RAG (Retrieval-Augmented Generation). Pour un Data Product Manager, le RAG est la clé pour transformer un gadget de chat en un outil métier fiable, capable de citer ses sources et de ne pas inventer de faits.

3.1 Le Paradigme "Livre Ouvert" : Résoudre l'hallucination

Le principal défaut des LLM est leur nature statique. Une fois entraînés, leurs connaissances sont figées à une date précise (le cutoff). De plus, face à une absence d'information, ils ont tendance à "halluciner" une réponse plausible mais fausse.

Le RAG change la donne. Au lieu de demander au modèle de puiser dans sa mémoire interne, on lui fournit un contexte pertinent extrait d'une base de données externe juste avant qu'il ne génère sa réponse. C'est l'équivalent de passer d'un examen de mémoire pure à un examen "livre ouvert".

3.2 Anatomie d'un Pipeline RAG : De la donnée brute au Prompt

L'implémentation d'un système RAG robuste suit un processus rigoureux en trois étapes :

  1. Retrieval (Récupération) : Lorsqu'une requête arrive, le système transforme la question en embedding et interroge la Base de Données Vectorielle pour extraire les $k$ segments de texte les plus proches sémantiquement.
  2. Augmentation : On "augmente" le prompt original. Au lieu d'envoyer simplement la question, on construit une instruction complexe incluant les documents trouvés.
  3. Generation (Génération) : Le LLM traite ce prompt enrichi pour produire une réponse argumentée.

Le défi du Chunking

En tant qu'ingénieur, vous devez décider comment découper vos documents (le chunking). Un chunk trop petit perd le contexte ; un chunk trop grand dilue le signal sémantique et dépasse la fenêtre de contexte du LLM. Une stratégie courante est le découpage par paragraphes avec un "overlap" (chevauchement) pour maintenir la continuité du sens.

3.3 RAG vs Fine-Tuning : L'arbitrage stratégique

C'est le débat favori des architectes IA. Voici comment trancher selon vos objectifs :

Critère RAG Fine-Tuning
Données dynamiques Excellent : mise à jour instantanée. Médiocre : nécessite un réentraînement.
Transparence Élevée : peut citer précisément ses sources. Nulle : c'est une "boîte noire".
Coût d'entrée Faible à modéré (coût de la VDB). Élevé (GPU, ingénierie de données).
Usage cible Base de connaissances, support client. Style, ton, jargon très spécifique.

3.4 L'Hybridation et les Agents (Focus Tavily)

Le RAG ne se limite pas à vos documents internes. On parle de plus en plus d'Agentic RAG ou de Web-RAG. Des outils comme Tavily permettent à l'IA d'aller chercher des informations sur le web en temps réel pour augmenter sa réponse.

L'astuce de cador consiste à faire du Hybrid Search : combiner la puissance des vecteurs pour le sens et la puissance du BM25 (mots-clés classiques) pour les termes techniques ou les noms propres qui pourraient être "écrasés" par le modèle d'embedding.

# Exemple de prompt "augmenté" type
prompt = f"""
Utilise les extraits suivants pour répondre à la question. 
Si la réponse n'est pas dans le contexte, dis poliment que tu ne sais pas.

CONTEXTE :
{extraits_de_la_base_vectorielle}

QUESTION :
{requete_utilisateur}

RÉPONSE :
"""
    

Jusqu'à présent, nous avons bâti un système RAG (Retrieval-Augmented Generation) s'appuyant sur une base de données vectorielle interne (comme notre index HNSW sous PostgreSQL). Bien que robuste, cette architecture souffre d'une limitation inhérente : la péremption des données. Votre base vectorielle est statique. Si un utilisateur pose une question sur un événement survenu hier, ou sur la toute dernière documentation d'une librairie Python, votre index interne restera muet (ou pire, le LLM hallucina).

C'est ici qu'intervient le concept d'Hybridation Agentique. Au lieu d'utiliser le LLM comme un simple générateur de texte, nous le transformons en un Agent de Raisonnement. L'Agent est capable d'analyser la question et de décider : "Dois-je chercher dans la base de données interne de l'entreprise (pgvector), ou dois-je interroger le Web en temps réel pour obtenir des informations fraîches ?"

Le problème des API de recherche classiques

Historiquement, pour connecter un LLM au web, les ingénieurs utilisaient les API Google Custom Search ou Bing. Le problème sur le terrain ? Ces API sont conçues pour des humains. Elles renvoient des URLs et des méta-descriptions remplies de balises HTML, de publicités et de contenu optimisé pour le SEO. Un LLM perd un temps d'inférence précieux (et beaucoup de tokens) à essayer d'extraire le sens de ce bruit numérique.

La solution Tavily : Une API de recherche construite POUR les LLMs

Pour des pipelines MLOps exigeants, la solution réside dans des outils spécialisés comme Tavily. Tavily n'est pas un simple moteur de recherche ; c'est une API d'extraction et d'agrégation conçue spécifiquement pour les Agents IA. En une seule fraction de seconde, Tavily va :

  • Exécuter la requête sur de multiples sources.
  • Visiter les sites web en arrière-plan.
  • Nettoyer le HTML, supprimer les pop-ups et le bruit.
  • Renvoyer un contenu pur (souvent en Markdown) que votre LLM peut ingérer instantanément comme contexte.

Exemple minimaliste : Un appel Tavily en Python

Voici comment un Agent pourrait utiliser l'outil Tavily pour récupérer un contexte ultra-frais avant de générer sa réponse finale :

import os
from tavily import TavilyClient

# Initialisation du client (nécessite une clé API)
tavily_client = TavilyClient(api_key=os.environ.get("TAVILY_API_KEY"))

# L'utilisateur pose une question nécessitant des données récentes
query = "Quelles sont les dernières fonctionnalités de la version 0.6.0 de pgvector ?"

print("Recherche Web en cours via Tavily...")

# Exécution de la recherche optimisée pour l'IA
response = tavily_client.search(
    query=query,
    search_depth="advanced", # Permet un scraping profond des pages trouvées
    max_results=2
)

# Affichage du contexte extrait, prêt à être injecté dans le prompt du LLM
for result in response['results']:
    print(f"\nURL Source : {result['url']}")
    print(f"Contenu purifié : {result['content'][:200]}...")

Dans un système en production, la chaîne de caractères `result['content']` est directement concaténée au prompt de votre LLM, lui offrant une "vision" en temps réel d'Internet sans saturer sa fenêtre de contexte.

🤖 Teasing : L'ère des Agents arrive

Ce script illustre l'utilisation brute de l'outil. Mais comment le modèle prend-il la décision autonome d'utiliser cet outil plutôt qu'un autre ? Comment gère-t-il les erreurs si le site web est inaccessible ? Comment boucle-t-il son raisonnement (boucle ReAct) ?

C'est précisément l'enjeu du passage du RAG classique au RAG Agentique. L'orchestration de ces comportements complexes à l'aide de frameworks comme LangGraph, AutoGen ou CrewAI fera l'objet de notre prochain article de fond complet dédié aux Agents IA en production. Restez connectés sur Aventures Data, car l'ingénierie logicielle est en train de muter !

Le RAG est le pont entre vos données et l'intelligence du modèle. Il offre la précision, l'actualité et la transparence qui manquent aux LLM bruts. Mais attention : un bon RAG dépend de la qualité de vos embeddings et de la propreté de vos données. C'est ce que nous allons voir dans la prochaine partie dédié au MLOps.

MLOps & Data Engineering — Industrialiser le cycle de vie des Vecteurs

Passer d'un notebook expérimental à une application de production exige une rigueur que seul le MLOps peut apporter. Dans cette partie 4, nous sortons de la pure sémantique pour entrer dans l'ingénierie lourde : comment garantir la cohérence de vos données dans le temps et automatiser la maintenance de votre stack vectorielle.

4.1 Data Contracts : La fin du chaos entre Embedding et Stockage

Le risque majeur en production est le "désalignement". Si votre pipeline d'ingestion utilise un modèle d'embedding (ex: text-embedding-3-small) et que votre API de requête utilise par erreur une version différente, les distances calculées par la base vectorielle n'auront plus aucun sens.

L'implémentation de Data Contracts est ici vitale. Un contrat de données définit strictement :

  • Le modèle source : Nom et version exacte de l'encodeur.
  • La dimensionnalité : Toute variation doit bloquer le déploiement (ex: forcer 1536 dimensions).
  • La normalisation : Si votre base attend des vecteurs normalisés pour la similarité cosinus, votre pipeline doit le garantir en amont.

Voici un exemple de code concret qui valide les trois critères mentionnés dans le texte (Modèle source, Dimensionnalité, et Normalisation) en reprenant le modèle `all-MiniLM-L6-v2` (dimension 384) :

import numpy as np
from pydantic import BaseModel, Field, field_validator
from typing import List

class EmbeddingDataContract(BaseModel):
    # 1. Le modèle source : Nom et version exacte forcés
    # On empêche l'injection d'un embedding généré par un autre modèle (ex: OpenAI)
    model_name: str = Field(..., pattern=r"^all-MiniLM-L6-v2$")
    model_version: str = Field(..., pattern=r"^1\.0\.0$")

    # Le contenu textuel original
    content: str = Field(..., min_length=1)

    # 2. La dimensionnalité : Le vecteur doit être une liste de nombres flottants
    embedding: List[float]

    @field_validator('embedding')
    def check_dimensionality(cls, vector):
        expected_dim = 384  # Dimension exacte pour all-MiniLM-L6-v2
        if len(vector) != expected_dim:
            raise ValueError(f"Dimensionnalité incorrecte. Attendue : {expected_dim}, Reçue : {len(vector)}")
        return vector

    # 3. La normalisation : Vérifier si la norme mathématique est égale à 1
    # Crucial si la base vectorielle utilise la similarité cosinus
    @field_validator('embedding')
    def check_normalization(cls, vector):
        norm = np.linalg.norm(vector)
        # On utilise isclose pour gérer les approximations des nombres flottants
        if not np.isclose(norm, 1.0, atol=1e-4):
            raise ValueError(f"Le vecteur n'est pas normalisé (L2). Norme actuelle : {norm:.4f}")
        return vector

# --- Test du Contrat de Données ---

# Création d'un vecteur factice parfaitement normalisé de dimension 384
dummy_vector = [1.0 / np.sqrt(384)] * 384

payload_valide = {
    "model_name": "all-MiniLM-L6-v2",
    "model_version": "1.0.0",
    "content": "Le processeur de l'ordinateur surchauffe",
    "embedding": dummy_vector
}

try:
    # Le contrat analyse et valide le dictionnaire
    validated_data = EmbeddingDataContract(**payload_valide)
    print("✅ Contrat respecté : L'embedding peut être inséré dans pgvector/Pinecone.")
except ValueError as e:
    print(f"❌ Rejeté par le contrat : {e}")

Que se passe-t-il concrètement en production ?

  1. Désalignement bloqué : Si un développeur met à jour le code d'ingestion et génère par erreur des vecteurs de dimension 1536 (ex: avec un modèle OpenAI) au lieu de 384, la classe `EmbeddingDataContract` lèvera une erreur immédiate. L'insertion en base n'aura pas lieu.
  2. Sécurité mathématique : Si le vecteur n'est pas normalisé, le calcul de la distance Cosinus dans PostgreSQL (via `<=>`) donnerait des résultats faussés. Le validateur `check_normalization` agit comme un bouclier mathématique.
  3. Traçabilité : En imposant les champs `model_name` et `model_version`, le contrat s'assure que vous savez exactement d'où vient la donnée. C'est indispensable pour anticiper la "Migration Sémantique" évoquée dans le paragraphe 4.2.

4.2 Le Versioning des Embeddings : Gérer la "Migration Sémantique"

Que se passe-t-il si un nouveau modèle d'embedding sort, promettant 20% de performance en plus ? Contrairement à une base SQL où l'on modifie un schéma, ici, vous devez ré-indexer l'intégralité de votre base.

Stratégie de cador (Blue-Green Deployment) :

  1. Créer une nouvelle collection (Collection_B) dans votre VDB.
  2. Relancer l'ingestion de tous vos documents avec le nouveau modèle.
  3. Une fois l'indexation terminée, basculer le trafic de l'API de Collection_A vers Collection_B.
  4. Supprimer l'ancienne collection pour optimiser les coûts de RAM.

4.3 CI/CD pour le RAG : Évaluer avant de déployer

On ne déploie pas un système RAG sans un pipeline de validation automatisé. Le défi est de mesurer la qualité de la "récupération" (Retrieval).

Utilisez des métriques spécifiques comme le Recall@K (est-ce que le document pertinent est dans les K premiers résultats ?) ou le MRR (Mean Reciprocal Rank). Des outils comme Ragas ou TruLens permettent d'automatiser ces tests au sein de votre CI/CD.

# Exemple de test de validation de dimensionnalité dans un pipeline CI
def test_embedding_dimension(sample_text, expected_dim=1536):
    vector = model.encode(sample_text)
    assert len(vector) == expected_dim, f"Erreur: Dimension attendue {expected_dim}, reçue {len(vector)}"
    

Le paragraphe 4.3 de l'article souligne l'importance d'automatiser l'évaluation du système de "Retrieval" (récupération de l'information) avant tout déploiement.
En MLOps, pour qu'un pipeline CI/CD puisse valider automatiquement une nouvelle version de votre modèle d'embedding ou de votre stratégie de chunking, il exécute des requêtes de test automatisées sur un jeu de données de référence (un Golden Dataset).
Pour chaque requête, le pipeline sait exactement quel(s) document(s) la base vectorielle est censée remonter. Voici comment les métriques citées interviennent dans ce processus.

1. Le Recall@K (Rappel à K)

Le Recall@K vérifie une condition simple : le document pertinent est-il présent dans les K premiers résultats retournés par la recherche ?. En RAG, `K` correspond généralement au nombre maximum de blocs de texte que vous êtes prêt à injecter dans le prompt de votre LLM (par exemple, 3, 5 ou 10).

Exemple concret :
Supposons que vous cherchiez à récupérer le document exact sur "la configuration de pgvector". Vous avez configuré votre base vectorielle pour renvoyer 5 résultats (K=5).

  1. Rang 1 : Texte sur l'installation de Postgres.
  2. Rang 2 : Texte sur les index HNSW.
  3. Rang 3 : Texte contenant la configuration de pgvector (le bon document !).
  4. Rang 4 : Texte sur la distance Cosinus.
  5. Rang 5 : Texte sur la fonction de coût.
Calcul des métriques :
  1. Recall@5 : Le bon document est-il dans le Top 5 ? Oui. Le score pour cette requête est de 1 (soit 100%).
  2. Recall@1 : Le bon document est-il dans le Top 1 ? Non. Le score est de 0.
Application en CI/CD : Si une Pull Request modifie l'algorithme de découpage du texte (chunking) et fait chuter le Recall@5 moyen de 95 % à 70 % sur vos données de test, le pipeline échoue et empêche le déploiement en production.

2. Le MRR (Mean Reciprocal Rank - Rang Réciproque Moyen)

Là où le Recall@K se contente d'un "oui" ou "non", le MRR est plus sévère : il évalue à quel point la base vectorielle classe bien l'information pertinente.
Plus le bon document apparaît tôt (proche du rang 1), plus le score est élevé.

La formule calcule l'inverse du rang (1/rang) du tout premier document pertinent rencontré.
Exemple concret sur un jeu de test de 3 questions :

  1. Question 1 : Le document pertinent est trouvé en 1ère position.
  2. Score de la requête = 1/1 = 1.0
  3. Question 2 : Le document pertinent est trouvé en 3ème position.
  4. Score de la requête = 1/3 = 0.33
  5. Question 3 : Le document pertinent n'est pas trouvé parmi les résultats.
  6. Score de la requête = 0.0
Calcul du MRR : On calcule la moyenne globale de ces scores : (1.0 + 0.33 + 0.0) / 3 = 0.44.

Pourquoi combiner les deux dans Ragas ou TruLens ?

Comme le mentionne l'article, des outils de validation comme Ragas ou TruLens calculent ces scores.
Ils sont complémentaires pour garantir la fiabilité du RAG :

  • Le Recall@K est vital car si le document n'est pas récupéré, le LLM n'aura tout simplement pas l'information pour répondre (risque d'hallucination).
  • Le MRR est crucial car les LLMs souffrent souvent du phénomène de "Lost in the Middle" : ils retiennent mieux les informations situées au tout début ou à la toute fin de leur contexte. Un MRR élevé garantit que l'information la plus vitale sera injectée en premier, maximisant la précision de la réponse générée.

Imaginez que votre jeu de test CI/CD contienne 100 questions différentes. Le pipeline va exécuter ces 100 requêtes et calculer le Recall@5 binaire (1 ou 0) pour chacune d'entre elles.

  • Pour 95 questions, le document pertinent est bien remonté dans le Top 5. (Score = 1)
  • Pour 5 questions, le système s'est trompé, le document n'est pas dans le Top 5. (Score = 0)
Le Recall@5 moyen est la moyenne de tous ces résultats individuels : ((95 × 1) + (5 × 0)) / 100 = 0,95
On multiplie par 100 pour l'exprimer en pourcentage, ce qui donne 95 %.
Un Recall@5 moyen de 95 % ne veut donc pas dire qu'un document est "à 95 % présent". Cela signifie que votre moteur de recherche réussit à trouver la bonne information pour 95 % des questions testées. Les 5 % restants représentent les failles de votre modèle (les questions pour lesquelles il a échoué à remonter le bon contexte pour le LLM).

Pour utiliser Ragas (Retrieval Augmented Generation Assessment), il faut comprendre son principe fondamental : il utilise l'approche "LLM-as-a-Judge" (un LLM en tant que juge). Au lieu d'avoir des humains qui notent la qualité des résultats, Ragas demande à un modèle performant (comme GPT-4) d'évaluer les performances de votre pipeline RAG de manière automatisée.

Pour fonctionner, Ragas a besoin que vous lui fournissiez un jeu de données (un Dataset) contenant généralement 4 éléments pour chaque test :

  1. question : La question posée par l'utilisateur.
  2. contexts : La liste des textes que votre base vectorielle a remontés c.a.d. la réponse générée par votre système RAG actuel en réponse à cette question.
  3. answer : La réponse finale générée par votre LLM c.a.d. la liste des segments de texte (chunks) que votre système RAG a récupérés de la base de connaissances pour générer cette réponseanswer
  4. ground_truth : La réponse idéale attendue (la "vérité terrain").

Les métriques clés de Ragas pour évaluer votre RAG

Ragas propose plusieurs métriques. Concentrons-nous sur les plus importantes pour évaluer à la fois la génération et la récupération.

1. Évaluation de la qualité de la génération (Le "G" de RAG)

Ces métriques évaluent la réponse (answer) produite par le LLM, en la comparant à la question (question) et au contexte (contexts) qui lui a été fourni.

  • faithfulness (Fidélité)
    Objectif : Mesurer si la réponse générée s'appuie exclusivement sur les informations présentes dans les contexts fournis. Un score faible (proche de 0) indique que la réponse contient des informations non sourcées ou inventées (hallucinations). Un score élevé (proche de 1) signifie que la réponse est bien ancrée dans le contexte.
    Calcul (Simplifié) : Ragas identifie les affirmations clés dans la answer et vérifie si chacune peut être directement justifiée par une partie des contexts.

  • answer_relevancy (Pertinence de la Réponse)
    Objectif : Mesurer si la answer est pertinente par rapport à la question initiale. Une réponse peut être parfaitement fidèle au contexte (faithfulness élevé) mais répondre complètement à côté de la plaque.
    Calcul (Simplifié) : Ragas évalue la pertinence sémantique (le sens) entre la question et la answer, souvent en utilisant des embeddings ou un LLM pour juger si la réponse aborde le sujet de la question. Un score élevé (proche de 1) est souhaité.

2. Évaluation de la qualité de la récupération (Le "R" de RAG)

Ces métriques évaluent l'efficacité de votre module de recherche (retriever) : a-t-il récupéré les bons contexts pour répondre à la question ?

  • context_precision (Précision du Contexte)
    Objectif : Mesurer la proportion d'informations pertinentes parmi les contexts récupérés. Est-ce que les documents/chunks remontés sont majoritairement utiles pour répondre à la question, ou y a-t-il beaucoup de "bruit" non pertinent ?
    Calcul (Simplifié) : Ragas évalue, pour chaque segment dans contexts, s'il est réellement pertinent pour la question. Un score élevé (proche de 1) signifie peu de bruit.

  • context_recall (Rappel du Contexte)
    Objectif : Mesurer si toutes les informations nécessaires pour répondre complètement à la question ont bien été récupérées dans les contexts. Est-ce qu'on a manqué des informations cruciales qui se trouvaient pourtant dans la base de connaissances ?
    Calcul (Simplifié) : C'est là que la ground_truth (vérité terrain) est essentielle. Ragas compare les informations présentes dans la ground_truth avec celles trouvées dans les contexts pour voir si tout le nécessaire a été récupéré. Sans ground_truth, l'estimation est beaucoup moins fiable. Un score élevé (proche de 1) indique que le retriever a bien retrouvé les éléments essentiels.

  • context_relevancy (Pertinence du Contexte)
    Objectif : Similaire à context_precision, mais se concentre davantage sur la pertinence globale du contenu des contexts par rapport à la question. Mesure à quel point les segments récupérés sont ciblés.
    Calcul (Simplifié) : Évalue la pertinence sémantique entre la question et l'ensemble des contexts récupérés.

Ensemble, ces métriques nous donnent une vue détaillée des forces et faiblesses de chaque étape de notre pipeline RAG.

Voici un exemple complet et exécutable en Python montrant comment évaluer un pipeline RAG.

Le Code Python (Exemple avec Ragas)

import os
from datasets import Dataset
from ragas import evaluate
from ragas.metrics import (
    context_recall,      # Évalue si les informations nécessaires ont été récupérées
    context_precision,   # Évalue si les bonnes informations sont bien classées (lié au MRR)
    faithfulness,        # Évalue les hallucinations (la réponse est-elle fidèle au contexte ?)
    answer_relevancy     # Évalue si la réponse répond bien à la question posée
)

# Ragas utilise un LLM (par défaut OpenAI) pour faire les évaluations mathématiques
os.environ["OPENAI_API_KEY"] = "votre-cle-api-openai"

# 1. Préparation du jeu de données (simulation de ce que votre RAG a produit)
data_samples = {
    "question": [
        "Comment activer l'extension pgvector dans PostgreSQL ?",
        "Quelle est la dimension du modèle all-MiniLM-L6-v2 ?"
    ],
    "contexts": [
        # Contextes remontés pour la question 1
        [
            "PostgreSQL est un système de gestion de base de données relationnelle.",
            "Pour utiliser les vecteurs, exécutez 'CREATE EXTENSION vector;' dans votre base PostgreSQL."
        ],
        # Contextes remontés pour la question 2 (Ici, le RAG s'est trompé de contexte !)
        [
            "Les modèles OpenAI text-embedding-ada-002 ont une dimension de 1536.",
            "La similarité cosinus est très utilisée en Machine Learning."
        ]
    ],
    "answer": [
        # Réponse générée par le LLM pour la question 1
        "Il suffit de taper la commande CREATE EXTENSION vector; dans la console.",
        # Réponse générée par le LLM pour la question 2
        "La dimension du modèle est 1536."
    ],
    "ground_truth": [
        # Réponses idéales attendues par le développeur
        "Vous devez vous connecter à la base et exécuter la requête SQL CREATE EXTENSION vector;.",
        "La dimension attendue pour all-MiniLM-L6-v2 est de 384."
    ]
}

# Conversion au format HuggingFace Dataset (requis par Ragas)
dataset = Dataset.from_dict(data_samples)

print("Lancement de l'évaluation Ragas...")

# 2. Exécution de l'évaluation
result = evaluate(
    dataset=dataset,
    metrics=[
        context_recall,
        context_precision,
        faithfulness,
        answer_relevancy
    ]
)

# 3. Affichage des résultats
# result.to_pandas() permet d'obtenir un tableau clair des scores
df_resultats = result.to_pandas()
print(df_resultats[['question', 'context_recall', 'context_precision', 'faithfulness', 'answer_relevancy']])

Comment lire les résultats générés ?

Pour chaque métrique, Ragas va générer un score entre 0.0 et 1.0. Si on analyse notre exemple :

  • Pour la Question 1 (pgvector) :
    • context_recall sera élevé (ex: 1.0) : La phrase contenant "CREATE EXTENSION vector;" a bien été récupérée par la base vectorielle.
    • context_precision sera moyen (ex: 0.5) : La bonne information a été trouvée, mais elle était en 2ème position (derrière la phrase généraliste sur PostgreSQL). Cela pénalise la précision.
    • faithfulness sera de 1.0 : Le LLM n'a pas halluciné, il s'est bien basé sur le texte fourni pour répondre.
  • Pour la Question 2 (dimension du modèle) :
    • context_recall sera de 0.0 : La base vectorielle n'a remonté *aucune* information sur "all-MiniLM-L6-v2", seulement sur OpenAI.
    • faithfulness sera élevé (ex: 1.0) mais trompeur : Le LLM a répondu "1536". Il est fidèle au mauvais contexte qu'on lui a fourni (il n'a pas inventé), mais la réponse finale est fausse par rapport à la question.

Le lien avec le CI/CD

Dans un pipeline d'intégration continue (CI/CD) sur GitHub Actions ou GitLab CI, vous feriez tourner ce script avec un dataset de 100 questions. À la fin du script, vous rajouteriez une condition bloquante :
# Exemple de règle CI/CD :
score_moyen_recall = result['context_recall']

if score_moyen_recall < 0.90:
    raise Exception(f"Échec du déploiement ! Le Recall est tombé à {score_moyen_recall*100}%.")
Ainsi, si une modification de votre code casse la recherche, le système refuse de passer en production.

Note :

Mais dans la réalité, la réponse answer est générée dynamiquement par le modèle de langage (LLM) lors du fonctionnement de votre pipeline RAG, juste avant d'être envoyée à Ragas pour évaluation. Voici exactement comment cette réponse est obtenue, étape par étape, dans un vrai système :

1. La construction du "Prompt RAG"

Dans le code applicatif (souvent géré par une librairie comme LangChain), il y un "Template" (un modèle de prompt) qui ressemble à ceci :
  • Système : Tu es un assistant technique. Réponds à la question de l'utilisateur de manière concise, en te basant uniquement sur le contexte fourni ci-dessous.
    Si la réponse n'y est pas, dis que tu ne sais pas.
  • Contexte : > {les_documents_que_la_base_vectorielle_a_trouves}
  • Question de l'utilisateur : > {la_question}

2. L'injection des données

Quand l'utilisateur pose sa question (ex: "Comment activer l'extension pgvector ?"), votre système interroge la base vectorielle. Il récupère le texte pertinent et l'injecte dans le prompt.
Le prompt final qui est envoyé à l'API de votre LLM (ex: OpenAI, Mistral, Llama) ressemble alors à ça :

Tu es un assistant technique. Réponds à la question...

Contexte :
- PostgreSQL est un système de gestion de base de données relationnelle.
- Pour utiliser les vecteurs, exécutez 'CREATE EXTENSION vector;' dans votre base PostgreSQL.

Question de l'utilisateur :
Comment activer l'extension pgvector dans PostgreSQL ?

3. La génération par le LLM (L'origine de l'`answer`)

Le LLM lit ce texte, réfléchit, et vous renvoie sa génération : "Il suffit de taper la commande CREATE EXTENSION vector; dans la console." C'est exactement cette chaîne de caractères que votre application affiche à l'utilisateur final.

4. La préparation pour Ragas

Pour pouvoir utiliser Ragas, vous devez historiser ce qui s'est passé. Votre application doit sauvegarder 3 éléments à chaque fois qu'un utilisateur pose une question :
  1. La question posée.
  2. Les contextes qui ont été injectés dans le prompt.
  3. L'answer exacte que le LLM a générée à l'étape 3.
Ensuite, vous, en tant que développeur, vous venez ajouter la ground_truth (la réponse idéale que vous attendez).
Vous regroupez tout cela dans un Dataset, et vous le donnez à Ragas.
Ragas va alors comparer l'answer générée par votre LLM avec les contextes (pour vérifier les hallucinations) et avec la ground_truth (pour vérifier l'exactitude).

4.4 Observabilité et Drift de l'Espace Latent

En production, vos données évoluent. Le Data Drift se manifeste ici par un changement de distribution dans l'espace vectoriel. Si vos utilisateurs commencent à poser des questions sur des sujets totalement absents de votre base initiale, la distance moyenne de vos résultats de recherche va augmenter.

Le rôle du MLOps : Monitorer la "distance de recherche" moyenne. Si elle dépasse un certain seuil, cela signifie que votre système RAG devient "aveugle" et qu'il est temps d'enrichir votre base de connaissances ou de mettre à jour votre stratégie de chunking.

L'industrialisation transforme un projet de recherche en un produit robuste. En imposant des contrats de données, en maîtrisant le versioning des index et en automatisant l'évaluation, vous garantissez la pérennité de votre architecture IA. La dernière partie nous emmènera vers la vision finale : le déploiement et la stratégie produit.

Vision Produit et Déploiement — Transformer l'IA en Valeur Métier

Nous arrivons au dernier acte de notre épopée technologique. Après avoir bâti l'infrastructure et sécurisé les pipelines MLOps, le Data Product Manager (DPM) doit s'assurer que cette complexité technique se traduit par une expérience utilisateur (UX) fluide et un avantage compétitif réel. La partie 5 est dédiée à l'orchestration finale et aux enjeux de mise sur le marché.

5.1 L'Avènement du RAG Agentique : L'exemple Tavily

Le RAG "statique" (interroger une base de documents interne) n'est que la première étape. Pour un produit vraiment performant en 2026, l'IA doit savoir quand sa mémoire interne ne suffit plus. C'est ici qu'interviennent les agents capables d'utiliser des outils de recherche web comme Tavily.

Le Workflow d'un Agent Moderne :

  • Analyse de la requête : L'agent détermine s'il possède l'info ou s'il doit chercher dehors.
  • Récupération Augmentée par le Web : Utilisation de Tavily pour scanner les sources d'actualité les plus récentes (postérieures au cutoff du modèle).
  • Synthèse Multi-Sources : Fusion des données internes (Base Vectorielle) et externes (Web) pour une réponse exhaustive et vérifiée.

5.2 Critères de Décision pour le DPM : Sécurité, Coût et Performance

Le choix de la stack finale n'est pas qu'une affaire de benchmarks techniques. Un profil Product doit arbitrer entre plusieurs dimensions critiques :

  • Confidentialité (Privacy-First) : Si vos données sont ultra-sensibles, l'auto-hébergement d'une base comme Weaviate ou Qdrant sur votre propre VPC est non négociable.
  • Le Time-to-Market : Pour un MVP, l'utilisation de Pinecone (SaaS) ou de Chroma DB permet de gagner des semaines de développement.
  • La structure des coûts : Surveillez le coût de la RAM. Plus vous avez de vecteurs et plus vous voulez une latence faible, plus la facture d'infrastructure grimpera. La "Quantification" évoquée dans la partie 4 devient ici un levier de rentabilité.

5.3 Éthique et Conformité : Le RGPD à l'heure des Vecteurs

Un point souvent oublié par les ingénieurs : le droit à l'oubli. Si un utilisateur demande la suppression de ses données personnelles, vous devez être capable de supprimer non seulement ses documents bruts, mais aussi les embeddings correspondants dans votre base vectorielle.

De même, attention au "Reverse Engineering" : il est parfois possible de reconstruire une partie du texte original à partir de son vecteur. L'anonymisation des données avant l'étape d'embedding est donc une bonne pratique de cador pour garantir la conformité RGPD.

Conclusion : L'Architecture du Sens est la nouvelle norme

Nous avons parcouru tout le spectre : de la mathématique fondamentale du vecteur à la gestion complexe des agents en production. En 2026, maîtriser la chaîne Embeddings > Vector DB > RAG n'est plus une compétence "bonus", c'est le standard de l'ingénierie logicielle moderne.

En tant que Data Scientists et MLOps, notre mission est de construire ces "autoroutes du sens" pour que l'intelligence artificielle ne soit plus une boîte noire capricieuse, mais un partenaire fiable, précis et ancré dans la réalité de vos données métier.

Merci d'avoir suivi cet article de mon blog ! Le code source des exemples et les configurations d'infrastructure sont disponibles sur mon GitHub. N'hésitez pas à partager vos retours d'expérience sur vos déploiements de bases vectorielles en commentaires. Bonne construction !