Search Modaic documentation

Find a Modaic guide or API reference

Fine-tuning

New

Fine-tuning supports mo (mo-1.3.1) with head_only or lora training. Mo Fast is inference-only.

Upload a dataset

from modaic import Modaic

client = Modaic()
upload = client.knowledge_base.uploads.upload_file(
"train.jsonl", kind="dataset", name="support-labels", workspace="acme",
)
if upload.status != "completed" or upload.result is None:
raise RuntimeError(upload.error)
training_file = upload.result.name

File helpers handle chunking and wait for validation by default. TypeScript's file helper requires Node.js. Dataset and artifact uploads support files up to 8 GiB. Names use lowercase letters, digits, _, and -, start with a letter or digit, and are at most 128 characters. They are unique across datasets and artifacts. If you omit a name, the server generates one.

Dataset format

Use UTF-8 JSONL, one example per line. Each row contains state and an answers object with exactly one question ID. Use the same ID on every row; it must match the job's task_id (Python) or taskId (TypeScript).

{"state":"Checkout is unavailable","answers":{"urgent":true},"split":"train"}
{"state":"Can I change my invoice address?","answers":{"urgent":false},"split":"validation"}
{"state":"All payment attempts fail","answers":{"urgent":true},"split":"test"}

Labels are booleans for Noul, option keys for Choice, or zero-based integer levels for Score. This three-row example shows the format; use representative data for training.

Provide split on every row or omit it everywhere for automatic assignment. Training datasets need nonempty train, validation, and test partitions. Optional groupId keeps related rows in one partition; identical visible inputs must also stay in one partition. IDs, when supplied, must be unique. Limits: 1,000,000 rows, 1 MiB per line, no blank lines.

Optional questions overrides instructions for that row's task only: {"questions":{"urgent":{"instructions":"Does this block checkout?"}}}.

Start fine-tuning

For an existing model, its saved question schema is reused:

job = client.fine_tunes.create(
    model="acme/support-priority",
    training_file=training_file,
    task_id="urgent",
    training_type="head_only",
    idempotency_key="support-tune-v1",
)
job = client.fine_tunes.wait(job.id)
print(job.status, job.error)

To create a new model, pass model="mo", a destination such as acme/support-priority, and questions containing the task schema. training_type="lora" / trainingType: "lora" selects LoRA training.

Successful training publishes a new checkpoint to the selected model branch; the branch defaults to main. The REST request can set branch to publish an experiment without moving main, and can set tag to create an immutable name for the completed checkpoint. The branch must already exist. This lets an orchestrator such as Protégé train and evaluate on a working branch, then use the repository merge API to fast-forward main after it decides to promote the result.

After artifact validation, training selects the new weights in model.json with readiness unknown, then evaluates the exact immutable artifact commit. Held-out model quality becomes passed, warning, or unknown readiness metadata. Evaluation infrastructure failure leaves the checkpoint published with unknown readiness. Runtime compatibility and serving isolation are verified before deployment rather than reported as per-model readiness. Malformed or unloadable artifacts and identity mismatches still fail the job.

Optional controls include epochs, learning rate, batch size, and evaluation frequency. Python accepts controls={"n_epochs": 2}; TypeScript accepts nEpochs: 2 directly. Evaluations require validation_file / validationFile; early stopping also requires enough evaluations for warmup and patience. See create fine-tune for all fields.

Monitor or cancel

job = client.fine_tunes.get(job.id)
logs = client.fine_tunes.logs(job.id)
recent = client.fine_tunes.list(workspace="acme")
client.fine_tunes.cancel(job.id)

wait returns done, failed, or cancelled jobs. Check status and error; a timeout stops waiting without cancelling the job. The completed job's result.publication identifies the commit, branch, and optional tag.

Artifacts and downloads

Upload other files with kind="artifact". Artifacts are stored resources; they are not training datasets.

artifact = client.knowledge_base.uploads.upload_file(
    "report.pdf", kind="artifact", name="support-report", workspace="acme",
)
resources = client.knowledge_base.resources.list(workspace="acme", kind="artifact")
metadata = client.knowledge_base.resources.get("support-report", workspace="acme")
content = client.knowledge_base.resources.download("support-report", workspace="acme")

For another resource page, pass both the returned cursor and commit: cursor=resources.next_cursor, commit_sha=resources.commit_sha in Python, or cursor: resources.nextCursor, commitSha: resources.commitSha in TypeScript.

Was this page helpful?