Providers
haiku.rag uses three kinds of model: an embedder, a question-answering model, and an optional reranker. Each is configured with a provider and a name.
Summary
| Provider | QA | Embeddings | Reranking | Extra on haiku.rag-slim |
Key |
|---|---|---|---|---|---|
ollama |
yes | yes | none | ||
openai |
yes | yes | none | OPENAI_API_KEY |
|
vllm |
yes | yes, multimodal | yes, multimodal | none | |
openrouter |
yes | yes, multimodal | yes, multimodal | none | OPENROUTER_API_KEY |
anthropic |
yes | anthropic |
ANTHROPIC_API_KEY |
||
google |
yes | google |
GOOGLE_API_KEY |
||
groq |
yes | groq |
GROQ_API_KEY |
||
mistral |
yes | mistral |
MISTRAL_API_KEY |
||
bedrock |
yes | bedrock |
AWS credentials | ||
voyageai |
yes, multimodal | voyageai (in haiku.rag) |
VOYAGE_API_KEY |
||
cohere |
yes, multimodal | yes | cohere (in haiku.rag) |
CO_API_KEY |
|
sentence-transformers |
yes | cross-encoder (in haiku.rag) |
|||
cross-encoder |
yes | cross-encoder (in haiku.rag) |
|||
zeroentropy |
yes | zeroentropy (in haiku.rag) |
ZEROENTROPY_API_KEY |
||
jina |
yes | none | JINA_API_KEY |
||
jina-local |
yes | jina (in haiku.rag) |
Any other provider Pydantic AI supports works for QA, passed to it by name. Installation lists the extras.
haiku-rag and haiku-ingester load a .env file from the working directory on start, which is a place for these keys. Library use does not read .env.
Ollama is reached at providers.ollama.base_url, which defaults to OLLAMA_BASE_URL or http://localhost:11434. A model's own base_url overrides it:
Model settings
These settings apply to the QA and title models. The picture-description model reads them only under rebuild --descriptions, see Picture handling:
- temperature: Sampling temperature. Unset by default. The built-in QA and title models set 0.3 when their section is omitted.
- max_tokens: Maximum tokens in a response. Unset by default, except title generation (100).
- thinking: Reasoning on or off, or an effort level, see Thinking.
- base_url: Endpoint of an OpenAI-compatible server (vLLM, LM Studio, sglang).
- api_key: Key for this endpoint, see Per-endpoint API keys.
- extra_body: Raw request fields, see Raw provider pass-through.
- vision: Whether the model reads images. Default
false, andtruefor the built-in QA model whenqais omitted.
haiku.rag applies them on the providers it builds directly: ollama, vllm, openai, openrouter, anthropic, google, groq, bedrock and mistral. Any other provider is passed to Pydantic AI by name, which applies none of them, and haiku.rag logs a warning when they are set.
Per-endpoint API keys
The openai provider reads OPENAI_API_KEY, so several OpenAI-compatible endpoints would share one key. api_key gives each its own, and variable expansion keeps the secret in the environment:
qa:
model:
provider: openai
name: some-model
base_url: https://vendor-a.example/v1
api_key: ${VENDOR_A_KEY}
embeddings:
model:
provider: openai
name: some-embedding-model
vector_dim: 1024
base_url: https://vendor-b.example/v1
api_key: ${VENDOR_B_KEY}
api_key is honored on the openai, ollama, openrouter and vllm providers, on vllm and openrouter embedders and rerankers, and on the picture-description endpoint, which falls back to OPENAI_API_KEY only for the public OpenAI endpoint. Other providers read their own environment variable, and setting api_key on them raises.
Thinking
thinking takes false, true, or an effort level: minimal, low, medium, high, xhigh. Unset leaves the model's default.
How the value reaches the model depends on the provider:
- Vendor APIs (
openaiwithout abase_url,anthropic,google,groq,bedrock,mistral): passed as Pydantic AI's unifiedthinkingsetting, which it maps per provider and clamps to what each model offers. See the Pydantic AI thinking documentation. - Self-hosted endpoints (
ollama,vllm,openaiwith abase_url, and the picture-description model): sent as the request'sreasoning_effortfield, whatever the model name.falsesendsnone,truesendsmedium, and a level is sent as written. The server decides what it means, and a chat template may reject a level it does not know. Ollama never rejects one, mappingminimaltolowandxhightomax.
Write the level the model accepts:
qa:
model:
provider: vllm
name: Inferact/Qwen3.8-27B-NVFP4
base_url: http://localhost:11439
thinking: xhigh
A chat template with a switch of its own ignores reasoning_effort and takes the switch through extra_body.chat_template_kwargs. Leave thinking unset when you set the switch, since a chat_template_kwargs value takes precedence:
qa:
model:
provider: vllm
name: RedHatAI/Muse-Glimmer-30B-NVFP4
base_url: http://localhost:11450
extra_body:
chat_template_kwargs:
reasoning_strength: high
Anthropic thinking and max_tokens
Anthropic requires max_tokens to exceed the thinking budget, and thinking: true requests Pydantic AI's default budget of 10000 tokens. Set max_tokens above 10000 on Claude models that use budget-based thinking, or leave it unset on Sonnet 4.6+ and Opus 4.6+, which use adaptive thinking.
provider: bedrock uses Bedrock Converse, which does not serve the proprietary OpenAI models and raises for one. provider: bedrock-mantle reaches them, passed to Pydantic AI by name, so its settings are not applied.
Raw provider pass-through
extra_body is forwarded verbatim as Pydantic AI's ModelSettings.extra_body, and its keys become top-level request fields:
qa:
model:
provider: vllm
name: Inferact/Qwen3.8-27B-NVFP4
base_url: http://localhost:11439
extra_body:
top_p: 0.95
top_k: 20
min_p: 0
It is honored by openai, ollama, openrouter, anthropic, groq and vllm, and ignored by google, bedrock and mistral. Ollama honors only top_p of the three above. extra_body.reasoning_effort overrides the value thinking sends.
Embedding providers
An embedding model needs provider, name and vector_dim, which must be the model's own output dimension. embeddings.batch_size (default 512) is how many text chunks go in one embedding call during ingest. Lower it for a provider that caps tokens per request. Pictures are embedded one per call.
embeddings:
model:
provider: sentence-transformers # in-process, HuggingFace models
name: all-MiniLM-L6-v2
vector_dim: 384
An OpenAI-compatible server takes provider: openai with a base_url that includes /v1:
embeddings:
model:
provider: openai
name: text-embedding-qwen3-embedding-4b
vector_dim: 2560
base_url: http://localhost:1234/v1 # LM Studio
Query and document prefixes
Some embedding models expect a task marker on every query and every document, embeddinggemma and e5 among them. embeddings.model.query_prefix is prepended to every query and embeddings.model.document_prefix to every chunk before embedding. Both default to empty. The string is used verbatim, trailing space included, so quote it in YAML: a plain scalar loses its trailing space, and a : inside one is read as a mapping.
embeddings:
model:
provider: vllm
name: google/embeddinggemma-2
vector_dim: 768
query_prefix: "task: question answering | query: "
document_prefix: "title: none | text: "
The query prefix is the embeddinggemma model card's question-answering prompt and the document prefix its document prompt. The card lists other query tasks with the same document prefix, among them "task: search result | query: " for document search.
The prefixes are honoured on ollama, openai, vllm and openrouter. voyageai, cohere and sentence-transformers mark queries and documents themselves and raise when either prefix is set. Images get no prefix, and full-text search indexes the chunk text without one.
Both prefixes are part of the recorded embedder identity, and changing one is treated like changing the model (see Storage). The document prefix shapes every stored vector, so a changed document_prefix needs haiku-rag rebuild --embed-only, and haiku-rag rebuild --set-embedder refuses it. The query prefix shapes only queries, so a changed query_prefix is recorded by haiku-rag rebuild --set-embedder without re-embedding.
Multimodal embedders
embeddings.model.multimodal: true puts pictures in the same vector space as text, for text-to-figure and image-as-query search. It is supported on vllm, openrouter, voyageai and cohere, and raises on any other provider. The same providers without the flag embed text only.
Only a multimodal embedder produces picture chunks at ingest. Without one, an image-only document produces no chunks and cannot be retrieved. Switching multimodal does not change the stored embedding identity and raises no drift error. Re-ingest or rebuild to add or drop picture chunks.
embeddings:
model:
provider: vllm
name: Qwen/Qwen3-VL-Embedding-8B
vector_dim: 4096
base_url: http://localhost:8000/v1
multimodal: true
provider: vllm sends text in the standard input field and images in vLLM's messages form. Tested with Qwen/Qwen3-VL-Embedding-8B (4096) and jinaai/jina-embeddings-v4 (2048).
embeddings:
model:
provider: openrouter
name: nvidia/llama-nemotron-embed-vl-1b-v2:free
vector_dim: 2048
multimodal: true
provider: openrouter defaults base_url to https://openrouter.ai/api/v1. Tested with nvidia/llama-nemotron-embed-vl-1b-v2:free (2048), voyageai/voyage-multimodal-3.5 (1024) and google/gemini-embedding-2 (3072). Its embedding models are listed at /v1/embeddings/models, not /v1/models.
VoyageAI's voyage-multimodal-3 (1024) and Cohere's embed-v4.0 take the flag the same way.
A data URI passed as a plain string is embedded as text by these endpoints, so an image reaches the image path only through a multimodal embedder. See Picture handling for how pictures, embedder and QA model combine.
Question-answering providers
Any provider Pydantic AI supports can answer. Ollama is the default:
OpenRouter sends thinking as its reasoning field, and the model decides what it honors.
provider: vllm serves a vLLM chat model, with base_url written with or without /v1. Its model profile, inferred from the model name, merges leading system messages and picks tool-schema behavior. thinking does not depend on that inference.
provider: vllm under embeddings.model and reranking.model is a different implementation, haiku.rag's own client for vLLM's embedding and rerank endpoints.
Other OpenAI-compatible servers take provider: openai with a base_url including /v1, and must serve a model that supports tool calling:
Google, Groq and Mistral follow the same shape, for example provider: google with name: gemini-2.5-flash. See the Pydantic AI model list.
Reranking providers
A reranker re-orders search results with a dedicated model. There is none by default. Configure reranking.model to enable one, and remove it or set model: null to disable it again. See Search settings for how it changes what search fetches.
Every reranker scores a chunk's text after its document title and section headings, each on its own line. A missing title or heading is left out.
reranking:
model:
provider: cross-encoder # any HuggingFace cross-encoder, in-process
name: Qwen/Qwen3-Reranker-0.6B
cross-encoder runs any sentence_transformers.CrossEncoder model. Also tested: BAAI/bge-reranker-v2-m3, cross-encoder/ms-marco-MiniLM-L-6-v2.
The local Jina Reranker v3 model is licensed CC BY-NC 4.0, which restricts commercial use. The API mode has no such restriction.
provider: vllm posts to vLLM's /v1/rerank, with base_url written with or without /v1.
Multimodal reranking
reranking.multimodal: true scores picture chunks by their image bytes as well as their text. It is supported on vllm and openrouter, and the model must accept images:
reranking:
multimodal: true
model:
provider: vllm
name: nvidia/llama-nemotron-rerank-vl-1b-v2
base_url: http://localhost:8001/v1
Picture chunks go as image documents beside the text documents in one rerank request. A chunk with neither text nor picture bytes is not sent.
On OpenRouter, base_url defaults to https://openrouter.ai/api/v1, and nvidia/llama-nemotron-rerank-vl-1b-v2:free is the reranker that takes images. Its text-only rerankers reject a document with no text. Rerank models are listed at /v1/models?output_modalities=rerank.
Model loading options
model_kwargs is forwarded to the Transformers model loader and is supported only by the cross-encoder provider.