All posts

Clef: Cloudflare's Open-Weight Decision Model to Replace Jev

Cloudflare has announced a new decision model called Clef. It supports an API, is available as open weights, and is faster. It may be able to replace Jev.

Contents

    Clef is Cloudflare's decision model that takes an input situation along with predefined questions and choices, then returns a probability for each choice. It is the first model family trained by the Cloudflare Workers AI team, and Clef and Clef-flash were released together.

    Introducing Clef: Cloudflare's first open-source decision models, now on Worker…

    For example, you ask a comment “Is this spam?”, “What topic is this?”, and “How high should review priority be?” The model assigns scores to the choices the developer specifies, and the application decides the next action based on those results.

    Its use is classification and routing. It differs from a general-purpose chat model that freely writes text. It's the same kind of classification as Jev.

    flowchart TD
      n1["댓글, 문서 등 선택지"]
      n2["Clef"]
      n3["확률과 구조화된 답"]
      n4["애플리케이션 승인 및 보류 규칙"]
      n1 --> n2
      n2 --> n3
      n3 --> n4

    Comparison of the two models

    ItemClefClef-flash
    Model size27B9B
    Base modelQwen/Qwen3.8-27BQwen/Qwen3.5-9B
    Workers AI ID@cf/cloudflare/clef@cf/cloudflare/clef-flash
    Workers AI context65,536 tokens65,536 tokens
    Vision encoderIncludedIncluded
    Public licenseApache 2.0Apache 2.0
    API input price per 1M tokensUS$0.24US$0.09
    When to chooseTasks where accuracy differences matter, evaluated comparativelyTasks where latency and cost matter, evaluate first

    According to Cloudflare, the model processes the input with a Qwen-based model, then uses the internal representations to evaluate the allowed choices in parallel. The decision step is non-autoregressive, so it skips the process of generating answer text token by token.

    In the public code, the last hidden state of the base model is passed to a dedicated JointSchemaHead. A per-question softmax is applied to the choice logits, and the result is converted into the API response format. The implementation path differs from the usual approach of parsing generated text output as JSON.

    A probability is the score the model assigns to a choice. A response of 0.95 does not guarantee a 95% accuracy rate in real-world service. Operating thresholds must be validated separately.

    Open weights

    The open-weight release is confirmed. Both repositories contain the base model weights, the decision head weights, the tokenizer and processor, and the inference code.

    Public fileRole
    model-*.safetensorsBase model weights
    model.safetensors.index.jsonWeight shard index
    joint_head.safetensorsDecision head weights
    joint_head_config.jsonHead configuration
    joint_schema_model.pyModel loading, input processing, and structured response generation
    Tokenizer and processor filesText and visual input processing
    LICENSEOriginal Apache 2.0 license text

    Question and answer formats

    Question typePurposeResponse meaning
    noulTrue/false judgmentProbability of being true
    choiceClassification among named choicesSelected item, confidence, per-choice probabilities
    scoreOrdered level ratingLevel score weighted by probabilities, and per-choice probabilities

    A score is not necessarily returned as an integer grade. The grade index starts at 0, and the probability-weighted value can be a decimal. It is provided to be compatible with the Jev/SystemOne request and response formats.

    The following is a partial hypothetical response to aid understanding. It is not the result of an actual model call.

    {
      "answers": {
        "spam": { "type": "noul", "noul": 0.94 },
        "topic": {
          "type": "choice",
          "choice": "advertising",
          "confidence": 0.9,
          "probabilities": {
            "technical": 0.07,
            "advertising": 0.9,
            "other": 0.03
          }
        }
      }
    }
    

    Mutually exclusive items fit naturally in a single choice question, while tags that can hold at the same time are better set up as separate noul questions. For example, to allow a judgment like “a tech post that is also an ad,” independent questions are needed. This is a suggestion about schema design.

    Multimodal and input limits

    The local inference path in the model card describes text, JSON, images, and video frames. However, you should distinguish between the capabilities of the local model and the supported scope of the hosted API.

    At the time of research, the Workers AI Clef API documentation listed the following limits:
    • Questions: 1 to 64 per request.
    • Images: up to 4, supporting PNG, JPEG, and WebP.
    • Remote image URLs are not allowed; images must be included in the request.
    • Per image: up to 4 MiB and 16 million pixels; total decoded images up to 8 MiB; request body up to 13 MiB.
    • Long text state may be truncated to fit the token limit.
    • The input schema has an image field, but I could not confirm a separate video field.

    How to use it

    You can call the REST API from a Next.js server. The following is a blog comment classification example written using the official endpoint and input schema. It is code that assumes the API token and account ID are set as server environment variables; I did not run it during this research.

    // Next.js 서버 코드에서 사용한다.
    export async function classifyBlogComment(commentText: string) {
      const account = process.env.CLOUDFLARE_ACCOUNT_ID;
      const token = process.env.CLOUDFLARE_API_TOKEN;
      if (!account || !token) throw new Error("Cloudflare 환경변수가 필요합니다.");
    
      const payload = {
        model: "clef-flash",
        state: { comment: commentText },
        questions: {
          spam: {
            type: "noul",
            instructions: "댓글이 글과 무관한 광고 또는 반복 스팸인가?",
          },
          topic: {
            type: "choice",
            instructions: "댓글의 주된 목적을 분류하라.",
            criteria: {
              technical: "기술 질문이나 기술 관련 의견",
              advertising: "상품·서비스·외부 사이트 홍보",
              other: "어느 항목에도 해당하지 않음",
            },
          },
        },
      };
    
      const endpoint = new URL(
        `https://api.cloudflare.com/client/v4/accounts/${account}/ai/run/@cf/cloudflare/clef-flash`,
      );
      const result = await fetch(endpoint, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${token}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(payload),
        signal: AbortSignal.timeout(10_000),
        cache: "no-store",
      });
      if (!result.ok) throw new Error(`Clef HTTP 오류: ${result.status}`);
    
      const envelope = await result.json();
      if (envelope.success !== true || !envelope.result) {
        throw new Error("Clef 응답을 확인할 수 없습니다.");
      }
      return envelope.result;
    }
    
    

    Production integration additionally requires comment length limits, call rate limits, response schema validation, and handling of failures by sending items to manual review. Keep the token on the server and do not include it in the browser bundle.

    Running locally with open weights

    The official model card explains that it was tested on a single H200 with torch 2.11 and transformers 5.10.2.

    You can load the model with the public loader and pass questions to the systemone function. The code below assumes a CUDA environment with sufficient memory. huggingface_hub, safetensors, PyTorch, and Transformers must be installed, and Pillow is also needed for visual input.

    import importlib.util
    import sys
    from pathlib import Path
    from huggingface_hub import snapshot_download
    
    release_dir = Path(snapshot_download(
        repo_id="Cloudflare/clef-flash",
        revision="17f0b0ad64efb65d273590632833508766b2aae6",
    ))
    module_spec = importlib.util.spec_from_file_location(
        "clef_runtime", release_dir / "joint_schema_model.py"
    )
    runtime = importlib.util.module_from_spec(module_spec)
    sys.modules[module_spec.name] = runtime
    module_spec.loader.exec_module(runtime)
    decision_model, input_processor = runtime.load_release_model(release_dir)
    
    decision = runtime.systemone(decision_model, input_processor, {
        "model": "clef-flash",
        "state": {"comment": "새 글의 예제 코드를 더 설명해 주세요."},
        "questions": {
            "technical_question": {
                "type": "noul",
                "instructions": "댓글이 기술 설명을 요청하고 있는가?",
            }
        },
    })
    print(decision["answers"])
    
    

    This example is written based on the public loader and function signature, and has not been run and verified. Default loading is CUDA and BF16. The default max_length of local systemone is 16,384 tokens, so do not assume it equals the 65,536-token context of Workers AI.

    Loading a general chat model alone cannot be taken to mean Clef's dedicated decision head will work. To use it with Ollama, GGUF, vLLM, or similar runtimes, you must check whether that runtime actually handles the head and the question schema.

    View the open-weight model

    Cloudflare/clef · Hugging Face

    Comments 1

    1. Loading comments.