Skip to main content

Lab SDK

The Lab SDK is a Python library that provides a simple, unified interface for integrating machine learning scripts with Transformer Lab.

While the Lab SDK is optional, adding it to your scripts allows for enhanced interaction with Transformer Lab, allowing you to better track the lifecycle of jobs, manage logs, store artifacts, save models, etc.

The SDK is published to PyPI as transformerlab-internal. The import name is lab, not the package name.

This guide covers available functionality with practical examples.

Getting Started

Installation

On a remote compute provider you do not need to install anything. Every job launched on a non-local provider gets pip install -q transformerlab-internal prepended to its setup step, so from lab import lab already works. Adding it to your own setup: only slows the job down.

To develop or test a script on your own machine:

pip install transformerlab-internal

Basic Usage

from lab import lab

# Initialize with an experiment
lab.init(experiment_id="my_experiment")

# Log messages
lab.log("Starting training...")

# Update progress
lab.update_progress(50)

# Save artifacts
lab.save_artifact("results.json", "my_results.json")

# Complete the job
lab.finish("Training completed successfully")

Initialization and Lifecycle

lab.init()

Initializes a job under the given experiment. This is the first method you should call.

Parameters:

  • experiment_id (str, optional): The experiment ID. Defaults to "alpha" if not provided.
  • config (dict, optional): Initial configuration to attach to the job.

Example:

from lab import lab

# Simple initialization with default experiment "alpha"
lab.init()

# Initialize with a specific experiment
lab.init(experiment_id="my_training_experiment")

lab.copy_file_mounts()

Copies the files uploaded with the task into the working directory on the machine the job is running on (~, or ~/sky_workdir when that directory exists). Jobs on the local provider get this call injected automatically, so you rarely need it yourself; call it explicitly when you launched with file mounts on another provider and want the uploaded files before your script reads them.

Does nothing when there are no task files to copy, so it is safe to call unconditionally.

Example:

from lab import lab

lab.init(experiment_id="training")
lab.copy_file_mounts() # uploaded task files are now in the working directory

Configuration Management

lab.get_config()

Retrieves configuration/parameters from job data. This is particularly useful when resuming jobs or accessing parameters that were set when the task was launched.

Returns:

  • dict: Configuration dictionary. Returns empty dict if no config found.

Example:

from lab import lab

lab.init(experiment_id="training")

# Get configuration (useful for remote jobs)
config = lab.get_config()
print(f"Model: {config.get('model_name')}")
print(f"Learning rate: {config.get('learning_rate')}")

lab.set_config()

Attaches a configuration dictionary to the current job. Useful for recording the resolved settings a run actually used, so the job page shows them alongside the results.

Parameters:

  • config (dict): Configuration to store on the job.

Example:

from lab import lab

lab.init(experiment_id="training")
lab.set_config({"model_name": "gpt2", "learning_rate": 2e-5, "seed": 42})

Secrets

lab.get_secret()

Reads a secret by name. Secrets are configured in Team Settings (team secrets) and User Settings (user secrets); where both define the same name, the user's value wins — the same precedence GitHub uses.

Keep credentials here rather than in envs: in your task.yaml: the YAML is stored with the task and visible to anyone who can read it.

Parameters:

  • secret_name (str): Name of the secret.

Returns:

  • str | None: The secret value, or None when it does not exist or cannot be read.

Example:

from lab import lab

lab.init(experiment_id="training")

api_key = lab.get_secret("OPENAI_API_KEY")
if api_key is None:
lab.error("OPENAI_API_KEY is not configured for this team")

Logging and Progress Tracking

lab.log()

Logs a message to the job's output. Messages are visible in the Transformer Lab UI.

Parameters:

  • message (str): The message to log.

Example:

from lab import lab

lab.init(experiment_id="training")

lab.log("Starting data preprocessing...")
lab.log("Loading dataset...")
lab.log("Dataset loaded successfully")
lab.log(f"Training epoch {epoch + 1}/{num_epochs}")

