CoderBlog
“AI Tech”

Jev: A Probabilistic Decision Primitive That Sits Between Code and LLMs

A working engineer's introduction to Jev, TypeSafe's System One model — what it is, how it differs from a regular LLM, and four production-ready patterns (sentiment classification, title reranking, content safety gate, user intent routing) with runnable Python examples.

Fig. 01 — Jev: A Probabilistic Decision Primitive That Sits Between Code and LLMs

1. Introduction

A year and a half after LLM became popular, most of the engineers I talked to encountered the same blind spot: they used a language model to generate everything, and then used a bunch of if-else to determine everything. The decision-layer - "Should this section be given to the reranker or summarizer?" "Can this LLM output be sent?" "Which of the five titles is the strongest?" - everyone treats it as a pipeline, using fragile regex, manually adjusted thresholds, or wrapping it with another layer of LLM and adding if judgment. You can run, but it will be not working if changed the business logic, and then no one dares to trust this system.

And I will introduce the other way for resolving the issue in this article: Jev, the System One model from TypeSafe AI. Jev is not a chatbot, it does not help to write the articles, it does not hallucinate. It is a decision primitive with type, probability, and calibrated confidence, it's accepted the structured state with natural-language questions and returns the clear Answer + full probability distribution + confidence level.

We will discuss what's Jev and how it differs from an LLM call, and how to use the three primitives it exposes (noul, choice, score) with sample python codes. After that, you will have a clear decision in your mind: “Should I use a large model, write a function, or go to Jev ? ”

2. What is Jev ?

Jev is the flagship model of TypeSafe AI's System One family. The whole product is built around a single observation: most of the decisions inside an AI system are not "write me a paragraph about X". They are "is this A or B", "which of these three options is best", "how confident are you on a scale of 1 to 5". The traditional response to that observation is to wrap an LLM call in a JSON parser and pray. Jev is the alternative: a model whose only job is to answer those questions, in a typed schema, with a full probability distribution.

The API interface is very simple. You just need to POST a state with one or more questions to ​https://api.typesafe.ai/v1/systemone , authenticate with a Bearer token, then it will return a structured answer.

The question is one of the three primitive:

  • noul — A yes/no question with a calibrated probability. Output: a float in [0, 1]. "Is this news article bullish on Apple?"
  • choice — A multiple-choice question over a fixed candidate set. Output: a categorical distribution. "Which of these five titles is best?"
  • score — A score on an ordered set of levels. Output: a categorical distribution over the levels. "How safe is this output: safe / risky / unsafe?"

Fig. 02 — The three primitives of Jev

You will get 3 items for each primitive:

  • The typed answer (the mode of the distribution).
  • The full probability distribution over the output set.
  • The confidence score in [0, 1].

The last number is where Jev gets really interesting. It is not a vibe. It is a calibrated probability that the model is right.

You can use it to gate downstream actions: only publish the news summary if Jev is > 0.85 confident the sentiment is correct; only ship the title if Jev is > 0.7 confident it beats the alternatives; only escalate to a human if Jev's confidence on "is this safe" is below 0.6.

3. How Jev differs from an LLM call

If you have been reaching for a chat completion every time you need a structured decision, Jev will feel different.

LLM (e.g. GPT-4-class) Jev
Output Free-form text, sometimes JSON Typed answer + distribution + confidence
Best at Generation, open-ended reasoning Structured decisions, calibrated yes/no
Failure mode Hallucinates confidently Returns a distribution; confidence can be low
Cost per call High (thousands of tokens) Low (hundreds of tokens)
Latency 1-5 s 200-800 ms
Can be parallelized in one request Limited Yes — one request, many questions
Tool use Native Not its job — pair it with tools

The simple result is:

  • If the output for human reading then use LLM
  • If the output for coding branch then use Jev

For examples, "should this go to agent A or agent B" can use Jev, and "Summarize this report" can use LLM.

4. The three primitives in one minute

Let's have a look the below examples of three primitives. Jev accepted a state (any JSON-serializable object describing the situation) and a list of questions. Each question has a primitive, a name, a question (the natural-language prompt), and a schema (the typed output space):

import json
from typing import Any

