Skip to content

Questions EN

sungaowei edited this page Oct 16, 2026 · 1 revision

Questions

English | 简体中文


Four question kinds are supported: Noul (yes/no), Choice (categorical), Score (ordinal rubric), and Box (bounding box object localization).

All accept instructions — what the model should decide or find — as a string, a JSON object, or an array, and all are answered with a calibrated probability distribution or bounding box coordinates you can threshold yourself.

Questions travel as a map (typesafe.Questions) because the names are yours to choose: they are the keys you read the answers back with, so they cannot be struct fields. The map's values are typed as typesafe.Question, which means a value that is not a question fails to compile. For a question shape this version does not model, wrap a plain map in typesafe.RawQuestion. A caller holding an untyped map[string]any passes it to the client directly; SystemOne accepts any of the containers typesafe.NormalizeQuestions documents and validates them at run time.


Noul — yes/no

The probability that a statement holds, in [0, 1]. Values near 1 mean yes or true, values near 0 mean no or false, and values near 0.5 mean the content does not decide it.

typesafe.NewNoul("Is this message spam?")

typesafe.NewNoul("Is this message spam?", typesafe.WithNoulCriteria(typesafe.NoulCriteria{
	True:  "Unsolicited advertising or phishing",
	False: "A legitimate conversation",
}))

NewNoul(instructions any, opts ...QuestionOption) *NoulQuestion — the instructions may be a string, a map, or a slice, and may be "" when criteria alone describe the question. Criteria are free-form: use a string, or a structured object when examples help.

typesafe.NewNoul("", typesafe.WithNoulCriteria(typesafe.NoulCriteria{
	True: map[string]any{"meaning": "Payments or invoices", "examples": []any{"charged twice", "refund"}},
}))

Threshold the answer where your decision needs it:

if response.Nouls()["is_spam"].Noul > 0.9 {
	quarantine(message)
}

Choice — categorical

The best-matching label, with the model's confidence and a probability for every label. Use it whenever the options are known ahead of time and exactly one applies.

typesafe.NewChoice(
	map[string]any{
		"billing":   "Charges, refunds, or invoices",
		"technical": "Bugs, crashes, or API problems",
		"other":     nil, // nil means "no description needed"
	},
	typesafe.WithInstructions("Which department should handle this request?"),
)

NewChoice(criteria map[string]any, opts ...QuestionOption) *ChoiceQuestion. Each criteria value is a label description: a string, a JSON object, an array, or nil for a label the name already describes. Supports up to 255 options. A choice question with no criteria is rejected before the request is sent.

answer := response.Choices()["category"]
fmt.Println(answer.Choice)         // billing
fmt.Println(answer.Confidence)     // 0.87
fmt.Println(answer.Probabilities)  // map[billing:0.87 technical:0.09 other:0.04]

Score — ordinal rubric

An expected value across an ordered rubric whose levels start at 0. Use it for priority, quality, and severity scales where "how much" matters more than "which one".

typesafe.NewScore(
	[]any{"routine", "elevated", "critical emergency"},
	typesafe.WithInstructions("Rate the severity of this issue"),
)

NewScore(criteria []any, opts ...QuestionOption) *ScoreQuestion. The score is the probability-weighted average of the rubric levels, so it may fall between two levels; the reported legend and probabilities are keyed by level, so you can always read the distribution. Supports between 2 and 10 levels. An empty rubric or fewer than 2 levels is rejected with a *typesafe.ScoreError.

answer := response.Scores()["urgency"]
fmt.Println(answer.Score)                  // 1.7
fmt.Println(answer.Confidence)             // 0.85
fmt.Println(answer.Legend[2])              // "critical emergency"
fmt.Println(answer.Probabilities[2])       // 0.80

Box — bounding box object localization

Locates an object or subject described by instructions within an image, returning normalized bounding box coordinates (BoxCoordinates).

Note: Box questions require image support enabled via WithImages(true) or WithCallImages(true) (x-typesafe-images: true header) and a multimodal model (such as jev-preview).

typesafe.NewBox("the coffee mug in the photo")
typesafe.NewBox("the person wearing glasses in state.photo")

NewBox(instructions any, opts ...QuestionOption) *BoxQuestion:

  • instructions describe the subject to locate in the image.
  • Box questions do not accept criteria (bounding box prediction is continuous spatial localization, not a discrete set of categories).
  • Returns normalized bounding box coordinates in [0, 1]:
    • Top: Distance from top edge as fraction of image height.
    • Bottom: Distance from top edge as fraction of image height.
    • Left: Distance from left edge as fraction of image width.
    • Right: Distance from left edge as fraction of image width.
    • Confidence: Optional model confidence float.
answer := response.Boxes()["cup_box"]
fmt.Printf("Top=%.2f, Bottom=%.2f, Left=%.2f, Right=%.2f\n",
	answer.Box.Top, answer.Box.Bottom, answer.Box.Left, answer.Box.Right)

Question options

Option Effect
WithInstructions(any) The question to ask: a string, a JSON object, or an array. Overrides instructions passed positionally.
WithNoulCriteria(NoulCriteria) Describes the yes and no outcomes of a noul question.
WithQuestionField(key string, value any) Adds a field this version does not model to the wire form; a colliding field replaces the modeled one.

Instructions that are nil or blank are left off the wire entirely, so typesafe.NewNoul("", typesafe.WithNoulCriteria(...)) sends a question described only by its criteria. A structured instruction (an object or an array) is always sent, even when empty.


Raw questions

RawQuestion sends a question as a plain map, for request fields this version does not model:

typesafe.Questions{
	"billing": typesafe.RawQuestion{"type": "noul", "instructions": "Is this about billing?"},
	"queue": typesafe.RawQuestion{
		"type":       "choice",
		"criteria":   map[string]any{"billing": nil, "other": nil},
		"weight":     3, // a hypothetical field a newer API accepts
	},
}

NormalizeQuestions(questions) is the same validation the client applies. It accepts Questions, map[string]Question, the typed question maps (map[string]*NoulQuestion, map[string]*BoxQuestion, and siblings), map[string]any, and RawQuestion, and rejects an empty set with At least one question is required.


Validation timing

Input When a mistake is caught
typesafe.Questions with a non-question value Compile time
NewChoice with no criteria Before the request is sent
NewScore with an empty rubric (< 2 levels) Before the request is sent
An untyped map[string]any question Before the request is sent, by NormalizeQuestions
A field the server rejects The server's 400/422, as a typed error

Validation happens before the request is built, so an invalid question never reaches the network.

Clone this wiki locally