跳到主要内容
Blog

Vela 2.0: Open Foundation Routing Models

Still one model. Still one request. Now with spans. Sound on.

Open Foundation Routing Models. Bringing span-level decisions to System One.

Vela 2.0 is a family of open models for routing, safety checks and span-level decisions. Define your options, labels and rubrics at request time; get structured answers with probabilities and character-offset spans through one SystemOne-compatible interface.

Explore the four models → · Read about Decision →

  1. One model for routing and guardrails. Combine domain, safety, PII and hallucination questions in one request.
  2. Decisions that locate text. Find personal data, unsupported claims and extractive evidence as labelled spans with character offsets.
  3. Tasks defined by your application. Supply choices, yes/no criteria, ordered rubrics and label sets when you call the model.

Choose your model​

ModelPositioningParametersInputSpan heads
Vela-2.0-0.3BCompact encoder for CPU and ONNX deployments307M8,192 tokensrouter
Vela-2.0-0.8BSmallest hybrid model with open-label extraction756M16,384 tokensrouter + broad
Vela-2.0-4BBalanced hybrid model for routing and safety4.2B16,384 tokensrouter + broad
Vela-2.0-9BFlagship: strongest measured general decisions and long-document PII in the family7.9B16,384 tokensrouter + broad

Quickstart​

Start with the 0.3B encoder on CPU:

pip install torch "transformers>=5.17" safetensors tokenizers numpy
from transformers import AutoModel

m = AutoModel.from_pretrained("vllm-sr/Vela-2.0-0.3B", trust_remote_code=True)
result = m.system_one(
state={"request": "Email Tom Baker at tom.baker@example.com."},
questions={
"route": {"type": "choice", "instructions": "What does this request ask for?",
"criteria": {"email": "send an email", "other": "another task"},
"over": "request"},
"pii": {"type": "span", "instructions": "Which spans are personal information?",
"criteria": m.vela2_engine.cal["pii_schema"]["labels"], "over": "request"}})
print(result["answers"])
print(result["spans"])

The same question format works at every size. The GPU example below combines request routing with PII and grounded hallucination checks.

Why decision models​

Vela 1.0 gave each routing signal its own model and fixed label set. Decision models let the application define the question and its answers at request time: a Choice among options, a Noul (yes/no) probability or a Score over ordered levels.

Vela 2.0 brings Span and Set answers to that interface, alongside training on the router's safety, prompt-attack, PII and hallucination signals. One request can ask which route to take, whether it is safe and which words require action.

The hybrid models build on Decision 2.0's Eos-0.8B, Nox-4B and Lux-9B, using Qwen3.5 text backbones to score supplied answers without generating text. The compact encoder starts from Decision-1.0-Kai's Choice trunk.

One request, every question​

Every Vela 2.0 model takes the same request: a state (plain text, or named parts such as request, context and answer) and named questions of five types. Choice, Noul and Score keep the decision format unchanged. Span questions return {label, start, end, text, probability} with offsets into the part they are asked over; set questions select labels with a probability for each.

In the decoders, the state prefix is read once per rendered sequence. Every question continues from that prefix in its own causal block. Full-attention layers reuse the prefix's keys and values; Gated-DeltaNet layers reuse its recurrent state and convolution tail. Each block sees the prefix and itself, with no connection to another question's block.

Decoder execution reuses a state prefix for isolated Choice, Span and Set question blocks. Additional span questions and long-target windows use additional rendered sequences.

For a fixed rendered state, each decoder question sees only the prefix and its own causal block. The prefix forks independently at every layer.

The 0.3B encoder uses the same interface, reading the questions and state together in a bidirectional sequence.

Decoder execution and long inputs

Questions are isolated for a fixed rendered state. Extra span questions use separate rendered sequences, and span targets longer than 2,048 tokens use additional window sequences. Adding questions can change how text is truncated to fit the input budget. These sequences stay behind one API call.

Spans inside a decision model​

A span question is a grid of yes/no decisions: one for every word of the text and every label in the question. Is Tom part of a PERSON? Is tom.baker@example.com an EMAIL_ADDRESS? Words that say yes for the same label and sit next to each other become one span, with character offsets into the original text. The question's entry in answers also exposes the grid's highest word probability as a Noul.

A span question looks like any other question, with a label block in place of options:

