Entry points and configuration
process_prompts
async_batch_llm.process_prompts
async
process_prompts(strategy: LLMCallStrategy[TOutput], prompts: PromptSource, *, config: ProcessorConfig | None = None, concurrency: int | None = None, progress: bool | ProgressCallbackFunc = False, preserve_order: bool = False, artifact_store: ArtifactStore | None = None, resume: ResumePolicy = ResumePolicy.NONE, **processor_kwargs: Any) -> BatchResult[TOutput, Any]
Run strategy over prompts and collect every result.
The one-liner entry point — drains :func:process_stream into a
:class:BatchResult (whose results are in completion order). For
lazy, bounded-input processing of very large inputs, use
:func:process_stream directly with a positive
config.max_queue_size and config.max_result_queue_size and consume
results promptly. This collection API still retains every final result in
its returned :class:BatchResult.
concurrency=N is shorthand for ProcessorConfig(concurrency=N) —
the single knob that coherently sizes workers, provider admission, and
built-in model connection pools (v0.20.0).
progress=True renders a tqdm bar when tqdm is installed
(pip install 'async-batch-llm[progress]') and falls back to interval
logging otherwise; pass a callable (completed, total, current_item_id)
for a custom reporter. Works for both collected and streamed runs
(v0.20.0).
Source code in src/async_batch_llm/streaming.py
process_stream
async_batch_llm.process_stream
async
process_stream(strategy: LLMCallStrategy[TOutput], prompts: PromptSource, *, config: ProcessorConfig | None = None, concurrency: int | None = None, progress: bool | ProgressCallbackFunc = False, artifact_store: ArtifactStore | None = None, resume: ResumePolicy = ResumePolicy.NONE, **processor_kwargs: Any) -> AsyncIterator[WorkItemResult[TOutput, Any]]
Yield terminal results in completion order.
Ordered streaming is intentionally not offered: a slow early item would
block later completed results and require a potentially unbounded reorder
buffer. Use process_prompts(..., preserve_order=True) when collection is
acceptable.
concurrency=N is shorthand for ProcessorConfig(concurrency=N) —
the single knob that coherently sizes workers, provider admission, and
built-in model connection pools (v0.20.0).
Source code in src/async_batch_llm/streaming.py
llm
async_batch_llm.llm
llm(spec: str, *, response_parser: Callable[[LLMResponse], Any] | None = None, temperature: float | None = None, generation_config: dict[str, Any] | None = None, **model_kwargs: Any) -> ModelStrategy[Any]
Build a ready-to-use strategy from a "provider:model" string.
Example
from async_batch_llm import llm strategy = llm("openai:gpt-6-luna") # reads OPENAI_API_KEY strategy = llm("gemini:gemini-3.5-flash") # reads GOOGLE_API_KEY strategy = llm("deepseek:deepseek-v4-flash", thinking=False, max_connections=150) strategy = llm("openrouter:anthropic/claude-haiku-4-5") strategy = llm( ... "openai-compatible:meta-llama/Llama-3.1-8B-Instruct", ... base_url="http://localhost:8000/v1", ... api_key="EMPTY", # local servers often ignore the key ... )
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
str
|
|
required |
response_parser
|
Callable[[LLMResponse], Any] | None
|
Optional function parsing :class: |
None
|
temperature
|
float | None
|
Default sampling temperature, forwarded to the strategy.
Pass |
None
|
generation_config
|
dict[str, Any] | None
|
Provider-specific config forwarded on every call
(see :class: |
None
|
**model_kwargs
|
Any
|
Forwarded to the model constructor — e.g. |
{}
|
Returns:
| Type | Description |
|---|---|
ModelStrategy[Any]
|
The same strategy objects the explicit two-object form builds: |
ModelStrategy[Any]
|
class: |
ModelStrategy[Any]
|
class: |
ModelStrategy[Any]
|
OpenAI-compatible providers the model is created via |
ModelStrategy[Any]
|
|
ModelStrategy[Any]
|
the framework's normal strategy cleanup. |
Raises:
| Type | Description |
|---|---|
ValueError
|
The spec has no |
ImportError
|
The provider's optional dependency is not installed; the message names the exact install extra. |
Added in v0.20.0.
Source code in src/async_batch_llm/factory.py
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | |
call and call_result
One-shot calls are documented with the shared call pool on Single Call & Shared Call Pool.
RetryState
async_batch_llm.RetryState
dataclass
Mutable state that persists across retry attempts for a single work item.
This allows strategies to maintain state between retry attempts, enabling multi-stage retry patterns where each attempt can build on previous attempts.
Example use cases: - Partial recovery: Save successfully parsed fields from failed attempts - Progressive refinement: Track which parts of output need improvement - Smart retry prompts: Build targeted prompts based on what failed - Model escalation: Track validation errors vs network errors separately
Usage
In strategy's on_error():
if state: state.set('last_error_type', type(exception).name) state.set('validation_failures', state.get('validation_failures', 0) + 1)
In strategy's execute():
if state and state.get('validation_failures', 0) > 1: # Use smarter model or modified prompt pass
Added in v0.3.0.
__contains__
__copy__
__deepcopy__
Deep-copy application data without copying framework runtime state.
Source code in src/async_batch_llm/base.py
__getstate__
__repr__
__setstate__
clear
delete
Delete a value from the state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
State key to delete |
required |
raise_if_missing
|
bool
|
If True, raise KeyError if key doesn't exist. If False, silently ignore missing keys (default). |
False
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If key doesn't exist and raise_if_missing=True |
Source code in src/async_batch_llm/base.py
get
Get a value from the state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
State key to retrieve |
required |
default
|
Any
|
Value to return if key doesn't exist |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
Value associated with key, or default if not found |
Source code in src/async_batch_llm/base.py
set
Set a value in the state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
State key to set |
required |
value
|
Any
|
Value to store (can be any JSON-serializable type) |
required |
Middleware
async_batch_llm.middleware.Middleware
Bases: ABC, Generic[TInput, TOutput, TContext]
Abstract base class for middleware that intercepts the processing pipeline.
Ordering and failure semantics (onion model):
before_processruns once per logical item in registration order, inside its total deadline and before artifact lookup or strategy preparation;after_processruns in reverse registration order, so the first-registered middleware wraps outermost.on_errorruns in registration order and the first non-None result wins (remaining middlewares are not consulted).- A middleware that raises is logged and skipped — the item
continues through the rest of the chain (fail-open). Don't rely on
an exception in
before_processto block an item; returnNoneinstead, which skips it explicitly. Invalid returned items are rejected withMiddlewareContractError; cancellation and process-control exceptions propagate. - Replacement items may change prompt, context, and strategy, but must preserve the accepted item ID. The framework preserves the submission index and discards stale artifact keys.
after_processruns once on a newly executed success, before artifact append, and never on replay, filtering, oron_errorrecovery. Version changes to this hook withArtifactIdentity.application_versionorparser_versionwhen effective inputs do not otherwise change.- Middleware
on_errorruns for a terminal execution/preparation failure, not each retry. It is bypassed for filtering, invalid replacement items, controlled deadlines, and batch aborts. Strategyon_errorremains an attempt-level hook. Recovery result usage is additive: the framework includes usage consumed by failed provider attempts plus the usage returned by middleware. Do not duplicate failed-attempt usage in the returned result. - An invalid
after_processreturn value preserves the previous result, without retrying the provider or calling strategyon_error. A warning names the class and returned type once per middleware class per dispatcher.
after_process
abstractmethod
async
Called once after a newly executed success, in reverse registration order (onion-style: the first-registered middleware sees the result last).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
WorkItemResult[TOutput, TContext]
|
The result of processing |
required |
Returns:
| Type | Description |
|---|---|
WorkItemResult[TOutput, TContext]
|
Modified result (can add metadata, modify output, etc.) |
Source code in src/async_batch_llm/middleware/base.py
before_process
abstractmethod
async
before_process(work_item: LLMWorkItem[TInput, TOutput, TContext]) -> LLMWorkItem[TInput, TOutput, TContext] | None
Called once per accepted logical item per run, in registration order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
work_item
|
LLMWorkItem[TInput, TOutput, TContext]
|
The work item about to be processed |
required |
Returns:
| Type | Description |
|---|---|
LLMWorkItem[TInput, TOutput, TContext] | None
|
Modified work item, or None to skip processing this item |
LLMWorkItem[TInput, TOutput, TContext] | None
|
(the result fails with category |
Source code in src/async_batch_llm/middleware/base.py
on_error
abstractmethod
async
on_error(work_item: LLMWorkItem[TInput, TOutput, TContext], error: Exception) -> WorkItemResult[TOutput, TContext] | None
Called when an error occurs during processing, in registration order; the first middleware returning non-None handles the error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
work_item
|
LLMWorkItem[TInput, TOutput, TContext]
|
The work item that failed |
required |
error
|
Exception
|
The exception that was raised |
required |
Returns:
| Type | Description |
|---|---|
WorkItemResult[TOutput, TContext] | None
|
Custom result to use instead of error, or None to use default error handling |
Source code in src/async_batch_llm/middleware/base.py
BaseMiddleware
async_batch_llm.BaseMiddleware
Bases: Middleware[TInput, TOutput, TContext]
Base middleware with no-op implementations.
after_process
async
before_process
async
TokenEstimator
async_batch_llm.TokenEstimator
Bases: Protocol
Synchronous or asynchronous token estimate callable.
The explicit processor estimator is invoked after middleware and cooldown,
before quota or provider-capacity admission. attempt is ABL's logical
attempt number; rate-limit retries therefore reuse it while still receiving
a fresh estimate and reservation.
TokenEstimate
async_batch_llm.TokenEstimate
dataclass
CharacterTokenEstimator
async_batch_llm.CharacterTokenEstimator
dataclass
CharacterTokenEstimator(characters_per_token: float = 4.0, expected_output_tokens: int = 256, minimum_input_tokens: int = 1)
Explicit, approximate character-count token estimator.
This heuristic is intentionally never enabled automatically. It is useful for conservative local smoothing when a model-specific tokenizer is not available, but it does not claim provider- or model-specific accuracy.
__call__
__call__(prompt: str, *, strategy: LLMCallStrategy, attempt: int, state: RetryState | None) -> TokenEstimate
Estimate tokens without making a provider or network call.
Source code in src/async_batch_llm/token_estimation.py
ErrorClassifier, the built-in classifiers and the rate-limit strategies are on
Errors and Classification.