MistralEmbedder

On this page

embeddings.mistral_embedder.MistralEmbedder(BaseEmbedder) — Mistral AI Embeddings API client.

Purpose

Wraps mistralai.Mistral().embeddings.create() with a client-side requests-per-second rate limiter, an LRU cache, retry-with-backoff, and cost estimation/tracking.

Constructor

Python · 18 lines
MistralEmbedder(
    model_name: str = "mistral-embed",
    api_key: Optional[str] = None,
    base_url: str = "https://api.mistral.ai/v1",
    normalize_embeddings: bool = True,
    batch_size: int = 50,
    max_length: Optional[int] = None,
    cache_embeddings: bool = True,
    cache_size: int = 5000,
    show_progress: bool = False,
    timeout: int = 60,
    max_retries: int = 3,
    retry_delay: float = 1.0,
    enable_rate_limiting: bool = True,
    max_requests_per_second: int = 5,
    track_costs: bool = True,
    **kwargs,
)

Parameters

NameTypeDefaultNotes
model_namestr"mistral-embed"Only model in MODEL_SPECS; unrecognized names fall back to a generic 1024-dim/$0.10-per-1M spec with a warning
api_keyOptional[str]NoneFalls back to os.getenv('MISTRAL_API_KEY'); raises ValueError if unset
base_urlstr"https://api.mistral.ai/v1"Stored but not actually passed to the Mistral(...) client constructor — the SDK client is built with only api_key and timeout_ms, so a custom base_url here has no effect on requests
cache_sizeint5000Max entries in the LRU cache before oldest entries are evicted
enable_rate_limitingboolTrueEnables MistralRateLimiter
max_requests_per_secondint5
track_costsboolTrueEnables self.usage_stats = MistralUsageStats()

MODEL_SPECS (class attribute)

ModelDimensionsMax tokensCost per 1M tokensArabic support
mistral-embed10248192$0.10good

Raises

  • ValueError if no API key is resolvable.
  • ImportError if mistralai isn't installed.
  • ValueError from _validate_api_key() only for explicit unauthorized/401/"api key" error text; other validation errors are logged as warnings, not raised.

[!NOTE] base_url parameter is currently inert As noted above, MistralEmbedder.__init__ stores self.base_url, but the actual Mistral(...) client is constructed without passing it through. Passing a custom base_url will not redirect requests — this can only be confirmed by reading __init__; there is no test coverage to demonstrate the resulting behavior.

encode()

Python · 7 lines
encode(
    texts: Union[str, List[str]],
    show_progress_bar: bool = False,
    convert_to_numpy: bool = True,
    batch_size: Optional[int] = None,
    **kwargs,
) -> np.ndarray

Behavior

  1. Wraps single string in a list; raises ValueError if empty (before or after filtering blanks).
  2. Truncates each text to self.max_length characters if max_length is set (character truncation, not token-aware).
  3. Iterates in batch_size-sized chunks; checks the LRU cache (_cache_get/_cache_set) per text.
  4. Non-cached texts go through _process_batch(), which applies the rate limiter (MistralRateLimiter.wait_if_needed()) then calls client.embeddings.create(). Retries on rate-limit (429/"rate limit") and connection/timeout/5xx-looking errors with exponential backoff; other errors are raised immediately without retry.
  5. Tracks token usage and cost via MistralUsageStats.add_request() if track_costs=True.
  6. Stacks batches, L2-normalizes if normalize_embeddings=True, updates self._stats.

Returns

np.ndarray of shape (n, 1024) — always 2D, no single-string unwrap.

Raises

  • ValueError for empty input.
  • RuntimeError if all retries in _process_batch are exhausted.
  • Re-raises non-retryable errors from the Mistral SDK.

MistralRateLimiter

Tracks request timestamps in a list, protected by threading.RLock. wait_if_needed() sleeps just long enough to keep the count of requests in the trailing 1-second window at or below max_requests_per_second.

Cost tracking

estimate_cost(texts) -> Dict[str, Any]

Estimates tokens as total_chars // 4 (a rough heuristic, not a real tokenizer call) and multiplies by cost_per_1m_tokens. This is a local, non-API estimate.

get_usage_stats() -> Dict[str, Any]

Merges self._stats with cache size/hit-rate info and (if track_costs) MistralUsageStats.get_summary().

MistralUsageStats (dataclass)

Fields: total_tokens, total_requests, total_cost, start_time, errors, cache_hits. .add_request(token_count, cost) accumulates; .get_summary() derives avg_tokens_per_request and rounds total_cost_usd to 6 decimal places.

Context manager

__enter__ returns self; __exit__ logs a session summary (tokens, requests, cost, errors, elapsed time) if track_costs=True.

Examples

Python · 9 lines
from zerda.embeddings import MistralEmbedder

embedder = MistralEmbedder(api_key="your-key")
vectors = embedder.encode(["first document", "second document"])

cost = embedder.estimate_cost("a moderately long paragraph of text")

with MistralEmbedder(max_requests_per_second=2) as e:
    v = e.encode(["a", "b", "c"])

Related pages