lab.update_progress()

Updates the job's progress percentage (0-100).

Parameters:

  • progress (int): Progress percentage (0-100).

Example:

from lab import lab

lab.init(experiment_id="training")

# Update progress during training
for epoch in range(num_epochs):
train_epoch()
progress = int((epoch + 1) / num_epochs * 100)
lab.update_progress(progress)
lab.log(f"Completed epoch {epoch + 1}/{num_epochs}")

Artifacts Management

lab.save_artifact()

Saves a file or directory as an artifact for the current job. Artifacts are stored in the job's artifacts directory and are visible in the Transformer Lab UI.

Parameters:

  • source_path (str or DataFrame): Path to the file/directory to save, or a pandas DataFrame when type="evals" or type="dataset".
  • name (str, optional): Name for the artifact. If not provided, uses the source basename.
  • type (str, optional): Type of artifact. Special types:
    • "eval": Saves to eval_results directory and updates job data accordingly. Visible as Eval Results in the GUI.
    • "dataset": Saves as a dataset and tracks dataset_id in job data. Visible as under the Dataset tab in the GUI.
    • "model": Saves to workspace models directory and creates Model Zoo metadata. Visible as under the Model Registry tab in the GUI.
    • Otherwise: Saves to artifacts directory.
  • config (dict, optional): Configuration dict. See specific types below for details.

Returns:

  • str: The destination path on disk.

Example - Basic Artifact:

from lab import lab
import json

lab.init(experiment_id="training")

# Save a configuration file
config = {"learning_rate": 2e-5, "batch_size": 8}
with open("config.json", "w") as f:
json.dump(config, f)

artifact_path = lab.save_artifact("config.json", "training_config.json")
lab.log(f"Saved config to: {artifact_path}")

# Save a directory
lab.save_artifact("./output_dir", "training_output")

Checkpoint Management

lab.save_checkpoint()

Saves a checkpoint file or directory into the job's checkpoints folder. Checkpoints are tracked separately from artifacts and can be used to resume training.

Parameters:

  • source_path (str): Path to the checkpoint file or directory to save.
  • name (str, optional): Name for the checkpoint. If not provided, uses the source basename.

Returns:

  • str: The destination path on disk.

Example:

from lab import lab
import os

lab.init(experiment_id="training")

# Save a checkpoint during training
for epoch in range(num_epochs):
# ... training code ...

# Save checkpoint every 2 epochs
if (epoch + 1) % 2 == 0:
checkpoint_dir = f"./checkpoints/epoch_{epoch + 1}"
saved_path = lab.save_checkpoint(checkpoint_dir, f"epoch_{epoch + 1}")
lab.log(f"Saved checkpoint: {saved_path}")

lab.get_checkpoint_to_resume()

Gets the checkpoint path to resume training from. This checks for checkpoint resume information stored in the job data.

Returns:

  • str or None: The full path to the checkpoint to resume from, or None if no checkpoint resume is requested.

Example:

from lab import lab

lab.init(experiment_id="training")

# Check if we should resume from a checkpoint
checkpoint = lab.get_checkpoint_to_resume()
if checkpoint:
lab.log(f"Resuming training from checkpoint: {checkpoint}")
model.load_checkpoint(checkpoint)
else:
lab.log("Starting fresh training")

Note: This method is only available when resuming from a checkpoint using the GUI.

Job Directories and Paths

The SDK writes checkpoints and artifacts into per-job directories in shared storage. These helpers tell you where those are, so a script can write files there directly instead of staging them locally and calling save_artifact on each one.

lab.get_artifacts_dir() / lab.get_checkpoints_dir()

Return the artifacts and checkpoints directory for the current job, as a path on this machine.

from lab import lab

lab.init(experiment_id="training")

artifacts = lab.get_artifacts_dir()
checkpoints = lab.get_checkpoints_dir()

# e.g. point a training loop's output_dir straight at it
trainer_args.output_dir = checkpoints

