Quickstart: SystemOne API server
hf download kurcontko/clef-flash-FP8-Dynamic --local-dir clef-flash-FP8-Dynamic docker run --gpus all --ipc=host -p 8000:8000 -v $PWD/clef-flash-FP8-Dynamic:/model:ro \ --entrypoint bash vllm/vllm-openai:v0.28.0 -c \ "cp -r /model/vllm_plugin /tmp/p && pip install -q /tmp/p && clef-systemone --model /model --dp 1"
--dp N runs one engine per GPU behind the one port (recommended over tensor parallelism on PCIe GPUs).
The server warms up its kernels before /health reports ready (about 3-4 minutes from a cold container).
curl localhost:8000/v1/systemone -H 'content-type: application/json' -d '{ "model": "clef-flash", "state": "Our checkout started returning errors and orders are blocked.", "questions": { "department": {"type": "choice", "instructions": "Which team should handle the message?", "criteria": {"billing": "Payments or invoices", "technical": "Bugs or outages"}}, "urgency": {"type": "score", "criteria": ["Can wait", "This week", "Today"]}, "outage": {"type": "noul", "instructions": "Is a service down?"}}}'
The request and response bodies are the same as the systemone() function in the original release:
answers keyed by question ID (choice with confidence and probabilities, score with the expected score
and legend, noul with the probability of true) and usage. Also served: GET /v1/models, GET /health.
Quickstart: Python (offline vLLM)
# pip install ./clef-flash-FP8-Dynamic/vllm_plugin (in an environment with vllm==0.28.*)import sysfrom transformers import AutoTokenizerfrom vllm import LLM, PoolingParamsfrom clef_vllm import ARCHITECTURE, TASK, schema_layout path = "./clef-flash-FP8-Dynamic"sys.path.insert(0, path)from joint_schema_model import encode_record def main(): # Keep `llm` local: vLLM shuts its engine process down when the LLM object is freed. llm = LLM(model=path, hf_overrides={"architectures": [ARCHITECTURE]}, runner="pooling", enable_prefix_caching=False, language_model_only=True, max_model_len=16384) tokenizer = AutoTokenizer.from_pretrained(path) record = { "state": {"invoice": {"vendor": "Acme", "total": 1250.0, "currency": "USD", "status": "overdue"}}, "questions": { "status": {"type": "choice", "instructions": "What is the invoice status?", "criteria": {"paid": "Invoice is paid.", "overdue": "Invoice is past due.", "draft": "Not sent."}}, "large": {"type": "noul", "instructions": "Is the total above 1000 USD?"}, }, } encoded = encode_record(tokenizer, record) params = PoolingParams(task=TASK, extra_kwargs={"clef_questions": schema_layout(encoded)}) output = llm.encode([{"prompt_token_ids": list(encoded.input_ids)}], pooling_params=[params], pooling_task=TASK)[0] logits, offset = output.outputs.data.float(), 0 # every option logit of every question, in order for question in encoded.questions: n = len(question.option_ids) print(question.question_id, dict(zip(question.option_ids, logits[offset:offset + n].softmax(-1).tolist()))) offset += n if __name__ == "__main__": main()
Pass a list of prompts and a matching list of PoolingParams to score many records in one call; vLLM batches them.
Results
Accuracy and agreement with BF16
1,400 records, 200 per task, from held-out splits: BANKING77 (test), ARC-Challenge (test), MMLU (test),
HellaSwag (validation), ANLI R3 (test), BoolQ (validation), and a multi-question ANLI R1 set (3 questions per
record: choice + true/false + score). Accuracy is against gold labels. Agree is top-1 agreement with the
BF16 model and KL is mean KL(BF16 ‖ quantized) per question. BF16 is the original release run with
transformers 5.10.2; the quantized rows were measured in vLLM with real FP8/FP4 kernels.
Table with columns: Task, BF16 acc, FP8 acc, FP8 agree, FP8 KL, NVFP4 acc, NVFP4 agree, NVFP4 KL| Task | BF16 acc | FP8 acc | FP8 agree | FP8 KL | NVFP4 acc | NVFP4 agree | NVFP4 KL |
|---|
| BANKING77 (77-way intent) | 96.5 | 97.0 | 99.5 | 0.0005 | 97.5 | 98.0 | 0.013 |
| ARC-Challenge | 99.5 | 99.5 | 100.0 |
Accuracy differences of under 1 point are within noise at 200 records per task. The BF16 model run through the same
plugin in vLLM agrees with transformers on 99.8% of questions (KL 0.0001), so the plugin itself adds no error.
NVFP4 moves most on hard, near-chance cases (ANLI): treat its confidences on borderline inputs with care.
Throughput
Same 1,400 records (717k tokens, ~512 per record), RTX 5070 Ti 16 GB GPUs.
Table with columns: Setup, GPUs, Records/s, Tokens/s, vs BF16 transformers| Setup | GPUs | Records/s | Tokens/s | vs BF16 transformers |
|---|
BF16, transformers 5.10.2 (original release code, model split over 2 GPUs) | 2 | 6.1 | 3,113 | 1.0x |
| BF16, vLLM + plugin, tensor parallel 2 | 2 | 13.0 | 6,633 | 2.1x |
| FP8, vLLM + plugin | 1 | 19.5 | 9,986 |
Through the HTTP server with 64 concurrent clients: NVFP4 on 1 GPU 39.7 req/s (p50 0.95 s, p95 5.1 s),
NVFP4 on 2 GPUs 78.7 req/s; with 8 concurrent clients on 2 GPUs, p50 latency is 132 ms. On PCIe GPUs, tensor
parallelism was slower than one engine per GPU (FP8 TP2: 8,605 tok/s; NVFP4 TP2: 10,850 tok/s).
Quantization details
- Tool: llm-compressor 0.14.0 (compressed-tensors 0.19.0),
QuantizationModifier(targets="Linear", scheme="FP8_DYNAMIC").
- Scheme: FP8 (E4M3) W8A8: per-output-channel static weight scales, per-token dynamic activation scales.
- Calibration: None needed (weight scales from the weights, activation scales computed per token at runtime).
- Kept in BF16:
lm_head (the joint head reads its rows as lexical option embeddings, so it is never quantized),
the vision tower (model.visual.*), the Gated DeltaNet gate projections linear_attn.in_proj_a / in_proj_b
(32 outputs each), embeddings, norms, and the joint schema head (clef_head/).
- Gated DeltaNet fused scale: vLLM fuses
linear_attn.in_proj_qkv and in_proj_z into one GEMM, which needs a
shared NVFP4 weight global scale. llm-compressor 0.14 only shares scales for q/k/v and gate/up, so
scripts/quantize.py adds to its fused groups. Without this, vLLM applies the
larger scale to both halves and the qkv weights come out scaled by about 0.67 (we measured 92.9% instead of 94.3%
agreement). Anyone re-quantizing Qwen3.5-family models to NVFP4 for vLLM should do the same.
How the vLLM plugin works
vllm_plugin/ (pip install-able, package clef-vllm) registers ClefFlashForDecision, a subclass of vLLM's
Qwen3_5ForConditionalGeneration that runs as a pooling model. Its pooler collects each request's final hidden
states across chunked prefill and runs the original JointSchemaHead (from joint_schema_model.py) on the full
prompt. Each request carries its schema layout (question and option token spans from encode_record) in
PoolingParams.extra_kwargs["clef_questions"]; the output is one flat vector of every option logit. Prefix caching
must be off. Under tensor parallelism the vocab-sharded lm_head is gathered once on rank 0 for the head's lookups.
Files
Table with columns: Path, Purpose| Path | Purpose |
|---|
model.safetensors, config.json, recipe.yaml | Quantized backbone (12 GB, compressed-tensors format) |
clef_head/ | Joint schema head, BF16, unchanged from the original release (in a subfolder so vLLM does not load it as backbone weights) |
joint_schema_model.py | Original release code: encode_record, systemone_answer, the head module (unchanged) |
tokenizer*.json, chat_template.jinja, , |
See also kurcontko/clef-flash-NVFP4 (2x faster again, about -0.5 points).
License and attribution
Apache-2.0, following Cloudflare/clef-flash (itself post-trained from
Qwen/Qwen3.5-9B). All credit for the model goes to its original authors; this
repository only adds the quantization, the vLLM plugin and the server. Not an official Cloudflare release.