Backends¶
Every backend speaks the same protocol: given a Pydantic schema and a document, return a JSON-shaped extraction. Switching backends is a single argument.
Listing backends¶
Calling from Python¶
from idp.llm import get_backend
backend = get_backend("anthropic")
# or: "openai", "ollama", "nanonets", "china:qwen", "china:deepseek", ...
get_backend("auto") resolves in this order: anthropic > openai > ollama (if OLLAMA_HOST is set) > mock (last resort, with an INFO log line).
International providers¶
| provider | env var | default model | multimodal |
|---|---|---|---|
anthropic |
ANTHROPIC_API_KEY |
claude-3-5-sonnet-latest | yes |
openai |
OPENAI_API_KEY |
gpt-4o-mini | yes |
ollama |
(none — uses OLLAMA_HOST) |
whatever you have running | depends on the model |
nanonets |
(none — local model) | Nanonets-OCR2-3B | yes (it's a VLM) |
China LLM providers (8, OpenAI-compatible)¶
All eight speak the OpenAI Chat-Completions protocol, so the API-key-and-HTTP path is identical — only the env var name and the default model differ.
from idp.llm import get_china_backend
backend = get_china_backend("qwen", multimodal=True)
# backend.model == "qwen2.5-vl-72b-instruct"
| provider | env var | default model | multimodal model |
|---|---|---|---|
deepseek |
DEEPSEEK_API_KEY |
deepseek-chat | — (text only) |
qwen |
DASHSCOPE_API_KEY |
qwen-plus | qwen2.5-vl-72b-instruct |
zhipu |
ZHIPUAI_API_KEY |
glm-4-plus | glm-4v-plus |
moonshot |
MOONSHOT_API_KEY |
moonshot-v1-128k | moonshot-v1-128k-vision-preview |
yi |
YI_API_KEY |
yi-large | yi-vision |
doubao |
ARK_API_KEY |
doubao-pro-32k | doubao-1-5-vision-pro-32k |
hunyuan |
HUNYUAN_API_KEY |
hunyuan-pro | hunyuan-vision |
baichuan |
BAICHUAN_API_KEY |
baichuan4 | — (text only) |
MockBackend¶
get_backend("mock") returns a deterministic backend that produces empty defaults. Used for:
- CI runs without API keys (the full test suite runs against MockBackend).
- Showing the pipeline structure to a new contributor.
- Reproducing a known-bad extraction to debug a schema.
The mock backend is not a real LLM and shouldn't be confused with one — fields come back as defaults, the confidence is uniform 0.10, and the schema doesn't validate.
Self-hosted OCR (Nanonets-OCR2-3B)¶
A standalone, fully offline alternative for sensitive documents. No API key, no network. Heavy install: ~3 GB pip packages + ~7 GB model weights.
Speed: ~5–15 seconds per page on Apple M4 (CPU+GPU mixed, float16). First call downloads the model; subsequent calls use the ~/.cache/huggingface/hub/ cache.
Custom backends¶
When the 12+ shipped backends aren't enough — internal model gateway,
fixed-response test fixture, non-standard protocol — register your own
via the @register_backend decorator:
from idp.llm.backend import Backend, register_backend, get_backend
@register_backend("my-llm")
class MyBackend(Backend):
name = "my-llm"
def complete(self, req):
# ... call your model, return JSON string ...
return '{"field": "value"}'
backend = get_backend("my-llm") # looks up via the registry
For a full end-to-end example, see
examples/06_custom_backend.py.
Discovering what's registered¶
idp.llm.list_backends() returns a sorted list of canonical backend names
currently in the registry:
This does not include aliases ("openai" → "openai-compat") or
gated backends ("slowmock", "nanonets") — those require env-var opt-in.
The full alias map is exposed as _REGISTRY_ALIASES for programmatic
introspection.
Adding a new alias¶
If you need to keep an existing user-facing name working but route it to
a different backend (e.g. you want "ollama" to resolve to a custom
gateway), edit _REGISTRY_ALIASES in src/idp/llm/backend.py. The
existing test suite (tests/test_backend_registry.py) documents the
expected alias behaviour.