lab.get_artifact_paths() / lab.get_checkpoint_paths()

Return the list of files currently in those directories.

for path in lab.get_checkpoint_paths():
print(path)

lab.get_parent_job_checkpoint_path()

Full path to a named checkpoint belonging to another job — the way a job picks up where a previous one left off, for example an evaluation job reading the model a training job produced.

Parameters:

  • parent_job_id (str): The job that saved the checkpoint.
  • checkpoint_name (str): The checkpoint's name.

Returns:

  • str | None: The path, or None if that job has no such checkpoint.
from lab import lab

lab.init(experiment_id="evaluation")

config = lab.get_config()
ckpt = lab.get_parent_job_checkpoint_path(config["train_job_id"], "epoch-3")
if ckpt is None:
lab.error("training job produced no epoch-3 checkpoint")

Model Management

lab.save_model()

Saves a model file or directory to the workspace models directory. The model will automatically appear under the Model Registry tab in the GUI. This works the same as lab.save_artifact(..., type="model").

Parameters:

  • source_path (str): Path to the model file or directory to save.
  • name (str, optional): Name for the model. If not provided, uses source basename. The final model name will be prefixed with the job_id for uniqueness.
  • architecture (str, optional): Model architecture (e.g., "LlamaForCausalLM"). If not provided, will attempt to detect from config.json.
  • pipeline_tag (str, optional): Pipeline tag (e.g., "text-generation"). If not provided and parent_model is given, will attempt to fetch from parent model on HuggingFace.
  • parent_model (str, optional): Parent model name/ID for provenance tracking.

Returns:

  • str: The destination path on disk.

Example:

from lab import lab
import os

lab.init(experiment_id="training")

# Train your model...
# ... training code ...

# Save the trained model
model_dir = "./output/final_model"
os.makedirs(model_dir, exist_ok=True)

# Save model files
# ... save model files to model_dir ...

# Save to Model Zoo
saved_path = lab.save_model(
model_dir,
name="my_finetuned_model",
architecture="LlamaForCausalLM",
pipeline_tag="text-generation",
parent_model="meta-llama/Llama-2-7b-hf"
)
lab.log(f"Model saved to Model Zoo: {saved_path}")

Note: This method is a convenience wrapper around save_artifact() with type="model". For more control, use save_artifact() directly.

lab.save_artifact() with type="model"

Advanced model saving with more configuration options.

Example:

from lab import lab

lab.init(experiment_id="training")

# Save model with detailed config
saved_path = lab.save_artifact(
source_path="./output/final_model",
name="my_model",
type="model",
config={
"model": {
"architecture": "LlamaForCausalLM",
"pipeline_tag": "text-generation",
"parent_model": "meta-llama/Llama-2-7b-hf"
}
}
)

lab.list_models()

Lists all local models available in the workspace.

Returns:

  • list[dict]: List of dictionaries containing model metadata. Each dictionary includes:
    • model_id: The model identifier
    • name: The model name
    • json_data: Additional model metadata

Example:

from lab import lab

lab.init(experiment_id="training")

# List all available models
models = lab.list_models()
lab.log(f"Found {len(models)} models in workspace")
for model in models:
lab.log(f" - {model['model_id']}: {model.get('name', 'N/A')}")

lab.get_model()

Gets a specific local model by ID.

Parameters:

  • model_id (str): The identifier of the model to retrieve.

Returns:

  • ModelService: A Model instance for the specified model.

Raises:

  • FileNotFoundError: If the model directory doesn't exist.

Example:

from lab import lab

lab.init(experiment_id="training")

# Get a model
model = lab.get_model("my_model_id")
model_dir = model.get_dir()
lab.log(f"Model directory: {model_dir}")

lab.get_model_path()

Gets the filesystem path to a specific local model.

Parameters:

  • model_id (str): The identifier of the model.

Returns:

  • str: The full path to the model directory.

Raises:

  • FileNotFoundError: If the model doesn't exist.

Example:

from lab import lab

