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
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
MODEL_SPECS (class attribute)
Raises
ValueErrorif no API key is resolvable.ImportErrorifmistralaiisn't installed.ValueErrorfrom_validate_api_key()only for explicit unauthorized/401/"api key" error text; other validation errors are logged as warnings, not raised.
[!NOTE]
base_urlparameter is currently inert As noted above,MistralEmbedder.__init__storesself.base_url, but the actualMistral(...)client is constructed without passing it through. Passing a custombase_urlwill not redirect requests — this can only be confirmed by reading__init__; there is no test coverage to demonstrate the resulting behavior.
encode()
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
- Wraps single string in a list; raises
ValueErrorif empty (before or after filtering blanks). - Truncates each text to
self.max_lengthcharacters ifmax_lengthis set (character truncation, not token-aware). - Iterates in
batch_size-sized chunks; checks the LRU cache (_cache_get/_cache_set) per text. - Non-cached texts go through
_process_batch(), which applies the rate limiter (MistralRateLimiter.wait_if_needed()) then callsclient.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. - Tracks token usage and cost via
MistralUsageStats.add_request()iftrack_costs=True. - Stacks batches, L2-normalizes if
normalize_embeddings=True, updatesself._stats.
Returns
np.ndarray of shape (n, 1024) — always 2D, no single-string unwrap.
Raises
ValueErrorfor empty input.RuntimeErrorif all retries in_process_batchare 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
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 APIs
- BaseEmbedder — parent class
- OpenAIEmbedder, GeminiEmbedder — sibling hosted-API embedders