Part 6 of 9 · 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 question cannot see the route answer beside it.

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. One call can include all six checks and pay the state cost once.

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. Cost uses the documented price of $0.042 per million input tokens with free output tokens. 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.

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, split only when forced

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. The next part builds one end to end.