lab.init(experiment_id="training")

# Get model path
model_path = lab.get_model_path("my_model_id")
lab.log(f"Model path: {model_path}")

Dataset Management

lab.save_dataset()

Saves a dataset under the workspace datasets directory and marks it as generated. The dataset will appear in the Transformer Lab UI.

Parameters:

  • df: A pandas DataFrame or a Hugging Face datasets.Dataset to serialize to disk.
  • dataset_id (str): Identifier for the dataset directory under datasets/.
  • additional_metadata (dict, optional): Optional dict to merge into dataset json_data.
  • suffix (str, optional): Optional suffix to append to the output filename stem.
  • is_image (bool): If True, save JSON Lines (for image metadata-style rows).

Returns:

  • str: The path to the saved dataset file on disk.

Example:

from lab import lab
import pandas as pd

lab.init(experiment_id="data_processing")

# Create a dataset
data = {
"input": ["What is AI?", "What is ML?"],
"output": ["AI is...", "ML is..."],
"label": [1, 1]
}
df = pd.DataFrame(data)

# Save the dataset
dataset_path = lab.save_dataset(
df=df,
dataset_id="my_custom_dataset",
additional_metadata={
"description": "Custom training dataset",
"source": "manually_created"
}
)
lab.log(f"Dataset saved to: {dataset_path}")

Example - Using save_artifact with type="dataset":

from lab import lab
import pandas as pd

lab.init(experiment_id="data_processing")

# Create dataset
df = pd.DataFrame({
"question": ["Q1", "Q2"],
"answer": ["A1", "A2"]
})

# Save using save_artifact
dataset_path = lab.save_artifact(
source_path=df,
name="my_dataset",
type="dataset",
config={
"dataset": {
"description": "Question-answer dataset",
"task": "qa"
},
"suffix": "v1",
"is_image": False
}
)

lab.get_dataset()

Gets a single dataset by ID, scoped to the current team.

Parameters:

  • dataset_id (str): The dataset to retrieve.
  • job_id (str, optional): Look in that job's dataset directory instead of the workspace-wide one.

Returns:

  • Dataset: An object whose get_dir() gives you the directory to read from.

Raises: FileNotFoundError when the dataset does not exist.

from lab import lab

lab.init(experiment_id="training")

dataset = lab.get_dataset("my_generated_dataset")

Shared Storage

Shared storage is the team's own file space — the place for things too big or too reusable to live inside one job: corpora, base checkpoints, exports someone else will pick up. It is the same storage the lab storage CLI commands see, so a file a job uploads is one you can download from your laptop afterwards.

lab.storage_download()

Downloads a file or directory from shared storage onto this machine and returns its local path — never a storage URI, so the result can be opened directly.

Parameters:

  • remote_path (str): Path within your storage, e.g. "corpora/wiki.tar", or a directory such as "corpora".
  • dest (str, optional): Where to put it. For a file, an existing directory receives it under its own name and anything else is treated as the full target path; for a directory, the tree is written into dest. Omitted, it is cached under ~/.transformerlab/cache/user_storage/.
  • force (bool): Re-download even when a local copy of the right size exists. Defaults to False.

Returns:

  • str: The local path to the downloaded file, or the directory it filled.

A cached copy whose size matches is reused, so re-running a job does not re-fetch a large file it already has.

from lab import lab

lab.init(experiment_id="training")

corpus = lab.storage_download("corpora/wiki.tar")
train_on(corpus)

lab.storage_upload()

Uploads a local file into shared storage.

Parameters:

  • local_path (str): The file to upload.
  • remote_path (str, optional): Destination path within your storage. Defaults to the local file's basename.

Returns:

  • str: The path the file was stored under.
lab.storage_upload("final_model.safetensors", "exports/run-42/model.safetensors")

lab.storage_list()

Lists files in shared storage.

Parameters:

  • prefix (str, optional): Restrict the listing to this directory.

Returns:

  • list[dict]: Entries with relpath and size, sorted by relpath.