# A Jev question with the three primitives
questions = [
    {
        "primitive": "noul",
        "name": "is_bullish",
        "question": "Is this news article bullish on the stock mentioned?",
        "context": state,  # the article + headline
    },
    {
        "primitive": "choice",
        "name": "best_title",
        "question": "Which of the candidate titles is the strongest?",
        "context": {**state, "candidates": titles},
        "choices": titles,  # Jev requires the candidate set
    },
    {
        "primitive": "score",
        "name": "safety",
        "question": "How safe is this user-facing string to publish?",
        "context": state,
        "levels": ["safe", "risky", "unsafe"],
    },
]

You can send all questions within a request. Jev runs them in parallel and returns one answer per question. The cookbook from TypeSafe reports that 13 parallel questions cost roughly 12× cheap and 10× fast compared to 13 sequential calls.

5. The examples

The examples in this article will also bundle all of the decisions into one call, this is the right default.

Example 1. News sentiment classification

Suppose you have a stream of news headlines (or short article bodies) and you need to know the sentiment on a stock or a topic. The naive solution is a fine-tuned classifier. The medium solution is an LLM call with response_format={"type": "json_object"}. The Jev solution is a choice primitive over three labels with a full distribution.

# example-1-news-sentiment.py
"""
Classify news headlines into bullish / bearish / neutral on a stock.

Run:
    export TYPESAFE_API_KEY=apikey_...
    python3 example-1-news-sentiment.py
"""

import json
import os
import urllib.request
from typing import TypedDict

API_URL = "https://api.typesafe.ai/v1/systemone"

# Pull the key from the env. Never hardcode it.
API_KEY = os.environ["TYPESAFE_API_KEY"]


class Sentiment(TypedDict):
    label: str           # one of "bullish", "bearish", "neutral"
    confidence: float    # Jev's confidence on the chosen label
    distribution: dict   # full prob mass over bullish/bearish/neutral


def classify_sentiment(headline: str, ticker: str) -> Sentiment:
    # `state` is whatever context Jev needs to decide. Keep it small.
    state = {"headline": headline, "ticker": ticker}

    questions = [
        {
            "primitive": "choice",
            "name": "sentiment",
            "question": (
                f"Is this headline bullish, bearish, or neutral on {ticker}? "
                "A bullish headline suggests upside catalysts, earnings beats, "
                "upgrades, or product wins. A bearish headline suggests downside, "
                "misses, downgrades, or investigations. If the headline has no "
                "clear directional implication, choose neutral."
            ),
            "context": state,
            "choices": ["bullish", "bearish", "neutral"],
        }
    ]

    payload = json.dumps({"state": state, "questions": questions}).encode()
    req = urllib.request.Request(
        API_URL,
        data=payload,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
    )
    with urllib.request.urlopen(req) as resp:
        body = json.loads(resp.read())

    # Jev returns one answer per question, in order.
    answer = body["answers"][0]
    return {
        "label": answer["value"],
        "confidence": answer["confidence"],
        "distribution": answer["distribution"],
    }


if __name__ == "__main__":
    headlines = [
        ("Apple beats Q3 earnings, iPhone revenue up 8% YoY", "AAPL"),
        ("FTC opens antitrust probe into Google's ad business", "GOOGL"),
        ("Microsoft announces routine board meeting next Tuesday", "MSFT"),
    ]
    for headline, ticker in headlines:
        result = classify_sentiment(headline, ticker)
        # Print the label plus the distribution. The distribution is the part
        # you don't get from a regex or a single-token LLM response.
        print(f"{ticker}: {result['label']} ({result['confidence']:.2f})")
        print(f"  distribution = {result['distribution']}")
        

The interesting output is not the label. It is the distribution. If Jev says bullish: 0.45, bearish: 0.20, neutral: 0.35, your downstream code can decide to skip the headline (low max), treat it as bullish with a flag (bullish beats neutral but barely), or send it to a human for review. A regex returns "bullish" or None and tells you nothing about how close the call was. That is the practical difference between a decision primitive and a string matcher.

Example 2. Title reranking for SEO

