CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-google--genai

Google Gen AI JavaScript SDK for building applications powered by Gemini with content generation, image/video generation, function calling, caching, and real-time live sessions

Overview
Eval results
Files

tuning.mddocs/

Model Tuning (Experimental)

The Tunings module provides model fine-tuning capabilities, allowing you to create custom models adapted to your specific use cases through supervised fine-tuning.

Capabilities

tune

Create a supervised fine-tuning job.

/**
 * Create supervised fine-tuning job
 * @param params - Tuning job creation parameters
 * @returns Promise resolving to tuning job
 */
function tune(
  params: CreateTuningJobParameters
): Promise<TuningJob>;

interface CreateTuningJobParameters {
  /** Base model to tune (e.g., 'gemini-1.5-flash-001') */
  baseModel: string;
  /** Training dataset */
  trainingDataset: TuningDataset;
  /** Validation dataset (optional) */
  validationDataset?: TuningDataset;
  /** Tuning configuration */
  config?: TuningConfig;
}

interface TuningJob {
  /** Job name (unique identifier) */
  name?: string;
  /** Display name for tuned model */
  tunedModelDisplayName?: string;
  /** Base model used */
  baseModel?: string;
  /** Job state */
  state?: JobState;
  /** Creation timestamp */
  createTime?: string;
  /** Start timestamp */
  startTime?: string;
  /** End timestamp */
  endTime?: string;
  /** Training dataset */
  trainingDataset?: TuningDataset;
  /** Validation dataset */
  validationDataset?: TuningDataset;
  /** Hyperparameters */
  hyperparameters?: Hyperparameters;
  /** Resulting tuned model name */
  tunedModel?: string;
  /** Error if job failed */
  error?: Status;
}

Usage Examples:

import { GoogleGenAI } from '@google/genai';

const client = new GoogleGenAI({ apiKey: 'YOUR_API_KEY' });

// Prepare training data
const trainingExamples: TuningExample[] = [
  {
    contents: [
      { role: 'user', parts: [{ text: 'Input example 1' }] },
      { role: 'model', parts: [{ text: 'Output example 1' }] }
    ]
  },
  {
    contents: [
      { role: 'user', parts: [{ text: 'Input example 2' }] },
      { role: 'model', parts: [{ text: 'Output example 2' }] }
    ]
  }
  // ... more examples
];

// Create tuning job
const tuningJob = await client.tunings.tune({
  baseModel: 'gemini-1.5-flash-001',
  trainingDataset: {
    examples: trainingExamples
  },
  config: {
    tunedModelDisplayName: 'My Custom Model',
    epochCount: 3,
    learningRate: 0.001
  }
});

console.log('Tuning job created:', tuningJob.name);
console.log('State:', tuningJob.state);

list

List tuning jobs with pagination.

/**
 * List tuning jobs
 * @param params - List parameters
 * @returns Promise resolving to pager of tuning jobs
 */
function list(
  params?: ListTuningJobsParameters
): Promise<Pager<TuningJob>>;

interface ListTuningJobsParameters {
  /** Page size */
  pageSize?: number;
  /** Page token for pagination */
  pageToken?: string;
}

Usage Examples:

// List all tuning jobs
const pager = await client.tunings.list({
  pageSize: 10
});

for await (const job of pager) {
  console.log(`Job: ${job.name}`);
  console.log(`  Display Name: ${job.tunedModelDisplayName}`);
  console.log(`  Base Model: ${job.baseModel}`);
  console.log(`  State: ${job.state}`);
  console.log(`  Created: ${job.createTime}`);
  if (job.tunedModel) {
    console.log(`  Tuned Model: ${job.tunedModel}`);
  }
  console.log('');
}

get

Get tuning job status and details.

/**
 * Get tuning job status
 * @param params - Get parameters
 * @returns Promise resolving to tuning job
 */
function get(
  params: GetTuningJobParameters
): Promise<TuningJob>;

interface GetTuningJobParameters {
  /** Tuning job name */
  tuningJob: string;
}

Usage Examples:

