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

# Fine-tuning

> Fine-tune an open model on your own data. The data and the weights stay in an S3 bucket inside your organization's AWS account; you see the price before anything starts and never pick a provider.

Lab › Training turns a folder of chat examples into a model you own. You
choose a base model, LoRA or full fine-tuning, how the result must be
servable, and a price ceiling. AI Reserve validates the data, prices the run,
places it on a training backend internally, and puts the finished weights
back in your bucket. A provider is never an input: the quote hides the
placement the way a GPU instance quote does.

> [!NOTE]
>
> Fine-tuning needs the **AWS hub** (the per-organization AWS account that also
> powers [Elastic Container Service](/containers/ecs.md)). Enabling it is one
> click on the Training page and takes a few minutes. Your training bucket,
> `aireserve-training-<account id>`, is created in that account the first
> time the page opens.

## How it works

**1. Connect AWS**

An organization admin clicks **Enable AWS hub** on **Lab › Training** (or
calls `enable_containers` over MCP). The account is vended by AI Reserve
inside its AWS Organization; nothing else lives there. The page shows
the lifecycle and updates on its own.

**2. Add data**

Create a dataset folder — `datasets/<name>/` in your bucket — and put
**chat-format JSONL** in it: one example per line, a `messages` array
with user and assistant turns, the last turn by the assistant. Drop
files on the page (a presigned S3 upload), or use the AWS CLI with a
12-hour session scoped to that one folder. Then **Validate**: AI Reserve
pins the file's S3 version, checks every line, and reports the example
and token counts. Nothing trains until the data checks out.

**3. Choose a model**

Pick a base from the catalog (Llama 3.1 8B, Qwen3 8B, gpt-oss 20B, …),
**LoRA adapter** or **full fine-tune**, and how you will use the result:
a dedicated endpoint (per hour) or just the weights. Serverless
per-token serving of trained adapters is not offered yet — no current
backend serves them that way — and arrives with AI Reserve's own
multi-adapter lane. Training settings have sensible defaults and fold
away; a setting outside the placed backend's range is clamped and the
change is shown on the quote.

**4. Review and start**

The quote shows the training price, an estimated duration, the serving
price for the mode you chose, and your wallet balance after. The quote
is signed and valid two minutes. **Start** reserves the estimate from
your wallet; it is settled when the run succeeds and released if it
fails or is cancelled.

**5. Your run**

Follow the run live. When it finishes the model card shows where the
weights are (`s3://…/models/<id>/`), **Download**, and **Deploy** to a
dedicated endpoint. A deployment's model id is what you send to
`/v1/chat/completions`.

## Data format

```jsonl theme={"dark"}
{"messages":[{"role":"system","content":"You classify support tickets."},{"role":"user","content":"Please send my receipt for order 1182."},{"role":"assistant","content":"billing"}]}
{"messages":[{"role":"user","content":"The app crashes when I open settings."},{"role":"assistant","content":"bug"}]}
```

* One JSON object per line, UTF-8, `.jsonl`.
* Roles: `system`, `user`, `assistant`, `tool`, `developer`. Content is a
  string or an array of `{type: "text", text}` parts.
* Every example needs at least one `user` and one `assistant` turn; the
  **last** turn must be the assistant's (that is what the model learns).
* At least 10 examples. A `valid.jsonl` beside `train.jsonl` is used as the
  validation split automatically.

Validation names the first problems by line number and never returns the
examples themselves. Token counts are estimates for pricing; backends bill
on their own tokenizer and the run records the actual.

## Uploading with the AWS CLI

The page's **Use the AWS CLI instead** fold mints a 12-hour session that
can read and write one dataset folder and nothing else. The commands talk to
S3 directly; nothing customer-sized passes through AI Reserve.

```bash theme={"dark"}
export AWS_ACCESS_KEY_ID=<from the page>
export AWS_SECRET_ACCESS_KEY=<from the page>
export AWS_SESSION_TOKEN=<from the page>
export AWS_DEFAULT_REGION=us-east-1

aws s3 cp ./train.jsonl s3://aireserve-training-123456789012/datasets/support-tickets/train.jsonl
aws s3 sync ./data        s3://aireserve-training-123456789012/datasets/support-tickets/
aws s3 ls                 s3://aireserve-training-123456789012/datasets/support-tickets/
```

The same credentials come from `POST /v1/training/datasets/{datasetId}/session`
and `aireserve training datasets session <id>`.

## LoRA or full, and what you get

| | LoRA adapter | Full fine-tune |
| - | - | - |
| What is trained | A small set of extra weights on top of the base | Every weight |
| Result | `adapter_model.safetensors` (MBs) in your bucket | A complete checkpoint (GBs) in your bucket, or at the backend when above 1 GB |
| Serverless | Not yet (no current backend serves trained adapters serverless) | No — its own weights need their own hardware |
| Dedicated endpoint | Yes | Yes |
| Download | Yes | Yes |
| Training price | Lower | Higher (a surcharge over the LoRA rate) |

