damngoodprompts

Decisioning models and Jev

How non-generative decision engines evaluate state against typed questions, scores, and guardrails without text generation overhead.

Last reviewed: October 22, 2026

The concept

A decisioning model is a specialized AI engine built for discrete evaluation rather than text generation. Systems like TypeSafe Jev (System One), OpenAI’s Decisions API, and Perplexity’s Decisions API split work cleanly between generation and choice.

In an agentic architecture, responsibilities divide into three distinct layers:

LLM (System Two)    ->  Research, planning, writing, code generation
Decisioning (System One) -> Routing, scoring, approval, guardrails
Application code     ->  Deterministic execution and validation

Generative models excel at synthesis, explanation, and code writing. They are slower and costlier when asked to make repetitive classification choices, and forcing them to return JSON strings introduces parsing overhead and syntax drift. A decisioning model does not write prose, does not generate code, and does not provide conversational explanations. It reads a provided state payload, evaluates a set of typed questions in a single forward pass, and returns typed values with mathematical probability scores in milliseconds.

The current approach

Use a decisioning model when an application needs repeated, constrained choices from a closed list, numeric evaluation against a rubric, or verification of an assertion against evidence.

Decisioning engines rely on three core primitives:

  • Choice: Select one option from a closed set of options based on explicit criteria. Returns the selected choice, the probability distribution across all options, and an overall confidence score.
  • Score: Grade evidence against an ordered scale (such as urgency, quality, or risk). Returns the numeric level, rubric legend, and confidence.
  • Boolean assertion (Noul): Evaluate whether a factual statement holds true against the state. Returns a continuous probability value between 0 and 1, representing degree of belief.

Prompting a decisioning engine differs from prompting a chat model:

  1. Batch questions across shared state: Pass the context or document once and ask all relevant routing, severity, and verification questions in parallel. Calling the API once per question wastes latency and network overhead.
  2. Send concrete evidence, not subjective summaries: Do not pass phrases like “the agent finished research.” Pass the actual file diff, command output, or ticket body. The model needs raw facts to evaluate criteria accurately.
  3. Prune inactive choices dynamically: Supply only the options that are possible at the current execution step. Passing impossible choices siphons probability mass and artificially suppresses confidence scores.
  4. Bypass the model when only one choice remains: If only one option is valid, resolve it in code without an API call.
  5. Calibrate confidence thresholds by blast radius: Destructive or costly actions (deleting data, sending customer emails, modifying billing) require high confidence thresholds (such as 0.90 or higher). Low-risk routing can run at lower thresholds (such as 0.65).

Examples

API request evaluating routing, urgency, and automated resolution in a single pass:

{
  "model": "jev-latest",
  "state": "Customer ticket #4102:\nI was double-charged on invoice INV-8891 for my Pro subscription renewal yesterday. Please refund the duplicate $50 charge immediately.",
  "questions": {
    "team": {
      "type": "choice",
      "instructions": "Which department handles this ticket?",
      "criteria": {
        "billing": "Invoices, charges, refunds, subscription payments",
        "technical": "Software bugs, API outages, integration errors",
        "sales": "Custom enterprise quotes and plan upgrades"
      }
    },
    "urgency": {
      "type": "score",
      "instructions": "Rate customer financial urgency",
      "criteria": [
        "1: Routine inquiry with no active disruption",
        "2: Billing question without imminent service loss",
        "3: Incorrect charge or duplicate billing requiring prompt refund",
        "4: Critical account lock or disputed enterprise wire"
      ]
    },
    "eligible_for_auto_refund": {
      "type": "noul",
      "instructions": "The customer provides an explicit invoice ID and requests refund of a duplicate charge"
    }
  }
}

Handling the response in application code:

interface DecisionResponse {
  team: { choice: string; confidence: number };
  urgency: { score: number; confidence: number };
  eligible_for_auto_refund: { noul: number };
}

function handleTicket(decision: DecisionResponse) {
  // Derive certainty for noul: 0.5 is maximum uncertainty
  const refundCertainty = Math.abs(decision.eligible_for_auto_refund.noul - 0.5) * 2;
  const isEligible = decision.eligible_for_auto_refund.noul > 0.8 && refundCertainty > 0.6;

  if (isEligible && decision.team.choice === 'billing') {
    queueAutomatedRefundAudit();
    return;
  }

  routeToHumanQueue({
    department: decision.team.choice,
    priority: decision.urgency.score >= 3 ? 'high' : 'normal'
  });
}

What to avoid

  • Asking a decisioning model to draft text, summarize documents, or write code.
  • Calling the model once per question instead of batching questions over a single state payload.
  • Sending vague status labels instead of the underlying text, diffs, or error logs.
  • Using a single static confidence threshold across all application actions regardless of risk.
  • Treating high confidence as a substitute for deterministic unit tests and code-level schema validation.

Source set