Aller au contenu principal

E-06 Pipelines RAG

Brique E: Données, RAG, contexte, mémoire. Version anglaise: E-06-rag-pipelines

1. Rôle et responsabilités​

Pipelines Haystack d'ingestion (découpage, DLP, embedding) et de requête (recherche vectorielle ou hybride, filtrage ACL, reranking optionnel).

  • Embeddings par le Model Gateway (POST /v1/gateway/embeddings) avec le modèle d'embedding de la base de connaissances
  • Recherche filtrée par ACL et clearance, mode vector ou hybrid
  • Reranking optionnel via POST /v1/gateway/rerank
  • Réindexation vers un autre modèle d'embedding, sans mélange de vecteurs
  • Citations avec provenance

Chaque base de connaissances a un modèle d'embedding du registre (embedding_model, capacité embeddings) et une dimension, choisis à la création (défaut EAI_RAG_EMBEDDING_MODEL). Chaque appel d'embedding (segments d'un document, requête, réindexation) passe par les contrôles du Model Gateway : kill switch, plafond de classification et rétention du modèle, région, DLP, décision de politique model.invoke, garde de sortie, réservation de quota et Usage Event mesuré sur la réponse du fournisseur. Les segments partent avec la classification de leur document : un document au-dessus du plafond du modèle est refusé avant tout appel sortant.

Modèles livrés :

  • bge-m3-vllm : BAAI/bge-m3 servi par vLLM en mode embedding (1024 dimensions, français et anglais, plafond secret, aucune rétention), seul modèle livré pour les données restricted et secret ;
  • text-embedding-3-small : OpenAI (1536 dimensions, ou 256, 512 et 1024 avec dimensions), plafond confidential ;
  • local-hash-256 : hachage de mots et de trigrammes, sans modèle ni appel sortant, accepté en dev et en test seulement.

2. Position dans l'architecture et interactions​

  • Appelants: Agents (outil rag), SDK, Context Manager.
  • Chemin d'exécution: Synchrone (ingestion et requête), asynchrone (réindexation par le worker).
  • Toute interaction passe par l'API Control Plane v1 (/v1) derrière la passerelle API (D-14).

3. Composant open source et partie développée​

  • Open source: Haystack
  • Développé: Composants ACL, provenance, intégration passerelle, espaces d'embedding et réindexation.
  • Intégration externe via un adaptateur eai/integrations/<system>.py avec repli in-process lorsque l'URL n'est pas configurée.

4. Modèle de données​

Tables (schéma eai, RLS tenant_id):

  • eai.knowledge_bases (embedding_model, dimensions, vector_generation, vector_collection)
  • eai.kb_documents
  • eai.kb_chunks (generation, dimensions contrôlée contre la taille du vecteur)
  • eai.kb_reindex_jobs

Colonnes communes : id uuid, tenant_id uuid NOT NULL, created_at, updated_at ; politique RLS current_setting('app.tenant_id', true)::uuid.

5. Contrat​

  • Contrat appliqué: context-contract
  • Schéma JSON: contracts/v1/context-contract.schema.json
  • Champs clés: segments[].source, segments[].provenance
  • Validation : POST /v1/contracts/{name}/validate ; application d'un manifeste : POST /v1/manifests/apply.

6. Endpoints API​

  • GET /v1/knowledge-bases
  • POST /v1/knowledge-bases
  • GET /v1/knowledge-bases/{id}
  • DELETE /v1/knowledge-bases/{id}
  • POST /v1/knowledge-bases/{id}/documents
  • GET /v1/knowledge-bases/{id}/documents
  • DELETE /v1/knowledge-bases/{id}/documents/{doc_id}
  • POST /v1/knowledge-bases/{id}/query
  • PUT /v1/knowledge-bases/{id}/acl
  • POST /v1/knowledge-bases/{id}/reindex
  • GET /v1/knowledge-bases/{id}/reindex-jobs

Requête POST /v1/knowledge-bases:

{
"name": "support",
"classification": "confidential",
"embedding_model": "bge-m3-vllm"
}

Requête POST /v1/knowledge-bases/{id}/query:

{
"query": "délai de remboursement",
"top_k": 5,
"mode": "hybrid",
"rerank": true,
"rerank_model": "rerank-v3-5"
}

Réponse:

{
"knowledge_base_id": "0b6f3c1e-9a52-4d7e-8c1a-2f4e6d8b0a13",
"query": "délai de remboursement",
"results": [
{
"chunk_id": "5d2a7e90-3c14-4b8f-a6d1-7e9b2c4f6a80",
"document_id": "a3c5e7f9-1b2d-4e6a-8c0e-2f4a6c8e0b1d",
"title": "Conditions de remboursement",
"ordinal": 3,
"content": "Le remboursement intervient sous 14 jours...",
"score": 0.82,
"vector_score": 0.79,
"keyword_score": 0.85,
"rerank_score": 0.91,
"classification": "internal",
"provenance": {
"source_type": "rag",
"source_id": "a3c5e7f9-1b2d-4e6a-8c0e-2f4a6c8e0b1d",
"version": "2",
"classification": "internal"
}
}
],
"count": 1,
"mode": "hybrid",
"reranked": true,
"warnings": [],
"embedding_model": "bge-m3-vllm"
}

Requête POST /v1/knowledge-bases/{id}/reindex (réponse 202 avec la tâche job_id, status, from, to, documents_total, exécutée par le job embeddings_reindex du worker) :

{
"embedding_model": "text-embedding-3-small",
"dimensions": 512
}

7. Exemples SDK​

Python:

from enterprise_ai import EnterpriseAI

client = EnterpriseAI(base_url="<control-plane-url>", api_key="eai_xxx_secret")
kb = client.rag.create(name="support", chunk_size=800, embedding_model="bge-m3-vllm")
res = client.rag.query(kb.id, query="délai de remboursement", top_k=5, mode="hybrid")

TypeScript:

import { EnterpriseAI } from "@enterprise-ai/sdk";

const client = new EnterpriseAI({ baseUrl: "<control-plane-url>", apiKey: process.env.EAI_API_KEY });
const res = await client.knowledgeBases.query("kb_support", { query: "refund delay", top_k: 5 });

Java:

EnterpriseAIClient client = EnterpriseAIClient.builder()
.baseUrl("<control-plane-url>")
.apiKey(System.getenv("EAI_API_KEY"))
.build();
JsonNode res = client.knowledge().query("kb_support", Map.of("query", "refund delay", "top_k", 5));

Go:

c, _ := eai.NewClient(eai.WithBaseURL("<control-plane-url>"), eai.WithAPIKey(os.Getenv("EAI_API_KEY")))
res, _ := c.Knowledge.Query(ctx, "kb_support", map[string]any{"query": "refund delay", "top_k": 5})

8. Configuration​

  • Variables d'environnement: EAI_RAG_EMBEDDING_MODEL, EAI_MEMORY_EMBEDDING_MODEL, EAI_RAG_RERANK_MODEL, EAI_EMBEDDINGS_BATCH_SIZE, EAI_WORKER_EMBEDDINGS_REINDEX_INTERVAL_SECONDS, EAI_QDRANT_URL, EAI_DATABASE_URL
  • Clés Helm: qdrant.enabled
  • Modèle local : entrée bge-m3 de vllm.models (option --task embedding) et entrée bge-m3-vllm de litellm.config.model_list (mode: embedding) dans values-onprem-gpu.yaml

9. Contrôles de sécurité​

  • Scope rag:query ; ACL appliquée avant retour, jamais après génération
  • Classification > clearance -> chunk exclu
  • Segments envoyés au modèle d'embedding avec la classification du document : au-dessus du plafond du modèle, 403 classification_exceeded avant tout appel sortant
  • Clé du fournisseur injectée côté serveur par le gateway, jamais lue par la brique
  • Toutes les requêtes portent le tenant issu du credential ; RLS PostgreSQL
  • Chaque mutation et décision de politique écrit un événement d'audit chaîné

10. Observabilité​

  • Métriques Prometheus: eai_rag_queries_total{outcome}, eai_rag_retrieval_latency_seconds, eai_rag_embeddings_total{operation}, eai_vector_search_latency_seconds{store}
  • Traces: spans OpenTelemetry avec conventions sémantiques GenAI (gen_ai.operation.name, gen_ai.agent.id, gen_ai.tool.name), attributs eai.tenant_id, eai.run_id, propagation traceparent.
  • Actions d'audit: knowledge.query, knowledge.document.ingest, knowledge_base.reindex.request, knowledge_base.reindex.complete, model.invoke (chaque appel d'embedding)