// Get job details
const job = await client.tunings.get({
  tuningJob: 'tunedModels/my-model-abc123/operations/xyz'
});

console.log('Job state:', job.state);
console.log('Tuned model:', job.tunedModel);

// Poll until complete
while (
  job.state === JobState.JOB_STATE_RUNNING ||
  job.state === JobState.JOB_STATE_PENDING
) {
  console.log('Tuning in progress...');
  await new Promise(resolve => setTimeout(resolve, 30000)); // Wait 30s

  const updated = await client.tunings.get({
    tuningJob: job.name!
  });

  if (updated.state === JobState.JOB_STATE_SUCCEEDED) {
    console.log('Tuning completed!');
    console.log('Tuned model:', updated.tunedModel);
    break;
  } else if (updated.state === JobState.JOB_STATE_FAILED) {
    console.error('Tuning failed:', updated.error);
    break;
  }
}

Types

TuningDataset

Training or validation dataset.

interface TuningDataset {
  /** Training examples */
  examples?: TuningExample[];
}

interface TuningExample {
  /** Example contents (user input + model output) */
  contents?: Content[];
}

TuningConfig

Configuration for tuning job.

interface TuningConfig {
  /** Display name for tuned model */
  tunedModelDisplayName?: string;
  /** Tuning mode */
  tuningMode?: TuningMode;
  /** Tuning method */
  tuningMethod?: TuningMethod;
  /** Tuning task */
  tuningTask?: TuningTask;
  /** Number of training epochs */
  epochCount?: number;
  /** Learning rate */
  learningRate?: number;
  /** Batch size */
  batchSize?: number;
  /** Learning rate multiplier */
  learningRateMultiplier?: number;
}

Hyperparameters

Hyperparameters used in tuning.

interface Hyperparameters {
  /** Number of epochs */
  epochCount?: number;
  /** Learning rate */
  learningRate?: number;
  /** Batch size */
  batchSize?: number;
  /** Learning rate multiplier */
  learningRateMultiplier?: number;
}

Enumerations

enum TuningMode {
  TUNING_MODE_UNSPECIFIED = 'TUNING_MODE_UNSPECIFIED',
  /** Full model tuning */
  FULL = 'FULL',
  /** Parameter-efficient fine-tuning */
  PEFT_ADAPTER = 'PEFT_ADAPTER'
}

enum TuningMethod {
  TUNING_METHOD_UNSPECIFIED = 'TUNING_METHOD_UNSPECIFIED',
  /** Supervised fine-tuning */
  SUPERVISED_FINE_TUNING = 'SUPERVISED_FINE_TUNING',
  /** Preference tuning */
  PREFERENCE_TUNING = 'PREFERENCE_TUNING'
}

enum TuningTask {
  TUNING_TASK_UNSPECIFIED = 'TUNING_TASK_UNSPECIFIED',
  /** Image to video */
  I2V = 'I2V',
  /** Text to video */
  T2V = 'T2V',
  /** Reference to video */
  R2V = 'R2V'
}

enum JobState {
  JOB_STATE_UNSPECIFIED = 'JOB_STATE_UNSPECIFIED',
  JOB_STATE_QUEUED = 'JOB_STATE_QUEUED',
  JOB_STATE_PENDING = 'JOB_STATE_PENDING',
  JOB_STATE_RUNNING = 'JOB_STATE_RUNNING',
  JOB_STATE_SUCCEEDED = 'JOB_STATE_SUCCEEDED',
  JOB_STATE_FAILED = 'JOB_STATE_FAILED',
  JOB_STATE_CANCELLING = 'JOB_STATE_CANCELLING',
  JOB_STATE_CANCELLED = 'JOB_STATE_CANCELLED'
}

Complete Examples

Basic Supervised Fine-Tuning

import { GoogleGenAI, TuningExample } from '@google/genai';
import * as fs from 'fs';

const client = new GoogleGenAI({ apiKey: 'YOUR_API_KEY' });

