Fine-tuning
For detailed end-to-end fine-tuning examples and FAQ, check out our fine-tuning guide.
Every fine-tuning job comes with a minimum fee of $4, and there's a monthly storage fee of $2 for each model. For more detailed pricing information, please visit our pricing page.
Fine-tuning basics
Fine-tuning vs. prompting
When deciding whether to use prompt engineering or fine-tuning for an AI model, it can be difficult to determine which method is best. It's generally recommended to start with prompt engineering, as it's faster and less resource-intensive. To help you choose the right approach, here are the key benefits of prompting and fine-tuning:
- 
Benefits of Prompting - A generic model can work out of the box (the task can be described in a zero shot fashion)
- Does not require any fine-tuning data or training to work
- Can easily be updated for new workflows and prototyping
 Check out our prompting guide to explore various capabilities of Mistral models. 
- 
Benefits of Fine-tuning - Works significantly better than prompting
- Typically works better than a larger model (faster and cheaper because it doesn't require a very long prompt)
- Provides a better alignment with the task of interest because it has been specifically trained on these tasks
- Can be used to teach new facts and information to the model (such as advanced tools or complicated workflows)
 
Common use cases
Fine-tuning has a wide range of use cases, some of which include:
- Customizing the model to generate responses in a specific format and tone
- Specializing the model for a specific topic or domain to improve its performance on domain-specific tasks
- Improving the model through distillation from a stronger and more powerful model by training it to mimic the behavior of the larger model
- Enhancing the model’s performance by mimicking the behavior of a model with a complex prompt, but without the need for the actual prompt, thereby saving tokens, and reducing associated costs
- Reducing cost and latency by using a small yet efficient fine-tuned model
Dataset Format
Data must be stored in JSON Lines (.jsonl) files, which allow storing multiple JSON objects, each on a new line.
Datasets should follow an instruction-following format representing a user-assistant conversation. Each JSON data sample should either consist of only user and assistant messages ("Default Instruct") or include function-calling logic ("Function-calling Instruct").
1. Default Instruct
Conversational data between user and assistant, which can be one-turn or multi-turn. Example:
{
    "messages": [
        {
            "role": "user",
            "content": "User interaction n°1 contained in document n°2"
        },
        {
            "role": "assistant",
            "content": "Bot interaction n°1 contained in document n°2"
        },
        {
            "role": "user",
            "content": "User interaction n°2 contained in document n°1"
        },
        {
            "role": "assistant",
            "content": "Bot interaction n°2 contained in document n°1"
        }
    ]
}
- Conversational data must be stored under the "messages"key as a list.
- Each list item is a dictionary containing the "content"and"role"keys."role"is a string:"user","assistant", or"system".
- Loss computation is performed only on tokens corresponding to assistant messages ("role" == "assistant").
2. Function-calling Instruct
Conversational data with tool usage. Example:
{
    "messages": [
        {
            "role": "system",
            "content": "You are a helpful assistant with access to the following functions to help the user. You can use the functions if needed."
        },
        {
            "role": "user",
            "content": "Can you help me generate an anagram of the word 'listen'?"
        },
        {
            "role": "assistant",
            "tool_calls": [
                {
                    "id": "TX92Jm8Zi",
                    "type": "function",
                    "function": {
                        "name": "generate_anagram",
                        "arguments": "{\"word\": \"listen\"}"
                    }
                }
            ]
        },
        {
            "role": "tool",
            "content": "{\"anagram\": \"silent\"}",
            "tool_call_id": "TX92Jm8Zi"
        },
        {
            "role": "assistant",
            "content": "The anagram of the word 'listen' is 'silent'."
        },
        {
            "role": "user",
            "content": "That's amazing! Can you generate an anagram for the word 'race'?"
        },
        {
            "role": "assistant",
            "tool_calls": [
                {
                    "id": "3XhQnxLsT",
                    "type": "function",
                    "function": {
                        "name": "generate_anagram",
                        "arguments": "{\"word\": \"race\"}"
                    }
                }
            ]
        }
    ],
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "generate_anagram",
                "description": "Generate an anagram of a given word",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "word": {
                            "type": "string",
                            "description": "The word to generate an anagram of"
                        }
                    },
                    "required": ["word"]
                }
            }
        }
    ]
}
- Conversational data must be stored under the "messages"key as a list.
- Each message is a dictionary containing the "role"and"content"or"tool_calls"keys."role"should be one of"user","assistant","system", or"tool".
- Only messages of type "assistant"can have a"tool_calls"key, representing the assistant performing a call to an available tool.
- An assistant message with a "tool_calls"key cannot have a"content"key and must be followed by a"tool"message, which in turn must be followed by another assistant message.
- The "tool_call_id"of tool messages must match the"id"of at least one of the previous assistant messages.
- Both "id"and"tool_call_id"are randomly generated strings of exactly 9 characters. We recommend generating these automatically in a data preparation script as done here.
- The "tools"key must include definitions of all tools used in the conversation.
- Loss computation is performed only on tokens corresponding to assistant messages ("role" == "assistant").
Upload a file
Once you have the data file with the right format, you can upload the data file to the Mistral Client, making them available for use in fine-tuning jobs.
- python
- javascript
- curl
import os
from mistralai.client import MistralClient
api_key = os.environ.get("MISTRAL_API_KEY")
client = MistralClient(api_key=api_key)
with open("training_file.jsonl", "rb") as f:
    training_data = client.files.create(file=("training_file.jsonl", f))    
