Guide de démarrage
Créez un pipeline RAG en cinq minutes : importez des documents dans un vecteur store, puis effectuez une recherche dessus.
Prérequis
- Python 3.12+
- Docker (pour exécuter Vespa en local)
- Une clé API Mistral à obtenir sur console.mistral.ai
Installation
Installez Search Toolkit avec le plugin Vespa en utilisant uv :
uv add "mistralai-search-toolkit[vespa]"Configurer Vespa
Démarrez une instance Vespa locale avec Docker :
docker run --detach \
--name vespa \
--hostname vespa-container \
--publish 8080:8080 \
--publish 19071:19071 \
vespaengine/vespaAttendez que Vespa soit prêt :
curl --retry 10 --retry-delay 3 --retry-all-errors \
http://localhost:19071/state/v1/healthDéfinissez votre clé API Mistral :
export MISTRAL_API_KEY=your-api-keyDéfinir le schéma
Créez une migration pour décrire la structure de vos documents :
mistral-vespa generate-migration \
--app-dir ./vespa/migrations \
initial_schemaComplétez le fichier généré :
from mistralai.search.toolkit.plugins.vespa.app.schemas.app import FieldDefinition, SearchMode
from mistralai.search.toolkit.plugins.vespa.migration import VespaMigration, create_default_schema, set_app_name
class InitialSchema(VespaMigration):
def migrate(self) -> None:
set_app_name("myquickstart")
create_default_schema(
name="quickstart_collection",
mode=SearchMode.INDEX,
embedding_dimensions=1024,
schema_version=1,
additional_fields=[
FieldDefinition.TextField(name="title"),
],
)Restrictions sur le nom de l’application : le nom passé à set_app_name() doit contenir uniquement des lettres minuscules (a-z). Les chiffres, les traits de soulignement, les traits d’union et les autres caractères spéciaux ne sont pas autorisés.
Pour obtenir plus de détails sur la gestion et le déploiement d’applications Vespa, consultez Gérer et déployer des applications Vespa.
Déployer à partir des migrations
Déployez le schéma sur votre instance Vespa locale :
mistral-vespa migrate \
--app-dir ./vespa/migrations \
--config-server http://localhost:19071 \
--query-port 8080Cela construit le package applicatif à partir de vos migrations en mémoire, le déploie, et attend que l’application soit prête.
Ingestion des documents
Créez un pipeline qui charge des fichiers, extrait le texte, segmente en fragments, génère des embeddings et indexe dans Vespa :
import asyncio
from pathlib import Path
from mistralai.client import Mistral
from mistralai.search.toolkit.embedders import MistralEmbedder
from mistralai.search.toolkit.ingestion.extractors import PlainTextExtractor
from mistralai.search.toolkit.ingestion.loaders import FilesystemFileLoader
from mistralai.search.toolkit.ingestion.pipelines import Pipeline
from mistralai.search.toolkit.ingestion.text_splitters import CharacterTextSplitter
from mistralai.search.toolkit.plugins.vespa import VespaClientConfig
from vespa_app import app
async def main():
mistral_client = Mistral(api_key="your-api-key")
# Configure Vespa
config = VespaClientConfig(
endpoint="http://localhost:8080",
)
vector_store = app.get_search_index(config, collection_name="quickstart_collection")
# Create the pipeline
pipeline = Pipeline(
loader=FilesystemFileLoader(),
extractor=PlainTextExtractor(),
text_splitter=CharacterTextSplitter(chunk_size=500),
embedder=MistralEmbedder(client=mistral_client, model_name="mistral-embed"),
vector_store=vector_store,
)
# Ingest documents
await pipeline.run(
documents=[Path("doc1.txt"), Path("doc2.txt")],
collection_name="quickstart_collection",
)
print("Documents ingested!")
asyncio.run(main())Ce pipeline enchaîne cinq étapes :
FilesystemFileLoaderlit les octets du fichier depuis le disque.PlainTextExtractorextrait le contenu texte. Pour les PDF, utilisez à la placeMistralOCRExtractor.CharacterTextSplitterdécoupe le texte en fragments de 500 caractères.MistralEmbeddergénère un embedding vectoriel pour chaque fragment.vector_store(Vespa) indexe chaque fragment et stocke l’embedding pour la recherche vectorielle.
Recherche
Interrogez les documents indexés avec la recherche vectorielle :
import asyncio
from mistralai.client import Mistral
from mistralai.search.toolkit.embedders import MistralEmbedder
from mistralai.search.toolkit.plugins.vespa import VespaClientConfig
from mistralai.search.toolkit.retrieval import QueryEngine
from mistralai.search.toolkit.retrieval.retrievers import VectorRetriever
from vespa_app import app
async def main():
mistral_client = Mistral(api_key="your-api-key")
embedder = MistralEmbedder(client=mistral_client, model_name="mistral-embed")
# Configure Vespa for search
config = VespaClientConfig(
endpoint="http://localhost:8080",
)
vector_store = app.get_search_index(config, collection_name="quickstart_collection")
# Build query engine
query_engine = QueryEngine(
retriever=[VectorRetriever(client=vector_store, embedder=embedder)],
)
# Search
result = await query_engine.search(
query="What is RAG?",
top_k=5,
include_metadata=True,
include_content=True,
)
for i, r in enumerate(result.results, 1):
print(f"{i}. [Score: {r.score:.3f}] {r.chunk.content[:200]}...")
asyncio.run(main())Ingestion de PDF avec OCR
Pour des fichiers PDF, remplacez PlainTextExtractor par MistralOCRExtractor et utilisez MarkdownTextSplitter pour un découpage adapté à la structure du document :
from mistralai.search.toolkit.ingestion.extractors import MistralOCRExtractor
from mistralai.search.toolkit.ingestion.text_splitters import (
MarkdownTextSplitter,
MarkdownTextSplitterConfig,
)
pipeline = Pipeline(
loader=FilesystemFileLoader(),
extractor=MistralOCRExtractor(client=mistral_client),
text_splitter=MarkdownTextSplitter(
MarkdownTextSplitterConfig(chunk_size=5048, chunk_overlap=50)
),
embedder=MistralEmbedder(client=mistral_client),
vector_store=vector_store,
)