for entry in lab.storage_list("corpora"):
print(entry["relpath"], entry["size"])

Documents

Documents are the files uploaded to an experiment's document library through the UI. A job can read them without them being mounted into the task.

lab.list_documents()

Parameters:

  • folder (str, optional): Restrict to one folder of the library.
  • experiment_id (str, optional): Defaults to the current experiment.

Returns:

  • list[dict]: One entry per document, with name, path and type (the file extension, or "folder" for a subfolder), sorted by name.

lab.get_document_contents()

Reads a document as text.

Parameters:

  • document_name (str): The document to read.
  • folder (str, optional), experiment_id (str, optional): As above.
  • encoding (str): Defaults to "utf-8".
  • errors (str): Decoding error policy, defaults to "strict".

Returns: str

lab.get_document_bytes()

The same, without decoding — for PDFs, images and anything else that is not text.

Returns: bytes

from lab import lab

lab.init(experiment_id="research")

for doc in lab.list_documents(folder="papers"):
text = lab.get_document_contents(doc["name"], folder="papers")
summarize(text)

Evaluation Results

lab.save_artifact() with type="evals"

Saves evaluation results as a CSV file. The results are stored in the job's eval_results directory and are visible in the Transformer Lab UI.

Parameters:

  • source_path: A pandas DataFrame or Hugging Face datasets.Dataset with evaluation results.

  • name (str, optional): Name for the evaluation results file. Defaults to eval_results_{job_id}_{timestamp}.csv.

  • type (str): Must be "evals".

  • config (dict, optional): Configuration dict with column mappings under "evals" key:

    {
    "evals": {
    "input": "input_col", # Column name for input
    "output": "output_col", # Column name for model output
    "expected_output": "expected_col", # Column name for expected output (optional)
    "score": "score_col" # Column name for score
    }
    }

Default Column Names: If column mappings are not provided, the following defaults are used:

  • input: "input"
  • output: "output"
  • expected_output: "expected_output"
  • score: "score"

Example - Default Column Names:

from lab import lab
import pandas as pd

lab.init(experiment_id="evaluation")

# Create evaluation results with default column names for colour highlighting in the GUI.
results = pd.DataFrame({
"input": ["What is 2+2?", "What is 3+3?"],
"output": ["4", "6"],
"expected_output": ["4", "6"],
"score": [1.0, 1.0]
})

# Save evaluation results
eval_path = lab.save_artifact(
source_path=results,
name="eval_results.csv",
type="evals"
)
lab.log(f"Evaluation results saved to: {eval_path}")

Example - Custom Column Names:

from lab import lab
import pandas as pd

lab.init(experiment_id="evaluation")

# Create evaluation results with custom column names
results = pd.DataFrame({
"question": ["What is 2+2?", "What is 3+3?"],
"model_response": ["4", "6"],
"ground_truth": ["4", "6"],
"accuracy": [1.0, 1.0]
})

# Save with column mappings
eval_path = lab.save_artifact(
source_path=results,
name="eval_results_custom.csv",
type="evals",
config={
"evals": {
"input": "question",
"output": "model_response",
"expected_output": "ground_truth",
"score": "accuracy"
}
}
)
lab.log(f"Evaluation results saved to: {eval_path}")

Job Data

job_data is the free-form dictionary the job page reads. get_config() and set_config() are the shortcut for the configuration part of it; these two are the general form.

lab.set_job_data_field()

Sets one key on the current job's job_data.

Parameters:

  • key (str), value (any JSON-serializable value)
lab.set_job_data_field("best_epoch", 3)

lab.get_job_data()

Returns:

  • dict: The whole job_data dictionary for the current job.

Job Completion

lab.finish()

Marks the job as successfully completed and sets completion metadata.

Parameters:

  • message (str): Completion message. Defaults to "Job completed successfully".
  • score (dict, optional): Optional score/metrics dictionary to attach to the job.

Example:

from lab import lab

lab.init(experiment_id="training")