Suppose you have generated five candidate titles for a blog post with an LLM, and you need to pick the best one. The naive solution is "use the first one". The medium solution is "use the last one because the model warmup biased it". The Jev solution is a ​choice​ primitive that scores all five against your criteria.

# example-2-title-rerank.py
"""
Pick the best of N candidate titles using a Jev choice primitive.

Run:
    export TYPESAFE_API_KEY=apikey_...
    python3 example-2-title-rerank.py
"""

import json
import os
import urllib.request

API_URL = "https://api.typesafe.ai/v1/systemone"
API_KEY = os.environ["TYPESAFE_API_KEY"]


def rerank_titles(topic: str, candidates: list[str]) -> dict:
    """Return the best title plus Jev's full distribution over the candidates."""
    state = {"topic": topic, "candidates": candidates}

    questions = [
        {
            "primitive": "choice",
            "name": "best_title",
            "question": (
                "Which title will get the highest click-through rate for a "
                "senior software engineer reading a tech blog post on "
                f"`{topic}`? Prefer titles with: a concrete number or named "
                "technology, a hint of conflict or contrarian framing, and a "
                "promise of something the reader does not already know. Penalise "
                "clickbait, vague promises, and titles longer than 70 characters."
            ),
            "context": state,
            "choices": candidates,
        }
    ]

    payload = json.dumps({"state": state, "questions": questions}).encode()
    req = urllib.request.Request(
        API_URL,
        data=payload,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
    )
    with urllib.request.urlopen(req) as resp:
        answer = json.loads(resp.read())["answers"][0]

    return {
        "best": answer["value"],
        "confidence": answer["confidence"],
        # The full distribution lets you log the runner-ups for A/B comparison.
        "distribution": answer["distribution"],
    }


if __name__ == "__main__":
    topic = "TypeSafe AI Jev for engineering decisions"
    titles = [
        "TypeSafe Jev: A New AI Model for Engineers",
        "Jev vs LLM: When to Use a Probabilistic Primitive",
        "How I Replaced 200 Lines of Decision Code Using Jev",
        "An Introduction to TypeSafe's System One Model",
        "Why Your Agent Loop Needs a Decision Layer",
    ]

    result = rerank_titles(topic, titles)
    print(f"Best: {result['best']}")
    print(f"Confidence: {result['confidence']:.2f}")
    print("Full distribution:")
    for title, prob in sorted(result["distribution"].items(), key=lambda kv: -kv[1]):
        print(f"  {prob:.2f}  {title}")

This is a general example. Anywhere you have a small fixed candidate set and you need to pick one, Jev is the right tool. The four canonical cases: SEO titles, A/B test variants, error message wording, and which of three retry strategies to use.

Example 3. Content safety as a post-generation gate

LLMs are unpredictable in production. The third example is the one that gets product managers to fund your Jev budget: put Jev between the LLM and the user as a safety gate. The LLM generates. Jev scores the output. You branch on the score. The whole thing is ~80 lines.

# code-examples/example-3-content-safety.py
"""
Score an LLM-generated string as safe / risky / unsafe before publishing.

Run:
    export TYPESAFE_API_KEY=apikey_...
    python3 example-3-content-safety.py
"""

import json
import os
import urllib.request

API_URL = "https://api.typesafe.ai/v1/systemone"
API_KEY = os.environ["TYPESAFE_API_KEY"]


def score_safety(text: str, context: str) -> dict:
    """Return Jev's safety level plus the full distribution."""
    state = {"text": text, "context": context}

    questions = [
        {
            "primitive": "score",
            "name": "safety",
            "question": (
                "Rate the safety of the assistant's reply for a public blog "
                "comment section. Consider: (1) is the text toxic, harassing, "
                "or hateful toward any protected group? (2) does it include "
                "private data, PII, or internal company info? (3) does it "
                "contain actionable instructions that could cause real-world "
                "harm? Answer 'unsafe' if any of those are clearly present, "
                "'risky' if borderline, and 'safe' otherwise."
            ),
            "context": state,
            "levels": ["safe", "risky", "unsafe"],
        }
    ]

    payload = json.dumps({"state": state, "questions": questions}).encode()
    req = urllib.request.Request(
        API_URL,
        data=payload,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
    )
    with urllib.request.urlopen(req) as resp:
        answer = json.loads(resp.read())["answers"][0]

    return {
        "level": answer["value"],
        "confidence": answer["confidence"],
        "distribution": answer["distribution"],
    }


