Vector Store¶
La capability outbound vector-store indexe des projections vectorielles et
retrouve leurs voisins derrière VectorStorePort. Elle reste indépendante des
SDK fournisseurs et n'est pas la source de vérité métier par défaut.
Choisir La Bonne Persistance¶
| Besoin | Capability | Responsabilité |
|---|---|---|
| conserver les entités métier et leur cycle de vie | repository |
source de vérité CRUD |
| conserver des fichiers ou blobs | storage |
octets et métadonnées objet |
| retrouver des contenus proches d'un vecteur | vector-store |
index de recherche reconstruisible |
| calculer un vecteur depuis du texte | embedding |
inférence, sans persistance |
Qdrant ou un autre moteur vectoriel ne remplace donc pas automatiquement
Repository[T]. Le service consommateur peut faire ce choix explicitement,
mais Arclith traite l'index comme une projection reconstruisible.
Position Hexagonale¶
| Text Only | |
|---|---|
L'adapter inbound ne connaît ni le SDK ni les types d'un backend vectoriel. Le use case orchestre la persistance canonique puis l'indexation. En production, si ces écritures doivent résister à une panne entre les deux étapes, le service consommateur doit prévoir un mécanisme de reprise ou un outbox ; la capability n'ajoute pas de synchronisation implicite.
Contrat V1¶
Le contrat accepte uniquement des vecteurs denses et des payloads JSON :
null, booléens, nombres finis, chaînes, listes et objets. Les IDs sont des
chaînes provider-neutral ; pour une entité Arclith, utiliser
str(entity.uuid).
Les filtres v1 font un exact-match sur les champs de premier niveau du payload.
Les résultats sont triés du meilleur score au moins bon. Pour euclid,
l'adapter mémoire convertit la distance en similarité avec 1 / (1 + distance)
afin qu'un score supérieur reste meilleur pour les trois métriques.
Adapter Memory¶
memory fournit une recherche exacte, déterministe et sans dépendance externe.
Il cible les tests, les démonstrations et les smoke tests locaux, pas les grands
volumes ni la recherche approximate-nearest-neighbour.
| Bash | |
|---|---|
La commande crée de façon idempotente
config/adapters/outbound/vector_store.yaml :
| YAML | |
|---|---|
Puis l'assemblage passe par la factory publique :
| Python | |
|---|---|
ensure_collection() est idempotente. Les autres opérations échouent avec
VectorStoreCollectionNotFound si elle n'a pas encore été appelée. Les upserts
valident tout le batch avant de le modifier et lèvent
VectorStoreDimensionMismatch si une dimension diffère de vector_size.
Adapter Qdrant¶
qdrant fournit l'adapter de production dense via le client Python async
officiel. La dépendance reste optionnelle :
| Bash | |
|---|---|
La commande CLI installe l'extra et génère le même fichier scoped que
memory, sans écrire la clé API :
| Bash | |
|---|---|
config/adapters/outbound/vector_store.yaml :
| YAML | |
|---|---|
Le catalogue ajoute de façon idempotente les mappings suivants dans
config/secrets.yaml :
QDRANT_API_KEY reste optionnelle pour une instance locale. Une URL contenant
des credentials est refusée afin que ceux-ci ne puissent pas fuiter par la
configuration. Si l'endpoint doit lui aussi venir d'un resolver, le service
peut ajouter explicitement adapters.vector_store.url: QDRANT_URL à ses
mappings et fournir la variable correspondante.
Smoke Local¶
Un compose.yaml minimal peut lancer Qdrant sans service annexe :
Le service consommateur calcule l'embedding avant d'appeler le vector store ; Qdrant n'est jamais invoqué directement depuis le domaine ou l'adapter inbound :
Avant l'upsert ou la recherche, l'adapter vérifie que la dimension correspond
à vector_size, puis mappe les erreurs du SDK vers les erreurs communes. La
page Embedding détaille la production du vecteur.
Les filtres Qdrant v1 sont des exact-match sur un champ de premier niveau et
acceptent les chaînes, entiers et booléens pris en charge par MatchValue.
Les nombres flottants, null, listes et objets restent valides dans les
payloads mais ne sont pas acceptés comme valeur de filtre Qdrant v1.
Multitenant Et Cycle De Vie¶
Avec multitenant: true, le contexte d'adapter qdrant peut fournir url,
api_key et collection_name. Chaque champ absent retombe sur la
configuration single-tenant. L'URL effective est revalidée et aucun message
d'erreur ne contient la clé.
En single-tenant, l'adapter réutilise un unique AsyncQdrantClient et expose
await store.close() pour le fermer lors de l'arrêt du service. Un client
injecté appartient à l'appelant et n'est pas fermé. En multitenant, un client
isolé est créé pour l'opération puis fermé immédiatement, afin de ne pas
conserver les credentials tenant en cache.
Erreurs Communes¶
Les adapters exposent les erreurs provider-neutral suivantes :
VectorStoreUnavailable;VectorStoreCollectionNotFound;VectorStoreDimensionMismatch;VectorStorePermissionDenied;VectorStoreInvalidPayload.
Les modèles Pydantic refusent en amont les payloads non JSON, les vecteurs vides ou non finis et les limites non positives. Les adapters externes doivent mapper leurs erreurs sans exposer de token, de clé API ni d'URL contenant des credentials.
Limites V1¶
La recherche hybride, les sparse vectors, les named vectors multiples, recommend/discover, le reranking et la synchronisation automatique avec un repository sont hors scope. Ils devront étendre le contrat commun sans faire fuiter de types fournisseur dans le domaine.