11. Unités FinOps​

  • Embeddings : un Usage Event embeddings par appel du gateway, avec le fournisseur, la région et les tokens mesurés du modèle de la base (labels.operation : ingest, query, reindex).
  • Requêtes : Usage Event rag (retrieval_queries) ; reranking : Usage Event reranking.
  • Émis comme Usage Event (POST /v1/finops/usage) avec tenant, projet, agent et run.

12. Modes de défaillance et résilience​

  • Reranker indisponible, refusé ou non configuré : résultats dans l'ordre de la recherche, reranked: false et avertissement reranker_unavailable, rerank_refused ou reranker_not_configured
  • Vecteurs d'une autre taille renvoyés par le fournisseur : 502 embedding_dimension_mismatch ; base vectorielle indisponible : 503 vector_store_unavailable
  • Réindexation en échec : la génération précédente reste celle interrogée ; erreur transitoire (429, 502, 503, 504) retentée jusqu'à 3 fois
  • Erreurs normalisées (enveloppe error, message_i18n en/fr)

13. Adoption autonome (client d'un client)​

  • enterprise_ai.rag + Control Plane + Qdrant.
  • SDK: enterprise_ai.privacy / dlp / knowledge_bases / memory / retention / lineage
  • Déploiement minimal : chart Helm avec controlPlane.enabled=true et PostgreSQL ; les composants externes désactivés utilisent leur repli in-process.

14. Tests d'acceptation​

  1. Utilisateur sans ACL ne reçoit aucun chunk du document
  2. Suppression de document retire ses vecteurs
  3. Accès inter-tenant refusé
  4. Erreur renvoyée en fr avec Accept-Language: fr
  5. Document secret refusé par un modèle d'embedding plafonné à confidential, sans appel sortant
  6. Deux modèles d'embedding d'un même tenant ne mélangent jamais leurs vecteurs, réindexation comprise

RAG gouverné (kit L4)​

RAG gouverné : découpage Haystack (haystack-ai, extra rag) quand la bibliothèque est installée, ACL document et fragment (chunk_readers) filtrées dans le magasin de vecteurs puis à nouveau avant le contexte, vérification du connecteur source (source_connector) à l'ingestion et à la requête, quarantaine des documents suspects (injection, texte caché, instructions anormales, embeddings aberrants) avec revue par le responsable des données (GET /v1/knowledge-bases/{id}/quarantine, POST .../documents/{doc_id}/review), citations avec version du document, URI source et position du fragment, cache sensible chiffré par tenant. Tests : tests/test_rag_governance.py.