๐Ÿ“˜ How TELUS Agriculture & Consumer Goods Transformed Trade Promotions with Haystack Agents
Maintained by deepset

Integration: Mistral

Use the Mistral API for embedding and text generation models.

Authors
deepset

Table of Contents

Overview

Mistral AI currently provides two types of access to Large Language Models:

  • An API providing pay-as-you-go access to the latest Mistral models like mistral-embed and mistral-small.
  • Open-source models available under the Apache 2.0 License, available on Hugging Face which you can use with the HuggingFaceTGIGenerator.

For more information on models available via the Mistral API, see the Mistal docs.

In order to follow along with this guide, you’ll need a Mistal API key. Add it as an environment variable, MISTRAL_API_KEY.

Installation

pip install mistral-haystack

Usage

Components

This integration introduces 4 components:

  • The MistralOCRDocumentConverter: Extracts text from documents using Mistral’s OCR API, with optional structured annotations for image regions and full documents.
  • The MistralDocumentEmbedder: Creates embeddings for Haystack Documents using Mistral embedding models (currently only mistral-embed).
  • The MistralTextEmbedder: Creates embeddings for texts (such as queries) using Mistral embedding models (currently only mistral-embed)
  • The MistralChatGenerator: Uses Mistral chat completion models such as mistral-tiny (default).

Use Mistral Generative Models

import os
from haystack.dataclasses import ChatMessage
from haystack_integrations.components.generators.mistral import MistralChatGenerator

os.environ["MISTRAL_API_KEY"] = "YOUR_MISTRAL_API_KEY"
model = "mistral-medium"

client = MistralChatGenerator(model=model)


response = client.run(
    messages=[ChatMessage.from_user("What is the best French cheese?")]
)
print(response)
{'replies': [ChatMessage(content='The "best" French cheese is subjective and depends on personal taste...', role=<ChatRole.ASSISTANT: 'assistant'>, name=None, meta={'model': 'mistral-medium', 'index': 0, 'finish_reason': 'stop', 'usage': {'completion_tokens': 231, 'prompt_tokens': 16, 'total_tokens': 247}})]}

Mistral LLMs also support streaming responses if you pass a callback into the MistralChatGenerator like so:

import os

from haystack.components.generators.utils import print_streaming_chunk
from haystack.dataclasses import ChatMessage
from haystack_integrations.components.generators.mistral import MistralChatGenerator

os.environ["MISTRAL_API_KEY"] = "YOUR_MISTRAL_API_KEY"
model = "mistral-medium"

client = MistralChatGenerator(
    model=model,
    streaming_callback=print_streaming_chunk
)

response = client.run(
    messages=[ChatMessage.from_user("What is the best French cheese?")]
)
print(response)

Use Mistral OCR for Document Conversion

The MistralOCRDocumentConverter extracts text from documents (PDFs, images) using Mistral’s OCR API. It supports multiple source types and can optionally enrich the output with structured annotations.

OCR with Embeddings Pipeline

Extract text from documents using OCR, split by pages, create embeddings, and store them in a document store:

import os
from haystack import Pipeline
from haystack.components.preprocessors import DocumentSplitter
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack_integrations.components.converters.mistral import MistralOCRDocumentConverter
from haystack_integrations.components.embedders.mistral import MistralDocumentEmbedder
from mistralai.models import DocumentURLChunk

os.environ["MISTRAL_API_KEY"] = "YOUR_MISTRAL_API_KEY"

# Initialize document store
document_store = InMemoryDocumentStore()

# Create indexing pipeline
indexing_pipeline = Pipeline()
indexing_pipeline.add_component("converter", MistralOCRDocumentConverter())
indexing_pipeline.add_component(
    "splitter",
    DocumentSplitter(split_by="page", split_length=2, split_overlap=1)
)
indexing_pipeline.add_component("embedder", MistralDocumentEmbedder())
indexing_pipeline.add_component("writer", DocumentWriter(document_store=document_store))

# Connect components
indexing_pipeline.connect("converter.documents", "splitter.documents")
indexing_pipeline.connect("splitter.documents", "embedder.documents")
indexing_pipeline.connect("embedder.documents", "writer.documents")

# Process documents
sources = [
    DocumentURLChunk(document_url="https://arxiv.org/pdf/1706.03762"),
    "./invoice.pdf",  # Local PDF file
]

result = indexing_pipeline.run({"converter": {"sources": sources}})

