Before you start
Prepare:| Input | Description |
|---|---|
| Training file | A JSONL file with your training examples. Upload it with purpose: "fine-tune". |
| Validation file | Optional JSONL validation data. Upload it with purpose: "fine-tune". |
| Base model | The model ID you want to fine-tune, for example meetkai:functionary-medium. |
validating_files -> queued -> running -> succeeded
\-> paused
\-> failed
\-> cancelled
Step 1 - Upload your training files
Upload each JSONL file with the Files API andpurpose: "fine-tune".
mka1 llm files upload \
--file ./fine-tuning-train.jsonl \
--purpose fine-tune \
-H 'X-On-Behalf-Of: <end-user-id>'
mka1 llm files upload \
--file ./fine-tuning-validation.jsonl \
--purpose fine-tune
import { SDK } from '@meetkai/mka1';
const mka1 = new SDK({
bearerAuth: 'Bearer <mka1-api-key>',
});
const trainingFile = await mka1.llm.files.upload(
{
requestBody: {
file: Bun.file('./fine-tuning-train.jsonl'),
purpose: 'fine-tune',
},
},
{
headers: {
'X-On-Behalf-Of': '<end-user-id>',
},
}
);
const validationFile = await mka1.llm.files.upload(
{
requestBody: {
file: Bun.file('./fine-tuning-validation.jsonl'),
purpose: 'fine-tune',
},
},
{
headers: {
'X-On-Behalf-Of': '<end-user-id>',
},
}
);
console.log(trainingFile.id);
console.log(validationFile.id);
using System.Text;
using MeetKai.MKA1;
using MeetKai.MKA1.Types.Components;
using MeetKai.MKA1.Types.Requests;
var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");
var trainingFile = await sdk.Llm.Files.UploadAsync(new UploadFileRequestBody()
{
File = new UploadFileFile()
{
FileName = "fine-tuning-train.jsonl",
Content = File.ReadAllBytes("./fine-tuning-train.jsonl"),
},
Purpose = UploadFilePurpose.FineTune,
});
Console.WriteLine(trainingFile.File!.Id);
from meetkai_mka1 import SDK
sdk = SDK(bearer_auth="Bearer YOUR_API_KEY")
training_file = sdk.llm.files.upload(
file={"file_name": "fine-tuning-train.jsonl", "content": open("./fine-tuning-train.jsonl", "rb")},
purpose="fine-tune",
)
validation_file = sdk.llm.files.upload(
file={"file_name": "fine-tuning-validation.jsonl", "content": open("./fine-tuning-validation.jsonl", "rb")},
purpose="fine-tune",
)
print(training_file.id)
print(validation_file.id)
curl https://apigw.mka1.com/api/v1/llm/files \
--request POST \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>' \
--form 'file=@./fine-tuning-train.jsonl;type=application/jsonl' \
--form 'purpose=fine-tune'
Step 2 - Create a fine-tuning job
Callmka1.llm.fineTuning.create with the base model and your uploaded training file ID.
Add a validation file, suffix, metadata, and method settings when you need them.
mka1 llm fine-tuning create --body '{
"model": "meetkai:functionary-medium",
"training_file": "file-abc123",
"validation_file": "file-def456",
"suffix": "support-bot",
"seed": 42,
"method": {
"type": "supervised",
"supervised": {
"hyperparameters": {
"n_epochs": 3
}
}
},
"metadata": {
"experiment": "support-bot-v1"
}
}'
const job = await mka1.llm.fineTuning.create(
{
model: 'meetkai:functionary-medium',
trainingFile: trainingFile.id,
validationFile: validationFile.id,
suffix: 'support-bot',
seed: 42,
method: {
type: 'supervised',
supervised: {
hyperparameters: {
nEpochs: 3,
},
},
},
metadata: {
experiment: 'support-bot-v1',
},
},
requestOptions
);
console.log(job.id); // "ftjob_aa87e2b1112a455b8deabed784372198"
console.log(job.status); // "validating_files" | "queued" | "running" | ...
console.log(job.fineTunedModel); // null until the job succeeds
using MeetKai.MKA1;
using MeetKai.MKA1.Types.Components;
var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");
var job = await sdk.Llm.FineTuning.CreateAsync(new CreateFineTuningJobRequest()
{
Model = "meetkai:functionary-medium",
TrainingFile = trainingFile.File!.Id,
Suffix = "support-bot",
Seed = 42,
Method = new Method()
{
Type = MethodType.Supervised,
Supervised = new Supervised()
{
Hyperparameters = new SupervisedHyperparameters()
{
NEpochs = SupervisedHyperparametersNEpochs.CreateInteger(3),
},
},
},
});
Console.WriteLine(job.FineTuningJob!.Id); // "ftjob_aa87e2b1112a455b8deabed784372198"
Console.WriteLine(job.FineTuningJob!.Status); // "validating_files" | "queued" | "running" | ...
job = sdk.llm.fine_tuning.create(
model="meetkai:functionary-medium",
training_file=training_file.id,
validation_file=validation_file.id,
suffix="support-bot",
seed=42,
method={
"type": "supervised",
"supervised": {
"hyperparameters": {
"n_epochs": 3,
},
},
},
metadata={"experiment": "support-bot-v1"},
)
print(job.id) # "ftjob_aa87e2b1112a455b8deabed784372198"
print(job.status) # "validating_files" | "queued" | "running" | ...
print(job.fine_tuned_model) # None until the job succeeds
curl https://apigw.mka1.com/api/v1/llm/fine_tuning/jobs \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>' \
--data '{
"model": "meetkai:functionary-medium",
"training_file": "file-abc123",
"validation_file": "file-def456",
"suffix": "support-bot",
"seed": 42,
"method": {
"type": "supervised",
"supervised": {
"hyperparameters": {
"n_epochs": 3
}
}
},
"metadata": {
"experiment": "support-bot-v1"
}
}'
Step 3 - Poll job status
Retrieve the job until it reachessucceeded, failed, or cancelled.
mka1 llm fine-tuning retrieve \
--fine-tuning-job-id ftjob_aa87e2b1112a455b8deabed784372198
async function waitForFineTuningJob(
fineTuningJobId: string,
timeoutMs = 30 * 60_000
) {
const terminalStatuses = new Set(['succeeded', 'failed', 'cancelled']);
const start = Date.now();
while (Date.now() - start < timeoutMs) {
const current = await mka1.llm.fineTuning.retrieve(
{ fineTuningJobId },
requestOptions
);
if (terminalStatuses.has(current.status)) {
return current;
}
await new Promise((resolve) => setTimeout(resolve, 10_000));
}
throw new Error(`Fine-tuning job ${fineTuningJobId} did not finish in time`);
}
const completedJob = await waitForFineTuningJob(job.id);
if (completedJob.status === 'succeeded') {
console.log(completedJob.fineTunedModel);
} else {
console.log(completedJob.error);
}
using MeetKai.MKA1;
using MeetKai.MKA1.Types.Components;
var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");
var retrieved = await sdk.Llm.FineTuning.RetrieveAsync(jobId);
Console.WriteLine(retrieved.FineTuningJob!.Status);
import time
def wait_for_fine_tuning_job(sdk, job_id, timeout_ms=30 * 60_000):
terminal = {"succeeded", "failed", "cancelled"}
start = time.time() * 1000
while (time.time() * 1000) - start < timeout_ms:
current = sdk.llm.fine_tuning.retrieve(fine_tuning_job_id=job_id)
if current.status in terminal:
return current
time.sleep(10)
raise TimeoutError(f"Fine-tuning job {job_id} did not finish in time")
completed_job = wait_for_fine_tuning_job(sdk, job.id)
if completed_job.status == "succeeded":
print(completed_job.fine_tuned_model)
else:
print(completed_job.error)
curl https://apigw.mka1.com/api/v1/llm/fine_tuning/jobs/ftjob_aa87e2b1112a455b8deabed784372198 \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>'
mka1.llm.fineTuning.list({ limit, after }).
Step 4 - Inspect training events and checkpoints
Use events for training logs and metrics updates. Use checkpoints to inspect intermediate model checkpoints and their metrics.mka1 llm fine-tuning list-events \
--fine-tuning-job-id ftjob_aa87e2b1112a455b8deabed784372198 \
--limit 20
mka1 llm fine-tuning list-checkpoints \
--fine-tuning-job-id ftjob_aa87e2b1112a455b8deabed784372198 \
--limit 10
const events = await mka1.llm.fineTuning.listEvents(
{
fineTuningJobId: job.id,
limit: 20,
},
requestOptions
);
for (const event of events.data) {
console.log(event.createdAt, event.level, event.message, event.data);
}
const checkpoints = await mka1.llm.fineTuning.listCheckpoints(
{
fineTuningJobId: job.id,
limit: 10,
},
requestOptions
);
for (const checkpoint of checkpoints.data) {
console.log(
checkpoint.stepNumber,
checkpoint.fineTunedModelCheckpoint,
checkpoint.metrics
);
}
using MeetKai.MKA1;
var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");
var events = await sdk.Llm.FineTuning.ListEventsAsync(
fineTuningJobId: jobId, limit: 20);
var checkpoints = await sdk.Llm.FineTuning.ListCheckpointsAsync(
fineTuningJobId: jobId, limit: 10);
events = sdk.llm.fine_tuning.list_events(
fine_tuning_job_id=job.id,
limit=20,
)
for event in events.data:
print(event.created_at, event.level, event.message, event.data)
checkpoints = sdk.llm.fine_tuning.list_checkpoints(
fine_tuning_job_id=job.id,
limit=10,
)
for checkpoint in checkpoints.data:
print(checkpoint.step_number, checkpoint.fine_tuned_model_checkpoint, checkpoint.metrics)
curl "https://apigw.mka1.com/api/v1/llm/fine_tuning/jobs/ftjob_aa87e2b1112a455b8deabed784372198/events?limit=20" \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>'
curl "https://apigw.mka1.com/api/v1/llm/fine_tuning/jobs/ftjob_aa87e2b1112a455b8deabed784372198/checkpoints?limit=10" \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>'
train_loss, train_mean_token_accuracy, valid_loss, valid_mean_token_accuracy, full_valid_loss, and full_valid_mean_token_accuracy.
Step 5 - Pause, resume, or cancel a job
Usepause when you need to temporarily stop a running job.
Use resume to continue it.
Use cancel to stop it permanently.
mka1 llm fine-tuning pause \
--fine-tuning-job-id ftjob_aa87e2b1112a455b8deabed784372198
mka1 llm fine-tuning resume \
--fine-tuning-job-id ftjob_aa87e2b1112a455b8deabed784372198
mka1 llm fine-tuning cancel \
--fine-tuning-job-id ftjob_aa87e2b1112a455b8deabed784372198
await mka1.llm.fineTuning.pause(
{ fineTuningJobId: job.id },
requestOptions
);
await mka1.llm.fineTuning.resume(
{ fineTuningJobId: job.id },
requestOptions
);
await mka1.llm.fineTuning.cancel(
{ fineTuningJobId: job.id },
requestOptions
);
using MeetKai.MKA1;
var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");
// Pause
await sdk.Llm.FineTuning.PauseAsync(jobId);
// Resume
await sdk.Llm.FineTuning.ResumeAsync(jobId);
// Cancel
var cancelled = await sdk.Llm.FineTuning.CancelAsync(jobId);
Console.WriteLine(cancelled.FineTuningJob!.Status);
# Pause
sdk.llm.fine_tuning.pause(fine_tuning_job_id=job.id)
# Resume
sdk.llm.fine_tuning.resume(fine_tuning_job_id=job.id)
# Cancel
sdk.llm.fine_tuning.cancel(fine_tuning_job_id=job.id)
curl https://apigw.mka1.com/api/v1/llm/fine_tuning/jobs/ftjob_aa87e2b1112a455b8deabed784372198/pause \
--request POST \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>'
curl https://apigw.mka1.com/api/v1/llm/fine_tuning/jobs/ftjob_aa87e2b1112a455b8deabed784372198/resume \
--request POST \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>'
curl https://apigw.mka1.com/api/v1/llm/fine_tuning/jobs/ftjob_aa87e2b1112a455b8deabed784372198/cancel \
--request POST \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>'
Step 6 - Use the fine-tuned model
When the job reachessucceeded, job.fineTunedModel contains the new model ID.
Pass that model ID to a Responses request.
mka1 llm responses create \
--model ft:meetkai:functionary-medium:support-bot \
--input '"Write a support reply for a delayed shipment."'
import type { ResponseObject } from '@meetkai/mka1/models/components';
const response = await mka1.llm.responses.create({
xOnBehalfOf: '<end-user-id>',
responsesCreateRequest: {
model: completedJob.fineTunedModel!,
input: 'Write a support reply for a delayed shipment.',
},
}) as ResponseObject;
console.log(response.outputText);
using MeetKai.MKA1;
using MeetKai.MKA1.Types.Components;
var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");
var response = await sdk.Llm.Responses.CreateAsync(new ResponsesCreateRequest()
{
Model = completedJob.FineTuningJob!.FineTunedModel!,
Input = ResponsesCreateRequestInput.CreateStr(
"Write a support reply for a delayed shipment."),
});
response = sdk.llm.responses.create(
model=completed_job.fine_tuned_model,
input="Write a support reply for a delayed shipment.",
)
print(response.output_text)
curl https://apigw.mka1.com/api/v1/llm/responses \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <mka1-api-key>' \
--header 'X-On-Behalf-Of: <end-user-id>' \
--data '{
"model": "ft:meetkai:functionary-medium:support-bot",
"input": "Write a support reply for a delayed shipment."
}'