Skip to main content
Using a coding agent? Install the together-fine-tuning skill so your agent writes correct fine-tuning code automatically. See Coding agent setup for the install flow.
This quickstart walks through a full fine-tuning lifecycle. You’ll prepare a conversational dataset (CoQA), upload it, launch a LoRA job on Qwen3.5 9B, watch it complete, deploy the result, and compare it to the base model. End-to-end runtime is roughly 20 to 40 minutes for the example dataset. For background on what fine-tuning is and when to use it, see the overview. You can find a runnable notebook for this tutorial on GitHub.

Prerequisites

Before you begin, make sure you have:
Make sure to export your API key before you begin:

Step 1: Prepare your dataset

This quickstart uses the CoQA conversational dataset. Together AI supports four text data formats: conversational, instruction, preference, and generic text. JSONL is the default file format, but you can use Parquet for pre-tokenized data and custom loss masking. Transform CoQA into the conversational shape:
Python
To train the model on only part of each example (for instance, the assistant turns but not the user turns), you can use loss masking or data weights.
Next we’ll upload the file. files.upload() runs a local structural check by default (check=True), catching basic formatting errors such as non-UTF-8 encoding or malformed JSON lines before the file is sent. To inspect the check report yourself before uploading, run check_file() first (see Data preparation for details):
For very large files, you can skip the local check with check=False to speed up the upload. After upload, the server validates the full schema (conversation roles, tool calls, and other dataset requirements) during ingestion, reported through the file’s processing_status.
To see files you’ve already uploaded, list them with client.files.list() (tg files list).
If you upload a file whose contents already exist on Together AI, client.files.upload() doesn’t create a duplicate. It returns the existing file’s metadata, including its id, so you can reuse it directly. To force a re-upload, delete the existing file first with client.files.delete(<file_id>).
Upload returns before ingestion finishes, so poll the Files API until processing_status reaches COMPLETED before launching the job. If validation rejects the dataset, processing_status becomes INVALID_FORMAT and validation_report.error carries the reason.
Python
Once processing finishes, the file metadata reflects the outcome. A successful validation (processing_status: COMPLETED):
A user-correctable failure (processing_status: INVALID_FORMAT):
Save the id from the upload response. You’ll pass it as training_file in the next step.

Step 2: Launch the job

client.fine_tuning.create() starts a LoRA job by default. The example below tunes Qwen3.5 9B for three epochs. See the API reference for the full list of parameters.
Response:
Save the job ID.
Here are some common job parameters:See the API reference for the full list of parameters.
Each fine_tuning.create() call starts a new billed job. If you get a retryable error, run client.fine_tuning.list() first to make sure you aren’t launching a duplicate.

Step 3: Watch the job complete

Jobs move through these states: pending → queued → running → uploading → completed. Queue wait time is typically under an hour. Once running, multiply the first epoch’s duration by n_epochs to estimate the time remaining. Poll for completion (or error/cancellation), then read the Model Object ID:
Here’s a sample event log:
You can also monitor the run on the fine-tuning jobs dashboard. For per-step loss curves, see training metrics.

Step 4: Deploy and call your model

Fine-tuned models run on Together AI through dedicated model inference. A completed job is already a private model in your project, so there’s no upload step: you deploy it with the tg beta CLI by its Model Object ID (model_object_id, the ml_... value from Step 3). The deploy commands require Together CLI version 2.24.0 or later. The CLI’s deploy command creates the endpoint, attaches a deployment, and routes all traffic to it in one step. Then poll until the deployment reaches DEPLOYMENT_STATE_READY:
CLI
The SDK has no single-call equivalent, so it runs the same steps individually, referencing the fine-tune by its Model Object ID (ml_...):
Once the deployment is ready, send a request. The deploy output prints the endpoint string (your-project-slug/qwen-finetune): pass this as the model parameter. Point the base URL at https://api-inference.together.ai/v1:
When you’re done, delete the endpoint and its deployment to stop billing:
CLI
Pass the endpoint string (your-project-slug/qwen-finetune, printed by the deploy output) as the model parameter, not the Model Object ID. If deploy reports that the model has more than one deployment profile, re-run it with --config <cr_...>; list a model’s profiles with tg beta models configs "<MODEL_OBJECT_ID>".
Congrats! You just fine-tuned a model, deployed it to a dedicated endpoint, and ran inference end-to-end.

Step 5: Compare against the base model (optional)

To measure the impact of fine-tuning, run the same prompts through the base model and the fine-tuned model.
Many fine-tunable base models aren’t available on serverless. For example, calling Qwen/Qwen3.5-9B directly returns Unable to access non-serverless model. To compare, deploy the base on its own dedicated endpoint, evaluate against its endpoint string, then tear that endpoint down too. Serverless bases (those with a per-token price listed on the models dashboard) can be called directly without deploying anything.
This GitHub notebook runs an Exact Match and F1 comparison on the CoQA validation split. Here’s a sample result from one run:

Stop the endpoint

Dedicated model inference bills per minute per running replica as long as the deployment is running. Step 4 deletes the endpoint at the end, but if you skipped that step or want to delete it later, run:
Find the endpoint ID by running tg beta endpoints ls.

Continue from a checkpoint

Resume training from an existing job by passing from_checkpoint:
from_checkpoint accepts the output model name, the job ID, or a specific step in the form ft-...:{STEP_NUM}. List available checkpoints with tg fine-tuning list-checkpoints <JOB_ID>.

Next steps

Data preparation

See the full schema for conversational, instruction, preference, and tokenized data.

Supported models

Browse base models with context lengths and batch size limits.

Preference tuning

Align a model with paired preferred and dispreferred responses.

Deploy your model

Hosting, teardown, and local inference for fine-tuned models.