Part 8 of 12 · Connect the judgments

Build a workflow from small decisions

Follow a return request through five design choices: ask together, rank, review, select a source value, and batch. Each lab shows what changes when you move one of those choices into code.

The store, customers, and lab results are fictional. Cost estimates use a dated model-price snapshot; timings are adjustable assumptions.

Draw the decisions before the calls

Sketch the application before choosing a pattern. For a return request, code knows the order date and return window. The message supplies less tidy evidence: whether the customer wants a replacement, whether an item is damaged, and which order they mean.

Mark where interpretation is required. Then ask whether those judgments share their evidence, whether they need different evidence, and what the application should do with an uncertain result. The sections below work through those choices.

Speculative fan-out

A customer says “A replacement would be great; otherwise I’d like a refund.” You can ask about the requested remedy and the details of each remedy using the same message and order.

Write each conditional question with its premise included: “If the customer wants a replacement, which item are they referring to?” The request does not pass the returned route answer into the other question. Keep the premise explicit even on a joint schema model.

After the answers arrive, code selects a route and uses that route’s follow-ups. Questions for other routes may be irrelevant; their uncertainty should not block the chosen path.

This can save a repeated copy of the state and a network trip. It also asks questions that may go unused. Compare those costs for your request sizes instead of treating extra questions as free.

Lab

One request, four branches, code reads one

A return request with a route question and two follow-ups per branch. Click a branch to see which answers the code consumes. Answers and token counts are illustrative; tokens are estimated at four characters each.
State sent with the request
All nine questions in the request
Route answer Choice

Illustrative confidence 0.62. Two plausible readings of "replacement, otherwise refund" keep some mass on refund.

Branch answers (click to explore)
What the code does on this route
The request includes every branch, even though code reads one. Whether this saves tokens depends on state size and the number of unused questions. The estimate uses four characters per token; real usage will differ.

Composite scoring

You have six returns to review and only time for two. The order may depend on evidence quality, policy fit, account risk, and handling effort. Store each judgment separately so those priorities remain adjustable.

A single overall score is enough when you only need that one judgment. Use separate dimensions when you need to explain or change how the ranking is assembled.

Normalize the scales, choose weights, and sort in code. A weighted sum allows one strong factor to compensate for a weak one. Apply mandatory eligibility checks separately so a good score cannot cancel a disqualifying condition.

composite = Σi wi · vi / Σi wi, where vi = scorei / (levelsi − 1), or 1 − that when higher is worse
Lab

Re-rank six return requests without a new request

Four Score dimensions per request, each on four levels (0 to 3). Move the weights and watch the order change. Scores are illustrative expected values.
Weights

Evidence quality and policy fit count up. Account risk and cost to serve count down, so they are inverted before weighting.

Ranking by composite (0 to 1)
RequestEvidencePolicy fitAcct. riskCost to serve
Each dimension's score is the model's expected level. The re-ranking above is pure arithmetic on stored answers; changing a weight or a preset never calls the API. That is the point of keeping judgments raw and policy in code.

Confidence-gated cascade

Some returns can be routed from the first message. Others need an attachment, a follow-up, or a reviewer. A cascade gives those unresolved cases a next destination.

Keep the first stage small. Send cases that fail its tested acceptance rule to a stage with useful additional evidence or capability. Calling a larger model with the same missing facts may not resolve the problem.

Count the cost and delay of every stage reached. The lab assumes each stage resolves a chosen share of the cases it receives. The shares are inputs, not predictions.

Lab

Cost and coverage of a three-stage cascade

Set what each stage costs and how much of what reaches it the stage resolves. Outputs are per 1,000 return requests. All defaults are illustrative.

Stage 1 · System One fast

Stage 2 · Generative model slow

Stage 3 · Person queue

100% of what arrives

Select, do not generate

The customer mentions two order numbers but wants to return only one. A parser can find both numbers; interpreting which one the customer means is a different task.

Collect candidate values in code, offer them as Choice options, and keep an option for no match. Once a candidate is selected, use the original value rather than asking a model to reproduce it.

Test candidate collection before testing selection. A missing candidate cannot win. Even a correct selection still needs authorization before you change the associated order.

import re
from typesafe_sdk import Choice, TypeSafeClient

message = "Returning the jacket from order R-20931. My other order R-20877 is fine."
candidates = re.findall(r"\bR-\d{5}\b", message)          # ["R-20931", "R-20877"]

criteria = dict.fromkeys(candidates)               # every candidate, no description
criteria["none"] = "No order number in the message is the one being returned"

