Fine-Tuning
Fine-Tuning
toothfairyai@latest…Manager for fine-tuning operations.
This manager provides methods to list trainable models, generate datasets, start training, monitor job status, and cancel training jobs.
Example:
>>> client = ToothFairyClient(api_key="...", workspace_id="...")
>>> models = client.finetuning.list_models()
>>> job = client.finetuning.generate_dataset(
... name="my-sft-job",
... training_type="conversationalTraining",
... base_model="toothfairyai/Llama-3.2-1B-Instruct"
... )
>>> status = client.finetuning.get_status(job["training_log_id"])
Accessed via client.finetuning.
Methods
| Method | HTTP | Endpoint |
|---|---|---|
list_models | GET | GET /models |
list_jobs | GET | GET /jobs |
generate_dataset | POST | POST /dataset |
get_status | GET | GET /status/{training_log_id} |
start_training | POST | POST /start/{training_log_id} |
cancel_training | POST | POST /cancel/{training_log_id} |
download_dataset | GET | GET /dataset/{training_log_id} |
list_adapters | GET | GET /adapters |
create_adapter_version | POST | POST /adapters/{training_log_id}/version |
rollback_adapter | POST | POST /adapters/{training_log_id}/rollback |
get_serving | GET | GET /serving/{training_log_id} |
set_serving | POST | POST /serving/{training_log_id} |
serving_power | POST | POST /serving/{training_log_id}/power |
generate_training_data | POST | POST /magicwand |
list_models
List all trainable models with their configurations.
def list_models() -> List[TrainableModel]
Endpoint: GET /models · Fine-Tuning service
Example
client.finetuning.list_models()
list_jobs
List all fine-tuning jobs for the authenticated workspace.
def list_jobs() -> List[TrainingJob]
Endpoint: GET /jobs · Fine-Tuning service
Example
client.finetuning.list_jobs()
generate_dataset
Generate a training dataset from workspace documents.
def generate_dataset(
name: str,
base_model: str,
training_type: str = 'conversationalTraining',
topics: Optional[List[str]] = None,
test_size: Optional[float] = None,
test_size_threshold: Optional[int] = None,
description: Optional[str] = None
) -> Dict[str, Any]
Endpoint: POST /dataset · Fine-Tuning service
Request fields
| Python kwarg | Wire field | Type | Required | Description |
|---|---|---|---|---|
name | name | string | yes | Human-readable name for the training job |
training_type | training_type | string | no | Training method to use. Each method maps to a document type: |
conversationalTraining(SFT) — uses Conversation documentsgenerativeTraining(DPO) — uses Preference documentsgrpoTraining(GRPO) — uses Conversation documents (model self-generates)ktoTraining(KTO) — uses Preference documents (unpaired)continuedPretraining(CPT) — uses Conversation documents (plain text)
Defaults to conversationalTraining. Note: the REST endpoint does not enforce the enum at request time (validation occurs in the async worker); send one of the listed values.
Allowed: conversationalTraining, generativeTraining, grpoTraining, ktoTraining, continuedPretraining |
| base_model | base_model | string | yes | Base model to fine-tune (canonical id from the /models endpoint) |
| topics | topics | array<string> | no | Optional list of topic IDs to filter documents by |
| test_size | test_size | number | no | Fraction of the dataset to reserve as the test split (0.0–1.0) |
| test_size_threshold | test_size_threshold | integer | no | Minimum number of examples required in the test split |
| description | description | string | no | Optional human-readable description of the training job |
Always pass
snake_casekeyword arguments — the Python kwarg column shows the exact name to use for each wire field (as a named parameter where it appears in the method signature, otherwise via**kwargs). The SDK converts it deterministically to thecamelCasewire key the API expects. PassingcamelCasedirectly is deprecated: it emits a warning and converts to the same wire key.
Example
client.finetuning.generate_dataset(name="…", base_model="…")
get_status
Get detailed status of a fine-tuning job.
def get_status(training_log_id: str) -> TrainingStatusResponse
Endpoint: GET /status/{training_log_id} · Fine-Tuning service
Response fields
| Field | Type | Description |
|---|---|---|
training_log_id | string | Training log ID |
status | string | Current job status. Lifecycle: dispatched → inProgress → datasetReady → fineTuningRequested → training → completed (or inError). |
Allowed: dispatched, inProgress, datasetReady, fineTuningRequested, training, completed, inError, cancellationRequested |
| name | string | Job name |
| training_type | string | Training method |
| created_at | string | Job creation timestamp (ISO 8601) |
| duration | integer | Training duration in seconds (present once training has progressed) |
| dataset | object | Dataset paths (present after dataset generation reaches the relevant stage) |
| compute_uoi | number | UoI consumed by the training job (present when status is completed) |
| model_id | string | S3 path to the fine-tuned LoRA adapter (present when status is completed) |
| base_model | string | Base model used for training (present when status is completed) |
| metrics_summary | object | Final training metrics (present when status is completed) |
| downloads | object | Presigned download URLs (present when status is completed) |
| error | object | Error detail (present when status is inError) |
Example
client.finetuning.get_status(training_log_id="agent-id")
start_training
Start a fine-tuning training job.
def start_training(
training_log_id: str,
config: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]
Endpoint: POST /start/{training_log_id} · Fine-Tuning service
Request fields
| Python kwarg | Wire field | Type | Required | Description |
|---|---|---|---|---|
config | config | object | no | Training configuration overrides merged over the existing training configuration. Keys not present retain their prior values. Only the keys listed in x-recognized-config-keys are consumed by the managed Unsloth/QLoRA+SageMaker training engine; any other key is silently persisted but ignored. Evaluation and checkpoint frequency are controllable via evalStrategy*/evalSteps*, saveStrategy*/saveSteps*, and checkpointsNumber* (save_total_limit). |
Always pass
snake_casekeyword arguments — the Python kwarg column shows the exact name to use for each wire field (as a named parameter where it appears in the method signature, otherwise via**kwargs). The SDK converts it deterministically to thecamelCasewire key the API expects. PassingcamelCasedirectly is deprecated: it emits a warning and converts to the same wire key.
Example
client.finetuning.start_training(training_log_id="agent-id")
cancel_training
Cancel a running fine-tuning job.
def cancel_training(training_log_id: str) -> Dict[str, Any]
Endpoint: POST /cancel/{training_log_id} · Fine-Tuning service
Example
client.finetuning.cancel_training(training_log_id="agent-id")
download_dataset
Get a presigned download URL for a job's generated dataset.
def download_dataset(
training_log_id: str,
which: str = 'dataset'
) -> DatasetDownloadResponse
Endpoint: GET /dataset/{training_log_id} · Fine-Tuning service
Example
client.finetuning.download_dataset(training_log_id="agent-id")
list_adapters
List completed LoRA adapters for the workspace (adapter registry).
def list_adapters(
base_model: Optional[str] = None,
limit: Optional[int] = None,
next_token: Optional[str] = None
) -> AdapterListResponse
Endpoint: GET /adapters · Fine-Tuning service
Example
client.finetuning.list_adapters()
create_adapter_version
Snapshot a completed adapter as an immutable version (vN).
def create_adapter_version(
training_log_id: str,
label: Optional[str] = None
) -> AdapterVersionResponse
Endpoint: POST /adapters/{training_log_id}/version · Fine-Tuning service
Request fields
| Python kwarg | Wire field | Type | Required | Description |
|---|---|---|---|---|
label | label | string | no | Optional human-readable label for this version (e.g. "best-held-out", "promoted-2026-07"). |
Always pass
snake_casekeyword arguments — the Python kwarg column shows the exact name to use for each wire field (as a named parameter where it appears in the method signature, otherwise via**kwargs). The SDK converts it deterministically to thecamelCasewire key the API expects. PassingcamelCasedirectly is deprecated: it emits a warning and converts to the same wire key.
Response fields
| Field | Type | Description |
|---|---|---|
adapter_id | string | Training log ID of the snapshotted adapter |
version | integer | The version number assigned (1, 2, 3, …) |
snapshot | object | The immutable version record written to the manifest |
manifest_key | string | S3 key of the manifest storing this adapter's versions |
Example
client.finetuning.create_adapter_version(training_log_id="agent-id")
rollback_adapter
Get presigned artefacts to roll back to a pinned adapter version.
def rollback_adapter(
training_log_id: str,
version: Optional[int] = None
) -> AdapterRollbackResponse
Endpoint: POST /adapters/{training_log_id}/rollback · Fine-Tuning service
Request fields
| Python kwarg | Wire field | Type | Required | Description |
|---|---|---|---|---|
version | version | integer | no | Version number to roll back to (from a prior /version call). Omit to use the latest snapshot. |
Always pass
snake_casekeyword arguments — the Python kwarg column shows the exact name to use for each wire field (as a named parameter where it appears in the method signature, otherwise via**kwargs). The SDK converts it deterministically to thecamelCasewire key the API expects. PassingcamelCasedirectly is deprecated: it emits a warning and converts to the same wire key.
Response fields
| Field | Type | Description |
|---|---|---|
adapter_id | string | Training log ID the rollback was requested on |
rolled_back_to | integer | The version that was resolved (explicit version or latest); null when the latest snapshot was used implicitly |
target_adapter_id | string | The training log ID whose S3 prefix holds the target weights. May differ from adapter_id when rolling back along a parent-adapter lineage (a snapshot taken from a different completed job). |
weights_url | string | Presigned URL (valid 1h) to the pinned adapter_model.safetensors |
config_url | string | Presigned URL (valid 1h) to the pinned adapter_config.json, or null if the config file is absent in S3 |
base_model | string | Base model of the resolved snapshot (from the manifest, falling back to the training meta) |
inference_template | string | Inference chat-template key to use for serving this base model |
note | string | Explains that the inference switch is performed by the Chat routing layer; this endpoint only returns the pinned adapter artefacts. |
available_versions | array<integer> | Present only in the 404 response body (not on 200) when the requested version was not found — lists all known version numbers to aid retry. Returned here for reference. |
Example
client.finetuning.rollback_adapter(training_log_id="agent-id")
get_serving
Get the serving config and live lane state for a fine-tuned model.
def get_serving(training_log_id: str) -> ServingConfig
Endpoint: GET /serving/{training_log_id} · Fine-Tuning service
Response fields
| Field | Type | Description |
|---|---|---|
modelId | string | The fine-tuned model's API name (usable as model on chat-completions) |
trainingLogId | string | Training log ID that produced this fine-tuned model |
base_model | string | Trainable base the model was fine-tuned from |
inference_base | string | Canonical checkpoint the lane serves |
mode | string | Current serving mode |
Allowed: on-demand, scheduled, always |
| schedule | object | A recurring warm window in the given IANA timezone. end must be later than start (overnight windows are not supported). |
| lane | object | Live lane state for the fine-tuned model's inference lane. |
| warm_seconds_accrued | integer | Warm seconds accrued in the current billing day |
| warm_seconds_note | string | Billing note: warm hours bill daily in 1-hour units (minimum 1) at the size-tier hourly rate |
Example
client.finetuning.get_serving(training_log_id="agent-id")
set_serving
Set the serving mode for a fine-tuned model.
def set_serving(
training_log_id: str,
mode: str = 'on-demand',
schedule: Optional[Dict[str, Any]] = None
) -> ServingSetResponse
Endpoint: POST /serving/{training_log_id} · Fine-Tuning service
Request fields
| Python kwarg | Wire field | Type | Required | Description |
|---|---|---|---|---|
mode | mode | string | no | on-demand (default when omitted — wakes on first request, sleeps after ~15 min idle, $0 while idle), scheduled (warm inside recurring time windows), or always (kept warm continuously). |
Allowed: on-demand, scheduled, always |
| schedule | schedule | object | no | A recurring warm window in the given IANA timezone. end must be later than start (overnight windows are not supported). |
Always pass
snake_casekeyword arguments — the Python kwarg column shows the exact name to use for each wire field (as a named parameter where it appears in the method signature, otherwise via**kwargs). The SDK converts it deterministically to thecamelCasewire key the API expects. PassingcamelCasedirectly is deprecated: it emits a warning and converts to the same wire key.
Response fields
| Field | Type | Description |
|---|---|---|
modelId | string | The fine-tuned model's API name (usable as model on chat-completions) |
trainingLogId | string | Training log ID that produced this fine-tuned model |
mode | string | The stored serving mode |
Allowed: on-demand, scheduled, always |
| schedule | object | A recurring warm window in the given IANA timezone. end must be later than start (overnight windows are not supported). |
| mirrored_to_training_log | boolean | Whether the config was also mirrored onto the TrainingLog entity (inside trainingMeta) |
| note | string | scheduled/always modes take effect within ~2 minutes (the serving monitor picks up the change) |
Example
client.finetuning.set_serving(training_log_id="agent-id")
serving_power
Turn a fine-tuned model on or off right now.
def serving_power(
training_log_id: str,
state: str,
hours: Optional[int] = None
) -> ServingPowerResponse
Endpoint: POST /serving/{training_log_id}/power · Fine-Tuning service
Request fields
| Python kwarg | Wire field | Type | Required | Description |
|---|---|---|---|---|
state | state | string | yes | on = wake and hold warm for hours; off = release the hold now |
Allowed: on, off |
| hours | hours | integer | no | Hours to hold the lane warm (minimum 1, 1-hour billing units) |
Always pass
snake_casekeyword arguments — the Python kwarg column shows the exact name to use for each wire field (as a named parameter where it appears in the method signature, otherwise via**kwargs). The SDK converts it deterministically to thecamelCasewire key the API expects. PassingcamelCasedirectly is deprecated: it emits a warning and converts to the same wire key.
Response fields
| Field | Type | Description |
|---|---|---|
modelId | string | The fine-tuned model's API name |
trainingLogId | string | Training log ID that produced this fine-tuned model |
state | string | The power state applied |
Allowed: on, off |
| hours | integer | Hours booked (0 for off) |
| lane | object | Lane result returned by the serving power endpoint. With state: on, the orchestrator returns the lane's status plus pinned_until (epoch seconds the lane is held warm until). With state: off, it returns status: unpinned and the lane idles out per normal rules (up to 15 min grace). |
| billing_note | string | Warm hours accrue while held and bill daily in 1-hour units (minimum 1) |
Example
client.finetuning.serving_power(training_log_id="agent-id", state="…")
generate_training_data
Transform a chat conversation or uploaded file into training data.
def generate_training_data(
chat_id: Optional[str] = None,
file_key: Optional[str] = None,
training_type: str = 'conversationalTraining',
user_id: Optional[str] = None,
create_document: bool = True,
system_message: Optional[str] = None,
instructions: Optional[str] = None,
title: Optional[str] = None,
topics: Optional[List[str]] = None,
status: str = 'draft',
scope: str = 'training',
non_preferred_responses: Optional[List[Dict[str, Any]]] = None,
tools: Optional[List[Dict[str, Any]]] = None,
generate_non_preferred: bool = False,
chunk_size: Optional[int] = None,
overlap_percent: Optional[float] = None,
num_turns: Optional[int] = None,
samples_per_chunk: Optional[int] = None
) -> Dict[str, Any]
Endpoint: POST /magicwand · AI service
Request fields
| Python kwarg | Wire field | Type | Required | Description |
|---|---|---|---|---|
chatid | chatid | string | no | Chat mode: Unique chat session identifier to extract messages from. Mutually exclusive with file_key. |
file_key | file_key | string | no | File mode: S3 key of uploaded file to generate training data from. Obtain via /documents/requestPreSignedURL endpoint. Mutually exclusive with chatid. |
Supported formats: PDF, DOCX, XLSX, PPTX, TXT, MD, CSV, JSON, HTML, XML |
| workspace_id | workspaceid | string | yes | Unique workspace identifier |
| userid | userid | string | no | User identifier performing the operation |
| chunk_size | chunk_size | integer | no | File mode only: Target size of each text chunk in characters. Larger chunks provide more context but generate fewer training samples. |
| overlap_percent | overlap_percent | number | no | File mode only: Percentage of overlap between adjacent chunks to preserve context continuity. |
| num_turns | num_turns | integer | no | File mode only: Number of conversation turns (user-assistant pairs) to generate per chunk. Each turn adds a question and answer. |
| samples_per_chunk | samples_per_chunk | integer | no | File mode only: Number of independent training samples to generate per chunk. Useful for data augmentation. |
| create_document | create_document | boolean | no | Whether to create a training document in the knowledge hub. If false, only returns the transformed data without persisting. |
| system_message | system_message | string | no | Custom system message to prepend to the training data. If not provided, a default message will be used. |
| instructions | instructions | string | no | Optional instructions to refine the training data output.
Chat mode: Refine conversation messages. File mode: Guide conversation synthesis from document content.
Examples:
- "Focus on technical accuracy"
- "Remove any personal information"
- "Make the tone more professional"
- "Include code examples where relevant" |
|
title|title|string| no | Title for the training document (only used when create_document is true) | |topics|topics|array<string>| no | Topic IDs to tag the training document with (only used when create_document is true) | |training_type|training_type|string| no | Training method to use
Allowed: conversationalTraining, generativeTraining, grpoTraining, ktoTraining, continuedPretraining |
| non_preferred_responses | non_preferred_responses | array<string> | no | For DPO training: List of non-preferred responses. Only used when training_type is 'generativeTraining' (chat mode only). |
| generate_non_preferred | generate_non_preferred | boolean | no | For DPO training: Auto-generate non-preferred responses using AI. Only used when training_type is 'generativeTraining' (chat mode only). |
| tools | tools | array<object> | no | Optional tools/functions for function calling training (chat mode only). |
| scope | scope | string | no | The scope of the training document:
training(default): Document will be used for model trainingvalidation: Document will be used for model validation/evaluation
Allowed: training, validation |
| status | status | string | no | Status for the created training document
Allowed: draft, published |
Always pass
snake_casekeyword arguments — the Python kwarg column shows the exact name to use for each wire field (as a named parameter where it appears in the method signature, otherwise via**kwargs). The SDK converts it deterministically to thecamelCasewire key the API expects. PassingcamelCasedirectly is deprecated: it emits a warning and converts to the same wire key.
Response fields
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the operation completed successfully |
rawTrainingData | object | The transformed conversation in training data format |
messageCount | integer | Total number of messages in the generated training data |
chatId | string | Source chat identifier (chat mode only, null for file mode) |
fileKey | string | Source file S3 key (file mode only, null for chat mode) |
sourceType | string | Indicates whether training data was generated from chat or file |
Allowed: chat, file |
| documentCreated | boolean | Whether a training document was created in the knowledge hub |
| instructionsApplied | boolean | Whether custom instructions were applied to transform the data |
| trainingType | string | The type of training data generated
Allowed: conversationalTraining, generativeTraining |
| scope | string | The scope of the training document
Allowed: training, validation |
| chunksProcessed | integer | Number of chunks processed (file mode only) |
| samplesGenerated | integer | Number of training samples generated (file mode only) |
| chunksConfig | object | Configuration used for chunking (file mode only) |
| document | object | Created document details (only present when create_document is true) |
Example
client.finetuning.generate_training_data()