Skip to main content

Enterprise LLM Studio API Quickstart Guide

This notebook shows how to use the Enterprise LLM Studio API to manage projects, datasets, data generation, experiments, and deployments.

What you’ll do:

  • List/create/update projects
  • Upload and manage datasets
  • Run data generation
  • Validate, start, and monitor experiments
  • Get next-best-experiment suggestions (KGM)
  • Create and manage deployments
  • Run AutoML to explore configurations

Generate Your API Key​

To authenticate with the API, you’ll need to generate a personal API key:

  1. Log in to your H2O Enterprise LLM Studio environment.
  2. Click on your name in the top-right corner, then select API Keys.
  3. If no key has been generated yet, click Generate New API Key.
  4. You’ll be shown the key only once — make sure to copy it to a safe location immediately.
    Note

    Lost it? Just generate a new one — this will invalidate any existing key.

  5. After generation, you’ll see your key listed (e.g. <your name>'s API Key) with usage status and timestamp.

Before you begin​

First import the required packages.

# import required packages
import os
import requests
from pathlib import Path
import json

# Config
BASE_URL = os.getenv("LLM_STUDIO_BASE_URL")
TOKEN = os.getenv("LLM_STUDIO_TOKEN")

if not TOKEN:
raise SystemExit("Set LLM_STUDIO_TOKEN")
headers = {
"Accept": "application/json",
"Authorization": f"Bearer {TOKEN}",
}

1. Projects​

List all projects available to your token in the workspace.

resp = requests.get(BASE_URL+"/api2/api/projects", headers=headers, timeout=60)
resp.raise_for_status()
projects = resp.json()

print("Projects:")
for i, p in enumerate(projects, 1):
pid = p.get("project_id")
name = p.get("name")
print(f"{i}. {name} -> {pid}")

Create new project​

payload = {
"name": "New Project",
"description": "Created via API",
"visibility": "private",
}

resp = requests.post(BASE_URL + "/api2/api/projects", headers=headers, json=payload, timeout=60)
resp.raise_for_status()
project = resp.json()

print("Created Project:")
pid = project.get("project_id")
name = project.get("name")
print(f"{name} -> {pid}")

Fetch project details using project ID​

project_id = "6b62cd37-3080-490f-ba00-af911bb15981" #replace with your project ID

resp = requests.get(f"{BASE_URL}/api2/api/projects/{project_id}", headers=headers, timeout=60)
resp.raise_for_status()
project = resp.json()

print("Project:")
pid = project.get("project_id")
name = project.get("name")
description = project.get("description")
visibility = project.get("visibility")

print(f"""Name : {name}
ID : {pid}
Description: {description}
Visibility : {visibility}""")

Update project settings​

Update the name, description and visibility.

project_id = "6b62cd37-3080-490f-ba00-af911bb15981" #replace with your project ID

payload = {
"name": "Project Name Updated",
"description": "Updated Description",
"visibility": "private", # or "public"
}

resp = requests.put(f"{BASE_URL}/api2/api/projects/{project_id}", headers=headers, json=payload, timeout=60)
resp.raise_for_status()
project = resp.json()

name = project.get("name", "")
pid = project.get("project_id")
description = project.get("description", "")
visibility = project.get("visibility", "")

print(f"""Name : {name}
ID : {pid}
Description: {description}
Visibility : {visibility}""")

2. Data Generation​

Start a data generation job​

Start a synthetic data generation job with prompts, seeds, and generator settings.

project_id = "6b62cd37-3080-490f-ba00-af911bb15981" #replace with your project ID

datagen_payload = {
"datagen_name": "generate customer review v5", #datagen name
"problem_type": "datagen_generate_rows",
"dataset": {"n_rows": 10},
"transform": {
"llm_model_name": "gpt-4o-mini",
"max_new_tokens": 512,
"temperature": 0.2,
"suggestion": "Make the config better",
#####-------
"seed_data_dict": "{ \"aspects\": [\"network_connectivity\", \"billing_payment\", \"account_access\"], \"resolution_status\": [\"resolved\", \"unresolved\"] }"
,
"system_prompt_template": "You are a customer-service telco call summary generator that produces concise, realistic synthetic summaries in 3–6 factual, neutral, and specific sentences using active voice",
"user_prompt_template": "Please write a telco customer-care call summary in a factual, neutral, and specific tone that focuses on one or more of these {aspects}, with a {resolution_status}.",
######-------
"parse_these_columns_from_response": ""
},
"logging": {},
"project_id": project_id
}

resp = requests.post(f"{BASE_URL}/api2/api/datagen", headers=headers, json=datagen_payload, timeout=60)
resp.raise_for_status()
out = resp.json()

datagen_id = out.get("datagen_id")
status = out.get("status")
message = out.get("message", "")

print(f"Started datagen -> {datagen_id} [{status}]")

List data generation jobs​

project_id = "6b62cd37-3080-490f-ba00-af911bb15981" #replace with your project ID

resp = requests.get(
f"{BASE_URL}/api2/api/datagens",
params={"project_id": project_id},
headers=headers,
timeout=60,
)
resp.raise_for_status()
datagens = resp.json()

print("Datagens (newest first):")
for i, d in enumerate(datagens, 1):
did = d.get("datagen_id")
name = d.get("datagen_name")
status = d.get("status")
created = d.get("created_at")
print(f"{did} [{status}] created: {created}")

3. Datasets​

Upload, view, and delete datasets.

Upload data​

# Local file to upload 
FILE_PATH = "feedback.csv" #replace with your file path
DATASET_NAME = "feedback_snowflake" #replace with your dataset name
PROJECT_ID = "6b62cd37-3080-490f-ba00-af911bb15981" #replace with your project ID

form = {
"project_id": PROJECT_ID,
"name": DATASET_NAME,
}

file_path = Path(FILE_PATH)
if not file_path.exists():
raise SystemExit(f"File not found: {file_path}")

with open(file_path, "rb") as f:
files = {
"file": (file_path.name, f, "application/octet-stream"),
}
print(f"POST {BASE_URL} -> uploading {file_path.name} to project {PROJECT_ID}")
resp = requests.post(f"{BASE_URL}/api2/api/datasets/upload", headers=headers, data=form, files=files, timeout=600)

print("Status:", resp.status_code)
if resp.headers.get("content-type", "").startswith("application/json"):
print(json.dumps(resp.json(), indent=2))
else:
print(resp.text)

List the datasets​

PROJECT_ID = "6b62cd37-3080-490f-ba00-af911bb15981"  #replace with your project ID

resp = requests.get(f"{BASE_URL}/api2/api/datasets?project_id={PROJECT_ID}", headers=headers, timeout=60)
if resp.status_code == 200:
data = resp.json()
print("Datasets:")
if not data:
print(" (none)")
else:
for i, ds in enumerate(data, 1):
did = ds.get("dataset_id")
name = ds.get("name")
created = ds.get("created_at")
print(f"{i}. Name : {name}")
print(f" ID : {did}")
print(f" Created : {created}\n")

extras = {k: v for k, v in ds.items() if k not in {"dataset_id","id","name","dataset_name","status","created_at","created_on","size","row_count","num_rows"}}
elif resp.status_code == 403:
print("Access denied (403). Check token scopes/roles and project permissions.")
print(resp.text)
else:
print(f"Error {resp.status_code}: {resp.text}")

Get dataset by ID​

DATASET_ID = "f653e0f6-ab3a-4843-8033-e1d2964cc9f2" #replace with your dataset ID

resp = requests.get(f"{BASE_URL}/api2/api/datasets/{DATASET_ID}", headers=headers, timeout=60)

if resp.status_code == 200:
data = resp.json()
print("Dataset:")
fields = ["dataset_id", "project_id", "name", "file_type", "size_bytes",
"created_at", "row_count", "columns", "file_url"]
for k in fields:
if k in data:
print(f"- {k}: {data[k]}")
elif resp.status_code == 404:
print("Dataset not found (404). Check DATASET_ID.")
elif resp.status_code == 403:
print("Access denied (403). Check token scopes/permissions for this dataset/project.")
elif resp.status_code == 422:
print("Validation error (422). Ensure dataset_id format is correct.")
else:
print(f"Error {resp.status_code}: {resp.text[:1000]}")

Delete dataset by ID​

DATASET_ID = "f653e0f6-ab3a-4843-8033-e1d2964cc9f2" #replace with your dataset ID

resp = requests.delete(f"{BASE_URL}/api2/api/datasets/{DATASET_ID}", headers=headers, timeout=60)

if resp.status_code == 200:
print("Deleted:", resp.json())
elif resp.status_code == 404:
print("Dataset not found (404).")
elif resp.status_code == 403:
print("Access denied (403). Check permissions.")
elif resp.status_code == 422:
print("Validation error (422). Check dataset_id format.")
else:
print(f"Error {resp.status_code}: {resp.text[:1000]}")

4. Experiments​

Validate the experiment config and create, list, and delete experiments.

List experiments​

PROJECT_ID = "6b62cd37-3080-490f-ba00-af911bb15981" #replace with your project ID
LIMIT = 20 # optional

params = {"project_id": PROJECT_ID}
if LIMIT is not None:
params["limit"] = LIMIT

try:
resp = requests.get(f"{BASE_URL}/api2/api/datasets/", headers=headers, params=params, timeout=60)
resp.raise_for_status()
except requests.exceptions.HTTPError:
try:
print(f"HTTP {resp.status_code} error:\n" + json.dumps(resp.json(), indent=2))
except Exception:
print(f"HTTP {resp.status_code} error:\n{resp.text[:2000]}")
raise
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

experiments = resp.json()

print("Experiments (newest first):")
if not experiments:
print(" (none)")
else:
for i, exp in enumerate(experiments, 1):
eid = exp.get("experiment_id")
name = exp.get("name")
status = exp.get("status")
created = exp.get("created_at")
train_ds = exp.get("train_dataset_name")
val_ds = exp.get("validation_dataset_name")
error = (exp.get("error") or "").strip()
print(f"{i}. Name : {name}")
print(f" ID : {eid}")
print(f" Status : {status}")
print(f" Created : {created}")
print(f" Train DS : {train_ds}")
print(f" Val DS : {val_ds}")
if error:
print(f" Error : {error[:300]}")

Check experiment config​

Experiment config:​

  • TRAINING_MODE (training_mode)
    • Options: 'lora' | 'qlora' | 'full'
    • Default: 'lora'
    • Notes: LoRA = fastest; QLoRA = least VRAM; Full = most compute/memory.
  • DATA_SAMPLE_FRACTION (dataset.data_sample)
    • Type: float in 0, 1 ; Default: 1
  • DATASET_ID (dataset.train_dataset_id)
    • Type: str (UUID)
    • Notes: Required. Must match an uploaded dataset ID.
  • PROMPT_COLUMN (dataset.prompt_column)
    • Type: str; Default: "instruction"
    • Notes: Input text column in your dataset (e.g., "input").
  • ANSWER_COLUMNS (dataset.answer_column)
    • Type: list[str] | str | None; Default: "output"
    • Notes: Use list for multi-target; single string for single target.
  • VALIDATION_STRATEGY (dataset.validation_strategy)
    • Options: 'automatic' | 'custom'
    • Default: 'automatic'
    • Notes: 'automatic' splits train by validation_size; 'custom' expects separate validation data/id.
  • VALIDATION_SIZE (dataset.validation_size)
    • Type: float in (0,1); Default: 0.2
    • Notes: Used only when validation_strategy='automatic'.
  • MAX_SEQ_LENGTH (tokenizer.max_length)
    • Type: int; Default: 512
    • Notes: Truncation/padding length; lower to save memory.
  • PREDICTION_METRICS (prediction.metrics)
    • Type: list[str]; Default: []
    • Classification examples: "AUC", "Accuracy".
    • Language Modeling: "BLEU", "Perplexity"
  • EXPERIMENT_NAME (experiment_name)
    • Type: str; Default: "experiment"
    • Notes: Display name for the run.
  • PROJECT_ID (project_id)
    • Type: str (UUID)
    • Notes: Target project container for all resources.
  • LLM_BACKBONE (llm_backbone)
    • Type: str (Hugging Face model id); Default: "h2oai/h2o-danube3-500m-chat"
  • PROBLEM_TYPE (problem_type)
    • Options: 'text_causal_language_modeling' | 'text_causal_classification_modeling'
    • Default: 'text_causal_language_modeling'
    • Notes: Use classification for tasks like sentiment/topic classification.

Multi-target classification experiment setup​

# === Editable knobs ===
TRAINING_MODE = "lora" # training_mode
DATA_SAMPLE_FRACTION = 1.0 # data_sample (1.0 = use all data)
DATASET_ID = "7cb76178-6907-4610-a882-a766e4d84fdf" # dataset id
PROMPT_COLUMN = "input" # prompt_column
ANSWER_COLUMNS = [ # answer_column (multi-target) or (single-target)
"question_is_billing_issue",
"question_was_issue_resolved",
"question_is_technical_issue",
]
VALIDATION_STRATEGY = "automatic" # validation_strategy
VALIDATION_SIZE = 0.2 # validation_size
MAX_SEQ_LENGTH = 512 # tokenizer.max_length
TRAIN_BATCH_SIZE = 1 # training.batch_size
NUM_EPOCHS = 1 # training.epochs
LEARNING_RATE = 1e-4 # training.learning_rate
PREDICTION_METRICS = ["AUC","Accuracy"] # prediction.metrics
EXPERIMENT_NAME = "telco_v3_test" # experiment_id
PROJECT_ID = "6b62cd37-3080-490f-ba00-af911bb15981" # project_id
LLM_BACKBONE = "h2oai/h2o-danube3-500m-chat" # llm_backbone
PROBLEM_TYPE = "text_causal_classification_modeling" # text_causal_classification_modeling

# ======================

payload = {
"architecture": {
"training_mode": TRAINING_MODE,
"gradient_checkpointing": True,
"intermediate_dropout": 0,
"backbone_kwargs": "{}"
},
"dataset": {
"data_sample_choice": ["Train", "Validation"],
"data_sample": DATA_SAMPLE_FRACTION,
"prompt_column": PROMPT_COLUMN,
"answer_column": ANSWER_COLUMNS,
"train_dataset_id": DATASET_ID,
"validation_strategy": VALIDATION_STRATEGY,
"validation_size": VALIDATION_SIZE,
"unroll_conversations": False
},
"environment": {
"find_unused_parameters": False,
"huggingface_branch": "main",
"mixed_precision": True,
"use_fsdp": False,
"use_fsdp_cpu_offload": False,
"seed": -1,
"trust_remote_code": True
},
"tokenizer": {
"max_length": MAX_SEQ_LENGTH,
"padding_quantile": 1,
"tokenizer_kwargs": "{\"use_fast\": true, \"add_prefix_space\": false}"
},
"training": {
"attention_implementation": "auto",
"batch_size": TRAIN_BATCH_SIZE,
"differential_learning_rate_layers": [],
"differential_learning_rate": 1e-5,
"epochs": NUM_EPOCHS,
"evaluate_before_training": True,
"evaluation_epochs": 1,
"grad_accumulation": 1,
"gradient_clip": 0,
"learning_rate": LEARNING_RATE,
"lora_alpha": 16,
"lora_dropout": 0.05,
"lora_rank": 4,
"lora_target_modules": "",
"min_learning_rate_ratio": 0,
"optimizer": "AdamW",
"schedule": "Cosine",
"train_validation_data": False,
"use_length_based_sampler": True,
"warmup_epochs": 0,
"weight_decay": 0
},
"logging": {},
"prediction": {
"batch_size_inference": 0,
"max_length_inference": 128,
"metrics": PREDICTION_METRICS,
"min_length_inference": 2,
"num_beams": 1,
"repetition_penalty": 1,
"temperature": 0,
"top_k": 0,
"top_p": 1
},

"experiment_name": EXPERIMENT_NAME,
"project_id": PROJECT_ID,
"reference_experiment_ids": [],
"llm_backbone": LLM_BACKBONE,
"problem_type": PROBLEM_TYPE
}

try:
resp = requests.post(f"{BASE_URL}/api2/api/train/validate", headers=headers, json=payload, timeout=120)
resp.raise_for_status()
except requests.exceptions.HTTPError:
try:
print(f"HTTP {resp.status_code} error:\n" + json.dumps(resp.json(), indent=2))
except Exception:
print(f"HTTP {resp.status_code} error:\n{resp.text[:2000]}")
raise
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

result = resp.json()
valid = result.get("valid")
errors = result.get("errors")
warnings = result.get("warnings")

print("Validation result:")
print(f" valid : {valid}")
if errors:
print(" errors :")
for e in errors:
print(f" - {e}")
if warnings:
print(" warnings:")
for w in warnings:
print(f" - {w}")

Start experiment​

try:
resp = requests.post(f"{BASE_URL}/api2/api/train", headers=headers, json=payload, timeout=120)
resp.raise_for_status()
except requests.exceptions.HTTPError:
try:
print(f"HTTP {resp.status_code} error:\n" + json.dumps(resp.json(), indent=2))
except Exception:
print(f"HTTP {resp.status_code} error:\n{resp.text[:2000]}")
raise
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

out = resp.json()

exp_id = out.get("experiment_id")
status = out.get("status")
message = out.get("message", "")

print("Training started:")
print(f" experiment_id : {exp_id}")
print(f" status : {status}")
if message:
print(f" message : {message}")

Check experiment status​

EXPERIMENT_ID = "9619dfb4-b298-4ea6-b409-c7c3606087fa" #replace with your experiment ID

try:
resp = requests.get(f"{BASE_URL}/api2/api/experiments/{EXPERIMENT_ID}/status", headers=headers, timeout=60)
resp.raise_for_status()
except requests.exceptions.HTTPError:
try:
err = resp.json()
print(f"HTTP {resp.status_code} error:\n" + json.dumps(err, indent=2))
except Exception:
print(f"HTTP {resp.status_code} error:\n{resp.text[:2000]}")
raise
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

status = resp.json()

fields = {
"ETA": status.get("eta", "N/A"),
"HF Repo ID": status.get("hf_repo_id"),
"Num GPUs": status.get("num_gpus"),
"Price per GPU hour": status.get("price_per_gpu_hour"),
"Runtime": status.get("runtime"),
"Status": status.get("status"),
}

print("Experiment Status Summary")
print("-------------------------")
print(f"ETA : {fields['ETA']}")
print(f"Num GPUs : {fields['Num GPUs']}")
print(f"Price per GPU hour : {fields['Price per GPU hour']}")
print(f"Runtime : {fields['Runtime']}")
print(f"Status : {fields['Status']}")

Ask KGM​

EXPERIMENT_ID = "9619dfb4-b298-4ea6-b409-c7c3606087fa"   # the reference experiment's ID to base suggestions on

try:
resp = requests.post(f"{BASE_URL}/api2/api/agents/next-best-experiment/{EXPERIMENT_ID}", headers=headers, timeout=120)
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

if resp.status_code == 200:
try:
data = resp.json()
except ValueError:
raise SystemExit(f"Unexpected response format:\n{resp.text[:1000]}")

print("Next-Best-Experiment Recommendation:")
print(json.dumps(data, indent=2))

cfg = data.get("config") or data.get("payload") or {}
for k in [
("llm_backbone", cfg.get("llm_backbone")),
("training.learning_rate", cfg.get("training", {}).get("learning_rate") if isinstance(cfg.get("training"), dict) else None),
("training.batch_size", cfg.get("training", {}).get("batch_size") if isinstance(cfg.get("training"), dict) else None),
("training.epochs", cfg.get("training", {}).get("epochs") if isinstance(cfg.get("training"), dict) else None),
("architecture.training_mode", cfg.get("architecture", {}).get("training_mode") if isinstance(cfg.get("architecture"), dict) else None),
]:
if k[1] is not None:
print(f" - {k[0]}: {k[1]}")
else:
print(f"Error {resp.status_code}")
try:
print(json.dumps(resp.json(), indent=2))
except ValueError:
print(resp.text[:2000])

Delete experiment​

EXPERIMENT_ID = "9619dfb4-b298-4ea6-b409-c7c3606087fa" #replace with your experiment ID

try:
resp = requests.delete(f"{BASE_URL}/api2/api/experiments/{EXPERIMENT_ID}", headers=headers, timeout=60)
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

if resp.status_code == 200:
try:
data = resp.json()
except ValueError:
data = {"message": resp.text.strip() or "Deleted"}
print("Deleted experiment:")
print(json.dumps(data, indent=2))
elif resp.status_code == 403:
print("Access denied (403). Check token scopes/roles and project permissions.")
print(resp.text[:1000])
elif resp.status_code == 404:
print("Experiment not found (404). Verify EXPERIMENT_ID.")
print(resp.text[:1000])
elif resp.status_code == 422:
print("Validation error (422). The EXPERIMENT_ID format may be invalid.")
else:
print(f"Error {resp.status_code}:")

5. Deployments​

Create a deployment, check the live status of a deployment, and list deployments.

Create a deployment​

EXPERIMENT_ID = "6decfbe4-3e2f-4909-a195-83d7586cebcb"  # from a completed training run <replace>
PROJECT_ID = "6b62cd37-3080-490f-ba00-af911bb15981" # the project to attach the deployment to <replace>
DEPLOYMENT_NAME = "my-deployment-v2"

params = {
"project_id": PROJECT_ID,
"experiment_id": EXPERIMENT_ID,
"name" : DEPLOYMENT_NAME
}

try:
resp = requests.post(f"{BASE_URL}/api2/api/deployments/create_deployment/{EXPERIMENT_ID}", headers=headers, params=params, timeout=120)
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

if resp.status_code == 200:
try:
data = resp.json()
except ValueError:
raise SystemExit(f"Unexpected response format: {resp.text[:1000]}")
print("Deployment created:")
print(json.dumps(data, indent=2))
elif resp.status_code == 403:
print("Access denied (403). Check token scopes/roles and project permissions.")
print(resp.text[:1000])
elif resp.status_code == 404:
print("Not found (404). The experiment_id may not exist or is not visible in this project.")
print(resp.text[:1000])
elif resp.status_code == 422:
print("Validation error (422). Verify experiment_id format and required params.")
else:
print(f"Error {resp.status_code}:")

List existing deployments​

PROJECT_ID = "6b62cd37-3080-490f-ba00-af911bb15981" #replace with your project ID

params = {"project_id": PROJECT_ID}
try:
resp = requests.get(f"{BASE_URL}/api2/api/deployments", headers=headers, params=params, timeout=60)
resp.raise_for_status()
except requests.exceptions.HTTPError:
try:
print(f"HTTP {resp.status_code} error:\n" + json.dumps(resp.json(), indent=2))
except Exception:
print(f"HTTP {resp.status_code} error:\n{resp.text[:2000]}")
raise
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

deployments = resp.json()

if deployments:
print("\nSummary:")
for d in deployments:
print("-" * 60)
print(f"deployment_id : {d.get('deployment_id')}")
print(f"name : {d.get('name')}")
print(f"project_id : {d.get('project_id')}")
print(f"experiment_id : {d.get('experiment_id')}")
print(f"status : {d.get('status')}")
print(f"url : {d.get('url')}")
print(f"url_internal : {d.get('url_internal')}")
print(f"created_at : {d.get('created_at')}")
print(f"started_at : {d.get('started_at')}")
print(f"updated_at : {d.get('updated_at')}\n")

else:
print("No deployments found for this project.")

Check the status of the deployment​

DEPLOYMENT_ID = "5bd560ec-bdd1-4a42-bcda-3ea8a4e48e80" #replace with your deployment ID

try:
resp = requests.get(f"{BASE_URL}/api2/api/deployments/{DEPLOYMENT_ID}", headers=headers, timeout=60)
resp.raise_for_status()
except requests.exceptions.HTTPError:
try:
print(f"HTTP {resp.status_code} error:\n" + json.dumps(resp.json(), indent=2))
except Exception:
print(f"HTTP {resp.status_code} error:\n{resp.text[:2000]}")
raise
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

status = resp.json()

# Nice summary
print("Deployment Status")
print("-----------------")
print(f"deployment_id : {status.get('deployment_id')}")
print(f"project_id : {status.get('project_id')}")
print(f"name : {status.get('name')}")
print(f"experiment_id : {status.get('experiment_id')}")
print(f"status : {status.get('status')}")
print(f"url : {status.get('url')}")
print(f"url_internal : {status.get('url_internal')}")
print(f"created_at : {status.get('created_at')}")
print(f"started_at : {status.get('started_at')}")
print(f"updated_at : {status.get('updated_at')}\n")

Delete deployment​

DEPLOYMENT_ID = "5bd560ec-bdd1-4a42-bcda-3ea8a4e48e80" #replace with your deployment ID

try:
resp = requests.delete(f"{BASE_URL}/api2/api/deployments/{DEPLOYMENT_ID}", headers=headers, timeout=60)
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

if resp.status_code == 200:
try:
data = resp.json()
except ValueError:
data = {"message": resp.text.strip() or "Deleted"}
print("Deletion successful:")
elif resp.status_code == 403:
print("Access denied (403). Check token scopes/roles and project permissions.")
elif resp.status_code == 404:
print("Deployment not found (404). Verify DEPLOYMENT_ID.")
elif resp.status_code == 422:
print("Validation error (422). The DEPLOYMENT_ID format may be invalid.")
else:
print(f"Error {resp.status_code}:")

6. AutoML​

Create an AutoML job to explore multiple experiment configurations automatically.

automl_payload = {
"name": "my-automlv2", # AutoML job display name
"total_experiments": 1, # how many experiments AutoML should launch
"request": { # baseline experiment config to start from
"architecture": {
"training_mode": "lora",
"gradient_checkpointing": True,
"intermediate_dropout": 0,
"backbone_kwargs": "{}"
},
"dataset": {
"data_sample_choice": ["Train", "Validation"],
"data_sample": 1,
"prompt_column": "input",
"answer_column": [ # answer_column (multi-target) or (single-target)
"question_is_billing_issue",
"question_was_issue_resolved",
"question_is_technical_issue",
],
"train_dataset_id": "ed7e88a7-d459-4b97-bbc4-50e07a63fd5b",
"validation_strategy": "automatic",
"validation_size": 0.2,
"unroll_conversations": False
},
"environment": {
"find_unused_parameters": False,
"huggingface_branch": "main",
"mixed_precision": True,
"use_fsdp": False,
"use_fsdp_cpu_offload": False,
"seed": -1,
"trust_remote_code": True
},
"tokenizer": {
"max_length": 512,
"padding_quantile": 1,
"tokenizer_kwargs": "{\"use_fast\": true, \"add_prefix_space\": false}"
},
"training": {
"attention_implementation": "auto",
"batch_size": 1,
"differential_learning_rate_layers": [],
"differential_learning_rate": 1e-5,
"epochs": 1,
"evaluate_before_training": True,
"evaluation_epochs": 1,
"grad_accumulation": 1,
"gradient_clip": 0,
"learning_rate": 1e-4,
"lora_alpha": 16,
"lora_dropout": 0.05,
"lora_rank": 4,
"lora_target_modules": "",
"min_learning_rate_ratio": 0,
"optimizer": "AdamW",
"schedule": "Cosine",
"train_validation_data": False,
"use_length_based_sampler": True,
"warmup_epochs": 0,
"weight_decay": 0
},
"logging": {},
"prediction": {
"batch_size_inference": 0,
"max_length_inference": 128,
"metrics": [],
"min_length_inference": 2,
"num_beams": 1,
"repetition_penalty": 1,
"temperature": 0,
"top_k": 0,
"top_p": 1
},
"experiment_name": "experiment",
"experiment_id": "string",
"project_id": "1234",
"reference_experiment_ids": [],
"llm_backbone": "h2oai/h2o-danube3-500m-chat",
"problem_type": "text_causal_classification_modeling"
},
"project_id": "6b62cd37-3080-490f-ba00-af911bb15981", # project where AutoML will create experiments
"llm_backbones": ["string"]
}

try:
resp = requests.post(f"{BASE_URL}/api2/api/automl", headers=headers, data=json.dumps(automl_payload), timeout=180)
except requests.exceptions.RequestException as e:
raise SystemExit(f"Request failed: {e}")

if resp.status_code == 200:
try:
data = resp.json()
except ValueError:
raise SystemExit(f"Unexpected response format:\n{resp.text[:1000]}")
print("AutoML job created:")
print(json.dumps(data, indent=2))
elif resp.status_code == 403:
print("Access denied (403). Check token scopes/roles and project permissions.")
print(resp.text[:1000])
elif resp.status_code == 422:
print("Validation error (422). Check required fields and value types.")
try:
print(json.dumps(resp.json(), indent=2))
except ValueError:
print(resp.text[:1000])
else:
print(f"Error {resp.status_code}")
try:
print(json.dumps(resp.json(), indent=2))
except ValueError:
print(resp.text[:2000])

Feedback