Retrievers

Retrievers execute the search against your index. Search Toolkit provides vector (semantic) and keyword (BM25) retrievers, which you can combine for hybrid search.

Available retrievers

Available retrievers

RetrieverPurpose
Vector RetrieverSemantic search using embeddings
Keyword RetrieverBM25 / keyword search
Hybrid searchCombine vector and keyword retrievers
Custom RetrieversCustom search logic
Vector Retriever

Vector Retriever

Performs semantic search using embeddings. Finds chunks with similar meaning to the query, even if they use different words.

Installation: Core library (no extra required)

Example:

from mistralai.search.toolkit.retrieval.retrievers import VectorRetriever

retriever = VectorRetriever(
    client=vector_store,  # Vector store client (Vespa or custom implementation)
    embedder=embedder,    # MistralEmbedder or custom Embedder
)

results = await retriever.retrieve(
    query="What is semantic search?",
    top_k=10,
)

Configuration options:

OptionTypeDefaultPurpose
clientVectorStoreIndexRequiredVector store to search
embedderEmbedderRequiredEmbedder for query vectorization

When to use:

  • General semantic search across your documents
  • Finding conceptually similar content
  • Handling synonyms and paraphrasing naturally
Keyword Retriever

Keyword Retriever

Performs keyword search against a KeywordStoreIndex. It finds chunks that share terms with the query and ranks them by lexical relevance.

i
Information

The built-in Vespa and Postgres backends don't implement KeywordStoreIndex. Use KeywordRetriever with a custom keyword store. For hybrid search with a built-in backend, use VectorRetriever; it sends both the query text and embedding to the backend.

Installation: Core library (no extra required)

Example:

from mistralai.search.toolkit.retrieval.retrievers import KeywordRetriever

retriever = KeywordRetriever(
    client=keyword_store,  # Custom KeywordStoreIndex implementation
)

results = await retriever.retrieve(
    query="quarterly revenue report",
    top_k=10,
)

Configuration options:

OptionTypeDefaultPurpose
clientKeywordStoreIndexRequiredKeyword store to search

When to use:

  • Exact-term matching (names, identifiers, error codes)
  • Queries where lexical relevance matters more than semantics
  • As one arm of a hybrid search (see below)

If you have separate vector and custom keyword stores, run both retrievers and fuse their results. Pass the retrievers to QueryEngine and combine them with a fusion reranker such as RRFRanker:

from mistralai.search.toolkit.retrieval import QueryEngine
from mistralai.search.toolkit.retrieval.retrievers import VectorRetriever, KeywordRetriever
from mistralai.search.toolkit.retrieval.rerankers import RRFRanker

query_engine = QueryEngine(
    retriever=[
        VectorRetriever(client=vector_store, embedder=embedder),
        KeywordRetriever(client=keyword_store),
    ],
    rerankers=[RRFRanker(rrf_k=60, top_k=10)],
)

result = await query_engine.search(query="What is RAG?", top_k=10)

See Rerankers for RRF and other fusion strategies.

Custom retrievers

Custom retrievers

Implement the Retriever protocol for custom search logic:

from mistralai.search.toolkit.context import RetrievalContext
from mistralai.search.toolkit.retrieval.retrievers import Retriever
from mistralai.search.toolkit.search import SearchResult

class CustomRetriever(Retriever):
    """Custom retriever with domain-specific logic."""

    async def retrieve(
        self,
        query: str,
        top_k: int = 10,
        include_metadata: bool = True,
        include_content: bool = True,
        context: RetrievalContext = RetrievalContext(),
    ) -> list[SearchResult]:
        """Retrieve relevant chunks for the query."""
        # 1. Preprocess query
        processed_query = self._preprocess(query)

        # 2. Search with custom logic
        results = await self._search(processed_query, top_k)

        # 3. Post-process or augment results
        enhanced_results = self._enhance(results)

        return enhanced_results

    def _preprocess(self, query: str) -> str:
        # Custom preprocessing (stemming, lemmatization, etc.)
        return query.lower().strip()

    async def _search(self, query: str, top_k: int) -> list[SearchResult]:
        # Custom search implementation
        ...

    def _enhance(self, results: list[SearchResult]) -> list[SearchResult]:
        # Augment results with additional context
        ...

# Use in QueryEngine
query_engine = QueryEngine(retriever=CustomRetriever())
See also

See also