// Load training data from JSONL file
const trainingData: TuningExample[] = fs
  .readFileSync('./training-data.jsonl', 'utf-8')
  .split('\n')
  .filter(line => line.trim())
  .map(line => JSON.parse(line));

console.log(`Loaded ${trainingData.length} training examples`);

// Create tuning job
const tuningJob = await client.tunings.tune({
  baseModel: 'gemini-1.5-flash-001',
  trainingDataset: {
    examples: trainingData
  },
  config: {
    tunedModelDisplayName: 'Customer Support Bot',
    epochCount: 5,
    learningRate: 0.001,
    batchSize: 4
  }
});

console.log('Tuning job started:', tuningJob.name);

// Poll for completion
async function pollTuningJob(jobName: string): Promise<TuningJob> {
  let job = await client.tunings.get({ tuningJob: jobName });

  while (
    job.state === JobState.JOB_STATE_RUNNING ||
    job.state === JobState.JOB_STATE_PENDING ||
    job.state === JobState.JOB_STATE_QUEUED
  ) {
    console.log(`Status: ${job.state}`);
    await new Promise(resolve => setTimeout(resolve, 60000)); // Wait 1 minute

    job = await client.tunings.get({ tuningJob: jobName });
  }

  return job;
}

const completed = await pollTuningJob(tuningJob.name!);

if (completed.state === JobState.JOB_STATE_SUCCEEDED) {
  console.log('Tuning completed successfully!');
  console.log('Tuned model:', completed.tunedModel);

  // Use the tuned model
  const response = await client.models.generateContent({
    model: completed.tunedModel!,
    contents: 'Test input for tuned model'
  });

  console.log('Response:', response.text);
} else {
  console.error('Tuning failed:', completed.error);
}

Tuning with Validation Dataset

// Prepare training and validation data
const trainingExamples: TuningExample[] = [
  // ... 80% of your data
];

const validationExamples: TuningExample[] = [
  // ... 20% of your data
];

// Create tuning job with validation
const tuningJob = await client.tunings.tune({
  baseModel: 'gemini-1.5-flash-001',
  trainingDataset: {
    examples: trainingExamples
  },
  validationDataset: {
    examples: validationExamples
  },
  config: {
    tunedModelDisplayName: 'Validated Custom Model',
    epochCount: 10,
    learningRate: 0.0005
  }
});

console.log('Tuning with validation started:', tuningJob.name);

Prepare Training Data

// Helper to create training examples
function createTrainingExample(
  userInput: string,
  modelOutput: string
): TuningExample {
  return {
    contents: [
      {
        role: 'user',
        parts: [{ text: userInput }]
      },
      {
        role: 'model',
        parts: [{ text: modelOutput }]
      }
    ]
  };
}

// Create training dataset
const examples: TuningExample[] = [
  createTrainingExample(
    'What are your business hours?',
    'We are open Monday to Friday, 9 AM to 5 PM EST.'
  ),
  createTrainingExample(
    'How do I track my order?',
    'You can track your order using the tracking link sent to your email.'
  ),
  createTrainingExample(
    'What is your return policy?',
    'Items can be returned within 30 days of purchase with original receipt.'
  ),
  // ... more examples
];

// Save to JSONL format
const jsonl = examples.map(ex => JSON.stringify(ex)).join('\n');
fs.writeFileSync('./training-data.jsonl', jsonl);

console.log(`Prepared ${examples.length} training examples`);

Manage Tuning Jobs

// List all tuning jobs
const jobs = await client.tunings.list();

const activeJobs: TuningJob[] = [];
const completedJobs: TuningJob[] = [];
const failedJobs: TuningJob[] = [];

for await (const job of jobs) {
  if (job.state === JobState.JOB_STATE_RUNNING ||
      job.state === JobState.JOB_STATE_PENDING) {
    activeJobs.push(job);
  } else if (job.state === JobState.JOB_STATE_SUCCEEDED) {
    completedJobs.push(job);
  } else if (job.state === JobState.JOB_STATE_FAILED) {
    failedJobs.push(job);
  }
}