def publish_or_block(text: str, context: str = "blog comment moderation") -> str:
    """Branch on the safety score. The gate is the whole point."""
    result = score_safety(text, context)
    level, conf = result["level"], result["confidence"]

    # The gate logic. The thresholds are not magic — they encode your product
    # policy: high confidence on safe = publish, high confidence on unsafe =
    # block, anything else = queue for a human.
    if level == "unsafe" and conf > 0.7:
        return "BLOCK"
    if level == "risky" and conf > 0.5:
        return "QUEUE_FOR_HUMAN"
    if level == "safe" and conf > 0.6:
        return "PUBLISH"
    return "QUEUE_FOR_HUMAN"


if __name__ == "__main__":
    samples = [
        "Great post, the section on Jev primitives really clicked for me.",
        "You are an absolute moron if you believe this works.",
        "Here is my home address: 1234 Main St, email me at jane@example.com",
    ]
    for sample in samples:
        decision = publish_or_block(sample)
        print(f"[{decision}] {sample[:60]}...")

Please notice : the LLM does what it is good at (generating text), Jev does what it is good at (scoring it against a rubric), and Python does what it is good at (branching on the result).

Three responsibilities, three tools. The gate is the cheap part of the call (a few hundred tokens) and the part that most directly protects your users.

Example 4. User intent routing

The fourth example is the one that replaces the giant regex pile in your routing layer. You get a user query; you have N agents or N tools; you need to send the query to the right one. The LLM way is a chain-of-thought prompt that ends in a JSON {"intent": "..."}. The Jev way is one choice primitive.

# code-examples/example-4-user-intent.py
"""
Route a user query to the right downstream tool using Jev.

Run:
    export TYPESAFE_API_KEY=apikey_...
    python3 example-4-user-intent.py
"""

import json
import os
import urllib.request

API_URL = "https://api.typesafe.ai/v1/systemone"
API_KEY = os.environ["TYPESAFE_API_KEY"]


# The fixed candidate set. Jev will pick exactly one.
INTENTS = [
    "search_docs",      # user wants to find docs / FAQ
    "run_command",      # user wants to execute a CLI / tool
    "summarize",        # user wants a summary of something
    "translate",        # user wants translation
    "billing_question", # user has an account / billing question
]


def route_query(query: str) -> dict:
    """Return the chosen intent plus Jev's confidence and distribution."""
    state = {"query": query}

    questions = [
        {
            "primitive": "choice",
            "name": "intent",
            "question": (
                "Classify the user's intent into one of the predefined "
                "categories. Choose `run_command` only if the query clearly "
                "asks for an action to be performed (open, close, run, "
                "execute, delete, restart). Choose `summarize` only if the "
                "user explicitly asks for a summary. Choose `translate` only "
                "if the user asks to convert text between languages. Choose "
                "`billing_question` only if the user asks about account, "
                "subscription, payment, or invoice. Otherwise choose "
                "`search_docs`."
            ),
            "context": state,
            "choices": INTENTS,
        }
    ]

    payload = json.dumps({"state": state, "questions": questions}).encode()
    req = urllib.request.Request(
        API_URL,
        data=payload,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
    )
    with urllib.request.urlopen(req) as resp:
        answer = json.loads(resp.read())["answers"][0]

    return {
        "intent": answer["value"],
        "confidence": answer["confidence"],
        "distribution": answer["distribution"],
    }


def handle(query: str) -> None:
    """Wire Jev's answer to your actual tools."""
    result = route_query(query)
    intent, conf = result["intent"], result["confidence"]

    # The router's contract: high confidence = dispatch, low confidence =
    # ask the user to clarify. The threshold is your product decision.
    if conf < 0.5:
        print(f"  -> CLARIFY (low confidence {conf:.2f}): {query}")
        return

    if intent == "search_docs":
        print(f"  -> docs_search({query!r})")
    elif intent == "run_command":
        print(f"  -> dispatch_command({query!r})")
    elif intent == "summarize":
        print(f"  -> summarizer({query!r})")
    elif intent == "translate":
        print(f"  -> translator({query!r})")
    elif intent == "billing_question":
        print(f"  -> billing_support({query!r})")


