Instructions to use Remek/basal-omni-pico with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Remek/basal-omni-pico with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Remek/basal-omni-pico") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("Remek/basal-omni-pico") model = AutoModelForCausalLM.from_pretrained("Remek/basal-omni-pico", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Remek/basal-omni-pico with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Remek/basal-omni-pico" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Remek/basal-omni-pico", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/Remek/basal-omni-pico
- SGLang
How to use Remek/basal-omni-pico with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "Remek/basal-omni-pico" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Remek/basal-omni-pico", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "Remek/basal-omni-pico" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Remek/basal-omni-pico", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use Remek/basal-omni-pico with Docker Model Runner:
docker model run hf.co/Remek/basal-omni-pico
basal-omni-pico
basal-omni-pico is our smallest typed-decision model for Polish and English. It has 0.8B parameters, it is built on Qwen3.5-0.8B-Base (the larger basal-omni models are built on Gemma 4), it reads text only, and it was trained with our basal-omni-1.0-ultra (31B) as the teacher. It reads the same requests as the larger basal models.
What it is. The model reads a state (a message, a document, a sensor log, retrieved passages) and answers a typed
question about it (choice, yes/no noul, score, multi, act, tool) by returning a probability for each
allowed answer, in one forward pass, without generating text. The answer never falls outside the options you give.
| model | params | base |
|---|---|---|
| basal-omni-pico | 0.8B | Qwen3.5-0.8B-Base, text only; also as GGUF for llama.cpp (basal-omni-pico-GGUF) |
| basal-omni-1.0-mini | E4B | Gemma 4 E4B |
| basal-omni-1.1-max | 12B | Gemma 4 12B |
| basal-omni-1.0-ultra | 31B | Gemma 4 31B |
Intended use
- Good for: routing a request to the right queue, team or tool, and picking the relevant passage (Werdykt: routing 0.912, retrieval 0.886, real documents 0.848); Polish decisions (our Polish check set: 0.876).
- Languages: Polish and English.
- Not for: writing text or chatting; facts that are not in the state; rule checks (Werdykt rules 0.316); using the probabilities as error rates on a new kind of data before you check them there (see Calibration); decisions with serious consequences for people without human review. For harder cases use a larger basal model.
Quick start
1. Install basal 2.4.0 into a fresh uv environment (CPU wheels shown; for an NVIDIA GPU
use the cu128 index and add "flash-linear-attention==0.5.2", on a Mac the default index):
uv venv --python 3.12 --allow-existing ~/basal-env && source ~/basal-env/bin/activate
uv pip install torch==2.11.0 --index-url https://download.pytorch.org/whl/cpu
uv pip install "basal @ https://github.com/rkinas/basal/archive/refs/tags/v2.4.0.tar.gz"
2. Start the server. It prints basal: model ... ready:
basal-serve --model Remek/basal-omni-pico --port 8000
Without --mode, basal 2.4 serves this model in its fast CUDA-graph engine (fast) on Hopper GPUs (H100) when
flash-linear-attention is installed, and in eager elsewhere. basal 2.4 or later is needed for --mode fast; 2.3.2 or
later serves it in eager and gguf. fp8 and nvfp4 refuse this model.
3. Ask questions, as with every basal model:
curl -s localhost:8000/v1/systemone -H 'content-type: application/json' -d '{
"state": "Klient: od wczoraj nie mogę zalogować się do bankowości internetowej, system pokazuje błąd hasła.",
"questions": {
"dept": {"type": "choice", "instructions": "Do którego działu skierować zgłoszenie?",
"criteria": {"cards": "Reklamacje kart", "online": "Wsparcie bankowości elektronicznej", "loans": "Kredyty"}},
"urgent": {"type": "noul", "instructions": "Czy klient nie może korzystać z usługi?"}}}'
The answer (this model on one H100, installed as above, shortened):
{"model": "basal-omni-pico",
"answers": {
"dept": {"type": "choice", "choice": "online", "probabilities": {"cards": 0.0009, "online": 0.9983, "loans": 0.0008},
"confidence": 0.9983},
"urgent": {"type": "noul", "noul": 0.762, "probabilities": {"true": 0.762, "false": 0.238}, "confidence": 0.762}}}
Full API (multi, act, tool, option keys, max_error): API.
GGUF (llama.cpp, CPU or GPU)
basal-omni-pico-GGUF has a Q8_0 file with its own calibration file, served
by the same basal-serve with --mode gguf (llama.cpp in process, basal[gguf], basal 2.3.2 or later). On 1,700
development items it picks the same answer as this model in 99.24% of cases on one H100 and in 99.29% on the CPU.
On 16 CPU threads the request above takes about 0.5 s.
Results
Werdykt (our hidden Polish + English benchmark, 5,000 items): macro 0.660 [0.648, 0.671] (Polish 0.661, English 0.659). For comparison, basal-2.0-mini (1.5B) scores 0.618, basal-2.0 (4.5B) 0.729 and basal-omni-1.0-mini 0.769. By category: routing 0.912, retrieval 0.886, real documents 0.848, judging 0.752, scores 0.624, actions 0.592, long states 0.582, abstaining 0.544, contracts 0.542, rules 0.316.
Against the other decision models of 2B parameters or less that we ran (the same benchmark client for every model, each served by its own runtime):
| model | params | Werdykt macro [95% CI] | Polish / English | Werdykt ECE | dev v2 | LEK PL / EN | Polish check |
|---|---|---|---|---|---|---|---|
| basal-omni-pico | 0.8B | 0.660 [0.648, 0.671] | 0.661 / 0.659 | 0.138 | 0.646 | 35.9 / 45.1 | 0.876 |
| decider-2b (Mapika) | 1.9B | 0.587 [0.574, 0.599] | 0.580 / 0.593 | 0.123 | 0.576 | 45.0 / 59.1 | 0.582 |
| krino-2b | 2B | 0.566 [0.553, 0.579] | 0.552 / 0.580 | 0.051 | 0.528 | 36.8 / 50.7 | 0.598 |
| decision-2b (flymy-ai) | 2B | 0.546 [0.534, 0.558] | 0.492 / 0.600 | 0.030 | 0.532 | 29.0 / 45.7 | 0.542 |
| qev-0.8b | 0.8B | 0.544 [0.530, 0.556] | 0.530 / 0.558 | 0.088 | 0.572 | 33.2 / 44.5 | 0.592 |
| jiwo-0.8b | 0.75B | 0.542 [0.529, 0.554] | 0.516 / 0.567 | 0.047 | 0.518 | 30.0 / 40.8 | 0.533 |
- dev v2: our development set of 10,606 decisions (accuracy). LEK: the Polish medical final exam, Polish and English versions. Polish check: our Polish decision check set.
- Where others are ahead: decider-2b on LEK (45.0 / 59.1) and on our English, generated-Polish and panel check sets; every other model in the table is better calibrated on Werdykt (ECE 0.030 to 0.123 against 0.138), and decider-2b automates 9.8% of Werdykt at a 1% target, where this model automates none.
Public benchmarks: BH 75.3 (ECE 0.070); JevExtra 68.4, JevSpatial 68.7, Rules-7 68.6; JevBench accuracy 83.9, coherence 74.3. qev-0.8b is ahead on BH (77.9), JevExtra (71.8), JevSpatial (74.2) and JevBench accuracy (85.1).
Development sets (not test sets): dev macro 0.685 (panel 0.789, BH 0.552, JDI-shaped 0.706, agent 0.693); dev v2 accuracy 0.646 (Polish 0.633, English 0.656); our check sets: Polish 0.876, generated Polish 0.601, English 0.607, real Polish cases 0.940, panel 0.593.
Calibration
CALIBRATION.json holds per-type temperatures and certified thresholds for max_error 1% and 5%. It was fitted on
readouts of this model as basal-serve runs it (--mode eager, bf16, one option order, the default), on our
calibration set (fit and certification splits), and evaluated on a frozen test split of 8,560 decisions:
| choice | yes/no (noul) |
score | all | |
|---|---|---|---|---|
| ECE after the temperature (test) | 0.0125 | 0.0109 | 0.0645 | 0.0059 |
| accuracy (test) | 0.883 | 0.813 | 0.601 | 0.831 |
- Automation on the test split: at
max_error1%, 35.0% of decisions are decided automatically (observed error 0.93%); at 5%, 58.2% (observed error 4.38%). At 1% onlychoicequestions have a threshold (yes/no and score questions defer); at 5% score questions defer. - Held-out-family check (each task family left out of the fit in turn, pooled ECE per type): choice 0.015, yes/no 0.016, score 0.038, all under our 0.05 bar.
CALIBRATION.o2.jsonis the same fit for--orders 2(both option orders); basal-serve picks it when you serve with--orders 2.- What the guarantees cover. The 1% and 5% thresholds hold on our held-out test split (35.0% and 58.2% of decisions automated, above). On Werdykt, an out-of-domain benchmark, served with this file, the model is overconfident: mean confidence 0.80 against accuracy 0.66 (ECE 0.138, Brier 0.475). At a 1% target nothing is automated; at 5%, 33.9% is automated with an observed error of 6.3%, so the 5% target is not met there.
- Outside our domains, refit first. Fit the thresholds on your own labelled cases (
basal-calibrate) before you automate withmax_error.
Speed
basal 2.4 on one H100 80 GB, basal-serve --no-calibration, one connection per request; p50 at concurrency 1 /
throughput at 16 clients (decisions/s; questions/s with five questions per request). Short states are about 1,500
tokens, long ones 3,000–10,000.
| path | 1 question, short state | 5 questions, short state | 1 question, long state | 5 questions, long state |
|---|---|---|---|---|
--mode fast (basal 2.4, the default on an H100) |
13.5 ms / 134.6 | 26.6 ms / 400.4 | 45.9 ms / 34.4 | 90.6 ms / 94.4 |
--mode fast-nocompile (basal 2.4) |
17.4 ms / 89.3 | 33.5 ms / 328.2 | 64.0 ms / 22.9 | 110.5 ms / 80.1 |
--mode eager |
45.5 ms / 32.8 | 112 ms / 41.9 | 183 ms / 6.6 | 908 ms / 6.6 |
--mode vllm (vLLM 0.31.0) |
54.3 ms / 93.9 | 67 ms / 188.7 | 39 ms / 43.7 | 109 ms / 90.6 |
--mode gguf Q8_0 on the GPU |
56.5 ms / 18.1 | 98 ms / 54.7 | 283 ms / 4.7 | 360 ms / 18.6 |
- basal 2.4 serves this model in its fast CUDA-graph engine: 3.5x eager's speed on one question and 4-10x with
five questions over one state, whose recurrent state is computed once for all of them. Install
flash-linear-attention for it:
uv pip install "flash-linear-attention==0.5.2". Without it, and on GPUs other than Hopper, the model runs ineagerunless you pass--mode fast(on other GPUs it has not been checked). - The same answers as eager: in fp32 the top answer agrees with
--mode eageron 99.94–99.99% of 1,700 development items (one question, five questions, two option orders, both); in bf16fastagrees with the fp32 answers as often aseagerdoes (99.44–99.65% against 99.48–99.71%). Under load,--deterministicand batched serving gave the same top answer on 99.83% of the 10,606 dev decisions (eager: 99.42%). - One question over a long state is still faster in
--mode vllm(39 against 46 ms). - Werdykt's own speed pass on this model (one H100, eager): 47 ms p50 at concurrency 1, 32.4 decisions/s at 16.
--mode vllmagreed with eager on the top answer for 99.47% of 1,700 development items (same checkpoint); it has no calibration file of its own and usesCALIBRATION.json.--mode fastusesCALIBRATION.jsontoo.- CPU: see the GGUF section.
Evaluation notes
- Contamination checks on the training mix (exact, 13-gram and short-state matching), hits left in the final mix in brackets: Werdykt, hidden (0); the Jev Decision Index 0.3 test requests, 150 rows dropped (0); our evaluation documents, 204 rows dropped (0); the insurance benchmark v1 325 + v2 3,042 items (0); LEK, the Polish medical final exam, pl 4,727 + en 3,151 items, 331 rows dropped (0): statute and social-insurance wording that our legal rows share with 29 medical-law questions, not exam items.
- Werdykt (hidden benchmark). Run on these weights with basal 2.3.1
--mode eager(flash-linear-attention 0.5.2), one H100 80 GB (RunPod), 5,000 of 5,000 items answered; then rerun on a RunPod pod with this repository's files (basal 2.3.2,--mode eager, the shippedCALIBRATION.json): the same macro (0.660). The Werdykt calibration numbers on this card come from the rerun. - Selection. Two runs of the same recipe (seeds 0 and 1) and their 50/50 weight average were the candidates. The rule fixed before the runs picked the single seed-0 run, since the average led it on dev by only 0.28 points (0.685 vs 0.682, inside the rule's 0.5-point tie). We release the average: we chose it after both Werdykt results were known (0.660 vs 0.649, overlapping intervals).
Files
model.safetensors,config.json,generation_config.json: the weights (bf16; the 18A_logtensors and the 18 Gated DeltaNet norms in fp32; Qwen3_5ForCausalLM, text only);model.safetensorssha256ac52f85bf4af603b2d2408d314e9c1bb59e351884f7cacd72464c49dca9149e9- the tokenizer files and
chat_template.jinja basal.json(prompt format 2, readout),CALIBRATION.json(one option order),CALIBRATION.o2.json(two)MANIFEST.md: training data by source and language, guard reportsSHA256SUMS: the sha256 of every file above (check withsha256sum -c SHA256SUMS)
How it works
Prompt format 2 of the basal engine: the state and the question with its options as one prompt, then a short answer prefix; the logits of the option codes at the first answer position, scaled by the calibrated temperature of the question type, are the probabilities. Nothing is generated.
Training
Full fine-tuning of Qwen/Qwen3.5-0.8B-Base (revision
dc7cdfe2ee4154fa7e30f5b51ca41bfa40174e68; the language model, every weight) on 1,428,543 rows in prompt format 2, none
over 6,144 tokens: the guarded basal training mix plus 100k generated short edge cases (rows by source and language:
MANIFEST.md). Two runs with seeds 0 and 1, each 1.4 epochs: 27,778 steps at a global batch of 72 (8 sequences × 3
accumulation steps × 3 GPUs), learning rate 5e-6 with 20 warm-up steps and a cosine decay to 0.1×, AdamW (0.9, 0.95),
no weight decay, fp32 master weights with a bf16 forward. The released weights are the 50/50 average of the two final
checkpoints.
The loss is cross-entropy on the gold answer plus three terms:
- a Brier term on
choicequestions (weight 0.5); - the squared error of the expected level on
scorequestions (weight 1.0); - distillation from basal-omni-1.0-ultra (31B), whose option-code probabilities are the targets (weight 1.0) on 1,254,097 rows. It is skipped on 67,885 rows where the teacher's top answer differs from the gold label, and on yes/no rows where the teacher is not decisive.
Trained on 3× H100 with PyTorch 2.11, the flash-linear-attention 0.5.2 kernels for the Gated DeltaNet layers and Triton 3.7.1.
Limitations
- Trained on prompts of up to 6,144 tokens (Werdykt long states: 0.582); at most 255 options per question (prompt format 2).
- A 0.8B model knows little: put every fact the decision needs into the state.
- Rule checks are its weakest area (Werdykt rules 0.316): check it on your own rule cases before you rely on it.
- Exact arithmetic is a weak spot of one-pass decisions: compute numbers in code and pass the result.
- Overconfident on new kinds of data (see Calibration).
- Decisions with serious consequences for people should be reviewed by a person.
Citation
@software{kinas2026basal20,
title = {basal-2.0: typed-decision models and inference engine for Polish and English},
author = {Kinas, Remigiusz},
year = {2026},
version = {2.0.0},
url = {https://github.com/rkinas/basal}
}
License and attribution
Apache-2.0. Fine-tuned from Qwen/Qwen3.5-0.8B-Base (Apache-2.0) by the Qwen team; the base's vision encoder is not included (text only).
- Downloads last month
- 18