"pii": {"type": "span",
"instructions": "Which spans are personal information?",
"criteria": {"PERSON": "a person's name", "EMAIL_ADDRESS": "an email address"},
"over": "request"}

Inside a decoder, the span block is laid out as its instructions, then one label block per label (name and description), then a second copy of the target text. For one short-target span question, the tree forward produces every vector the selected span head needs:

  1. A vector per label. LayerNorm of the mean hidden state over the label's whole block, plus a learned slot embedding. With two or more labels, these vectors are centred by subtracting their mean.
  2. A vector per word. The hidden state of the word's first sub-word token, read from the second copy of the text, then LayerNorm and centring over the target's words.
  3. A score per word × label. A bilinear + MLP scorer rates every pair in FP32.
  4. Spans. The grid logits are temperature-scaled and passed through a sigmoid. Pairs above the chosen threshold are switched on, neighbouring words with the same label are merged, and word offsets become character offsets.

Conceptually, for one span question:

parts_h, blocks_h = tree_backbone(state_prefix, question_blocks)
head = choose_span_head(question) # router or broad weights
labels = head.label_norm(mean_pool(blocks_h, label_blocks)) # [L, H]
labels = labels + head.slot_embedding[arange(L).clamp(max=63)]
labels = labels - labels.mean(0) if L >= 2 else labels
words = head.word_norm(blocks_h[first_subword_positions_in_copy]) # [W, H]
words = words - words.mean(0)
logits = head.bilinear_plus_mlp(words, labels) # [W, L], FP32
probs = sigmoid(logits / head_temperature)
spans = decode_spans(probs, threshold) # highest-label words, merge, trim
SpanHeadV2 selects word and label states, applies LayerNorm, word and label centring and a 64-slot embedding, then sums bilinear and GELU MLP scores. Router and broad heads use independently selected weights.

Router and broad heads share this topology, with independent parameters. Dispatch selects the head and its calibration; the resulting word × label grid is decoded into spans.

Two choices make this work in a causal decoder:

  • Read words from a second copy. Under a causal mask, a word's state sees only the words to its left, which is the wrong view for deciding where an entity starts and ends. In the second copy, placed after the labels, every word has already seen the whole text and every label it is asked about. Targets up to 2,048 tokens are copied whole; longer ones are read in overlapping windows of up to 1,800 tokens with stride 1,536. Word logits are averaged across covering windows before temperature scaling and sigmoid.
  • Read each label from its whole block. Our first decoder span head read each label at a single marker token. The label vectors came out almost identical (pairwise cosine 0.997), so the head learned whether a word is an entity but not which one. Pooling over the name and description separates the labels, and it lets a question use labels the model has never seen: the label is understood from its description.

On development data, the two changes together raise short-text PII F1 from 0.828 to 0.959, and PII F1 on long documents from about 0.06 to 0.94.

The 0.3B encoder needs neither change. It reads the questions and the text in one bidirectional sequence, so every word already sees both sides and every label, and its span head scores word × label pairs by cosine similarity.

Two span heads, chosen per question​

The decoders carry two span heads of the same form with separate weights:

  • the router head, trained on PII, unsupported claims and toxic spans, the signals a router acts on;
  • the broad head, trained on open extraction: named entities of any type, relations, entity mentions and extractive evidence for a question.

The broad head trains last, with the backbone, the decision heads and the router head frozen. Every router output is therefore bitwise identical with and without it; we checked this on 700 rows per model. By default, dispatch recognises the pii, halu and toxic question IDs, the router's label sets, PII subsets and hallucination aliases. Other labels go to the broad head, and the response names the head that answered. An explicit head field overrides the rule.

The result is one model that is a router signal model and an open extractor at once, with no change to its routing behaviour. The 0.3B encoder ships with the router head.

Where Vela 2.0 sits​

Vela 2.0 sits between two lines of work: span extractors that read labels at request time, and decision models that answer typed questions.

Typed decisions (Choice / Noul / Score)Spans for labels named in the requestGrounded check (context vs answer)Trained on router safety, PII and hallucination
GLiNER—entities——
GLiNER2classificationentities and structured fields——
LettuceDetect—fixed label (unsupported)yeshallucination only
Decision 2.0yes———
Vela 2.0yesrouter spans; hybrids add a broad headyesyes

