> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.milliseconds.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.milliseconds.ai/_mcp/server.

# Writing good statements and labels

Every capability scores your words against the input. A statement, a label name, a scale level, a
question and a field description all act as the instruction. The model reads that text literally.

So one rule covers every capability: **the text must describe the case, not the verdict.** `"yes"` and
`"no"` describe nothing. `"A"`, `"B"` and `"1"` to `"5"` describe nothing either.

> **Note**
>
> **Write in English, even for non-English input.** English descriptions scored every non-English test
> input correctly. [Languages](/concepts/languages) carries the measured probes.

## Statements for yes-no

A statement is a sentence that is true or false about the text. Write it in the third person, as a
claim about what the text says. Put one idea in it.

| Weak                           | Why it fails                       | Better                                                          |
| ------------------------------ | ---------------------------------- | --------------------------------------------------------------- |
| `Python`                       | A keyword, not a claim             | `The letter states the candidate writes Python professionally.` |
| `Is the customer angry?`       | A question, not a claim            | `The customer expresses anger.`                                 |
| `Good fit and available soon`  | Two ideas in one score             | Two statements in a `statements` batch                          |
| `The candidate is a good fit.` | A judgment the text cannot support | `The letter states five or more years of backend experience.`   |

Split compound judgments into separate statements and send them in one `statements` batch. Read
[Batching](/capabilities/batching) for the shape of the response.

## when_true and when_false hints

Without hints, the API scores your statement alone and returns that raw score. With hints, it scores
`when_true` against `when_false` and normalizes the pair. The hint text replaces your statement as the
thing being scored, so a verdict word destroys the signal.

This measured pair uses the same text and the same statement. Only the hints change.

**`Hints that describe the case`**

```json title="Hints that describe the case"
{"statement":"The customer expresses urgency.","answer":true,"probability":1}
```

**`Hints that state a verdict`**

```json title="Hints that state a verdict"
{"statement":"The customer expresses urgency.","answer":false,"probability":0.004}
```

The second call is wrong. `"yes"` and `"no"` carry no meaning about urgency, so the pair scores noise.

Write each hint as a short description of the world in that case:

```json
{
  "statement": "The letter states five or more years of backend experience.",
  "when_true": "the letter states a number of years of backend engineering experience that is five or more",
  "when_false": "the letter states no years of experience, or fewer than five"
}
```

Send both hints together. If you send `when_true` alone, the API scores it against the generic phrase
`none of the above`. If you send `when_false` alone, your statement takes the true side.

> **Tip**
>
> Use hints when the statement alone is ambiguous, or when the negative case needs its own words. Skip
> them when a plain statement already separates your cases.

## Labels for classify

Label names must be words that describe the content. Descriptions raise the winner's probability
further. This ticket went through `classify` three ways:

> I was charged twice for my subscription this month and support has not replied.

| `labels`                    | Winner    | `probability` | `confidence` |
| --------------------------- | --------- | ------------- | ------------ |
| `["A","B","C"]`             | `C`       | 0.603         | 0.379        |
| `["billing","bug","sales"]` | `billing` | 0.91          | 0.723        |
| Named with descriptions     | `billing` | 0.956         | 0.835        |

The letters name nothing, so the model splits the weight and picks a meaningless winner.

The described form is the object form of `labels`:

```json
{
  "labels": {
    "billing": "a question or dispute about an invoice, charge, refund or price",
    "bug": "the product behaves incorrectly or fails",
    "sales": "a request for a quote, a demo or a new contract"
  }
}
```

Your code still reads back the short name in `label` and in `scores`. The description only steers the
model. Make labels mutually exclusive, and add a catch-all label such as `other` when the real world
has cases outside your set.

## Levels for rate

A `scale` is a list of level descriptions, ordered low to high. Numbers are not descriptions. This
message went through `rate` twice, with four levels each time:

> This is the third time I have written. My order still has not shipped and nobody answers. If it is
> not fixed today I am cancelling my account.

**`Scale of numbers`**

```json title="Scale of numbers"
{"score":1.423,"level":2,"label":"3","confidence":0.247,"scores":[0.157,0.279,0.548,0.016]}
```

**`Scale of descriptions`**

```json title="Scale of descriptions"
{"score":2.5,"level":3,"label":"angry and threatening to cancel","confidence":0.5,"scores":[0,0,0.5,0.5]}
```

The numeric scale spreads weight over all four levels and reports confidence 0.247. The described
scale (`["calm and factual","mildly annoyed","clearly frustrated","angry and threatening to cancel"]`)
rules out both calm levels and reports 0.5. It still splits the top two levels evenly, and the
confidence reports that split honestly.

Keep the levels on one axis, and make the step between neighbours the same size. The API accepts two
to ten levels. Four or five is usually enough.

## Questions for answer and entities

`answer` turns each question into an extraction label. A bare noun matches the first thing of that
kind, and that is rarely the thing you want. Three questions against one invoice line:

> Invoice 8812 from Meridian Design. Issued 3 March 2026 by Nadia Rossi. Payment is due 2 April 2026.

```json
{
  "results": [
    {"question":"date","answer":"3 March 2026","probability":0.998,"start":42,"end":54},
    {"question":"When is the invoice due?","answer":"2 April 2026","probability":0.988,"start":86,"end":98},
    {"question":"Who issued the invoice?","answer":"Meridian Design","probability":0.979,"start":18,"end":33}
  ]
}
```

The text holds two dates. `"date"` returned the issue date. The full question returned the due date.
Name the role, not the type: "the date the payment is due", not "date".

The same rule applies to `entities` types and to `verify` fields. For `extract`, a property
`description` becomes the field instruction. Without one, the API falls back to `title`, then to the
property name with underscores turned into spaces. So `invoice_number` works, and `n1` does not.

## Worked example: the cover-letter false positive

A vague statement scores tone instead of fact. This letter states no software experience at all.

> Dear hiring manager, I am so excited about this backend engineer role. I spent the last three years
> managing a coffee shop \[...] I have no professional software experience yet, but I am a passionate
> self-starter and I know I would be a great addition to your team.

Two statements against that one text, in one `statements` batch:

```json
{
  "results": [
    {"statement":"The candidate is a good fit.","answer":true,"probability":1},
    {"statement":"The letter states the candidate has professional software engineering experience.","answer":false,"probability":0}
  ]
}
```

The vague statement returns `true` at probability 1. Nothing in the letter supports it. The model
matched enthusiasm, because "a good fit" describes an opinion and the letter is full of opinion.

The precise statement returns `false` at probability 0. It names something the text either says or does
not say. No threshold can rescue the first statement. Only the wording can.

> **Warning**
>
> A confident wrong answer looks exactly like a confident right one. Probabilities cannot tell you your
> statement was vague. A [golden set](/evaluate/golden-sets) can.

## Checklist

* Describe the case. Never write `yes`, `no`, `true`, `false`, `A`, `B` or a bare number.
* One idea per statement, per label and per level. Batch the rest.
* Claim what the text says, not what you conclude about the subject.
* Name the role in a question, not the data type.
* Add descriptions to labels, entity types and schema fields.
* Keep label names short and stable; your code reads those, not the descriptions.

## Next

#### [Yes / no](/capabilities/yes-no)

The full request shape for statements, batches and hints.

#### [Golden sets](/evaluate/golden-sets)

Fifty real examples will find a bad statement that no probability can.

#### [Thresholds and confidence routing](/concepts/thresholds)

Once the wording is right, pick the cut-off per action.