Mistral Search Index
Utilisez Search Index, le stockage de recherche hébergé par Mistral, pour stocker et rechercher les fragments de vos pipelines Search Toolkit. MistralSearchIndex implémente VectorStoreIndex, NavigableIndex et RetrievableIndex, et utilise donc les mêmes interfaces de pipeline que les backends Vespa et Postgres. Vous n'avez pas à provisionner ni à gérer de base de données : l'index réside dans votre espace de travail Mistral.
Le client est inclus dans le package principal et ne nécessite aucune dépendance optionnelle :
uv add mistralai-search-toolkitSearch Index est en préversion publique. Son API, son comportement et ses outils peuvent évoluer pendant cette phase, et une mise à jour peut nécessiter des modifications de votre code.
Fonctionnement
Le client se compose de trois objets, tous situés dans mistralai.search.toolkit.mistral_search_index :
MistralSearchIndexCollectionSchema: déclare le nom de l'index, le modèle de représentation vectorielle et les champs personnalisés dérivés de votre sous-classe deDocument.MistralSearchIndexService: gère le cycle de vie de l'index (create_index,update_index,delete_index,get_index_info,index_exists) et récupère le store d'un index existant avecget_search_index.MistralSearchIndex: indexe, supprime, recherche, récupère et parcourt des documents. Transmettez-le àPipeline(stores=...)pour l'ingestion, et interrogez-le avecsearchetretrieve.
Le serveur fait autorité : get_search_index lit le schéma et le modèle de représentations vectorielles depuis l'index. Un processus qui effectue uniquement des requêtes n'a donc pas besoin de déclarer le schéma. Ne construisez pas vous-même MistralSearchIndex. Récupérez-le plutôt avec get_search_index pour qu'il corresponde à l'index sur le serveur.
Authentification
MistralSearchIndexService() construit un client Mistral à partir de la variable d'environnement MISTRAL_API_KEY et lève une exception RuntimeError si elle n'est pas définie. Pour appeler un Point de terminaison API autre que https://api.mistral.ai, définissez MISTRAL_API_URL. Pour réutiliser un client déjà configuré, passez-le en argument :
from mistralai.client import Mistral
from mistralai.search.toolkit.mistral_search_index import MistralSearchIndexService
service = MistralSearchIndexService(client=Mistral(api_key="..."))Pour créer un index, vous devez disposer de l'autorisation create_search_indexes dans l'espace de travail. Pour comprendre le fonctionnement des autorisations, consultez Créer un index.
Déclarer une collection
Générez le schéma à partir de votre type de document avec from_document_type. Comme pour les autres backends, embedding_model accepte un EmbeddingModel ou un MistralEmbeddingPreset, décrits dans Modèle de Représentations vectorielles :
from typing import Annotated, Sequence
from mistralai.search.toolkit.document import Document, DocumentChunk
from mistralai.search.toolkit.embedding import MistralEmbeddingPreset
from mistralai.search.toolkit.mistral_search_index.schema import (
MistralSearchIndexCollectionSchema,
MistralSearchIndexField,
MistralSearchIndexFieldType,
)
class ReportChunk(DocumentChunk):
page: Annotated[int | None, MistralSearchIndexField(indexed=True)] = None
class ReportDocument(Document):
title: str
category: Annotated[str, MistralSearchIndexField(type=MistralSearchIndexFieldType.KEYWORD, indexed=True)]
chunks: Sequence[ReportChunk] = []
SCHEMA = MistralSearchIndexCollectionSchema.from_document_type(
collection_name="reports",
document_type=ReportDocument,
embedding_model=MistralEmbeddingPreset.MISTRAL_EMBED_DIM_1024,
)| Champ | Type | Rôle |
|---|---|---|
collection_name | str | Nom de l'index. Il doit commencer par une lettre minuscule, ne contenir que des lettres minuscules, des chiffres et des tirets bas isolés, se terminer par une lettre ou un chiffre et compter au maximum 32 caractères. Les noms sont uniques par espace de travail. |
document_type | type[Document] | Votre sous-classe de Document. Les champs qu'elle et son type de fragment ajoutent aux modèles de base deviennent des champs typés dans l'index. |
embedding_model | EmbeddingModel | MistralEmbeddingPreset | Modèle de Représentations vectorielles, qui définit les dimensions, le type de données et la métrique de distance. Vous ne pouvez plus le modifier une fois l'index créé. |
Associer l'embedder à l'index
Le modèle de représentations vectorielles est fixé lors de la création de l'index. Chaque représentation vectorielle que vous envoyez doit provenir du même modèle et avoir les mêmes dimensions, aussi bien lors de l'ingestion que pour les requêtes que vous vectorisez vous-même. En cas de différence, la requête échoue. Associez la configuration prédéfinie au modèle MistralEmbedder correspondant :
| Preset | Dimensions | Embedder |
|---|---|---|
MISTRAL_EMBED_DIM_128 | 128 | MistralEmbedder() (le modèle par défaut) |
MISTRAL_EMBED_DIM_256 | 256 | MistralEmbedder(model_name=MODEL_256_EMBEDDING) |
MISTRAL_EMBED_DIM_1024 | 1024 | MistralEmbedder(model_name=MODEL_1024_EMBEDDING) |
Les constantes MODEL_*_EMBEDDING proviennent de mistralai.search.toolkit.embedding. Sans nom de modèle, MistralEmbedder() utilise le modèle à 128 dimensions. Passez donc model_name si l'index utilise une autre configuration prédéfinie.
Champs personnalisés
Chaque champ que votre sous-classe de Document ou de DocumentChunk ajoute au modèle de base devient un champ typé dans l'index. Les champs du document décrivent le document entier, et ceux du fragment décrivent un passage. La boîte à outils gère les champs de base (source_id, content, chunks, metadata et les autres).
Le toolkit déduit le type de chaque champ à partir de son annotation :
| Annotation | Type de champ | Indexé par défaut |
|---|---|---|
str | text | Oui |
StrEnum | keyword | Oui |
int | long | Non |
float | float | Non |
bool | bool | Non |
datetime | timestamp | Non |
list[T] | T[] (keyword[] pour une liste de StrEnum) | Non |
dict, un modèle Pydantic | json | Non |
Un champ est obligatoire, sauf si son annotation autorise None. MistralSearchIndexField(type=..., indexed=..., required=..., default=..., ignore=...) remplace toute valeur déduite, et ignore=True exclut un champ de l'index :
from datetime import datetime
from enum import StrEnum
from mistralai.search.toolkit.mistral_search_index.schema import MistralSearchIndexField, MistralSearchIndexFieldType
class Category(StrEnum):
BILLING = "billing"
SHIPPING = "shipping"
class Article(Document):
title: str # text, full-text searchable
category: Category # keyword, exact match
sku: Annotated[str, MistralSearchIndexField(type=MistralSearchIndexFieldType.KEYWORD)]
published_at: Annotated[datetime | None, MistralSearchIndexField(indexed=True)] = None
internal_note: Annotated[str | None, MistralSearchIndexField(ignore=True)] = None- Utilisez
keywordpour les identifiants comme les SKU, les codes ou les tags : unstrcorrespond par défaut àtext, un type tokenisé pour la recherche par mot-clé. - Les types non pris en charge provoquent une erreur dès la construction du schéma. Un champ dont le type n'a aucune correspondance lève une exception
ValueErrorlors de cette étape. Pour corriger le problème, ajoutez une déclaration expliciteMistralSearchIndexField(type=...)ou définissezignore=True. - Les champs obligatoires sont vérifiés localement. Avant chaque écriture, le schéma vérifie que chaque champ personnalisé obligatoire est défini, de sorte qu'un champ manquant entraîne un échec avant l'envoi de la requête.
Pour les règles de nommage des champs et les champs système, voir Champs personnalisés. Pour filtrer sur les champs personnalisés, voir Filtres.
Gérer l'index
Les opérations de création, de mise à jour et de suppression s'exécutent de manière asynchrone sur le serveur. create_index renvoie un résultat alors que le provisionnement de l'index est encore en cours. Attendez donc que l'index soit prêt avant d'y écrire :
import asyncio
from mistralai.search.toolkit.mistral_search_index import MistralSearchIndexService
from mistralai.search.toolkit.mistral_search_index.models import MistralSearchIndexStatus
service = MistralSearchIndexService()
if not await service.index_exists("reports"):
info = await service.create_index(SCHEMA)
while info.status == MistralSearchIndexStatus.PROVISIONING:
await asyncio.sleep(1)
info = await service.get_index_info("reports")
if info.status != MistralSearchIndexStatus.READY:
raise RuntimeError(f"provisioning failed: {info.status_message}")
store = await service.get_search_index("reports") # -> MistralSearchIndexupdate_index(schema) transmet un schéma étendu. Les mises à jour sont additives : vous pouvez ajouter des champs optionnels ou activer indexed. Pour toute autre modification, recréez l'index. delete_index(name) supprime l'index et tous ses documents.
Indexation
Utilisez le store dans un pipeline d'ingestion :
from mistralai.search.toolkit.embedding import MODEL_1024_EMBEDDING, MistralEmbedder
from mistralai.search.toolkit.ingestion.extractors import MistralOCRExtractor
from mistralai.search.toolkit.ingestion.loaders import FilesystemFileLoader
from mistralai.search.toolkit.ingestion.pipelines import Pipeline
from mistralai.search.toolkit.ingestion.text_splitters import MarkdownTextSplitter, MarkdownTextSplitterConfig
pipeline = Pipeline(
loader=FilesystemFileLoader(),
extractor=MistralOCRExtractor(),
text_splitter=MarkdownTextSplitter(MarkdownTextSplitterConfig()),
processors=[ReportEnricher()], # your processor that sets title, category, and page
embedder=MistralEmbedder(model_name=MODEL_1024_EMBEDDING),
stores=store,
)
await pipeline.run(documents=["docs/report.pdf"])L'index ne calcule pas les représentations vectorielles lors de l'ingestion. Chaque fragment doit donc en contenir une. Conservez dans le pipeline un composant de vectorisation qui utilise le modèle de l'index (MISTRAL_EMBED_DIM_1024 dans cet exemple). Si un Pipeline écrit dans un index vectoriel sans composant de vectorisation, une erreur est levée lors de sa construction. Le source_id d'un document constitue son identité : indexer à nouveau le même source_id remplace le document et ses fragments.
index_document lève une exception DocumentRejectedError, sous-classe de IndexingError, lorsque le serveur rejette le document pour une raison déterministe, comme un champ manquant ou un texte que l'index ne peut pas stocker. Le message indique chaque champ en échec. Réessayer ne résout pas cette erreur : corrigez les données avant d'envoyer à nouveau le document. Un pipeline signale l'échec du document et poursuit le traitement du reste du batch. delete_document(doc_id) accepte l'identifiant du document, et non celui de la source, et lève une exception DocumentNotFoundError si aucun document ne correspond.
Recherche
Recherche vectorielle et hybride
search(VectorSearchQuery) construit le retriever pour vous. VectorRetriever et QueryEngine fonctionnent donc sans modification :
- Avec uniquement un
embedding, il exécute un module de recherche des plus proches voisins. - Avec à la fois
queryetembedding, il combine un module de recherche par mots-clés et un module de recherche des plus proches voisins par fusion des rangs réciproques.
from mistralai.search.toolkit.search import VectorSearchQuery
results = await store.search(
VectorSearchQuery(query="quarterly revenue", embedding=vec, top_k=10)
)La requête respecte également exclude_ids, exclude_source_ids et approximate_options=ApproximateQueryOptions(max_candidates=...). La recherche par mots-clés porte uniquement sur content, et chaque résultat inclut ses champs personnalisés.
Récupération
Pour un guide complet, consultez Recherche documentaire. Pour filtrer sur vos champs, rechercher des mots-clés dans un champ personnalisé ou ajuster la fusion, appelez retrieve avec un module de recherche de mistralai.search.toolkit.mistral_search_index.retriever :
from mistralai.search.toolkit.mistral_search_index.retriever import (
In,
KeywordRetriever,
NearestNeighbourRetriever,
RRFRetriever,
)
results = await store.retrieve(
RRFRetriever(
top_k=10,
filter=In(field="category", values=["financial", "legal"]),
retrievers=[
KeywordRetriever(query="termination clauses", top_k=10),
KeywordRetriever(query="termination clauses", field="title", top_k=10),
NearestNeighbourRetriever(query="termination clauses", top_k=10),
],
weights=[1.0, 2.0, 1.0],
)
)| Retriever | Rôle |
|---|---|
NearestNeighbourRetriever | Recherche approximative des plus proches voisins parmi les représentations vectorielles des fragments. Avec un modèle de représentations vectorielles Mistral, passez query : le serveur vectorise la requête. Avec un modèle personnalisé, passez query_embedding. |
KeywordRetriever | Correspondance de texte intégral sur content, ou sur un autre champ text indexé via field. operator est "or" (par défaut) ou "and". |
RRFRetriever | Combine les classements de ses modules de recherche enfants par fusion des rangs réciproques. weights et rank_constant permettent de l'ajuster, et son filter s'applique à chaque module enfant. |
Chaque retriever prend un filter construit à partir de Equal, In, Range, And, Or et Not. Le top_k de premier niveau est plafonné à 100. Pour les limites et la sémantique des scores, voir Interroger un index.
Navigation
MistralSearchIndex implémente NavigableIndex : navigate, read, grep et get_chunk parcourent un document source dans l'ordre de lecture plutôt que par pertinence. Ces méthodes sont les primitives sur lesquelles repose la Recherche Agentique. Pour connaître chaque méthode et ses cas d'utilisation, consultez Navigation dans les documents.
Limites
- Pas de mises à jour partielles.
MistralSearchIndexn'implémente niPatchableIndexniVersionedIndex. Pour modifier un document, réindexez-le. - Vérifications de l'état. Les appels de documents et de requêtes sur un index qui n'est pas
readyéchouent. Le service lève uneIndexNotFoundErrorlorsqu'un appel de cycle de vie cible un index qui n'existe pas ou auquel vous n'avez pas accès.
Voir aussi
- Search Index : le produit hébergé, son API REST et ses autorisations.
- Opérations de base : champs personnalisés, champs système et équivalents REST de chaque appel de cette page.
- Index de recherche : comparaison de ce backend avec les autres.
- Modèle de représentation vectorielle : l'argument
embedding_modeldeMistralSearchIndexCollectionSchema. - Modèle de document : les types
DocumentetDocumentChunkà partir desquels le schéma est généré.