What if a model could tell you “this ticket is urgent, send it to the technical team” in tens of milliseconds, with a probability on every answer, and never invent a field you didn’t ask for? That’s a decision model.
Clef is Cloudflare’s take on one. Below: what it is, how it compares with Jev, and how to call it from a short Python script.
A quick Jev recap
Decision models got attention with Jev from TypeSafe AI. Instead of generating text, it takes a state and a set of typed questions and returns typed answers, each with a probability, in one fast pass. I covered it in the Jev tutorial and the images post, so start there if you want the full story.
What Clef is
Cloudflare released Clef on October 1, 2026, as the first models from its Workers AI team. Cloudflare calls it Jev-API compatible. It uses the same three question types (noul, choice and score) and the same request format, so by Cloudflare’s account you can move existing Jev code over by changing the endpoint and the model name. The weights are open source under Apache 2.0 on Hugging Face, so you can also run it yourself.
How it’s trained
Cloudflare says it starts from a Qwen base model and freezes it. On top it trains a small routing head and low-rank adapters. Qwen reads your input once, then Clef scores every valid answer in parallel, so there is no token-by-token generation. Training adds a Brier loss and reinforcement learning aimed at calibration, so a 0.86 should mean something close to an 86 percent chance.
Clef and Clef-flash
That recipe produced two models:
- Clef, built on Qwen3.8-27B, is the precision model.
- Clef-flash, built on Qwen3.5-9B, is for latency-critical decisions.
Clef also has a vision encoder, so it accepts images alongside the state. Its context window is 64k. Cloudflare’s launch post sets that against Jev’s 32k, while TypeSafe’s docs give Jev 64k per request and 32k per question, so check which limit you’d hit. Images set Clef apart on October 1, but Jev 1.14 added them on October 14 (covered in the images post).
Fine-tuning
Cloudflare will fine-tune Clef on your own data. For now that means working directly with their engineers; a self-serve platform is planned. And since the weights are on Hugging Face, nothing stops you from fine-tuning it yourself and running it on your own hardware.
Set up the project
You need a free Cloudflare account and an API token. I show how to create the token in the video. Give the token two permissions, Workers AI Read and Workers AI Write, then copy it along with your Account ID. Keep both off camera and out of your code.
I’m using uv instead of pip because it’s fast.
uv init clef-test
cd clef-test
uv venv --seed
uv add requests python-dotenv
Put your two values in a .env file:
ACCOUNT_ID=your-account-id
AUTH_TOKEN=your-api-token
Then keep it out of git so the token never gets committed:
echo ".env" >> .gitignore
The code
Here’s the whole of main.py; the four steps after it walk through each part.
import os
import requests
from dotenv import load_dotenv
load_dotenv()
def main():
ticket = "Checkout has been failing for every customer for the last hour"
account_id = os.getenv("ACCOUNT_ID")
auth_token = os.getenv("AUTH_TOKEN")
headers = {"Authorization": f"Bearer {auth_token}"}
api_url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/cloudflare/clef"
model = "clef"
payload = {
"model": model,
"state": ticket,
"questions": {
"urgent": {
"type": "noul",
"instructions": "Is this support request urgent?",
},
"team": {
"type": "choice",
"instructions": "Which team should handle this request?",
"criteria": {
"billing": "Payments, Invoices, and refunds",
"technical": "Outages, errors, and configuration",
"sales": "Plans and upgrades",
},
},
"severity": {
"type": "score",
"instructions": "How severe is the customer impact?",
"criteria": ["No impact", "Minor", "Major", "Critical"],
},
},
}
response = requests.post(api_url, headers=headers, json=payload)
try:
print(response.json())
except requests.exceptions.JSONDecodeError:
print(f"HTTP {response.status_code}: {response.text!r}")
if __name__ == "__main__":
main()
1. Load the secrets
load_dotenv() reads the .env file into the environment, and os.getenv pulls out the two values.
2. Set up the request
The ticket is our state. The URL is the Workers AI run endpoint: your account ID, ai/run, then the model ID @cf/cloudflare/clef. Authentication is a bearer token.
3. Build the payload
model is the model name, state is what to evaluate, and questions is the schema: 1 to 64 questions, each with an ID you choose.
There are three question types:
| Type | What it does | What comes back |
|---|---|---|
noul | A yes/no question (spelled n-o-u-l) | The probability of yes |
choice | Picks one option from criteria you define | The chosen option and a probability for each |
score | Rates against an ordered rubric | A probability-weighted score |
4. Send and print
requests.post sends the payload with json=payload. The try catches a non-JSON reply, such as one caused by a bad token, and prints the status and body instead.
Run it
uv run main.py
This is what I got:
{'result': {'model': 'clef', 'answers': {'urgent': {'type': 'noul', 'noul': 0.9878}, 'team': {'type': 'choice', 'choice': 'technical', 'probabilities': {'billing': 0.1237, 'technical': 0.8622, 'sales': 0.0141}, 'confidence': 0.6384}, 'severity': {'type': 'score', 'score': 2.9487, 'legend': {'0': 'No impact', '1': 'Minor', '2': 'Major', '3': 'Critical'}, 'probabilities': {'0': 0.0043, '1': 0.0044, '2': 0.0296, '3': 0.9617}, 'confidence': 0.9011}}, 'usage': {'input_tokens': 346, 'output_tokens': 0}}, 'success': True, 'errors': [], 'messages': []}
The numbers below come from my own run. If you run the same code, expect the probabilities to differ slightly.
| Question | Type | Result |
|---|---|---|
| urgent | noul | 0.9878 probability of yes |
| team | choice | technical at 0.8622 (billing 0.1237, sales 0.0141), confidence 0.6384 |
| severity | score | 2.9487 on a 0 to 3 scale, Critical at 0.9617, confidence 0.9011 |
| usage | 346 input tokens, 0 output tokens |
So there’s a 98.8 percent chance the ticket is urgent, it goes to technical at 86 percent, and severity is 2.95 on a scale of 0 to 3. The legend maps 3 to Critical, which holds 96 percent of the probability.
Usage and cost
Look at usage: 346 input tokens and zero output tokens. Cloudflare doesn’t charge for output, and Clef costs $0.24 per million input tokens, so this call cost about eight thousandths of a cent.
Acting on the numbers
Your own code can act on these values with plain rules. If urgent is above 0.9 and severity is above 2.5, page the on-call engineer. If the confidence is low, hand the ticket to a human.
Clef-omni: audio and video
On October 9, Cloudflare added Clef-omni, which also takes audio (wav or mp3) and video (mp4 or webm). There’s no pipeline to transcribe speech or split frames first: one call, one decision.
It’s built on Qwen3-Omni, a 30-billion-parameter mixture-of-experts model with 3 billion parameters active. The request has the same shape. You add images, audio and videos arrays of base64 data URLs, up to 4 images, 4 audio clips and 2 videos.
{
"model": "clef-omni",
"state": "Review the installation: a photo of the unit, an audio recording of it running, and a video of the fan.",
"images": ["data:image/png;base64,<base64-png>"],
"audio": ["data:audio/mpeg;base64,<base64-mp3>"],
"videos": ["data:video/mp4;base64,<base64-mp4>"],
"questions": {
"fan_running": {
"type": "noul",
"instructions": "Is the fan running in the video?"
}
}
}
To try it with our script, change two lines in main.py:
api_url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/@cf/cloudflare/clef-omni"
model = "clef-omni"
Price and speed compared with Jev
Prices are per million input tokens, and output is free for all of them. Cloudflare cut Clef-flash from $0.09 to $0.038, which puts it about ten percent under Jev’s $0.042. Clef is $0.24, nearly six times Jev, and Clef-omni is $0.15. To reach the flash price, Cloudflare cut the hosted context window to 24k tokens. The weights on Hugging Face are unchanged.
| Model | Input price per M tokens | Median latency | Hosted context |
|---|---|---|---|
| Jev | $0.042 | 524.1 ms in Cloudflare’s benchmark; TypeSafe lists 70 to 500 ms | 64k per request, 32k per question |
| Clef | $0.24 | 209.3 ms at launch; Cloudflare later reported 1.7 to 2.0x faster hosted medians | 64k |
| Clef-flash | $0.038 (was $0.09) | 38.8 ms | 24k (was 64k) |
| Clef-omni | $0.15 | about 130 ms for text-only input | 64k |
On speed, Cloudflare’s benchmark puts Jev’s median at 524 milliseconds, Clef at 209 (about 2.5 times faster) and Clef-flash at 39 (about 13 times faster). TypeSafe’s own 70 to 500 ms figure comes from its own runs, which it says were generally run from laptops on the West Coast, so the two aren’t a like-for-like comparison.
Cloudflare also says a Clef model tops 7 of 10 decision benchmarks and that Clef beats Jev on 3 of 4 of TypeSafe’s workflow evals. Jev still wins the fourth, and the Clef wins are narrow in places (76.3 against 76.0 on customer service, for one). Every one of these is a Cloudflare number, so test on your own data.
Recap
- A decision model trades open-ended text for typed answers with probabilities, in milliseconds.
- Clef follows the same request format as Jev, with
noul,choiceandscorequestions. - Clef is the precision model, Clef-flash is built for speed, and Clef-omni adds audio and video.
- Check
confidencein your code and send doubtful cases to a human. - Try changing the model ID to
clef-flashand time the call.
For a different kind of model call, where the model asks for tools and your code runs them, read how AI agents work.