console.log(`Active jobs: ${activeJobs.length}`);
console.log(`Completed jobs: ${completedJobs.length}`);
console.log(`Failed jobs: ${failedJobs.length}\n`);

// Display active jobs
if (activeJobs.length > 0) {
  console.log('Active Tuning Jobs:');
  activeJobs.forEach(job => {
    console.log(`  - ${job.tunedModelDisplayName}`);
    console.log(`    State: ${job.state}`);
    console.log(`    Started: ${job.startTime}`);
  });
}

// Display completed models
if (completedJobs.length > 0) {
  console.log('\nCompleted Tuned Models:');
  completedJobs.forEach(job => {
    console.log(`  - ${job.tunedModelDisplayName}`);
    console.log(`    Model: ${job.tunedModel}`);
    console.log(`    Completed: ${job.endTime}`);
  });
}

Use Tuned Model

// Get completed tuning job
const job = await client.tunings.get({
  tuningJob: 'tunedModels/my-model-abc123/operations/xyz'
});

if (job.state === JobState.JOB_STATE_SUCCEEDED && job.tunedModel) {
  console.log('Using tuned model:', job.tunedModel);

  // Generate with tuned model
  const response = await client.models.generateContent({
    model: job.tunedModel,
    contents: 'Input for tuned model'
  });

  console.log('Response:', response.text);

  // Create chat with tuned model
  const chat = client.chats.create({
    model: job.tunedModel,
    config: {
      temperature: 0.7
    }
  });

  const chatResponse = await chat.sendMessage({
    message: 'Hello!'
  });

  console.log('Chat response:', chatResponse.text);
}

Hyperparameter Tuning

// Try different hyperparameter configurations
const configs = [
  { epochCount: 3, learningRate: 0.001, batchSize: 4 },
  { epochCount: 5, learningRate: 0.0005, batchSize: 8 },
  { epochCount: 10, learningRate: 0.0001, batchSize: 4 }
];

const tuningJobs = await Promise.all(
  configs.map((config, index) =>
    client.tunings.tune({
      baseModel: 'gemini-1.5-flash-001',
      trainingDataset: { examples: trainingData },
      validationDataset: { examples: validationData },
      config: {
        tunedModelDisplayName: `Model Config ${index + 1}`,
        ...config
      }
    })
  )
);

console.log(`Started ${tuningJobs.length} tuning experiments`);

// Monitor all jobs
const results = await Promise.all(
  tuningJobs.map(job => pollTuningJob(job.name!))
);

// Compare results
console.log('\nResults:');
results.forEach((result, index) => {
  console.log(`Config ${index + 1}:`, configs[index]);
  console.log(`  State: ${result.state}`);
  if (result.tunedModel) {
    console.log(`  Model: ${result.tunedModel}`);
  }
});

Error Handling and Retry

async function tuneWithRetry(
  params: CreateTuningJobParameters,
  maxRetries: number = 3
): Promise<TuningJob> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      console.log(`Attempt ${attempt}/${maxRetries}`);

      const job = await client.tunings.tune(params);
      const completed = await pollTuningJob(job.name!);

      if (completed.state === JobState.JOB_STATE_SUCCEEDED) {
        console.log('Tuning succeeded');
        return completed;
      } else if (completed.state === JobState.JOB_STATE_FAILED) {
        throw new Error(`Tuning failed: ${completed.error?.message}`);
      }
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error);

      if (attempt === maxRetries) {
        throw error;
      }

      // Exponential backoff
      const backoffMs = Math.pow(2, attempt) * 60000; // Minutes
      console.log(`Retrying in ${backoffMs / 60000} minutes...`);
      await new Promise(resolve => setTimeout(resolve, backoffMs));
    }
  }

  throw new Error('Max retries exceeded');
}

// Use with retry
try {
  const result = await tuneWithRetry({
    baseModel: 'gemini-1.5-flash-001',
    trainingDataset: { examples: trainingData },
    config: {
      tunedModelDisplayName: 'Robust Model',
      epochCount: 5
    }
  });

  console.log('Final tuned model:', result.tunedModel);
} catch (error) {
  console.error('Tuning failed after retries:', error);
}

