Instructions to use Remek/basal-2.0-4.5B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Remek/basal-2.0-4.5B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Remek/basal-2.0-4.5B") 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-2.0-4.5B") model = AutoModelForCausalLM.from_pretrained("Remek/basal-2.0-4.5B", 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-2.0-4.5B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Remek/basal-2.0-4.5B" # 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-2.0-4.5B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/Remek/basal-2.0-4.5B
- SGLang
How to use Remek/basal-2.0-4.5B 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-2.0-4.5B" \ --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-2.0-4.5B", "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-2.0-4.5B" \ --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-2.0-4.5B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use Remek/basal-2.0-4.5B with Docker Model Runner:
docker model run hf.co/Remek/basal-2.0-4.5B
basal-2.0-4.5B
basal-2.0 (4.5B) is part of basal-2.0, a family of typed-decision models for Polish and English; it is the main model: the best balance of accuracy and speed. Built on Bielik-4.5B-v3.0-Instruct. Trained further from earlier basal checkpoints.
What it is. The model reads a state (a message, a document, retrieved passages, an agent trace, a web page as
JSON) and answers a typed question about it (choice, yes/no noul, score, multi, act, tool) by returning a
calibrated probability for each allowed answer, in one forward pass, without generating text. The answer never falls
outside the options you give, and the probability says how sure the model is. Because the classes are described in the
request, one model serves many tasks without retraining: routing, rule and policy checks, questions about long
documents, RAG decisions, urgency and risk scores, judging answers, agent and tool decisions, and triage with a
confidence threshold.
| model | params | use |
|---|---|---|
| basal-2.0-mini | 1.5B | fastest |
| basal-2.0 (4.5B) | 4.5B | main model; experimental thinking mode |
| basal-2.0-max | 11B | most accurate |
Each model also comes as -FP8 (NVIDIA Hopper and Blackwell), -GGUF (Q8_0 and Q5_K_M; Ollama, llama.cpp) and -MLX-8bit (Apple Silicon).
Intended use
- Good for: routing messages and documents to one of the options you describe; yes/no checks of rules and policies;
urgency and risk scores; questions about long documents and retrieved passages (is the answer there, is it relevant);
judging answers; choosing an agent's next action or tool (a
toolquestion over OpenAI or MCP tool definitions picks the tool, not its arguments); triage that hands uncertain cases to a person (anactquestion with a defer action andmax_error). - Languages: Polish and English (the state and the question may be in either).
- Not for: writing text or chatting (the model only picks among the options you give); facts that are not in the state; decisions with serious consequences for people without human review.
Quick start
1. Install the basal engine v2.0.0 into a fresh uv environment (NVIDIA GPU; the cu128 torch needs a driver for CUDA 12.8 or newer; DGX Spark and B300 use the cu130 build, see docs/HARDWARE.md):
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/cu128
uv pip install "basal[fp8] @ https://github.com/rkinas/basal/archive/refs/tags/v2.0.0.tar.gz"
2. Start the server and wait for basal: model ... ready:
basal-serve --model Remek/basal-2.0-4.5B --mode fast --template-prefix off --port 8000
--template-prefix off is needed for this model (bf16 and -FP8): the prompt-template cache failed its check, and its numbers were measured without it.
3. Ask questions with curl. Several questions about one state go into one request and share the state:
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?"}}}'
Each answer has a probability for every option, the chosen key and the confidence:
"dept": {"type": "choice", "choice": "<key>", "probabilities": {"cards": p, "online": p, "loans": p}, "confidence": p}.
To send uncertain decisions to a person, ask the same question as an act question with a defer action and
"max_error": 0.05 (max_error works on act and tool questions only):
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": "act", "instructions": "Do którego działu skierować zgłoszenie?",
"criteria": {"cards": "Reklamacje kart", "online": "Wsparcie bankowości elektronicznej", "loans": "Kredyty"},
"option_keys": "hide", "costs": {"wrong": 19, "defer": 1}, "max_error": 0.05}}}'
The answer is the action with the lowest expected cost (an option key, or defer). Below the confidence threshold
certified for 5% error it returns defer, names the refused action and says "deferred": true. "option_keys": "hide" shows the model the option descriptions only, as the calibration was fitted (with the keys shown, answers say
"calibration": "unvalidated"); keep the cost of a wrong answer moderate, because a large one defers by expected cost
alone, before max_error is applied.
Or from Python (the package includes a small client):
from basal.client import Basal
b = Basal("http://127.0.0.1:8000")
state = "Klient: od wczoraj nie mogę zalogować się do bankowości internetowej, system pokazuje błąd hasła."
a = b.choice(state, "Do którego działu skierować zgłoszenie?",
{"cards": "Reklamacje kart", "online": "Wsparcie bankowości elektronicznej", "loans": "Kredyty"})
print(a["choice"], a["confidence"])
print(b.yes_no(state, "Czy klient nie może korzystać z usługi?")["noul"]) # P(yes)
Many items from a file: basal-run --input items.jsonl --output answers.jsonl. API and features: README.
The same basal engine v2.0.0 also serves the experimental basal-omni-1.0 models (images and audio): README.
Results against basal-1.5
Measured once on the frozen release weights, bf16 (basal-serve --mode fast) on one H100, and published as measured, including where basal-2.0 is not better.
| benchmark | basal-1.5 | basal-2.0 | 2.0 - 1.5 | note |
|---|---|---|---|---|
| Werdykt v1, macro [95% CI] | 0.721 [0.710, 0.733] | 0.729 [0.717, 0.739] | +0.7 pt | hidden PL + EN benchmark, 5,000 decisions |
| Werdykt v1, PL / EN | 0.724 / 0.718 | 0.729 / 0.728 | +0.4 / +1.0 pt | |
| Werdykt calibration error (ECE) | 0.068 | 0.060 | -0.008 | lower is better |
| Werdykt automated at 1% target error | 22.5% at 1.23% observed error | 11.9% at 0.66% observed error | share automated, error observed | |
| Werdykt automated at 5% target error | 50.1% at 5.04% observed error | 51.3% at 5.08% observed error | share automated, error observed | |
| Werdykt board rank | 46 | 45 | of 94 systems on the public board | |
| Werdykt speed pass, decisions/s at 16 clients (public board) | 23.0 (c1 p50 34 ms) | 32.2 (c1 p50 25 ms) | x1.4 | basal-1.5 on SGLang, basal-2.0 in basal-serve's default mode; bf16, one H100 80GB |
| Werdykt speed pass, both in basal-serve's default mode | 8.0 (c1 p50 31 ms) | 32.2 (c1 p50 25 ms) | x4.0 | basal-1.5 on its own basal-serve engine |
| Decision Index (JDI 0.2.1) | 27.65 | 39.86 | +12.21 | |
| JDI requests left unanswered | 17.2% (25,782 of 150,317) | 0.00% (0 of 150,317) | basal-1.5 answers questions with at most 10 options | |
| LEK, Polish medical licensing exam, PL / EN (% correct) | 60.5 / 59.7 | 62.0 / 63.0 | +1.5 / +3.3 pt | 5 options |
| PL-Holdout (4,000 items) | 0.8505 | 0.8560 | +0.0055 [-0.0018, +0.0130] | paired |
| Polish decisions (7,081 items) | 0.9223 | 0.9236 | +0.0013 [-0.0040, +0.0066] | paired |
| Polish general (3,079 items; dev label) | 0.7463 | 0.7619 | +0.0156 [+0.0042, +0.0276] | paired |
| English corpus test (1,479 items; dev label) | 0.6430 | 0.6444 | +0.0014 [-0.0169, +0.0189] | paired |
| English panel (10 tasks; mean accuracy) | 0.6881 | 0.6519 | -0.0362 (items -0.0362 [-0.0527, -0.0201]) | mean of tasks; items paired |
| PL-Real-300, doc-clean subset (158 items; primary) | 0.9494 | 0.9494 | +0.0000 [-0.0316, +0.0316] | paired |
| PL-Real-300, all 300 items | 0.9633 | 0.9433 | -0.0200 [-0.0433, +0.0033] | paired |
basal-1.5 is basal-1.5-4.5B, the previous release (Remek/basal-1.5-4.5B). Werdykt rows are the public board's rows (basal-1.5 served on SGLang, basal-2.0 by basal-serve v2.0.0 in its default mode), each release with its own calibration file, accuracy with --deterministic; automated at X% target error = a confidence threshold chosen on one half of the items for that error, applied to the other half. The speed pass is the board's (bf16, 16 clients, one H100 80GB; separate pods); the second speed row has basal-1.5 in basal-serve's default mode too. The rank is on the public Werdykt board (basal.si5.pl/benchmark), 94 systems, one row per system. All other rows: both models served by engine v2.0.0 (commit adc4c71) on the same items; differences are paired, with 95% bootstrap intervals. Polish general and the English corpus test were used to choose between training runs, so their numbers are development numbers. LEK questions: NASK-PIB Reassess, 2008-2026 sessions (CC BY-NC-SA 4.0), shown for the basal models only, with no comparison to other systems.
What is new since basal-1.5
- Prompt format 2. Up to 255 options per question (basal-1.5: 10), read in one forward pass with one option order by default (basal-1.5 read two orders).
- Training. Trained further from earlier basal checkpoints.
- Calibration. Temperatures per question type and option-count bucket, fitted on question families the model was not trained on.
- Engine v2.0.0. Compact batching (+19% decisions/s at 16 clients, +17% at 32, +8% at one client) (one H100, bf16, each change left out in turn); the prompt-template cache is off for this model (
--template-prefix off: it failed this model's check). They need FlashAttention 3 (Hopper): the Werdykt rows on this card ran with FlashAttention 3; the release check, the port checks, the FP8 speed and the calibration ran with FlashAttention 2, without them. Engine v2.0.0 schedules long requests (over 2,048 tokens) behind short ones: in a mixed load at 32 clients short requests answer in 0.81 s instead of 1.38 s (p50), and long requests take about 7% longer (p50 1.96 s instead of 1.83 s);--scheduler offserves in arrival order. - Thinking mode (experimental, off by default). See below.
Thinking mode (experimental)
Off by default, and we recommend leaving it off. With --think auto the model writes a short reasoning note before
it decides, but only for questions whose calibrated confidence is below the type's certified 5% threshold; the decision is
then read out again over the state and the note, with its own calibration file (CALIBRATION.think.json). The note is
generated by a vLLM server that basal-serve starts in its own process on the think weights in think/. vLLM brings its
own torch (vLLM 0.31: torch built for CUDA 13.0, which needs an NVIDIA driver 580 or newer), so install it in its own
environment and point --think-python at that environment's Python; the server itself runs from the quick-start
environment:
uv venv --python 3.12 --allow-existing ~/basal-vllm
uv pip install --python ~/basal-vllm/bin/python "basal[vllm] @ https://github.com/rkinas/basal/archive/refs/tags/v2.0.0.tar.gz"
source ~/basal-env/bin/activate
basal-serve --model Remek/basal-2.0-4.5B --mode fast --template-prefix off --think auto --think-python ~/basal-vllm/bin/python --port 8000
basal-serve --model Remek/basal-2.0-4.5B --mode fast --template-prefix off --think auto --think-tokens 128 \
--think-python ~/basal-vllm/bin/python --port 8000 # shorter notes (default 256)
basal-serve --model Remek/basal-2.0-4.5B --mode fast --template-prefix off --port 8000 # off (the default: --think off)
Per request, on a --think auto server: "think": "auto" (the default), "off" (one-pass answer for this request) or
"force" (every question of a think type thinks); "think_text": true returns the note. A question that thought answers
with the second readout's probabilities and confidence plus "think": {"tokens", "ms", "calibration", "no_think": {...}};
every answer of a think server carries "meta": {"think": {"used", "tokens"}}. Multi questions, tool sets and requests
whose state was truncated never think. On a server started without --think auto (the default) there is no think path.
Measured once on Werdykt, both rows on the same pod (one H100 80GB, default mode, 16 clients for the speed column):
| server | macro | PL / EN | ECE | automated at 5% | questions that thought | c1 p50 | decisions/s |
|---|---|---|---|---|---|---|---|
--think off |
0.729 | 0.729 / 0.728 | 0.060 | 51.3% | - | 23 ms | 31.2 |
--think auto |
0.719 | 0.718 / 0.720 | 0.099 | 47.1% | 56.7% (mean 142 tokens) | 499 ms | 11.5 |
On Werdykt, thinking lowered the macro score by 0.9 points (0.719 against 0.729), raised the calibration error (0.099 against 0.060) and cut throughput to 11.5 decisions/s from 31.2. Every other number on this card is the default one-pass mode. Try --think auto only with your own measurement on
your own data.
Ports
Every port is checked against this bf16 model on the development set dev v2: agreement is the share of decisions where the port picks the same option. Bars for this tier: agreement 2-10 >= 0.9415, agreement at reference margin >= 0.2 >= 0.9863, accuracy within 1 point, ECE at most +0.01.
| package | agreement with bf16 (options 2-10) | agreement at margin >= 0.2 | accuracy diff | ECE diff | size | speed | gate |
|---|---|---|---|---|---|---|---|
| FP8 | 0.9478 | 0.9890 | -0.0008 | +0.0009 | 4.9 GB | 38.6 dec/s c16, c1 p50 29 ms (H100) | PASS |
| GGUF Q8_0 | 0.9839 | 0.9988 | +0.0002 | +0.0035 | 4.8 GB | not measured in this release | PASS |
| GGUF Q5_K_M | 0.9569 | 0.9920 | -0.0039 | +0.0040 | 3.2 GB | not measured in this release | PASS |
| MLX 8-bit | 0.9792 | 0.9989 | +0.0000 | -0.0009 | 4.9 GB | 278 ms c1 p50, 698 ms for 5 questions (Mac) | PASS |
Calibration
For every question basal returns a probability for each answer; the confidence is the probability of the answer it picks. The probabilities are calibrated (a temperature per question type and option-count bucket) on question families that were never used for training, so they hold on new tasks but are cautious. Held-out numbers below are leave-one-family-out on the development and test splits.
| basal-2.0-4.5B, held-out | |
|---|---|
| calibration error (ECE) | 0.015 |
| worst question family (ECE) | 0.101 (agent) |
| automated at the 5% error threshold | 33.2% at 2.39% observed error |
| 1% error threshold, shipped file | defers every decision (no 1% threshold certified on the full fit) |
On Werdykt (hidden, measured once, not used to choose the model) the calibration error is 0.060 (basal-1.5: 0.068). The calibration is a file, separate from the weights (CALIBRATION.json, one
option order; CALIBRATION.o2.json, two orders), so you can swap it or refit it on your own data with basal-calibrate.
Fitted with engine v2.0.0 (commit adc4c71).
Speed
One decision = one question, one option order. Hardware is named on every number.
- Werdykt speed pass (bf16, one H100 80GB): basal-2.0 32.2 decisions/s at 16 clients, c1 p50 25 ms (p95 188 ms) in basal-serve v2.0.0's default mode; basal-1.5 23.0 decisions/s at 16 clients, c1 p50 34 ms (p95 270 ms) on SGLang, as on the public board; in basal-serve's default mode basal-1.5 does 8.0 decisions/s at 16 clients, c1 p50 31 ms (p95 795 ms). Separate pods of the same GPU type.
- FP8 package: 38.6 dec/s c16, c1 p50 29 ms (H100); one NVIDIA H100 80GB (cluster node), one option order.
- Measured setup: the Werdykt rows (accuracy and the speed pass) ran on the Werdykt pods with FlashAttention 3 installed, which the engine needs for compact rows (an engine default; the template prefix stays off for this model); the release check, the port checks, the FP8 speed and the calibration fits ran with FlashAttention 2, so compact rows and the template prefix were off there. FP8 keeps FlashAttention 2 unless
--attn fa3. - Accuracy rows use
--deterministic; default minus--deterministicaccuracy on dev v2: bf16 +0.0000, FP8 -0.0025 (run 1; 32 requests in flight);--deterministicitself: bf16 200/200 identical at 16 clients, FP8 200/200 identical at 16 clients.
basal-1.5's other configuration. basal-1.5 also shipped FP8 checkpoints served by vLLM. On one RunPod H100 (median of 3 fresh servers; synthetic ~1.6k-token states and a 400-request mix, a different workload from the Werdykt speed pass) the two basal-1.5 configurations measured:
| basal-1.5 configuration | c1 p50 | decisions/s, 16 / 32 clients | mixed traffic, sequential / 32 clients (requests/s) | 16k-token state x 5 questions |
|---|---|---|---|---|
| bf16 on v1.5.0 | 59.0 ms | 17.8 / 18.7 | 2.1 / 2.2 | 20,441 ms |
| FP8 package on v1.5.0 vLLM | 59.1 ms | 32.0 / 36.5 | 11.3 / 46.0 | 620 ms |
basal-2.0 was not measured on that machine, so the speed-ups in the results table hold only against the basal-1.5 rows of the Werdykt speed pass. For mixed traffic with long, repeated documents, measure both on your own load before you switch.
Evaluation notes
- Werdykt (hidden benchmark). Every training file after basal-1.5 was checked against the Werdykt guard list (exact state, rare 13-word shingles, source documents) and builds fail on any hit. This model continues earlier basal checkpoints back to basal-1.5, so it inherits basal-1.5's exposure to 7 boilerplate rows (effect at most 0.14 points on basal-1.5).
- PL-Real-300. Training rows of the basal checkpoints between basal-1.5 and basal-2.0 came from 27 of the PL-Real source judgments (their guard excluded PL-Real states, not the source documents); the 2.0 training files add 0. The primary PL-Real figure is therefore the doc-clean subset (158 items on the other judgments), for both models; the full 300 is shown next to it.
- Selection sets. Polish general and the English corpus test were used to choose between training runs, so their numbers are development numbers. PL-Holdout, PL-Real, LEK, JDI and Werdykt were not used to select basal-2.0.
Files
model.safetensors, tokenizer,chat_template.jinja: the modelCALIBRATION.json(one option order) andCALIBRATION.o2.json(two orders): per-type temperatures and confidence thresholds for 1% / 5% errorthink/(the think weights) andCALIBRATION.think.json: the experimental thinking modebasal.json: prompt format 2 and readout protocol
How it works
The model receives a fixed chat prompt with the state, the question and coded options; the decision is the softmax over the next-token logits of the option codes only (one forward pass, fp32 code logits, no text generation), then the per-type calibrated temperature from CALIBRATION.json. Confidence thresholds were chosen on calibration data, before testing, for 1% or 5% error among accepted decisions.
Training
Fine-tuned from Bielik-4.5B-v3.0-Instruct for typed decisions in Polish and English, trained further from earlier basal checkpoints. LoRA stages, merged.
Limitations
- Validate on your own documents before relying on it: hidden and held-out sets do not cover every domain.
- Polish world knowledge of a small model is limited: put the relevant facts in the state. Legal rules change.
- Exact arithmetic and thresholds are a weak spot of one-pass decisions: compute them in code (or
"facts": "auto"). - The calibration is cautious on unseen tasks: no 1% threshold is certified in the shipped files, so
"max_error": 0.01on anactortoolquestion defers every decision; use 0.05, or certify thresholds on your own data withbasal-calibrate. actandmultiover many labels are experimental. Up to 255 options per question (Ollama: 20); the context is 32,768 tokens. The 2.0 models ship no evidence head.- 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 speakleash/Bielik-4.5B-v3.0-Instruct (Apache-2.0). Bielik is a project of SpeakLeash and ACK Cyfronet AGH.
- Downloads last month
- 10
Model tree for Remek/basal-2.0-4.5B
Base model
speakleash/Bielik-4.5B-v3