Stockages vectoriels personnalisés
Les pages Récupération, Récupérateurs et Filtres sont écrites pour un Mistral Search Index. Avec un store personnalisé, les filtres ne fonctionnent que si votre méthode search applique VectorSearchQuery.filter, et retrieve ne fonctionne que si le store implémente RetrievableIndex.
Pour implémenter un backend de stockage personnalisé, créez une sous-classe de VectorStoreIndex (ou de KeywordStoreIndex pour la recherche par mot-clé) et implémentez ses trois méthodes. Un vector store expose aussi un attribut embedding_model (un EmbeddingModel) qui correspond à l'embedder :
from mistralai.search.toolkit.context import IngestContext, RetrievalContext
from mistralai.search.toolkit.search import VectorStoreIndex, VectorSearchQuery, SearchResult
from mistralai.search.toolkit.document import Document
from mistralai.search.toolkit.embedding import EmbeddingModel
class MyVectorStore(VectorStoreIndex):
embedding_model: EmbeddingModel
async def index_document(self, document: Document, context: IngestContext = IngestContext()) -> None:
# Store the document and its chunks
pass
async def search(self, query: VectorSearchQuery, context: RetrievalContext = RetrievalContext()) -> list[SearchResult]:
# Search and return results
pass
async def delete_document(self, doc_id: str, context: IngestContext = IngestContext()) -> None:
# Delete a document by ID
passUne fois que le store implémente VectorStoreIndex, transmettez-le à Pipeline(stores=...) et à un VectorRetriever(client=...) utilisé par QueryEngine, comme avec les backends intégrés.
Opérations agentiques facultatives
Au-delà de l’indexation et de la recherche, un backend peut exposer une navigation positionnelle en implémentant le protocole facultatif @runtime_checkable NavigableIndex. C’est opt-in : un store qui ne l’implémente pas n’annonce tout simplement pas cette capacité, et les appelants conditionnent l’accès avec isinstance.
NavigableIndex
Ces méthodes assurent la navigation positionnelle dans un index qui associe un fragment à chaque document. Un agent peut passer aux fragments adjacents, lire un intervalle, récupérer un fragment par ID et rechercher dans une source. Dans les boucles agentiques open et navigate, le modèle conserve uniquement un chunk_id opaque issu d’un résultat de recherche, puis le serveur résout sa position.
from mistralai.search.toolkit.search import NavigableIndex, NavigationDirection, GrepMode
class MyVectorStore(VectorStoreIndex): # also implements NavigableIndex
async def navigate(self, source_id, start_offset, end_offset, direction, *, top_k=1, content_type=..., context=...):
# Adjacent chunks in the requested direction (NEXT / PREVIOUS)
...
async def read(self, source_id, start_offset, end_offset, *, content_type=..., top_k=20, context=...):
# Chunks whose span falls within [start_offset, end_offset)
...
async def get_chunk(self, chunk_id, *, context=...):
# Resolve a chunk_id to its SearchResult (or None)
...
async def grep(self, source_id, pattern, *, mode=GrepMode.PHRASE, content_type=..., top_k=5, context=...):
# Lexical match within a single source (no vector ranking)
...Les appelants vérifient la capacité au lieu d’intercepter NotImplementedError :
from mistralai.search.toolkit.search import NavigableIndex
if isinstance(store, NavigableIndex):
results = await store.get_chunk(chunk_id)Les offsets suivent la convention semi-ouverte [start, end) utilisée par DocumentChunk. read et navigate lèvent SourceNotFoundError lorsque source_id ne correspond à aucune source existante, et renvoient une liste vide lorsqu’une requête atteint la limite d’une source.
Mises à jour partielles facultatives
Un backend peut aussi exposer des mises à jour partielles sans réindexation complète en implémentant le protocole facultatif PatchableIndex. Ce protocole peut modifier des valeurs de métadonnées, ou le contenu ou les représentations vectorielles d'un fragment, sans redécouper et réindexer le document complet. Implémentez patch_chunk et patch_document :
from mistralai.search.toolkit.search import PatchableIndex, VectorStoreIndex
class MyVectorStore(VectorStoreIndex): # also implements PatchableIndex
async def patch_chunk(self, chunk_id, patch, context=...):
...
async def patch_document(self, document_id, patch, context=...):
...ChunkPatch et DocumentPatch (depuis mistralai.search.toolkit.search) décrivent les champs à réattribuer ou les clés de métadonnées à fusionner ; une clé de métadonnées définie sur None est supprimée.
Voir aussi
- Index de recherche : les backends intégrés.
- Mistral Search Index, Vespa et Postgres : les implémentations intégrées, utiles comme référence pour les vôtres.