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. Version 0.3.0 adds dataframe-native tool use / MCP integration, provider-native prompt caching, a DSPy-style prompt optimization engine, and a broad round of reliability, security, and performance work.
Send multiple inference requests in parallel without waiting for individual completions
Leverages efficient Polars dataframe operations and a fluent .llama namespace for request management
LLMs emit tool calls as structured output; execute_tool_calls runs every call of every row batch-parallel against an MCP server or a Python callable
Connects with OpenAI, Anthropic, Gemini, Groq, and AWS Bedrock models, all with current, non-deprecated default models
Minimum supported Python version is now 3.9 (abi3-py39 wheels).
Get started with a simple example
LLMs emit tool calls as structured output; execute_tool_calls runs every call of every row batch-parallel against an MCP server or a Python callable
Instead of running an opaque agent loop inside each row, the loop is unrolled into the dataframe: one "turn" is one with_columns pass, and every intermediate is an ordinary column you can inspect, explode, filter, cache, and resume — row text → emit calls → execute (parallel) → synthesize → answer.
Builds a Pydantic emission schema from tool definitions — the LLM emits tool calls as ordinary structured output; nothing is executed
Executes a column of emitted calls, every call of every row in parallel, against transport= (MCP server) or executor= (Python callable). Failures are data (is_error, _error), not exceptions
Renders a results column as a message for the synthesis turn (combine_messages + inference_messages)
Fetches tool definitions from an MCP server via tools/list. Supports streamable HTTP and stdio transports
Anything callable from Python can be a tool target via the executor escape hatch — a database, an internal API, a local function. Runs on a thread pool with the same errors-as-data semantics.
Three explicit turns, each a column: meal text -> emit searches -> execute in parallel -> synthesize summary
What's deliberately not here: no per-row agent loop (multi-turn pipelines are explicit emit → execute passes), no MCP sessions/state per row, no planners, memory, or graphs. Full guide: docs/TOOL_USE.md.
Share a cached system prefix across rows via cache=True or a CacheConfig
inference_async and inference_messages now accept a cache parameter. When enabled, Polar Llama detects shared prefixes (system prompts, schemas) across rows, groups rows by shared content, adds provider-specific cache control markers, and orders requests to maximize cache hits. Currently implemented via Anthropic cache_control content blocks, with 5-minute (default) and 1-hour (ttl="1h", extended-cache-ttl beta) TTLs. Bedrock also emits a CachePoint block on the Converse request (5-minute cache only).
inference_messages now also accepts List(Struct) input directly, in addition to JSON strings, and is handled natively in Rust rather than wrapped in a Python map_batches UDF — the default path stays lazy/streaming. Rows with no cacheable system prefix are no longer lumped into a single serial cache group; they are processed as individual rows.
polar_llama.optimize — declare a task, then tune instructions and few-shot demos against your labeled data
A small, declarative framework for building and optimizing LLM programs over Polars DataFrames, inspired by DSPy. Every candidate is evaluated with one parallel, batched inference call across the whole DataFrame — not per row — and the engine is fully testable offline via an injectable inference_fn backend.
Declarative task spec — "question -> answer" shorthand, or explicit InputField / OutputField with types and descriptions
Executable LLM module that runs one parallel, batched inference pass per DataFrame and returns pred_<field> columns
Metric-based scoring of a module against a labeled DataFrame
Mines few-shot demos from rows the module already answers correctly, or runs a COPRO-style instruction search where an LLM proposes rewrites and the best candidate wins
Output fields can be typed and described for stronger structured outputs
Maintain context across multiple messages for more natural interactions
Process customer feedback at scale
Polar Llama supports multiple LLM providers, with updated defaults and new capabilities in 0.3.0
Requests no longer hardcode temperature / max_tokens — the o-series and GPT-5 reject those parameters. Pricing data and o200k tokenizer detection added for GPT-5/4.1/o-series. Supports OPENAI_BASE_URL for proxies and gateways.
Pricing data added for Claude 4.x / Fable 5. Supports cache=True prompt caching and ANTHROPIC_BASE_URL for proxies and gateways.
Gemini now has native system_instruction support and native JSON-schema structured outputs (response_json_schema). Structured-output requests now authenticate via the x-goog-api-key header instead of the previously-broken OpenAI-style Bearer auth.
Requests no longer hardcode temperature / max_tokens.
Bedrock now works from the synchronous inference expression (previously errored), structured outputs route through the AWS SDK instead of a raw HTTP POST, region now respects AWS_REGION / AWS_DEFAULT_REGION before falling back to us-east-1, and prompt caching emits a real CachePoint block (5-minute cache only). Pricing data added for Bedrock Claude 4.5.
Set up your API keys and new 0.3.0 tuning knobs in a .env file:
| Variable | Purpose | Default |
|---|---|---|
| OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY / GROQ_API_KEY | Provider credentials | — |
| AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY | Bedrock credentials | — |
| AWS_REGION / AWS_DEFAULT_REGION | Bedrock region (checked in this order) | us-east-1 |
| OPENAI_BASE_URL | Base URL override for OpenAI-compatible endpoints (proxies, gateways) | https://api.openai.com |
| ANTHROPIC_BASE_URL | Base URL override for the Anthropic endpoint | https://api.anthropic.com |
| POLAR_LLAMA_MAX_CONCURRENCY | Max concurrent in-flight requests per batch | 64 |
Run tests with configured providers:
x-goog-api-key.inference expression.ring rustls provider instead of aws-lc-rs, whose native build failed under MSVC.join_all, JSON schemas compiled once per batch, and roughly 400 lines of duplicated per-row dispatch removed from the expression layer.new() / with_model() (deprecated since 0.2.0) — use new_with_model(). Removed import-time debug printing from the Python package and native module.CHANGELOG.md under the 0.3.0 entry.Process large datasets with AI insights - sentiment analysis, classification, entity extraction with validated structured outputs
Emit tool calls per row, execute them in parallel against an MCP server or database, and synthesize results - fully inspectable at every turn
Tune instructions and few-shot demos against labeled data with BootstrapFewShot and InstructionOptimizer before shipping a prompt to production
Cut input-token costs on shared system prompts with provider-native prompt caching across thousands of rows
Licensed under MIT.
Questions or issues? Open one on GitHub.