Model Backends¶
Model backends adapt model APIs into one standard Krisis interface. In v0.2,
Krisis uses a single APIBackend powered by OpenRouter: the same clinical task
can run across OpenAI, Anthropic, Grok, Gemini, and other routed models by
changing only the model id.
Krisis also includes an experimental TransformersBackend for local Hugging
Face models. It defaults to CPU and can use GPU runtimes by passing
device="cuda".
API Backend¶
| Backend | Default model | API key |
|---|---|---|
APIBackend |
openai/gpt-5.5 |
OPENROUTER_API_KEY |
Example model ids:
| Provider route | Example model id |
|---|---|
| OpenAI | openai/gpt-5.5 |
| Anthropic | anthropic/claude-opus-4.7 |
| Grok/xAI | x-ai/grok-4.3 |
| Google Gemini | google/gemini-3.5-flash |
from krisis.backends.api import APIBackend
backend = APIBackend(
model="anthropic/claude-opus-4.7",
reasoning_effort="low",
)
Local Transformers Backend¶
Install the Hugging Face extra:
pip install "krisis[hf]"
Experimental backend
TransformersBackend is experimental in v0.2.7. It is useful for Colab,
Deepnote, and local GPU experiments, but full benchmark runs on CPU will be
very slow and the backend API may still change as it is hardened.
Text-generation models only
The Hugging Face backend only supports causal text-generation models that
can be loaded with AutoModelForCausalLM. Classifier, embedding,
masked-language, seq2seq, and multimodal-only models are not supported and
will raise an error during backend initialization.
Then provide a Hugging Face model id:
from krisis.backends.huggingface import TransformersBackend
backend = TransformersBackend(
model_id="Qwen/Qwen2.5-0.5B-Instruct",
device="cpu",
max_new_tokens=512,
)
Gated Hugging Face models can use either the HF_TOKEN environment variable or
the explicit hf_token argument:
backend = TransformersBackend(
model_id="meta-llama/Llama-3.1-8B-Instruct",
device="cuda",
hf_token="<your-hugging-face-token>",
)
For Colab, Deepnote, or another GPU runtime:
backend = TransformersBackend(
model_id="Qwen/Qwen2.5-7B-Instruct",
device="cuda",
dtype="bfloat16",
max_new_tokens=512,
)
Local model performance
CPU inference can be very slow. For serious benchmarking with local Transformers models, use a GPU runtime and start with a small batch size.
Example script:
python examples/basic_ckd_hf_eval.py --limit 3 --batch-size 1
Backend Contract¶
Every backend returns the same response shape:
BackendResponse(
prediction=...,
abstained=...,
confidence=...,
raw_response=...,
prompt=...,
prompt_mode=...,
input_tokens=...,
output_tokens=...,
total_tokens=...,
)
Field meanings:
| Field | Meaning |
|---|---|
prediction |
Parsed model prediction, or None when the model abstained |
abstained |
Whether the model declined to answer |
confidence |
Model-reported confidence between 0 and 1 |
raw_response |
Raw provider text or JSON for auditability |
prompt |
Prompt/messages with patient data redacted |
prompt_mode |
single for one-row calls, batch for batched calls |
input_tokens |
Provider-reported input token count when available |
output_tokens |
Provider-reported output token count when available |
total_tokens |
Combined token count when available |
API Keys¶
Create an API key from OpenRouter, then
set OPENROUTER_API_KEY or pass the key directly:
from krisis.backends.api import APIBackend
backend = APIBackend(api_key="YOUR_OPENROUTER_KEY")
The example runner accepts --api-key, reads OPENROUTER_API_KEY through the
backend, and still supports API_KEY as a local convenience when passed from
the examples.
One OpenRouter key can be used with routed model ids such as
openai/gpt-5.5, anthropic/claude-opus-4.7, x-ai/grok-4.3, and
google/gemini-3.5-flash, subject to model availability and your OpenRouter
account settings.
Do not commit API keys
Keep API keys in environment variables, local secret managers, or CI secrets. Never put provider keys in benchmark scripts committed to GitHub.
Batching And Concurrency¶
Krisis can evaluate records in provider batches:
from krisis.benchmark import Benchmark
result = Benchmark(
suite,
backend,
batch_size=8,
max_concurrency=2,
).run()
batch_size and max_concurrency control different things:
| Setting | Meaning |
|---|---|
batch_size |
How many patient records are sent in one provider call |
max_concurrency |
How many provider calls may run at the same time |
max_output_tokens |
Per-row output-token cap passed to the API backend |
reasoning_effort |
API reasoning effort for supported models; defaults to low |
Example: batch_size=8 and max_concurrency=2 can evaluate up to 16 records in
flight, split across two API calls.
Start conservative
Use batch_size=8 and max_concurrency=1 or 2 for first runs. Increase
only after checking provider rate limits and structured JSON reliability.
Empty provider responses
If a provider returns an empty response or truncated JSON, increase the
example runner's --max-output-tokens value. For larger frontier models,
also try a smaller --batch-size so each call has less JSON to produce.
API token caps
APIBackend defaults to 1024 output tokens per row. This
is higher than the visible JSON usually needs because larger reasoning
models may consume part of the completion budget before emitting the final
JSON.
Reasoning effort
APIBackend defaults to reasoning_effort="low" for faster,
lower-token schema-constrained evaluation. Pass reasoning_effort=None to
omit the provider parameter entirely. In the example CLI, use
--reasoning-effort omit to omit it.
Structured Output¶
Backends request structured JSON when the provider supports it. The expected single-row response is:
{
"abstained": false,
"confidence": 0.82,
"prediction": 0
}
Batched responses use:
{
"results": [
{
"id": "case_0",
"abstained": false,
"confidence": 0.82,
"prediction": 0
}
]
}
If a batched response is malformed, Krisis can shrink the batch and retry smaller groups before falling back to single-row evaluation.
Failure Handling¶
Backend hardening includes:
- retry with backoff for transient provider failures
- parsing safeguards for markdown-wrapped or malformed JSON
- recursive batch shrinking when batched JSON fails
- single-row fallback for difficult cases
- actionable empty-response errors when output-token caps are too low
- raw response preservation for debugging
- token usage aggregation in benchmark execution metadata
Batching reduces calls, not reasoning time
Large frontier models may still take time to reason over batched clinical cases. Batching usually reduces HTTP overhead and rate-limit pressure, but it does not make the model itself free.
Choosing A Model¶
For fast smoke tests, use a lightweight provider model and small synthetic counts. For publishable comparisons, use fixed seeds, fixed task settings, and the same batch/concurrency settings across models where provider limits allow.
Always report:
- provider
- model ID
- task
- feature set
- batch size
- max concurrency
- output-token cap
- elapsed seconds
- token total