if __name__ == "__main__":
    queries = [
        "How do I rotate my API key?",
        "Restart the production server now",
        "TL;DR the Q3 earnings call transcript",
        "Traduci questo in italiano per favore",
        "Why was I billed twice this month?",
        "asdfghjkl",
    ]
    for q in queries:
        print(f"\nQuery: {q}")
        handle(q)

The essence of this example is that "a router is a typed function." The router is no longer with 200 lines of edge cases with regex. It's just a Jev call with a clear candidate set and a confidence threshold.

The Low-confidence queries get sent to a clarification flow; and the high-confidence queries get dispatched. The whole router is debuggable: you can log the distribution and see exactly which intent almost won, which makes your edge cases obvious.

6. When to use Jev and when not to use it

As the above 4 examples, the rules are simple now. We can use Jev when:

  • The output is branched on by code, not read as prose.
  • You have a fixed candidate set or a boolean / score rubric.
  • You want a calibrated confidence to gate downstream actions.
  • The decision is frequent enough that a hand-tuned function has been drifting for months.

Do not use Jev when:

  • You need to generate prose (use an LLM).
  • The decision requires multi-turn reasoning or tool use (use an LLM agent).
  • The decision is a pure function of structured inputs that you can write in Python (write the PythonJev is for the cases where the Python gets ugly).
  • You have a latency budget under 100 ms (Jev is 200-800 ms; if you need 10 ms, the answer is a small classifier).

There is also a meta-rule about combining them:

Use an LLM for the outer loop (interpret the user, call tools, synthesize the answer) and Jev for the inner loop (classify, rerank, gate, route). The two are not competitors. They are different layers.

7. The threshold trap

One thing that will save you a day of debugging: the right confidence threshold is not 0.5. I learned this the hard way running Jev against a corpus of 66 short paragraphs. With a 0.6 threshold, every paragraph was flagged for review. With 0.4, the right paragraphs were flagged and the noise dropped. The catch is that different tasks have different confidence profiles:

  • For noul yes/no on factual questions, Jev tends to be confident when right. A 0.6 threshold is usually fine.
  • For choice reranking between similar options, Jev is often unsure. You need a 0.4 threshold or you will reject everything.
  • For score safety rubrics, the levels are often close in probability. You need to look at the distribution, not just the confidence.

The practical rule: start at 0.4, log the distribution, and tune from there. Do not start at 0.5 because it "feels symmetric". The model is calibrated, not symmetric.

8. Cost and latency in practice

Numbers from production runs in late 2026, on a small agent pipeline:

  • Single noul call: ~200 input tokens + ~50 output tokens, ~300 ms.
  • Single choice call with 5 candidates: ~400 input + ~80 output, ~400 ms.
  • Bundled call with 4 questions: ~1,200 input + ~300 output, ~600 ms (parallel).
  • Cost: roughly $0.0001 per call for typical prompts. The expensive part is your prompt, not the model.

The bundle-multiple-questions trick is the single biggest cost optimisation. If your agent makes 5 sequential Jev calls, bundle them into one POST and you cut latency by ~5× and cost by ~12×. This is why all four examples in this article look the same shape: that shape is the bundled call, and you should default to it.

9. Conclusion

If you take only one idea from this article, take this: the next time you write a regex to decide between two strings, or a hand-tuned threshold to gate an LLM output, ask whether Jev would do the job. The answer is yes more often than you think. You can try more examples with Jev below:

Difficulty estimation, regression test selection, prompt-template selection, retrieval-query rewriting, anything where the input is structured and the output is a typed decision.

Jev is not a replacement for your LLM. It is the layer you have been writing in Python and wishing was smarter. Wire it in. You will get a smaller codebase, a more honest system, and a team that trusts the decisions their agents are making.

Winson Yau

Engineer, writer, and founder of CoderBlog. Building tools and writing about the craft of software from Hong Kong.

Comments

Discuss the article below. Markdown is supported. Sign in with email or GitHub to leave a comment.