print(f"Indexed {len(document_store.filter_documents())} documents")

OCR with Structured Annotations

Define Pydantic schemas to extract structured information from images and documents:

import os
from typing import List
from haystack_integrations.components.converters.mistral import MistralOCRDocumentConverter
from mistralai.models import DocumentURLChunk
from pydantic import BaseModel, Field

os.environ["MISTRAL_API_KEY"] = "YOUR_MISTRAL_API_KEY"

# Define schema for image annotations (applied to each image/bbox)
class ImageAnnotation(BaseModel):
    image_type: str = Field(..., description="Type of image (diagram, chart, photo, etc.)")
    description: str = Field(..., description="Brief description of the image content")

# Define schema for document-level annotations
class DocumentAnnotation(BaseModel):
    topics: List[str] = Field(..., description="Main topics covered")
    urls: List[str] = Field(..., description="URLs found in the document")

converter = MistralOCRDocumentConverter()

sources = ["./financial_report.pdf"]

result = converter.run(
    sources=sources,
    bbox_annotation_schema=ImageAnnotation,
    document_annotation_schema=DocumentAnnotation,
)

# Documents now include enriched content and metadata
doc = result["documents"][0]
print(doc.content)  # Markdown with image annotations inline
print(doc.meta["source_topics"])    # e.g., ["finance", "quarterly report", "revenue", "expenses", "performance"]
print(doc.meta["source_urls"])      # e.g., ["https://example.com", ...]

For a complete example with structured annotations in a pipeline, see the OCR indexing pipeline example.

Use a Mistral Embedding Model

Use the MistralDocumentEmbedder in an indexing pipeline:

import os

from haystack import Document, Pipeline
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack_integrations.components.embedders.mistral.document_embedder import MistralDocumentEmbedder

os.environ["MISTRAL_API_KEY"] = "YOUR_MISTRAL_API_KEY"

document_store = InMemoryDocumentStore(embedding_similarity_function="cosine")

documents = [Document(content="My name is Wolfgang and I live in Berlin"),
             Document(content="I saw a black horse running"),
             Document(content="Germany has many big cities")]

embedder = MistralDocumentEmbedder()
writer = DocumentWriter(document_store=document_store)

indexing_pipeline = Pipeline()
indexing_pipeline.add_component(name="embedder", instance=embedder)
indexing_pipeline.add_component(name="writer", instance=writer)

indexing_pipeline.connect("embedder", "writer")

indexing_pipeline.run(data={"embedder": {"documents": documents}})

Use the MistralTextEmbedder in a RAG pipeline:

import os

from haystack import Document, Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack_integrations.components.embedders.mistral.document_embedder import MistralDocumentEmbedder
from haystack_integrations.components.embedders.mistral.text_embedder import MistralTextEmbedder
from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever
from haystack.components.builders import ChatPromptBuilder

os.environ["MISTRAL_API_KEY"] = "YOUR_MISTRAL_API_KEY"

document_store = InMemoryDocumentStore()

documents = [Document(content="My name is Wolfgang and I live in Berlin"),
             Document(content="I saw a black horse running"),
             Document(content="Germany has many big cities")]

document_embedder = MistralDocumentEmbedder()
documents_with_embeddings = document_embedder.run(documents)['documents']
document_store.write_documents(documents)

text_embedder = MistralTextEmbedder()
retriever = InMemoryEmbeddingRetriever(document_store=document_store)
prompt_builder = ChatPromptBuilder()
llm = MistralChatGenerator(streaming_callback=print_streaming_chunk)

messages = [ChatMessage.from_user("Here are some the documents: {{documents}} \\n Answer: {{query}}")]

rag_pipeline = Pipeline()
rag_pipeline.add_component("text_embedder", text_embedder)
rag_pipeline.add_component("retriever", retriever)
rag_pipeline.add_component("prompt_builder", prompt_builder)
rag_pipeline.add_component("llm", llm)


rag_pipeline.connect("text_embedder.embedding", "retriever.query_embedding")
rag_pipeline.connect("retriever.documents", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder.prompt", "llm.messages")

question = "Who lives in Berlin?"

result = rag_pipeline.run(
    {
        "text_embedder": {"text": question},
        "prompt_builder": {"template_variables": {"query": question}, "template": messages},
        "llm": {"generation_kwargs": {"max_tokens": 165}},
    }
)

License

mistral-haystack is distributed under the terms of the Apache-2.0 license.