Data Validation

function validateTrainingData(examples: TuningExample[]): boolean {
  if (examples.length < 10) {
    console.error('Need at least 10 training examples');
    return false;
  }

  for (let i = 0; i < examples.length; i++) {
    const example = examples[i];

    if (!example.contents || example.contents.length !== 2) {
      console.error(`Example ${i}: Must have exactly 2 content items (user and model)`);
      return false;
    }

    const [userContent, modelContent] = example.contents;

    if (userContent.role !== 'user') {
      console.error(`Example ${i}: First content must be 'user' role`);
      return false;
    }

    if (modelContent.role !== 'model') {
      console.error(`Example ${i}: Second content must be 'model' role`);
      return false;
    }

    if (!userContent.parts?.[0]?.text) {
      console.error(`Example ${i}: User content must have text`);
      return false;
    }

    if (!modelContent.parts?.[0]?.text) {
      console.error(`Example ${i}: Model content must have text`);
      return false;
    }
  }

  console.log(`Validated ${examples.length} examples successfully`);
  return true;
}

// Validate before tuning
if (validateTrainingData(trainingExamples)) {
  const job = await client.tunings.tune({
    baseModel: 'gemini-1.5-flash-001',
    trainingDataset: { examples: trainingExamples },
    config: {
      tunedModelDisplayName: 'Validated Model'
    }
  });
}

Track Multiple Tuning Jobs

class TuningJobTracker {
  private jobs: Map<string, TuningJob> = new Map();

  async startJob(params: CreateTuningJobParameters): Promise<string> {
    const job = await client.tunings.tune(params);
    this.jobs.set(job.name!, job);
    console.log(`Started job: ${job.name}`);
    return job.name!;
  }

  async checkAll(): Promise<void> {
    console.log(`\nChecking ${this.jobs.size} jobs...`);

    for (const [name, _] of this.jobs) {
      const updated = await client.tunings.get({ tuningJob: name });
      this.jobs.set(name, updated);

      console.log(`${updated.tunedModelDisplayName}: ${updated.state}`);

      if (updated.state === JobState.JOB_STATE_SUCCEEDED) {
        console.log(`  ✓ Model ready: ${updated.tunedModel}`);
      } else if (updated.state === JobState.JOB_STATE_FAILED) {
        console.log(`  ✗ Failed: ${updated.error?.message}`);
      }
    }
  }

  getCompleted(): TuningJob[] {
    return Array.from(this.jobs.values()).filter(
      job => job.state === JobState.JOB_STATE_SUCCEEDED
    );
  }

  getActive(): TuningJob[] {
    return Array.from(this.jobs.values()).filter(
      job => job.state === JobState.JOB_STATE_RUNNING ||
           job.state === JobState.JOB_STATE_PENDING
    );
  }
}

// Use tracker
const tracker = new TuningJobTracker();

await tracker.startJob({
  baseModel: 'gemini-1.5-flash-001',
  trainingDataset: { examples: dataset1 },
  config: { tunedModelDisplayName: 'Model 1' }
});

await tracker.startJob({
  baseModel: 'gemini-1.5-flash-001',
  trainingDataset: { examples: dataset2 },
  config: { tunedModelDisplayName: 'Model 2' }
});

// Monitor progress
const checkInterval = setInterval(async () => {
  await tracker.checkAll();

  if (tracker.getActive().length === 0) {
    clearInterval(checkInterval);
    console.log('\nAll jobs completed');

    const completed = tracker.getCompleted();
    console.log(`${completed.length} models ready to use`);
  }
}, 60000); // Check every minute

Install with Tessl CLI

npx tessl i tessl/npm-google--genai

docs

auth-tokens.md

batch.md

caching.md

chat.md

client.md

content-generation.md

embeddings.md

file-search-stores.md

files.md

function-calling.md

image-generation.md

index.md

live.md

mcp.md

models.md

operations.md

tuning.md

video-generation.md

tile.json