# ... training code ...

# Complete the job with a message
lab.finish("Training completed successfully")

# Complete with score/metrics
lab.finish(
message="Training completed successfully",
score={
"final_loss": 0.15,
"accuracy": 0.92,
"f1_score": 0.89
}
)

lab.error()

Marks the job as failed and sets completion metadata.

Parameters:

  • message (str): Error message describing what went wrong.

Example:

from lab import lab

lab.init(experiment_id="training")

try:
# ... training code ...
pass
except Exception as e:
error_msg = f"Training failed: {str(e)}"
lab.error(error_msg)
raise

HuggingFace Integration

lab.get_hf_callback()

Gets a HuggingFace TrainerCallback instance for Transformer Lab integration. This callback automatically:

  • Updates training progress in Transformer Lab
  • Logs training metrics (loss, etc.)
  • Saves checkpoints to Transformer Lab when they are created
  • Logs epoch completion and training end events

Returns:

  • LabCallback: A TrainerCallback instance that can be passed to HuggingFace Trainer.

Example:

from lab import lab
from transformers import Trainer, TrainingArguments

lab.init(experiment_id="training")

# Get the callback
callback = lab.get_hf_callback()

# Create trainer with the callback
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
callbacks=[callback], # Add the callback
)

# Train - progress will be automatically tracked
trainer.train()

Example - Custom Callback:

You can also create a custom callback that extends the Lab callback:

from lab import lab
from transformers import TrainerCallback

lab.init(experiment_id="training")

class CustomLabCallback(TrainerCallback):
def __init__(self):
self.lab_callback = lab.get_hf_callback()

def on_step_end(self, args, state, control, **kwargs):
# Call the lab callback
self.lab_callback.on_step_end(args, state, control, **kwargs)

# Add custom logic
if state.global_step % 100 == 0:
lab.log(f"Custom logging at step {state.global_step}")

trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
callbacks=[CustomLabCallback()],
)

Experiment Tracking

If your script already reports to Weights & Biases or Trackio, these register that run with Transformer Lab so the job page links to it instead of the two records living apart.

lab.capture_wandb_url()

Records a W&B run URL on the job.

Parameters:

  • wandb_url (str): The run URL.
import wandb
from lab import lab

lab.init(experiment_id="training")
run = wandb.init(project="my-project")
lab.capture_wandb_url(run.url)

The SDK also tries to detect an active W&B run on its own; call this when that detection does not fire, for example when the run is started in a subprocess.

lab.capture_active_trackio_run()

Snapshots the Trackio database of the run currently in progress into this job's artifacts. Call it after your metrics have been logged.

lab.capture_trackio_metadata()

The explicit form: saves a Trackio directory or database file from this machine into the shared trackio_runs directory for the experiment. Requires TLAB_TRACKIO_PROJECT_NAME to be set.

Parameters:

  • db_path (str): Path to the Trackio directory, or a single DB file.

Returns:

  • str: Where the data was saved.

Async Variants

Methods that touch storage or the job record have an async_-prefixed twin — async_save_artifact, async_get_secret, async_storage_download, async_save_checkpoint, async_get_job_data, and so on. The plain method is a synchronous wrapper around the async one, and calling that wrapper from inside a running event loop raises RuntimeError rather than blocking:

RuntimeError: Cannot use sync method when already in async context.
Use the async version instead (e.g. await lab.async_save_artifact() ...).

The lifecycle methods have no twins. lab.init(), lab.log(), lab.update_progress(), lab.finish() and lab.error() are sync-only — there is no async_init. So the shape of an async task is a sandwich: open and close the job outside the loop, and use the async_ twins inside it.

import asyncio
from lab import lab

async def main():
corpus = await lab.async_storage_download("corpora/wiki.tar")
await lab.async_save_artifact("metrics.json")

lab.init(experiment_id="training") # sync, before the loop
asyncio.run(main()) # async_ twins inside
lab.finish(message="done") # sync, after the loop