The request shape is identical; only `method` differs. A combination that
cannot be placed — full + serverless, a base nobody trains fully, a ceiling
under the estimate — is refused at quote time with what would work, before
any money moves.

## API

Every step is a `/v1/training` call under your organization's API key with
compute `read` (quotes, reads) or `manage` (datasets, starts, deployments)
access. The full reference is in the [API reference](/api-reference.md).

```bash theme={"dark"}
# 1. a dataset folder, a presigned upload, validation
curl -X POST https://api.aireserve.com/v1/training/datasets \
  -H "Authorization: Bearer $AIRESERVE_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"support-tickets"}'
curl -X POST https://api.aireserve.com/v1/training/datasets/$DATASET/upload \
  -H "Authorization: Bearer $AIRESERVE_API_KEY" -H "Content-Type: application/json" \
  -d '{"filename":"train.jsonl","contentType":"application/jsonl"}'
# PUT the file bytes to the returned url, then:
curl -X POST https://api.aireserve.com/v1/training/datasets/$DATASET/validate \
  -H "Authorization: Bearer $AIRESERVE_API_KEY"

# 2. quote, then start from the quote
curl -X POST https://api.aireserve.com/v1/training/jobs/quote \
  -H "Authorization: Bearer $AIRESERVE_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"triage v1","datasetId":"'$DATASET'","baseModel":"meta-llama/llama-3.1-8b-instruct","method":"lora","serving":"dedicated","maxCostUsd":25}'
curl -X POST https://api.aireserve.com/v1/training/jobs \
  -H "Authorization: Bearer $AIRESERVE_API_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: triage-v1-$(date +%s)" \
  -d '{"quoteId":"'$QUOTE_ID'","name":"triage v1","costAcknowledged":true}'

# 3. follow, then deploy
curl https://api.aireserve.com/v1/training/jobs/$JOB -H "Authorization: Bearer $AIRESERVE_API_KEY"
curl -X POST https://api.aireserve.com/v1/training/deployments \
  -H "Authorization: Bearer $AIRESERVE_API_KEY" -H "Content-Type: application/json" \
  -d '{"modelId":"'$MODEL'","name":"triage-prod","kind":"dedicated","costAcknowledged":true}'
```

The CLI twin is `aireserve training bases | datasets | jobs | models | deployments`,
and every step is an MCP operation (`quote_training_run`, `start_training_run`,
…) for a coding agent on the AI Reserve connection.

## Pricing

* **Training** is priced per trained token (the validated token count ×
  epochs) at the backend's list rate, with a surcharge for full fine-tuning
  and a \$1 minimum. The quote is the price: it is reserved from your wallet
  when you start, settled when the run succeeds, and released if it fails or
  is cancelled. A run that fails costs nothing.
* **Dedicated endpoints** bill every hour they are up, from the first hour,
  at the rate the quote showed; stopping the deployment ends it.
* **Storage** in your bucket is AWS's S3 price, reconciled from the daily
  AWS cost check rather than metered by the hour; the bucket shows on **My
  Resources › AWS**.

## When something goes wrong

Every refusal and failure is one plain sentence with the fix, never a
provider's raw text. Before any money moves, the quote refuses a
combination that cannot be placed (`409 no_placement`) and says what would
work; a hyperparameter outside the placed backend's range is clamped and
the change is listed on the quote (`adjustments`), never applied silently.
A run that fails after starting is released from your wallet and the run
shows one of:

| What you see | What happened | What to do |
| - | - | - |
| "The provider could not read the dataset…" | The file passed our checks but the backend's stricter validation refused it | Fix the line it names, re-validate |
| "The run ran out of GPU memory…" | Sequence length, rank or batch too large for the hardware | Lower max sequence length or LoRA rank |
| "Training became unstable…" | Loss went to NaN | Lower the learning rate |
| "The training hardware was reclaimed…" | Spot preemption at the backend | Start again; nothing was charged |
| "The training backend has no capacity right now" / "is having trouble" | 429 / 5xx at the backend | Try again in a few minutes |
| "The training backend rejected our credentials" / "refused the run under its account limits" | Our provider account, not yours | The ops team is alerted; nothing was charged |

## Limits and notes

* Dataset files up to a few GB each over the browser; larger sets go in
  with the CLI. Per-backend dataset limits are checked at quote time.
* Weights above 1 GB (full checkpoints) stay with the training backend for
  now and serve from there; the model card says so.
* Managed backends receive a copy of your pinned dataset file to train on
  and it is deleted when the run ends; the bucket is the system of record.
* Objectives: supervised fine-tuning (SFT). Preference and reinforcement
  objectives are not offered yet.
* Serving: dedicated endpoints and download. Serverless per-token serving
  of adapters is not offered until AI Reserve's own multi-adapter lane
  ships; the request shape already carries `serving: "serverless"` for it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.