Model Fine-Tuning
Provon can train adapters and small models from project Datasets and serve the resulting checkpoints behind the AI Gateway. The Node runtime owns job scheduling, checkpoint trackin
Node does not spawn Python child processes for training. It calls the Python service over HTTP, which keeps PyTorch, Transformers, and PEFT dependencies out of the Node process.
When To Use It#
Use model fine-tuning when you have curated Dataset examples and want to:
- improve model behavior on a recurring task shape seen in traces;
- produce a project-specific checkpoint that stays inside your infrastructure;
- compare a fine-tuned checkpoint against the base model in the Playground.
Fine-tuning is a follow-up step after Dataset collection. See Datasets for how training examples are produced and validated.
Architecture#
flowchart LR dataset["Dataset examples"] --> node["Node runtime"] node --> manifest["Dataset manifest"] manifest --> python["services/python-fine-tuning"] python --> checkpoint["Checkpoint artifact"] checkpoint --> runtime["Model runtime"] runtime --> gateway["AI Gateway self/ target"]
The Node runtime:
- validates the Dataset schema and example count;
- materializes a training manifest from the Dataset;
- submits the job to
services/python-fine-tuning; - polls for status and stores checkpoint metadata;
- registers completed checkpoints for inference and optionally auto-deploys them.
Supported Training Configuration#
| Dimension | Supported values |
|---|---|
| Engine | transformers |
| Method | sft (API/CLI current); dpo, orpo, kto implemented in Python service only |
| Adapter | lora, qlora, full |
| Output format | safetensors, gguf |
| GGUF quantization | q4_0, q4_k_m, q4_k_s, q5_0, q5_k_m, q6_k, q8_0, f16, bf16, f32 |
| Compressed quantization | fp8, fp8_dynamic, fp8_static, int8 |
Output format determines the default inference engine when the checkpoint is deployed: Safetensors checkpoints are typically served by vLLM or SGLang; GGUF checkpoints are served by llama.cpp. Compressed quantization produces safetensors checkpoints with compressed-tensor metadata for efficient vLLM/SGLang serving; static FP8 requires a calibration dataset.
sftuses chat-formatted examples.dpo,orpo, andktouse preference-format examples (prompt/chosen/rejectedfor DPO/ORPO,prompt/completion/labelfor KTO). These methods are implemented inservices/python-fine-tuningbut are not yet exposed through the API or CLI; create jobs withmethod: "sft"for now.
Create A Fine-Tuning Job#
A job references a base model and a Dataset:
curl -X POST "$PROVON_API_URL/projects/$PROJECT_ID/fine-tuning/jobs" \
-H "Authorization: Bearer $PROVON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"baseModelId": "<base-model-id>",
"datasetId": "<dataset-id>",
"engine": "transformers",
"method": "sft",
"adapter": "lora",
"hyperparameters": {
"learningRate": 0.0001,
"numTrainEpochs": 3,
"perDeviceTrainBatchSize": 1
},
"output": {
"format": "safetensors"
}
}'The base model must already be known to the runtime. The Dataset must use the chat schema with at
least one example.
Job Lifecycle#
Jobs move through queued, running, completed, failed, and cancelled. Poll status:
curl "$PROVON_API_URL/projects/$PROJECT_ID/fine-tuning/jobs/$JOB_ID" \
-H "Authorization: Bearer $PROVON_API_KEY"Cancel a running job:
curl -X POST "$PROVON_API_URL/projects/$PROJECT_ID/fine-tuning/jobs/$JOB_ID/cancel" \
-H "Authorization: Bearer $PROVON_API_KEY"Tuning Configs#
A tuning config is a reusable recipe that binds a base model, a Dataset, hyperparameters, and an output format. You can create configs through the API and reuse them to start jobs, or enable automatic triggers and deployment.
curl -X POST "$PROVON_API_URL/projects/$PROJECT_ID/fine-tuning/tuning-configs" \
-H "Authorization: Bearer $PROVON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"baseModelId": "<base-model-id>",
"datasetId": "<dataset-id>",
"engine": "transformers",
"method": "sft",
"adapter": "lora",
"hyperparameters": {
"learningRate": 0.0001,
"numTrainEpochs": 3
},
"output": {
"format": "safetensors"
},
"autoTrigger": {
"enabled": true,
"minExampleCount": 10
},
"autoDeploy": {
"enabled": true
}
}'autoTriggerstarts a new job automatically when the Dataset reachesminExampleCountnew examples.autoDeploydeploys the resulting checkpoint to the model runtime when the job completes successfully.
List, update, and delete configs with the same path pattern. Exact request and response shapes are in the Fine-Tuning API.
Checkpoints#
When a job completes, it produces a checkpoint stored in the project checkpoint registry. List checkpoints:
curl "$PROVON_API_URL/projects/$PROJECT_ID/fine-tuning/checkpoints" \
-H "Authorization: Bearer $PROVON_API_KEY"Deploy a checkpoint to the model runtime:
curl -X POST "$PROVON_API_URL/projects/$PROJECT_ID/fine-tuning/checkpoints/$CHECKPOINT_ID/deploy" \
-H "Authorization: Bearer $PROVON_API_KEY"Deployment loads the checkpoint into the model runtime and makes it available as a self/ Gateway
target. The checkpoint must have a registered inference profile.
Lineage#
Trace the provenance of a model:
curl "$PROVON_API_URL/projects/$PROJECT_ID/fine-tuning/lineage/$ROOT_MODEL_ID" \
-H "Authorization: Bearer $PROVON_API_KEY"Lineage records the chain of base models, fine-tuning jobs, and checkpoints.
Export Checkpoints#
Export a checkpoint or a Hugging Face model to the Hugging Face Hub:
curl -X POST "$PROVON_API_URL/projects/$PROJECT_ID/fine-tuning/export" \
-H "Authorization: Bearer $PROVON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sourceType": "checkpoint",
"checkpointId": "<checkpoint-id>",
"format": "gguf",
"quantMethod": "q4_k_m",
"destination": "huggingface-hub",
"hfRepoId": "owner/repo"
}'Supported export formats are gguf and merged-16bit. lora-adapter export is not currently supported by the API.
Export requires a configured Hugging Face connector with a valid access token. The token is resolved from the project connector and passed to the export worker securely; it is not persisted on the job record.
Configuration#
Node runtime variables that control the fine-tuning and export background loops:
| Variable | Default | Purpose |
|---|---|---|
PROVON_PYTHON_FINE_TUNING_URL |
http://127.0.0.1:8001 |
Base URL of services/python-fine-tuning |
PROVON_PYTHON_FINE_TUNING_API_KEY |
none | Bearer token shared with Node |
PROVON_MODEL_FINE_TUNING_WORK_DIR |
none | Root for training temporary files and manifests |
PROVON_MODEL_EXPORT_WORK_DIR |
none | Root for export temporary files |
PROVON_MODEL_FINE_TUNING_INTERVAL_MS |
5000 | Poll interval for the fine-tuning consumer |
PROVON_MODEL_FINE_TUNING_LOCK_MS |
1,800,000 (30 min) | Lease duration for a fine-tuning job |
PROVON_MODEL_EXPORT_INTERVAL_MS |
5000 | Poll interval for the export consumer |
PROVON_MODEL_EXPORT_LOCK_MS |
3,600,000 (1 hour) | Lease duration for an export job |
The Python fine-tuning service is configured separately from Node:
| Variable | Default | Purpose |
|---|---|---|
PROVON_HOST |
0.0.0.0 |
Bind host |
PROVON_PORT |
8001 |
Bind port |
PROVON_API_KEY |
none | Bearer token shared with Node |
PROVON_LOG_LEVEL |
info |
Service log level |
PROVON_LLAMA_CPP_PATH |
llama.cpp |
Path to llama.cpp checkout for GGUF export |
Node and the Python service must see the training work directory at the same absolute path, because
training requests pass filesystem paths for the Dataset manifest and checkpoint output. When running
on different hosts, mount or replicate the configured PROVON_MODEL_FINE_TUNING_WORK_DIR so both
processes resolve the same paths.
Capability Requirements#
The project API key needs:
workspace:readorproject:data:readto list jobs, checkpoints, and lineage;models:manageorproject:data:writeto create jobs, cancel jobs, and export checkpoints;models:manageorproject:models:manageto deploy checkpoints.
Limitations#
- Fine-tuning is only available in the Node runtime. Cloudflare Workers do not provide local training or checkpoint storage.
- The current supported engine set is
transformers; others may be added over time. - GGUF export requires a local checkout of llama.cpp with
convert_hf_to_gguf.pyand thellama-quantizebinary. - Compressed quantization (FP8/INT8) requires the
compressedoptional dependency (llm-compressor) in the Python fine-tuning service.