with TypeSafeClient() as client:
    r = client.system_one(
        state={"message": message},
        questions={"which": Choice(
            instructions="Which order number does the customer want to return?",
            criteria=criteria,
        )},
    )

picked = r.choices["which"]
order_id = None if picked.choice == "none" else picked.choice  # copied, never retyped

For a large catalogue, you can narrow candidates in stages. Keep alternatives when an early branch is uncertain, and measure whether the extra paths improve your final selections.

Reuse the evidence within a request

Suppose a return message needs six independent checks. Six separate calls repeat the message six times. Jev and Kev can include all six checks over a shared state prefix. Clef scores a joint schema; Laya forms per-question encoder rows. One HTTP call does not guarantee identical compute or isolation across implementations.

Split when a later request needs newly fetched evidence, a different state, or room beyond the current request budget. For latency, distinguish sequential calls from concurrent calls: parallel network requests can finish sooner, but still repeat the input.

Lab

N questions in one request versus N single-question requests

Change the sizes and see the token, cost, and latency gap. This Jev-specific cost sketch uses the documented price of $0.042 per million input tokens with free output tokens. Jev 1.14 price checked October 15, 2026. This estimate covers text, not image tokens or long-context latency. Round-trip time is adjustable and illustrative.
Your numbers
One requestN requestsRatio
Where the saving comes from

Each teal block represents another copy of the same state. Batching removes those repeated copies. Questions still contribute their own tokens.

The N-request column assumes sequential calls for latency. Concurrent calls bring latency back to about one round trip, but every call still carries the full state, so the token multiplier stays.

Many questions and many items are different experiments

The lab above adds questions to one unchanged state. Packing many customer messages into that state changes the evidence every question sees. Test that growth separately from question count; fitting the context budget does not establish reference accuracy.

Numeric reference
{
  "state": {"messages": ["First return…", "Second return…"]},
  "questions": {"route_1": {
    "type": "choice",
    "instructions": "Which queue fits `messages[1]`?",
    "criteria": {"returns": "Returning an item", "other": "No fit"}
  }}
}
Named reference
{
  "state": {"messages": {"case_a": "First return…", "case_b": "Second return…"}},
  "questions": {"route_b": {
    "type": "choice",
    "instructions": "Which queue fits `messages.case_b`?",
    "criteria": {"returns": "Returning an item", "other": "No fit"}
  }}
}

These are request excerpts; add a model to send them. IDs such as route_b match answers for code and are not visible to the model. Put the complete item reference in the instructions.

Numeric paths are documented and useful, but the model still has to resolve them. Our long-array experiments favoured named or quoted items; the 48-item results are a reason to compare forms on your own workload. Quoting duplicates text in the questions. Naming adds keys. Neither form guarantees isolation from adversarial content.

  1. Compare your single-item request with the batch template at size one.
  2. Sweep larger sizes on tuning data, keeping wording and reference form fixed.
  3. Rotate item positions and composition; inspect errors by position and class, as well as failures.
  4. Measure the time until the complete batch returns. Dividing it by item count gives amortized time, not each customer’s wait.

Shared definitions save repetition but change the question

A store taxonomy can live once in state, with each question pointing to it. The model must then resolve an extra reference. Compare that wording against inline criteria before treating token savings as an improvement.

Our shared-definition follow-up saved input tokens at eight items, while shifting an urgency Noul’s probabilities and changing errors differently at two cutoffs. At one item, indirection can cost more. Re-evaluate the exact shared form and select its thresholds afresh; the study notes give the observed scope.

Choose fan-out versus route-then-ask using full workflow measurements. Unused branch questions consume tokens; staged calls can avoid them while resending state and adding a sequential wait. Use a later call when a first answer is needed to retrieve evidence or construct candidates.

Choosing a pattern

You need toPatternPrimitivesThe code's job
Route, then act differently per routeFan-outChoice + branch questionsRead one branch
Rank items on several factorsCompositeScore per dimensionNormalize, weight, sort
Act automatically only when safeCascadeAny, plus its probabilitiesThreshold, escalate, account
Pull an exact value from textSelectChoice over candidatesFind candidates, copy verbatim
Answer many things about one documentBatchAny mixPack compatible questions; validate item references

These compose. A real return-handling flow is a fan-out request whose branch answers feed a composite priority, gated by a cascade for the ambiguous cases, with order numbers pulled by selection. Next, evaluate the frame and action policy, then use the build guide to connect them to software.