Decision Tier

Level 2 201 · for practitioners

Asking well, using answers

A decision model's answers are only as good as the questions. And once you have answers, how you combine them matters as much as the model. This page collects what held up across several months of a real inbox, graded blind against labeled concepts.

How the evidence was gathered

Each concept ("someone is waiting on a reply", "a payment failed") got hand-made labels, blind to any model score. Every question phrasing was graded with AUC against its own concept. AUC is the chance that a random true example scores above a random false one: 0.5 is a coin flip, 1.0 is perfect ranking.

What a decision model judged well

ConceptBest question shapeAUC (hosted Jev)
An action with a deadlineContrastive Choice: deadline / event / offer / informational / none0.980
A payment failed or a service is endingContrastive Choice (an exact Noul was nearly as good, 0.993)0.997
Someone is waiting on a replyContrastive Choice0.986
An unexpected future chargeSurprise framing0.96
Same matter as an open recordNoul on the pair0.980
The new message resolves the open recordNoul on the pair0.933

Nine rules for phrasing

  1. Prefer a Choice whose options name the near misses. It was the best single question on every concept tested. "Deadline / event / offer / informational / none" works because each wrong answer has somewhere to go. Describe none well: with a vague none, accuracy on true negatives was 50%.
  2. Exact Nouls are the best calibrated. One exact payment Noul had 88% precision at 0.5. Use them where a threshold has to mean something.
  3. Abstract wording ranks but over-fires. "Involves a deadline" averaged 0.31 on negatives. It fails outright when the abstraction changes the concept: "personal" isn't "someone is waiting" (0.744).
  4. Consequence and surprise framing depends on the concept. It won for hidden charges and waiting-on-reply, and lost for deadlines and payment failures. Test it; don't assume.
  5. Don't decompose a concept the model already grasps. Surface-fact sub-questions lost by 0.03–0.08 AUC. Decomposition fits conjunctions of checkable facts, such as spam signals.
  6. Grade every question against its own concept first. One question looked like chance against the target label but scored 0.89 against its own concept. It was a good question pointed at the wrong target.
  7. Plain propositions beat custom true/false criteria. Custom criteria made one Noul fire at about 0.9 on noise and another read about 0 on invitations.
  8. Batching is free. Send every question in one request with the shared state once. On a local model with a shared-prefix cache, six questions over about 10k tokens took 4.8 s instead of 16.9 s.
  9. Phrasing doesn't transfer between models. Framings tuned on hosted Jev fell by up to 0.20 AUC on another model. Re-grade any phrasing ladder per model.

A worked example

Here's the shape of the contrastive Choice that won on deadlines. The near misses (an event, an offer) are named so that "there's a date in it" doesn't pull everything toward deadline:

"deadline_kind": {
  "type": "choice",
  "instructions": "What does this message ask of the reader, if anything, with respect to time?",
  "criteria": {
    "deadline":      "The reader must do something by a stated date or time, or lose something.",
    "event":         "A scheduled happening the reader may attend; nothing is lost by not acting.",
    "offer":         "A promotion or sale that expires; ignoring it costs nothing.",
    "informational": "Dates appear, but nothing is asked of the reader.",
    "none":          "No date, time or time pressure is involved at all."
  }
}

What it can't do, so code must

Using answers: features, not judges

The tempting design is to set a hand-picked threshold on each answer. The better design feeds every answer, plus the rule facts code already knows, into a small learned combiner (gradient-boosted trees). Same safety, about twice the filtering:

SetupMail filtered with zero LLM tokensMissed actions
Frozen hand thresholds29%0
Local model, learned combiner (leave-one-month-out)47%0
Hosted model, learned combiner (leave-one-month-out)58%1

The same held on an unrelated public dataset. On TypeSafe's wine-review cookbook, 38 questions combined by a model predicted critic scores with an error of 1.75 points, against 2.20 for asking the score directly. And a small local model nearly matched hosted Jev when many questions were combined (+5% error), while trailing badly as a single judge (+23%).

One answer is a judge. Thirty-eight answers are features. Features are more forgiving of a weaker model.

Gates, facts and rules

As a gate, modestly

Escalating a filed message whenever any concept Choice had P ≥ 0.5 caught 1 of 2 filed actions, at a cost of 2.8 points of filtering. Useful, not magic.

Facts beat more questions for the remaining misses

Rules are facts, not overrides

In the email pipeline, rules ran in parallel with the model and contributed facts. Only bad input and embedded instructions (prompt injection) could force a review. Other rules could only keep mail out of the zero-token buckets, and the model's category never suppressed mail on its own. An earlier "not bulk-looking" override saved zero important messages over three evaluation sets and cost filtering.

Thresholds belong to a (model, rubric) pair

A number like 0.62 means nothing on its own. It means something for one model, one runtime and one set of questions. Changing any of them means refitting:

In an agent loop

Next: 301 is the engineering: honest evaluation, drift, adapters across vendors and running it in production.