Calling lab.init() as the first line of main() fails immediately — it is the easiest version of this mistake to make, and the traceback points at the _run_async helper rather than at your call.

Escape Hatches

Two properties expose the underlying objects when the facade does not cover what you need. Their methods are async only.

  • lab.job — the current Job: status, progress, job_data, per-job directories.
  • lab.experiment — the current Experiment: its config, and the jobs under it.

There is also lab.load_generation_model(config), a small provider-agnostic helper for text generation:

from lab import lab

gen = lab.load_generation_model({"provider": "local", "model": "MyModel"})
output = gen.generate("Hello")

Complete Example

Here's a complete example that demonstrates most of the functionality:

from lab import lab
import pandas as pd
import os
from datetime import datetime

def train_model():
"""Complete training script using Lab SDK"""

# 1. Initialize
lab.init(experiment_id="my_training_experiment")

# 2. Load data
lab.log("Loading dataset...")
# ... load dataset ...
lab.update_progress(10)

# 3. Training loop
lab.log("Starting training...")
for epoch in range(config["num_epochs"]):
# ... training code ...

# Save checkpoint
if (epoch + 1) % 2 == 0:
checkpoint_dir = f"./checkpoints/epoch_{epoch + 1}"
lab.save_checkpoint(checkpoint_dir, f"epoch_{epoch + 1}")
lab.log(f"Saved checkpoint for epoch {epoch + 1}")

# Update progress
progress = int((epoch + 1) / config["num_epochs"] * 100)
lab.update_progress(progress)

# 4. Save model
model_dir = "./output/final_model"
saved_model_path = lab.save_model(
model_dir,
name="trained_model",
architecture="GPT2LMHeadModel",
parent_model="gpt2"
)
lab.log(f"Model saved: {saved_model_path}")

# 5. Run evaluation
lab.log("Running evaluation...")
eval_results = pd.DataFrame({
"input": ["test input 1", "test input 2"],
"output": ["output 1", "output 2"],
"expected_output": ["expected 1", "expected 2"],
"score": [1.0, 0.8]
})

eval_path = lab.save_artifact(
eval_results,
name="eval_results.csv",
type="evals"
)
lab.log(f"Evaluation results saved: {eval_path}")

# 6. Save additional artifacts
summary = {"final_loss": 0.15, "accuracy": 0.92}
import json
with open("summary.json", "w") as f:
json.dump(summary, f)

lab.save_artifact("summary.json", "training_summary.json")

# 7. Complete job
lab.finish(
message="Training completed successfully",
score=summary
)

return {
"status": "success",
"job_id": lab.job.id,
"model_path": saved_model_path,
"eval_path": eval_path
}

if __name__ == "__main__":
result = train_model()
print(result)

Best Practices

  1. Always initialize first: Call lab.init() at the beginning of your script.

  2. Log frequently: Use lab.log() to provide visibility into your script's progress.

  3. Update progress regularly: Call lab.update_progress() to keep the UI updated.

  4. Save checkpoints: Use lab.save_checkpoint() regularly during long-running training jobs.

  5. Handle errors: Use lab.error() in exception handlers to mark jobs as failed.

  6. Complete jobs: Always call lab.finish() or lab.error() at the end of your script.

  7. Use appropriate artifact types: Use type="model" for models, type="evals" for evaluation results, and type="dataset" for datasets.

  8. Check for resume: Use lab.get_checkpoint_to_resume() to support resuming from checkpoints.

  9. Keep credentials out of task.yaml: Use lab.get_secret() rather than putting keys in envs:. When a value has to arrive as an environment variable — because a third-party library reads it directly and never calls your code — reference the secret instead of pasting it: OPENAI_API_KEY: "{{secrets.OPENAI_API_KEY}}". The placeholder is what gets stored; the value is substituted when the job launches.

  10. Put large shared files in shared storage: lab.storage_download() caches by size, so a corpus is fetched once per machine instead of once per run. Do not bake big files into the repo the task clones.