Skip to main content

LBI: LLM Batch Inference

Many LLM providers offer discounts (often 50%) for requests submitted through their batch APIs instead of the regular synchronous endpoints. Each provider's batch API looks different, though: different upload formats, different status fields, different ways of matching results back to requests. This project wraps OpenAI, Anthropic, Mistral, and Gemini's batch APIs in one normalized interface, so you can submit a batch, poll for completion, and read back results the same way regardless of provider.

Features

  • One interface, four providers - BaseBatchProvider gives OpenAI, Anthropic, Mistral, and Gemini the same create_batch / get_batch / get_results / cancel_batch / list_batches shape.
  • Normalized request/response models - build a BatchRequest once and run it against any provider; results always come back as BatchResult, matched to requests by custom_id.
  • Multi-target fan-out - send the same batch to several provider/model combinations at once and collect results independently, with per-target overrides and no single failure blocking the rest (run_batches_and_wait).
  • Async-first, with a one-call convenience - submit_and_wait handles submission, polling, and result retrieval in a single await; the individual steps are also available when you need to submit and collect in separate processes.

Supported providers

Provider Class Backing API
OpenAI OpenAIBatchProvider Batch API (file upload), or Chat Completions when inline
Anthropic AnthropicBatchProvider Message Batches API
Mistral MistralBatchProvider Batch API (file upload)
Gemini GeminiBatchProvider Batch API (inline requests)

Installation

pip install llm-batch-inference

or with uv:

uv add llm-batch-inference

The package is imported as lbi.

Configuration

Every provider accepts an explicit api_key, and falls back to its standard environment variable if one isn't passed:

Provider Environment variable
OpenAI OPENAI_API_KEY
Anthropic ANTHROPIC_API_KEY
Mistral MISTRAL_API_KEY
Gemini GEMINI_API_KEY (or GOOGLE_API_KEY)

See .env.example for a template.

Quickstart

lbi.v1 is the library's current public API.

import asyncio

import lbi.v1 as lbi


async def main() -> None:
    provider = lbi.create_provider('openai', api_key='sk-...')

    requests = [
        lbi.BatchRequest(
            custom_id='1',
            messages=[
                lbi.Message(role=lbi.Role.USER, content='Say hi in French.'),
            ],
        ),
        lbi.BatchRequest(
            custom_id='2',
            messages=[
                lbi.Message(role=lbi.Role.USER, content='Say hi in German.'),
            ],
        ),
    ]

    results = await provider.submit_and_wait(
        requests,
        model='gpt-4o-mini',
        batch_filename='greetings.jsonl',
    )

    for result in results:
        print(result.custom_id, result.status, result.content)


asyncio.run(main())

submit_and_wait is a convenience wrapper around three steps you can also call individually. If you want to submit a batch in one process and collect it in another later on:

info = await provider.create_batch(
    requests, model='gpt-4o-mini', batch_filename='greetings.jsonl'
)
info = await provider.wait_for_completion(info.batch_id)  # polls until terminal
results = await provider.get_results(info.batch_id)

get_batch, cancel_batch, and list_batches are also available for checking on or managing batches.

Running one batch across multiple providers or models

import lbi.v1 as lbi

targets = [
    lbi.BatchTarget(
        provider=lbi.create_provider('openai', api_key=OPENAI_KEY),
        model='gpt-4o-mini',
    ),
    lbi.BatchTarget(
        provider=lbi.create_provider('anthropic', api_key=ANTHROPIC_KEY),
        model='claude-haiku-4-5-20251001',
    ),
]

results = await lbi.run_batches_and_wait(requests, targets)

for r in results:
    print(r.label, r.status, r.error)

A failure on one target (submission, polling, or downloading results) is recorded on that target's MultiBatchResult and never stops the others. Call lbi.pre_validate(requests, targets) first to catch per-target constraint violations (e.g. a model that rejects a non-default temperature) before submitting anything.

Per-target overrides let you tune requests for one target without touching the shared request list:

lbi.BatchTarget(
    provider=lbi.create_provider('anthropic', api_key=ANTHROPIC_KEY),
    model='claude-sonnet-5',
    overrides=lbi.BatchOverrides(temperature=None),  # this model rejects a set temperature
)

Error handling

All exceptions raised by LBI subclass lbi.BatchLLMError:

Exception Raised when
BatchCreationError The provider rejected the batch at submission time
BatchNotFoundError The batch ID is unknown to the provider
ResultsNotReadyError Results were requested before the batch reached a terminal state
BatchPollTimeoutError wait_for_completion / submit_and_wait exceeded its timeout
BatchCancelledError An operation was attempted on a cancelled batch
ProviderError The underlying provider SDK returned an unexpected error

Running Tests

To run the unit tests:

uv run pytest

To run the integration tests:

uv run pytest -m integration

Use the verbose flag -v to get more detailed output and use the -n flag to run multiple tests in parallel (-n auto runs one test per CPU core in parallel).

Example:

uv run pytest -n auto -v -m integration

You can also run specific tests and fixtures by keyword:

uv run pytest -n auto -v -m integration -k 'full_batch_lifecycle and mistral'

Publishing to PyPI

  1. Bump the version in [pyproject.toml](./pyproject.toml):

    version = "0.2.x"
    
  2. Build the package:

    uv build
    
  3. Publish package:

    uv publish
    
  4. Add tag in Git:

    git add pyproject.toml
    git commit -m "Bump version to 0.2.x"
    git tag v0.2.x
    git push origin main --tags
    

Contact

If you have any questions or feedback, feel free to connect with me on LinkedIn at linkedin.com/in/daniel-di-giovanni/ or send me an email at dannyjdigio@gmail.com.

Metadata

Release files for llm-batch-inference 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llm-batch-inference 0.2.1
File Size Uploaded Provenance Actions
llm_batch_inference-0.2.1.tar.gz 20.8 kB Without provenance Details for llm_batch_inference-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for llm-batch-inference 0.2.1
File Interpreter ABI Platform Actions
llm_batch_inference-0.2.1-py3-none-any.whl Python 3 none any Details for llm_batch_inference-0.2.1-py3-none-any.whl

Total release size: 50.7 kB

Release files / llm_batch_inference-0.2.1.tar.gz

Download URL llm_batch_inference-0.2.1.tar.gz
Size 20.8 kB
Tags Source
SHA-256 checksum
How to use checksums
7785e0bc67b6805ed262fe6aacb35049b028aae5f67d807852aac95790c03827
BLAKE2b-256 checksum
How to use checksums
6e3b4ddc5d35d01aebab2580e1525eb6497f340b1e491e3d83dc68add4892393
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / llm_batch_inference-0.2.1-py3-none-any.whl

Download URL llm_batch_inference-0.2.1-py3-none-any.whl
Size 29.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e416f694a219384093f0edb63c5e24fe6ac3af50e8ff2040a8b483f313fd334c
BLAKE2b-256 checksum
How to use checksums
94423a330f1a2bd52ce4660b1c5d1744a7fa7155c3647cd65fe3c4e15d5a3e89
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for llm-batch-inference 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page