Skip to content
Go back

Cloudflare Clef in Python: Typed AI Answers in Milliseconds

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 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:

TypeWhat it doesWhat comes back
noulA yes/no question (spelled n-o-u-l)The probability of yes
choicePicks one option from criteria you defineThe chosen option and a probability for each
scoreRates against an ordered rubricA 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.

QuestionTypeResult
urgentnoul0.9878 probability of yes
teamchoicetechnical at 0.8622 (billing 0.1237, sales 0.0141), confidence 0.6384
severityscore2.9487 on a 0 to 3 scale, Critical at 0.9617, confidence 0.9011
usage346 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.

ModelInput price per M tokensMedian latencyHosted context
Jev$0.042524.1 ms in Cloudflare’s benchmark; TypeSafe lists 70 to 500 ms64k per request, 32k per question
Clef$0.24209.3 ms at launch; Cloudflare later reported 1.7 to 2.0x faster hosted medians64k
Clef-flash$0.038 (was $0.09)38.8 ms24k (was 64k)
Clef-omni$0.15about 130 ms for text-only input64k

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

For a different kind of model call, where the model asks for tools and your code runs them, read how AI agents work.

Sources


Share this post:

Previous Post
Who Actually Runs the Command? How AI Agents Work (Build One in Python)
Next Post
Next-Concept Modeling (NCM): Up to 31x Faster Text Generation