> ## Documentation Index
> Fetch the complete documentation index at: https://docs.protege.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Route a task down

> Move a task to a cheaper model without giving up quality, and roll it back if you do.

With a contract in place, this is mostly waiting and one decision.

```mermaid theme={null}
flowchart LR
  A["Switch to auto"] --> B["Candidates scored<br/>offline"] --> C{"Clears the<br/>contract?"} 
  C -->|"yes"| D["Proposed to you"] --> E["You approve"] --> F["Serving"]
  C -->|"no"| G["Stays on incumbent"]
  F -.->|"anytime"| H["Roll back"]
```

**Prerequisite:** an [eval contract](/tutorials/write-an-eval-contract) on the
task.

<Steps>
  <Step title="Switch the task to auto">
    ```python theme={null}
    client.chat.completions.create(
        model="deepseek-v4-flash",                                  # was a pinned model
        messages=messages,
        extra_body={"task": "invoice_extraction"},
    )
    ```

    Nothing changes yet. With no approved route the task still serves from your
    default model, so this deploy is safe on its own.
  </Step>

  <Step title="Wait for a candidate">
    Cheaper models are replayed against the contract out of band. Your production
    traffic is not used as the experiment, and no candidate touches a live request
    before you accept it.

    You get the candidate's score against the contract and its measured cost
    delta, both on the same examples.
  </Step>

  <Step title="Read the proposal, not just the price">
    Two questions, in this order:

    1. Does it clear the contract, including the hard examples?
    2. What does it cost?

    A candidate that clears by a hair on a set with no hard cases is not a
    candidate. If the margin looks too comfortable, the contract is probably too
    easy, and that is worth fixing before accepting anything.
  </Step>

  <Step title="Approve, then watch the route field">
    After approval, new calls for that workload use the new route. Log the
    response's `model` so a quality change can be traced to a route change rather
    than guessed at.

    ```
    x-protege-workload: invoice_extraction
    ```
  </Step>
</Steps>

## If it goes wrong

Roll back. It is a route change, not a redeploy of your application, and the
previous route is versioned. Pinning the old model in your request body also
works as an immediate stop.

## If nothing ever clears

That is a real answer, and a useful one: no existing cheaper model can do this
task. It is the point at which a model trained on the task's own traces and
[failures](/concepts/failures) becomes the cheaper option rather than the
expensive one.

<Card title="How failures decide what to train" icon="gavel" href="/concepts/failures">
  Why the calls that went wrong are the training signal.
</Card>
