Guide · October 10, 2026

How to Ask Helm a Question

Every Helm request has three parts: the state, the questions, and the options. Put each piece of information where it belongs and Helm gives you its best answers. This guide shows where things go, and why it matters.

Saina · October 10, 2026 · 6 min read

Helm is a decision model: you give it a situation and a few possible answers, and it returns a probability for each answer instead of writing text. It doesn't need a prompt. It needs a well-formed request, and a well-formed request has exactly three parts:

Helm was trained on requests shaped this way. When each piece of information sits in its own field, Helm reads the situation, the question and the answers the way it learned to, and you get its best accuracy. When the pieces are mixed together, it still answers, but less well. The rest of this guide shows how to get the shape right.

A complete request

Here is a request that routes a banking support message:

curl https://api.saina.run/v1/ask \
  -H "Authorization: Bearer $SAINA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "saina-helm-2-0.8b",
    "state": "I ordered a new card two weeks ago and it still has not arrived.",
    "questions": {
      "topic": {
        "type": "single_choice",
        "question": "What is the customer asking about?",
        "options": {
          "card arrival": null,
          "card linking": null,
          "exchange rate": null,
          "lost or stolen card": null
        }
      },
      "urgent": {"type": "yes_no", "question": "Does the customer need a reply today?"}
    }
  }'

The customer's message is the state. Each question asks one thing. Each option is a plain name that says what it means. That's the whole pattern.

1. Put the context in state

The state is everything Helm should look at before answering. Put the customer's message, the ticket, or the record there, and nowhere else.

A common mistake is to paste the message into the question and leave the state empty:

{
  "state": {},
  "questions": {
    "topic": {
      "type": "single_choice",
      "question": "Classify this customer message:\nI ordered a new card two weeks ago and it still has not arrived.",
      "options": {"card arrival": null, "card linking": null}
    }
  }
}

This is valid, and Helm will answer it. But Helm learned to read the situation from the state and the question from the question, so mixing them costs accuracy. In our own testing on a banking intent benchmark, requests phrased this way (message in the question, empty state, opaque option names) scored 3.4 points lower than the same items rewritten into the shape this guide recommends.

The fix is simple: move the message into state, and keep the question to the question.

{
  "state": "I ordered a new card two weeks ago and it still has not arrived.",
  "questions": {
    "topic": {
      "type": "single_choice",
      "question": "What is the customer asking about?",
      "options": {"card arrival": null, "card linking": null}
    }
  }
}

State can be structured

The state doesn't have to be a single string. If your situation is a record, send it as a JSON object with meaningful field names:

{
  "state": {
    "channel": "email",
    "customer_tier": "business",
    "subject": "Card still missing",
    "message": "I ordered a new card two weeks ago and it still has not arrived."
  }
}

Helm reads objects as JSON, so field names are part of what it sees. customer_tier tells it more than f3. Leave out fields that have nothing to do with the decision: they cost input tokens and add noise.

2. Ask one decision per question

Each question should ask one thing, in plain words, the way you would ask a colleague who has just read the state.

You don't need to restate the context or add instructions like "read carefully" or "answer with one option". The question type already tells Helm how to answer, and the state already holds the context.

Asking several questions about the same state is cheap. Put them all in one request: the state is charged once, however many questions read it, and Helm 2 answers every question in a request from a shared read of the state.

3. Name options by what they mean

Option keys are not just identifiers. Helm reads them. Each option reaches the model as its key, or as key: description when you give a description. So the key should carry the meaning.

Option What Helm reads Verdict
"card arrival": null card arrival Clear
"billing": "Charges, refunds and invoices" billing: Charges, refunds and invoices Clear, with useful detail
"option_0": "card_arrival" option_0: card_arrival Works, but the meaning is buried behind an arbitrary label
"A": null A Meaningless to the model

A few habits help:

4. Pick the right question type

The type tells Helm what shape of answer you want. There are four:

Type Use it for You send You get back
yes_no A single fact that is true or false question (optional descriptions for yes and no) yes and no probabilities
single_choice Exactly one answer from a list (2 to 255 options) question, options A probability for every option
multi_choice Any number of answers that can apply at once (2 to 255 options) question, options An independent membership score for every option
rating A position on an ordered scale (2 to 10 levels) question, levels in order A probability for every level and the expected level

Two choices people often get wrong:

"severity": {
  "type": "rating",
  "question": "How severe is the customer's problem?",
  "levels": ["cosmetic", "inconvenient", "blocking", "data loss or money lost"]
}

5. Let Helm say when it isn't sure

By default Helm returns its full probability distribution ("mode": "distribution"). For automation you usually want a decision you can act on, plus a safe way out when the model is unsure. That's decision mode:

{
  "model": "saina-helm-2-0.8b",
  "mode": "decision",
  "threshold": 0.8,
  "min_margin": 0.2,
  "state": "I ordered a new card two weeks ago and it still has not arrived.",
  "questions": {
    "topic": {
      "type": "single_choice",
      "question": "What is the customer asking about?",
      "options": {"card arrival": null, "card linking": null, "none of these": null}
    }
  }
}

Every answer then comes with a reason. accepted means the top option cleared both bars and its key is in selection. below_threshold, below_margin and tie mean Helm declined to choose; send those to a person or a fallback path instead of guessing. You can set threshold and min_margin for the whole request or per question.

A checklist before you ship

Try it

Questions about structuring a request for your use case: [email protected].