# Automatic Model Selection

Source: https://staging-docs.aiand.com/models/auto/

`auto` is a reserved model name. Send it in `model` and ai& picks a concrete model for that request, then serves it normally — same request and response shapes, same streaming behaviour, same billing rules as naming the model yourself.

It exists so a workload with mixed traffic doesn't have to send every request to its most expensive model. Short lookups resolve to a cheap model; work that needs reasoning resolves to one that can do it.

## Using it

<Tabs>
<TabItem label="curl">

```bash
curl -i https://api.aiand.com/v1/chat/completions \
  -H "Authorization: Bearer sk-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "messages": [{"role": "user", "content": "What is the capital of Japan?"}]
  }'
```

</TabItem>
<TabItem label="Python">

```python
from openai import OpenAI

client = OpenAI(base_url="https://api.aiand.com/v1", api_key="sk-...")

response = client.chat.completions.with_raw_response.create(
    model="auto",
    messages=[{"role": "user", "content": "What is the capital of Japan?"}],
)
print(response.headers["x-model"])
print(response.parse().choices[0].message.content)
```

</TabItem>
<TabItem label="Node.js">

```ts

const client = new OpenAI({ baseURL: "https://api.aiand.com/v1", apiKey: "sk-..." });

const { data, response } = await client.chat.completions
  .create({
    model: "auto",
    messages: [{ role: "user", content: "What is the capital of Japan?" }],
  })
  .withResponse();

console.log(response.headers.get("x-model"));
console.log(data.choices[0].message.content);
```

</TabItem>
</Tabs>

`auto` works on `/v1/chat/completions`, `/v1/completions`, `/v1/responses`, and `/v1/messages`.

## Knowing which model ran

The `X-Model` response header carries the resolved model's catalog name, lowercased — compare it case-insensitively. It is present on streaming responses too — response headers arrive before the first body chunk, so you can read it as soon as the stream opens.

```
X-Model: deepseek-ai/deepseek-v4-flash
```

The header is exposed via CORS, so browser clients can read it. Your [request logs](/analytics/logs/) and usage records also store the resolved name — never `auto` — so cost attribution and analytics work without knowing selection happened. See [Response Headers](/reference/response-headers/).

## How the model is chosen

Three steps, in order:

1. **Filter** to models your organization can call for _this_ request. A model is eligible only if it has been added to the automatic-selection pool, your plan entitles you to it, the prompt fits its context window, and it supports every input modality in the request (image, video, audio).
2. **Order** what survives by capability, least capable first. Where two models are equally capable, the cheaper one comes first.
3. **Select** by complexity. The request is graded into one of four tiers, and the tier picks a position in that ordered list.

| Tier        | Resolves toward                  | Typical request                                                 |
| ----------- | -------------------------------- | --------------------------------------------------------------- |
| `simple`    | the least capable eligible model | greetings, acknowledgements, a factual lookup                   |
| `medium`    | lower-middle of the list         | everyday requests needing some explanation                      |
| `complex`   | upper-middle of the list         | non-trivial code, multi-step analysis, domain expertise         |
| `reasoning` | the most capable eligible model  | proofs, derivations, debugging from symptoms, design trade-offs |

Capability is ranked from published benchmark results, not from price — the two do not reliably track each other, and a model being expensive is not evidence that it is stronger. A model we have not yet ranked is not selected by `auto` at all; name it directly to use it.

**The pool is curated so that capability and price rise together**, which is why "a cheap model" and "the least capable eligible model" describe the same choice above rather than competing ones. A model earns a place only if nothing cheaper is at least as capable, so ordering the pool by capability also orders it by cost. Ranking on benchmarks rather than on price is what keeps that true as the catalog moves: a model that grows more expensive without growing stronger loses its place instead of drifting up the list.

At the `reasoning` tier, selection first narrows to models tagged with the `reasoning` capability when your organization has any.

**Judging the difficulty usually involves a second model.** Greetings and acknowledgements are recognised locally and resolve to the least capable model in the pool. Everything else is graded by a small model we choose, which is the only difficulty judgement involved — there is no local scoring of hard requests, because a keyword list cannot grade one reliably in every language.

Where that model is asked, the text of your request — clipped, with your system instructions labelled separately — is sent to it before the model that answers you runs. It comes from our catalog and need not be a model your organization otherwise calls, so it can be a different provider. The classification is never billed to you and never appears in your usage. A small random sample of other requests is also classified in the background for calibration. If your data handling requires that a request only reaches the model you named, name it.

**`auto` does not accept `reasoning_effort`.** Sending one is a 400 — name a model directly if you want to choose the effort. The ranking above comes from each model's published index, and that index is recorded at one configuration per model, so an effort you picked would move models off the very point the ranking describes. `auto` chooses the model and leaves the effort at the model's own default, which is the setting its ranking was measured at.

`reasoning_effort: "none"` is rejected with the rest, and for the sharpest version of that reason: a reasoning model with its thinking suppressed is the furthest it ever gets from the point it was ranked at.

The same rule covers `reasoning.effort` on `/v1/responses` — whichever name your endpoint gives the field.

**With no credit left, selection narrows to free models first**, whatever the tier — choosing a paid model would only produce an insufficient-credit error on a model you didn't name. If nothing in your pool is free, you get that error as usual.

The pool is per-organization, so two organizations sending the same prompt can resolve to different models.

## Billing

You are charged the resolved model's price, at its normal input and output rates. There is no surcharge for using `auto`, and no separate line item — the charge appears against the model that ran.

This means **the cost of an identical request can differ between calls** if the pool changes. Budget against your [usage](/billing/usage/) totals rather than a single model's rate.

## Conversations

`auto` decides per request, so a multi-turn conversation is re-decided on every turn. A follow-up that reads as harder than the turn before it can resolve to a different model, and `X-Model` can change during a thread.

That has a cost worth knowing about: the [prompt-prefix discount](/models/pricing/) only applies while a conversation keeps going to the same model, so a thread that switches models loses it for that turn. If you need one model for a whole conversation, name it — a named model is never re-routed.

## Other limits

- **If the grading model is unavailable, requests take the middle of the pool.** On a timeout or an outage there is no difficulty judgement, so anything that isn't a recognised greeting resolves to a mid-capability eligible model rather than being guessed at. That is deliberately not the weakest one — it means a hard request is never quietly downgraded — but it does mean `X-Model` can differ from what the same request usually resolves to. Name a model directly if you need that fixed.
- **`auto` is not listed in `GET /v1/models`.** It's a routing instruction, not a model, so it has no capabilities, context window, or price of its own.
- **The pool changes.** Models are added to and removed from it as the catalog evolves. Don't build logic that assumes a given prompt always lands on a given model.
- **Capability requirements narrow it, they don't override it.** A request with an image only considers models that accept images. If nothing in your pool does, the request is rejected rather than silently dropping the image.

## Errors

| Status | Message                                                | Cause                                                                                                                                      |
| ------ | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| 400    | `Model 'auto' is not supported.`                       | Automatic selection is not enabled. Name a model directly.                                                                                 |
| 400    | `No model available to 'auto' can serve this request.` | Nothing in your pool satisfies the request — commonly a modality or context-window fit.                                                    |
| 400    | `Model 'auto' does not accept reasoning_effort.`       | `auto` chooses the effort along with the model. Name a model directly to set one yourself.                                                  |

All are the ordinary `invalid_request_error` shape documented under [Errors](/errors/), with `param` set to `model` — or to the effort field you sent, for the last one.