GLiNER showed that a span extractor can read its labels from the request, and GLiNER2 extended that to classification and structured extraction in one schema. Vela 2.0 combines the SystemOne decision format with routing-specific training and grounded checks, following GLiNER2's label resampling recipe.

Results​

The router comparisons use identical test rows and paired bootstraps; open extraction uses a shared harness. The charts retain the reported evaluation protocols, described below and in each model card.

Selection protocol. Checkpoint selection used development splits. The 0.3B card records that final release selection also considered test results and its shipped PII threshold floor was lowered after the test effect was observed.

Prompt attacks
0.989AUC · unseen attack families · 9Bfrom 0.792 · Vela 1.0 Guard
Multilingual hate speech
0.855AUC · Multilingual HateCheck · 9Bfrom 0.646 · Vela 1.0 Safety
Extractive evidence
24.5word-F1 · ACL-Verbatim, held out · 9Bfrom 7.0 · best GLiNER-family model
Vela 2.0 9B against each Vela 1.0 specialist on the specialist test rows: prompt attacks 0.792 to 0.989, HateCheck 0.646 to 0.855, RTP-LX 0.761 to 0.801, long-document PII 0.908 to 0.940, hallucination 0.875 to 0.885, domain 0.831 to 0.844, short PII 0.976 to 0.985.
One Vela 2.0 9B against the Vela 1.0 specialists on identical test rows. PII uses the research scorer with per-length development thresholds.

Router signals. One 9B model is ahead of or level with every Vela 1.0 specialist on the specialist's own test rows, and clearly ahead where specialists generalise worst: prompt attacks from unseen families (0.792 → 0.989 AUC, paired 95% CI +15.4 to +23.9 points) and multilingual hate speech (0.646 → 0.855). It also leads on RTP-LX request harm (0.761 → 0.801), PII in 8K-token documents (0.908 → 0.940 F1), hallucination spans (0.875 → 0.885 example-F1) and domain (0.831 → 0.844 macro-F1). The 0.3B encoder reaches 0.995 F1 on short-text PII, ahead of the Vela 1.0 PII model (0.976), and runs on CPU.

Safety across the family. Over 14 public safety and prompt-attack sets the four sizes reach a macro AUC of 0.871, 0.875, 0.921 and 0.921, against 0.704 for GLiNER2.5-Decide.

Hallucination. On the 2,700 RAGTruth test rows, the 9B reaches 0.774 example-F1, ahead of the LettuceDetect v2 encoder re-scored on the same rows (0.743, +3.1 points, paired 95% CI [+0.5, +5.4]), while answering every other routing question in the same call.

Open extraction. ACL-Verbatim asks for the exact sentences in a paper that support an answer, and it was held out of training. The broad head reaches 23.6 to 24.5 word-F1 at all three decoder sizes; no GLiNER-family model exceeds 7.0.

Cost. A full router request takes 0.09 s on an A40 for the 0.3B, 0.13 s for the 0.8B, 0.40–0.49 s for the 4B and 0.60–0.71 s for the 9B. That is one call for every signal, where Vela 1.0 needed one model per signal.

General decisions. On the Jev Decision Index 0.2.1 (38 benchmarks), the 9B reaches 41.09 against 46.23 for Lux-9B, keeping 89% of its base; the 4B keeps 74% and the 0.8B 79%. The harness reproduces the published Decision 2.0 scores within 0.1 points. On fast-decisions, the 9B scores 62.5 against 62.9 for GLiNER2.5-Decide, while also answering the router's safety and span questions.

Noul calibration. The Jev chart and table use noul_calibration=False. With it enabled, the model cards report 16.01 / 31.91 / 41.63 for 0.8B / 4B / 9B. This optional setting is separate from the router's trained safety thresholds.

Full numbers

Router signals against the Vela 1.0 specialists, on each specialist's own test rows. Differences are paired bootstraps over identical rows. PII uses the research scorer's per-length development thresholds, rather than the shipped runtime calibration.

