A Python library for parallel LLM inference across providers, built on Polars DataFrames.
Polar Llama is a Python library that enables parallel inference calls to multiple Large Language Model providers through Polars dataframes. It streamlines batch processing of AI queries without serial request delays, making it ideal for data-intensive AI applications. 0.5.0 adds a local MLX inference backend for Apple Silicon, folding on-device generation into the same .llama expression API used for hosted providers — no keys, no network required.
Send multiple inference requests in parallel without waiting for individual completions
Leverages efficient Polars dataframe operations for request management
Supports context-preserving conversations across multiple message exchanges
Connects with OpenAI, Anthropic, Gemini, Groq, AWS Bedrock — and now on-device MLX
Apple Silicon only, Python ≥ 3.10 — installs mlx + mlx-lm for the in-process local backend:
Get started with a simple example
col(...).llama.inference_local(...) — run generation on-device on Apple Silicon, no provider API, no keys, no network
The headline feature of 0.5.0: a local inference backend built on mlx-lm, exposed through the same .llama namespace you already use for OpenAI, Anthropic, Gemini, Groq, and Bedrock. There are two selectable engines:
Points the existing async Rust fan-out at a local OpenAI-compatible endpoint (mlx_lm.server, vllm-mlx) via OPENAI_BASE_URL — no Rust changes, inherits all existing concurrency and error handling
A map_batches UDF wrapping mlx-lm's BatchGenerator directly in the Python process, behind a LocalEngine protocol with a FakeEngine test seam. Optional extra: pip install polar-llama[local]
10.36× faster prefill on shared prompts, at exact greedy parity
When rows in a batch share a long common prefix — a shared system prompt, or few-shot demonstrations — the in-process engine normally re-prefills that identical prefix for every row. Collapsed prefill (polar_llama/local/collapsed_prefill.py) computes the shared token-level longest-common-prefix once and batches only the per-row suffixes. Measured 10.36× vs sequential on gemma-3n E4B (32 rows, 5 KB shared prompt) at 32/32 exact greedy parity. It falls back to the plain batch_generate path automatically when the shared prefix is short, so it's safe to leave on.
~47% KV-memory cut at fp16 parity, opt-in via POLAR_LLAMA_LOCAL_KV_BITS=4
BatchQuantizedKVCache closes mlx-lm's "quantized KV × batching" gap. Setting POLAR_LLAMA_LOCAL_KV_BITS=4 cuts KV memory by roughly 47% at parity with fp16 batched output, roughly doubling the batch size or context length that fits in 24 GB — a memory/capacity win rather than a throughput speedup with the current unfused attention path.
Runtime monkeypatch correcting garbled batched generation on hybrid Gemma models
A runtime monkeypatch (polar_llama/local/_mlx_patches.py) corrects a RoPE offset-aliasing bug in mlx-lm that garbled batched generation on hybrid Gemma 3n / Gemma 4 models — verified token-identical to sequential generation. Applied automatically whenever a Gemma 3n or Gemma 4 model is loaded through inference_local. A ready-to-post upstream PR lives in patches/PR_1384.md.
Start with engine="server" unless you need the lowest latency for a single Mac with no server process to manage
| engine="server" (default) | engine="in_process" | |
|---|---|---|
| How it runs | Existing async Rust fan-out talks HTTP to a local OpenAI-compatible server you start yourself | A Python map_batches UDF drives mlx-lm directly in the same process |
| Requires | Any local server implementing /v1/chat/completions (mlx_lm.server, vllm-mlx, llama.cpp server, LM Studio) | pip install polar-llama[local] (mlx + mlx-lm) and an Apple Silicon Mac |
| Concurrency | Rust futures::buffered, same POLAR_LLAMA_MAX_CONCURRENCY knob as hosted providers | mlx-lm's own continuous-batching scheduler (BatchGenerator) |
| Maturity | Low risk — no new code path, just a different base URL | Newer, more moving parts — treat as experimental |
Ships with mlx-lm, Apple Silicon only:
Continuous batching (BatchGenerator) and batched, left-padded KV cache (BatchKVCache / BatchRotatingKVCache) — Polar Llama doesn't reimplement either:
The loaded model is held in a process-global singleton behind a lock, keyed by (model, engine), so repeated calls reuse the same weights and cache instead of reloading per batch. The result column is String completions in the original row order — the same contract as every other inference_* function in the library.
Emit tool calls as structured output, execute them batch-parallel, then synthesize a summary — three explicit turns, each an ordinary column
DSPy-style Signature / Predict / BootstrapFewShot / InstructionOptimizer against a labeled DataFrame
Maintain context across multiple messages for more natural interactions
Process customer feedback at scale
Polar Llama supports multiple LLM providers, plus on-device MLX
Default model: gpt-4o-mini
Default model: claude-opus-4-8
Default model: gemini-2.5-flash. Native system_instruction support and native JSON-schema structured outputs (response_json_schema).
Default model: llama-3.3-70b-versatile
Default model: us.anthropic.claude-haiku-4-5-20251001-v1:0. Requires AWS credentials configured; region resolves from AWS_REGION / AWS_DEFAULT_REGION before falling back to us-east-1.
New in 0.5.0 — no provider API, runs entirely on-device via mlx-lm
Set up your API keys and overrides in a .env file:
Provider-native prompt caching shares a cached system prefix across rows (Anthropic cache_control, 5m/1h TTL):
Run tests with configured providers:
inference_local), collapsed prefix prefill, batched quantized KV cache, and the mlx-lm #1384 batched-RoPE fix for hybrid Gemma models.tools_to_response_model, execute_tool_calls), provider-native prompt caching, a DSPy-style prompt optimization engine (Signature, Predict, BootstrapFewShot, InstructionOptimizer), OPENAI_BASE_URL / ANTHROPIC_BASE_URL proxy support, and POLAR_LLAMA_MAX_CONCURRENCY.gpt-4-turbo and claude-3-opus-20240229 replaced), fixed Gemini and Bedrock structured-output auth, removed disabled TLS verification, and a significant performance pass (shared HTTP client, bounded concurrency, cached Bedrock credentials).embedding_async), similarity functions (cosine_similarity, dot_product, euclidean_distance), and HNSW approximate nearest neighbor search (knn_hnsw).Notable functions and the .llama namespace methods available as of 0.5.0
| Function / Method | Purpose |
|---|---|
| .llama.inference_local(model=..., engine=..., ...) | Local MLX generation, new in 0.5.0 |
| mcp_tools(transport) | Fetch tool definitions from an MCP server (tools/list) |
| tools_to_response_model(tools) | Build the structured-output emission schema for tool calls |
| execute_tool_calls(expr, transport=... | executor=...) | Run every emitted call of every row in parallel; failures are data |
| tool_results_to_message(expr) | Render a results column as a message for the synthesis turn |
| Signature / Predict / evaluate | Declare a task and run one batched inference per DataFrame |
| BootstrapFewShot / InstructionOptimizer | Mine few-shot demos / search instructions against labeled data |
| embedding_async(expr, provider=..., model=...) | Parallel embedding generation |
| cosine_similarity / dot_product / euclidean_distance | Rust-powered vector similarity metrics |
| knn_hnsw(query, corpus, k=...) | HNSW approximate nearest neighbor search |
| tag_taxonomy(expr, taxonomy, ...) | Taxonomy-based classification with reasoning and confidence |
Process large datasets with AI insights — sentiment analysis, classification, entity extraction with validated structured outputs
Batch-parallel tool-call emission and execution against an MCP server or Python callable, with every intermediate step an inspectable column
Run classification, tagging, or prompt tuning entirely on Apple Silicon with no API keys and no network dependency
Generate embeddings and run HNSW nearest-neighbor search combined with taxonomy filtering for precise, context-aware retrieval
Licensed under MIT.
Questions or issues? Open one on GitHub.