import MistralClient from '@mistralai/mistralai';
const apiKey = process.env.MISTRAL_API_KEY;
const client = new MistralClient(apiKey);
const file = fs.readFileSync('training_file.jsonl');
const training_data = await client.files.create({ file });
const file = fs.readFileSync('validation_file.jsonl');
const validation_data = await client.files.create({ file });
curl https://api.mistral.ai/v1/files \
  -H "Authorization: Bearer $MISTRAL_API_KEY" \
  -F purpose="fine-tune" \
  -F file="@training_file.jsonl"
curl https://api.mistral.ai/v1/files \
  -H "Authorization: Bearer $MISTRAL_API_KEY" \
  -F purpose="fine-tune" \
  -F file="@validation_file.jsonl"
Create a fine-tuning job
The next step is to create a fine-tuning job.
- model: the specific model you would like to fine-tune. The choices are open-mistral-7b(v0.3) andmistral-small-latest(mistral-small-2402).
- training_files: a collection of training file IDs, which can consist of a single file or multiple files
- validation_files: a collection of validation file IDs, which can consist of a single file or multiple files
- hyperparameters: two adjustable hyperparameters, "training_step" and "learning_rate", that users can modify.
- python
- javascript
- curl
from mistralai.models.jobs import TrainingParameters
created_jobs = client.jobs.create(
    model="open-mistral-7b",
    training_files=[training_data.id],
    validation_files=[validation_data.id],
    hyperparameters=TrainingParameters(
        training_steps=10,
        learning_rate=0.0001,
        )
)
created_jobs
const createdJob = await client.jobs.create({
  model: 'open-mistral-7b',
  trainingFiles: [training_data.id],
  validationFiles: [validation_data.id],
  hyperparameters: {
    trainingSteps: 10,
    learningRate: 0.0001,
  },
});
curl https://api.mistral.ai/v1/fine_tuning/jobs \
--header "Authorization: Bearer $MISTRAL_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
  "model": "open-mistral-7b",
  "training_files": [
    "<uuid>"
  ],
  "validation_files": [
    "<uuid>"
  ],
  "hyperparameters": {
    "training_steps": 10,
    "learning_rate": 0.0001
  }
}'
List/retrieve/cancel jobs
You can also list jobs, retrieve a job, or cancel a job.
You can filter and view a list of jobs using various parameters such as
page, page_size, model, created_after, created_by_me, status, wandb_project, wandb_name, and suffix. Check out our API specs for details.
- python
- javascript
- curl
# List jobs
jobs = client.jobs.list()
print(jobs)
# Retrieve a jobs
retrieved_jobs = client.jobs.retrieve(created_jobs.id)
print(retrieved_jobs)
# Cancel a jobs
canceled_jobs = client.jobs.cancel(created_jobs.id)
print(canceled_jobs)
// List jobs
const jobs = await client.jobs.list();
// Retrieve a job
const retrievedJob = await client.jobs.retrieve({ jobId: createdJob.id });
// Cancel a job
const canceledJob = await client.jobs.cancel({ jobId: createdJob.id });
# List jobs
curl https://api.mistral.ai/v1/fine_tuning/jobs \
--header "Authorization: Bearer $MISTRAL_API_KEY" \
--header 'Content-Type: application/json'
# Retrieve a job
curl https://api.mistral.ai/v1/fine_tuning/jobs/<jobid> \
--header "Authorization: Bearer $MISTRAL_API_KEY" \
--header 'Content-Type: application/json'
# Cancel a job
curl -X POST https://api.mistral.ai/v1/fine_tuning/jobs/<jobid>/cancel \
--header "Authorization: Bearer $MISTRAL_API_KEY" \
--header 'Content-Type: application/json'
Use a fine-tuned model
When a fine-tuned job is finished, you will be able to see the fine-tuned model name via retrieved_jobs.fine_tuned_model. Then you can use our chat endpoint to chat with the fine-tuned model:
- python
- javascript
- curl
from mistralai.models.chat_completion import ChatMessage
chat_response = client.chat(
    model=retrieved_job.fine_tuned_model,
    messages=[ChatMessage(role='user', content='What is the best French cheese?')]
)
const chatResponse = await client.chat({
  model: retrievedJob.fine_tuned_model,
  messages: [{role: 'user', content: 'What is the best French cheese?'}],
});
curl "https://api.mistral.ai/v1/chat/completions" \
     --header 'Content-Type: application/json' \
     --header 'Accept: application/json' \
     --header "Authorization: Bearer $MISTRAL_API_KEY" \
     --data '{
    "model": "ft:open-mistral-7b:daf5e488:20240430:c1bed559",
    "messages": [{"role": "user", "content": "Who is the most renowned French painter?"}]
  }'
Delete a fine-tuned model
- python
- curl
client.delete_model(retrieved_job.fine_tuned_model)
curl --location --request DELETE 'https://api.mistral.ai/v1/models/ft:open-mistral-7b:XXX:20240531:XXX' \
     --header 'Accept: application/json' \
     --header "Authorization: Bearer $MISTRAL_API_KEY"