TaskVela 1.0Vela 2.0 0.3BVela 2.0 9BΔ 9B vs Vela 1.0 [95% CI]
Prompt attacks, unseen families (AUC)0.792 (Guard)0.8820.989+19.8 [+15.4, +23.9]
Multilingual HateCheck (AUC)0.646 (Safety)0.6620.855+20.9 [+20.3, +21.5]
RTP-LX request harm (AUC)0.761 (Safety)0.7280.801+4.0 [+3.4, +4.5]
PII, short texts (F1)0.9760.9950.985+0.9 [+0.1, +1.9]
PII, 8K-token documents (F1)0.9080.8940.940+3.2 [−1.1, +7.0]
Hallucination, 10,698 examples (example-F1)0.8750.8480.885+1.0 [+0.4, +1.7]
Domain (macro-F1)0.8310.8250.844+1.3 [−0.3, +2.8]

PII protocol. The 0.3B's 8K value above is 0.894 with the research scorer; its exported runtime gives 0.896 with the test-blind 0.001 threshold floor and 0.929 with the shipped floor selected after observing the test effect. For 9B, the table's short-text value is 0.985; shipped calibration gives 0.987. These protocols are documented in the model cards.

Open extraction with the broad head, every model scored by one harness. The harness reproduces the GLiFormer-base card on all seven NER sets and the GLiNER-large-v2.5 average within 0.2 points. Latency is the mean over 100 questions on one A40.

ModelZero-shot NER, 7 sets (F1)ACL-Verbatim evidence (word-F1)ms per question, 3K-token context
Vela 2.0 9B, broad head43.524.52,288
Vela 2.0 4B, broad head40.724.41,499
Vela 2.0 0.8B, broad head28.923.6477
GLiFormer-large63.67.0930
GLiNER-large-v2.561.34.6496
GLiNER2.5-Decide51.52.3415
GLiNER2.5-small42.54.6197

General decisions on the Jev Decision Index 0.2.1 (38 benchmarks), with noul_calibration=False.

SizeDecision 2.0 baseVela 2.0Kept
0.8B20.14 (Eos-0.8B)16.0179%
4B42.55 (Nox-4B)31.6374%
9B46.23 (Lux-9B)41.0989%

Four sizes, one interface​

Vela 2.0 0.3B: a 22-layer ModernBERT encoder with hidden width 768, GEGLU width 1152, cosine plus MLP decision readout and word-label cosine span readout.
The 0.3B encodes schema and typed state together. Its 22-layer bidirectional backbone feeds a cosine plus option MLP decision readout and a cosine span readout.

The four checkpoints share the question format, with independently trained backbones and readout weights. The 0.3B supports CPU and ONNX deployment; the hybrid models add the broad span head through the same interface.

Backbone and readout operators

The backbone diagrams expand the attention, recurrence, gating and feed-forward operators behind the four model views.

ModernBERT attention with QKV projection, 12 heads, Q and K RoPE, local or global bidirectional masking, and GEGLU feed-forward split branches.
The encoder combines local and global bidirectional attention with GEGLU. RoPE transforms queries and keys; it is not an addition to token embeddings.

The readout differs between the encoder and the decoders even though the client interface stays the same.

The encoder combines normalised option and question projections with a pooled target for a cosine score, adds an option MLP score, and uses separate normalised word and label projections for spans.
The encoder adds a cosine decision score to an option MLP score. Its span grid uses normalised word and label projections with a learned temperature.

The diagrams trace the public system_one() path at fixed model revisions. Source notes and editable SVG generators accompany the figures.

Training​

Three decoder training stages: a full fine-tune on the routing recipe, then the router span head, then the broad span head, each later stage on a frozen model.

The decoders train in three stages from the released Decision 2.0 models. Each later stage freezes everything trained before it.

All four sizes use shared signal families and schema resampling. Sources become parts, typed questions and answers; options are anonymised, dropped and paraphrased so the model learns to read labels.

The hybrid models train in three stages:

  1. Routing recipe. Fine-tune the whole Decision 2.0 base for 4,000 steps, with a KL term on replayed base-model rows to retain general decisions.
  2. Router spans. Train the router span head on the frozen backbone.
  3. Open extraction. Train the broad head with everything else frozen: 90% named entities, relations, entity mentions and extractive evidence; 10% router span replay. Evidence sources include the training splits of SQuAD 2.0, HotpotQA and Natural Questions.

The 0.3B encoder trains in one stage of 101,000 steps from Kai's Choice trunk, about 6.9 hours on one AMD MI325X.

