Lesson 03 · Jev 101
Writing questions: Choice, Score, Noul
The 101 skill is writing questions your code can act on. This page restates TypeSafe’s primitives, State, and how-to-build docs. It is not a substitute for the official pages.
Official sources:Primitives · Choice · Score · Noul · State · How to build.
Ask for one snap judgment
Official primitives page: System One is built for a judgment a knowledgeable person makes in a second, given the right context. “Does this message convey urgency?” is a good question. “Analyze this message and determine the best course of action” is not — that needs slow reasoning, so break it up and compose in code.
Official how-to-build: “This is probably the most important concept in this guide.” Broad questions hide several judgments. Atomic questions expose them so code can inspect, tune, and combine.
One broad question
Hide several judgments
Analyze this message and determine the best course of action.
Atomic questions
Expose each one
Does this message convey urgency? What is the main request? How frustrated does the customer appear?
Every question has four parts
ID
A key for your code, such as refund_requested. Official: the model never sees the ID. Write the full question in instructions even if the ID sounds obvious.
type
choice, score, or noul. Pick the shape your code can act on: Choice → a branch, Score → a threshold or rank, Noul → an if.
instructions
The question about the state. Official: a snap judgment a knowledgeable person makes in a second. A string is enough for most. Object or array when you need extra fields — see Advanced: structure.
criteria
Choice: a map of option → description (names and descriptions both go to the model). Score: an ordered list of level descriptions. Noul: optional true / false clarifications.
Pick the type your code can act on
| Type | Answers | Returns | When |
|---|---|---|---|
| Choice | Which of these options? | choice, probabilities, confidence | One of a known set with no order: department, document type, language. |
| Score | Which level? | score, legend, probabilities, confidence | A spectrum you can describe: severity, frustration, skill, relevance. |
| Noul | Is this true? | noul (0 to 1) | A clean yes/no where the probability itself is the signal: PII present? refund asked? |
Prefer Choice when…
The answer is one of a known set and the options are not ordered. Official example shape: refund / rebook / information. Add other when the set might be incomplete.
Prefer Score when…
You can describe what each point on a spectrum means. Official warning: “Is this candidate strong in Python?” is a bad Noul — 0.5 is not medium skill. Use a Score with levels such as no experience / some familiarity / daily use / deep expertise.
Prefer Noul when…
Yes/no is the whole decision and you will threshold P(yes). Official: use 0.5 when both errors are cheap; raise it when a false yes is expensive (page someone, issue a refund); lower it when missing a true yes is expensive (safety).
Choice
Give the full list. Official Choice page: up to 255 options, and adding one costs a few tokens. Add other or none of the above when the list might miss an input.
Score
Levels are an ordered list: at least two, API accepts up to 10. The score can land between two levels — it is a probability-weighted mean of the level numbers, not a count of customers.
Noul
Near 1 is a strong yes; near 0 a strong no; near 0.5 is uncertain. Official docs: no separate confidence field. 0.5 is not “medium skill.”
State first: string, object, or array
Official State page: state is the content you evaluate — a support message, a passage, or application state. All questions in a request see the same state and run independently. Text only; no image, audio, or video yet. English is primary.
| Format | Useful for | Example |
|---|---|---|
| String | One message, article, or passage | "My card was charged twice." |
| Object | Named fields, related records, application state — official default for most requests | { ticket, order, refund_policy } |
| Array | A sequence of messages or records | ["Hi", "My customer number is TS1337.", "My card was charged twice."] |
Official State page: one object can hold a conversation, an order, and a policy. Point questions at fields with a backticked dot-and-index path.
Does `ticket.messages[0].text` request a refund?Does `refund_policy` support the refund requested in `ticket.messages[0].text`, given `order.charges`?
Keep content in state and judgments in questions. Filter first — official name: context rot. Do not rely on model weights when your knowledge base has the current fact.
Official Python questions.md: state cannot be None, but values inside an object may be. You can mix question objects (Noul / Choice / Score) and dictionaries that carry a type key in the same request.
Writing Score levels
Official Score page, beginner wording. The score is a position on your levels and can sit between two of them. Different distributions can produce the same score — read probabilities andconfidence with it. Confidence 1.0 means all probability sat on one level; it is not a guarantee the answer is correct. Use the score to rank or threshold — not to reconstruct “40% of the way from frustrated to angry.” Official: it does not measure a fraction of customers.
- Describe situations, not degrees. “Broken, but a workaround exists” beats “moderately severe.”
- Every level is evaluated separately. The model does not see a level’s number or its neighbours — “worse than the previous level” means nothing.
- Numbers-only levels fail. Official demo: “Rate 0 to 2” with criteria ["0","1","2"] split probability; the same report with descriptive levels scored 0.0 at confidence 1.0.
- One dimension per Score. “Punctual and smart and experienced” is three questions hiding in one.
- Use as many levels as you can describe distinctly, up to 10. Three is fine. Don’t invent levels you can’t describe.
- Give rare extremes their own level if you must act differently (e.g. “abusive or threatening” vs “very angry”).
Writing a Noul
- Make the yes/no boundary unambiguous. Official: “Does this candidate have any Python experience?” works because “any” leaves no middle.
- When the boundary is subtle, add criteria.true and criteria.false. Try with and without; keep whichever is better on your documents.
- Do not treat a Noul as a Score. Official primitives page: a Noul of 0.5 means equal probability of yes and no — not a medium rating.
- Noul and a yes/no Choice on the same idea are different numbers. Do not copy a threshold from one to the other (official jaggedness).
When a string is not enough
OfficialAdvanced: structure: instructions and criteria are an EntryType — string, object, array, or null. Start with a string. Add JSON when the question has parts, or when the data is already an object.
| Field | Applies to | Accepted shape |
|---|---|---|
instructions | Choice, Score, Noul | string, object, array, or null |
criteria values (options) | Choice | string, object, array, or null |
criteria entries (levels) | Score | string, object, array, or null |
criteria.true / criteria.false | Noul | string, object, array, or null |
- Clarity: a question with several parts is easier to read when the keys are labeled.
- Supporting data: a schema, taxonomy, or database row is already JSON — pass the object instead of stuffing it into a string template.
- Loops: build one structured question per field or record in code, send them in one call (official SDE cascade does this).
Official API example: put a database row in one field and the question in another, then point at the row with backticks — same path style as state.
{
"instructions": {
"potential_duplicate": {
"name": "John Smith",
"location": "Oakland, California",
"last_employer": "Google"
},
"question": "Is the resume for the same person as `potential_duplicate`?"
}
}Choice options can be objects that say what an option covers, what it does not, and a few examples. Use the same field names on every option. Score levels can be objects too. For a deep taxonomy, walk one Choice per level in code — official hierarchical classification cookbook, including beam search when probabilities are close. Trim huge subtrees to direct children plus a sample of leaves.
Ask many questions in one call
Official: every question sees the same state, is evaluated independently, and returns a typed answer under the ID you chose. Adding questions barely changes response time and costs only the extra question tokens. Ask speculative ones and ignore them in code — that is fan-out, not waste.
Questions in one request are independent. Make a second request only when code cannot build it until it has the first answer: fetch more data, decide what the state is made of, or pick the next options. Official examples: skill suggestion (rank, then re-read top three), structure recovery (merge lines, then classify blocks), hierarchical classification (each Choice narrows the next options).
Official how-to-build: keep deterministic work in code (days overdue is a date subtraction, not a Jev question). Combine answers with weights you own, or feed probabilities into a classical model. Two requests are the exception.
Conceptual only · pin the official SDK
# One state, three question types — official primitives shape
state = { ticket_message, refund_policy }
refund_requested: Noul("Does `ticket_message` request a refund?")
request_type: Choice(refund | rebooking | information)
frustration: Score([calm, concerned, very angry])
# Then ordinary code:
if refund_requested.noul > 0.85 and request_type.choice == "refund":
start_refund()