Stage-1 data mix
DataSourcesShare of steps
Long-document PII, 17 typesgenerated, train-only pool of 10,457 documents27.8%
Synthetic router-style decisions304,593 rows, 63,043 labels, 21 languages, generated with Qwen3-30B-A3B-Instruct-250723.1%
General decisionsSNLI, BoolQ, ARC, MASSIVE, TyDi QA and other Decision 1.0 source families, in our own wording12.5%
Safety and prompt attacksAEGIS 2.0, PolyGuardMix, Nemotron-Safety-Guard v3, LLMail-Inject, Salad-Data12.2%
Hallucination spansLettuceDetect prose and code data, including the RAGTruth train split11.3%
Decision 2.0 replayDecision 2.0 training rows, with a KL term to the frozen base7.5%
Router tasksGlobal-MMLU, Aya, DiffusionDB, WildFeedback, router PII recipe, Presidio replay3.8%
Small in-house set~2%

A synthetic row is kept only when a blind re-label agrees with it (71% do). Training rows are deduplicated against every evaluation set. Each size was trained with three seeds, with checkpoint selection on development rows. The 0.3B final release selection also considered test results, as noted with the evaluation protocol above.

Try it​

With the same dependencies installed, use a hybrid model on GPU to combine request routing, PII and unsupported-claim spans:

from transformers import AutoModel

m = AutoModel.from_pretrained("vllm-sr/Vela-2.0-9B", trust_remote_code=True).to("cuda")
PII_LABELS = m.vela2_engine.cal["pii_schema"]["labels"] # the 17 trained PII types

result = m.system_one(
state={"request": "Hi, I'm Tom Baker (tom.baker@example.com). What is the maximum daily dose of paracetamol for an adult?",
"source": "For adults, the maximum dose of paracetamol is 4 grams in 24 hours, taken as 500 mg to 1 g every 4 to 6 hours.",
"answer": "Adults can take up to 6 grams of paracetamol in 24 hours, in doses of 500 mg to 1 g every 4 to 6 hours."},
questions={
"pii": {"type": "span", "instructions": "Which spans are personal information?",
"criteria": PII_LABELS, "over": "request"},
"halu": {"type": "span", "instructions": "Which spans of the answer are not supported by the context?",
"criteria": {"unsupported": "a claim not supported by the context"}},
"domain": {"type": "choice", "instructions": "Which subject area is this request about?", "over": "request",
"criteria": {"health": "medicine, clinical practice, nutrition, ageing or sexual health",
"math": "arithmetic, algebra, geometry, statistics or other mathematics",
"other": "a subject that fits none of the listed areas"}}})

Two span questions and a Choice, one call. The decoder evaluates the two span questions in separate rendered sequences. The recorded output (trimmed):

{
"answers": {
"pii": {"type": "noul", "noul": 1.0},
"halu": {"type": "noul", "noul": 0.996},
"domain": {"type": "choice", "choice": "health", "confidence": 0.977}
},
"spans": {
"pii": [{"label": "PERSON", "start": 8, "end": 17, "text": "Tom Baker", "probability": 0.999},
{"label": "EMAIL_ADDRESS", "start": 19, "end": 40, "text": "tom.baker@example.com", "probability": 1.0}],
"halu": [{"label": "unsupported", "start": 22, "end": 29, "text": "6 grams", "probability": 0.982}]
},
"span_heads": {"pii": "router", "halu": "router"}
}

Any other label set goes to the broad head. Asking "Which spans of the context answer the request?" over a product description returns March 2024 (0.997) and 499 euros (0.865) for "When did the X200 go on sale, and at what price?". A set question returns every label above its threshold, for example both billing and shipping for "My card was charged twice and the parcel never arrived."

Each model also ships vela2_serve.py, a small FastAPI server for the same request on POST /v1/systemone:

pip install fastapi uvicorn
python vela2_serve.py --model . --device cuda --port 8001

Towards open foundation routing models​

Vela 2.0 brings routing decisions and span answers into one model family. The next step is native signal-backend integration in vLLM Semantic Router, replacing per-signal classifiers with one Vela 2.0 request.

License. Weights, code and documentation are Apache-2.0. The 0.3B tokenizer carries the Gemma Terms of Use; training data retain their source licenses, including CC-BY-SA share-alike terms. Each model card links its notices and license scope.

We thank the Decision 2.0 team for releasing the base models openly; the label resampling follows GLiNER2's recipe.