or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth-tokens.mdbatch.mdcaching.mdchat.mdclient.mdcontent-generation.mdembeddings.mdfile-search-stores.mdfiles.mdfunction-calling.mdimage-generation.mdindex.mdlive.mdmcp.mdmodels.mdoperations.mdtuning.mdvideo-generation.md

tuning.mddocs/

0

# Model Tuning (Experimental)

1

2

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

3

4

## Capabilities

5

6

### tune

7

8

Create a supervised fine-tuning job.

9

10

```typescript { .api }

11

/**

12

* Create supervised fine-tuning job

13

* @param params - Tuning job creation parameters

14

* @returns Promise resolving to tuning job

15

*/

16

function tune(

17

params: CreateTuningJobParameters

18

): Promise<TuningJob>;

19

20

interface CreateTuningJobParameters {

21

/** Base model to tune (e.g., 'gemini-1.5-flash-001') */

22

baseModel: string;

23

/** Training dataset */

24

trainingDataset: TuningDataset;

25

/** Validation dataset (optional) */

26

validationDataset?: TuningDataset;

27

/** Tuning configuration */

28

config?: TuningConfig;

29

}

30

31

interface TuningJob {

32

/** Job name (unique identifier) */

33

name?: string;

34

/** Display name for tuned model */

35

tunedModelDisplayName?: string;

36

/** Base model used */

37

baseModel?: string;

38

/** Job state */

39

state?: JobState;

40

/** Creation timestamp */

41

createTime?: string;

42

/** Start timestamp */

43

startTime?: string;

44

/** End timestamp */

45

endTime?: string;

46

/** Training dataset */

47

trainingDataset?: TuningDataset;

48

/** Validation dataset */

49

validationDataset?: TuningDataset;

50

/** Hyperparameters */

51

hyperparameters?: Hyperparameters;

52

/** Resulting tuned model name */

53

tunedModel?: string;

54

/** Error if job failed */

55

error?: Status;

56

}

57

```

58

59

**Usage Examples:**

60

61

```typescript

62

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

63

64

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

65

66

// Prepare training data

67

const trainingExamples: TuningExample[] = [

68

{

69

contents: [

70

{ role: 'user', parts: [{ text: 'Input example 1' }] },

71

{ role: 'model', parts: [{ text: 'Output example 1' }] }

72

]

73

},

74

{

75

contents: [

76

{ role: 'user', parts: [{ text: 'Input example 2' }] },

77

{ role: 'model', parts: [{ text: 'Output example 2' }] }

78

]

79

}

80

// ... more examples

81

];

82

83

// Create tuning job

84

const tuningJob = await client.tunings.tune({

85

baseModel: 'gemini-1.5-flash-001',

86

trainingDataset: {

87

examples: trainingExamples

88

},

89

config: {

90

tunedModelDisplayName: 'My Custom Model',

91

epochCount: 3,

92

learningRate: 0.001

93

}

94

});

95

96

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

97

console.log('State:', tuningJob.state);

98

```

99

100

### list

101

102

List tuning jobs with pagination.

103

104

```typescript { .api }

105

/**

106

* List tuning jobs

107

* @param params - List parameters

108

* @returns Promise resolving to pager of tuning jobs

109

*/

110

function list(

111

params?: ListTuningJobsParameters

112

): Promise<Pager<TuningJob>>;

113

114

interface ListTuningJobsParameters {

115

/** Page size */

116

pageSize?: number;

117

/** Page token for pagination */

118

pageToken?: string;

119

}

120

```

121

122

**Usage Examples:**

123

124

```typescript

125

// List all tuning jobs

126

const pager = await client.tunings.list({

127

pageSize: 10

128

});

129

130

for await (const job of pager) {

131

console.log(`Job: ${job.name}`);

132

console.log(` Display Name: ${job.tunedModelDisplayName}`);

133

console.log(` Base Model: ${job.baseModel}`);

134

console.log(` State: ${job.state}`);

135

console.log(` Created: ${job.createTime}`);

136

if (job.tunedModel) {

137

console.log(` Tuned Model: ${job.tunedModel}`);

138

}

139

console.log('');

140

}

141

```

142

143

### get

144

145

Get tuning job status and details.

146

147

```typescript { .api }

148

/**

149

* Get tuning job status

150

* @param params - Get parameters

151

* @returns Promise resolving to tuning job

152

*/

153

function get(

154

params: GetTuningJobParameters

155

): Promise<TuningJob>;

156

157

interface GetTuningJobParameters {

158

/** Tuning job name */

159

tuningJob: string;

160

}

161

```

162

163

**Usage Examples:**

164

165

```typescript

166

// Get job details

167

const job = await client.tunings.get({

168

tuningJob: 'tunedModels/my-model-abc123/operations/xyz'

169

});

170

171

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

172

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

173

174

// Poll until complete

175

while (

176

job.state === JobState.JOB_STATE_RUNNING ||

177

job.state === JobState.JOB_STATE_PENDING

178

) {

179

console.log('Tuning in progress...');

180

await new Promise(resolve => setTimeout(resolve, 30000)); // Wait 30s

181

182

const updated = await client.tunings.get({

183

tuningJob: job.name!

184

});

185

186

if (updated.state === JobState.JOB_STATE_SUCCEEDED) {

187

console.log('Tuning completed!');

188

console.log('Tuned model:', updated.tunedModel);

189

break;

190

} else if (updated.state === JobState.JOB_STATE_FAILED) {

191

console.error('Tuning failed:', updated.error);

192

break;

193

}

194

}

195

```

196

197

## Types

198

199

### TuningDataset

200

201

Training or validation dataset.

202

203

```typescript { .api }

204

interface TuningDataset {

205

/** Training examples */

206

examples?: TuningExample[];

207

}

208

209

interface TuningExample {

210

/** Example contents (user input + model output) */

211

contents?: Content[];

212

}

213

```

214

215

### TuningConfig

216

217

Configuration for tuning job.

218

219

```typescript { .api }

220

interface TuningConfig {

221

/** Display name for tuned model */

222

tunedModelDisplayName?: string;

223

/** Tuning mode */

224

tuningMode?: TuningMode;

225

/** Tuning method */

226

tuningMethod?: TuningMethod;

227

/** Tuning task */

228

tuningTask?: TuningTask;

229

/** Number of training epochs */

230

epochCount?: number;

231

/** Learning rate */

232

learningRate?: number;

233

/** Batch size */

234

batchSize?: number;

235

/** Learning rate multiplier */

236

learningRateMultiplier?: number;

237

}

238

```

239

240

### Hyperparameters

241

242

Hyperparameters used in tuning.

243

244

```typescript { .api }

245

interface Hyperparameters {

246

/** Number of epochs */

247

epochCount?: number;

248

/** Learning rate */

249

learningRate?: number;

250

/** Batch size */

251

batchSize?: number;

252

/** Learning rate multiplier */

253

learningRateMultiplier?: number;

254

}

255

```

256

257

### Enumerations

258

259

```typescript { .api }

260

enum TuningMode {

261

TUNING_MODE_UNSPECIFIED = 'TUNING_MODE_UNSPECIFIED',

262

/** Full model tuning */

263

FULL = 'FULL',

264

/** Parameter-efficient fine-tuning */

265

PEFT_ADAPTER = 'PEFT_ADAPTER'

266

}

267

268

enum TuningMethod {

269

TUNING_METHOD_UNSPECIFIED = 'TUNING_METHOD_UNSPECIFIED',

270

/** Supervised fine-tuning */

271

SUPERVISED_FINE_TUNING = 'SUPERVISED_FINE_TUNING',

272

/** Preference tuning */

273

PREFERENCE_TUNING = 'PREFERENCE_TUNING'

274

}

275

276

enum TuningTask {

277

TUNING_TASK_UNSPECIFIED = 'TUNING_TASK_UNSPECIFIED',

278

/** Image to video */

279

I2V = 'I2V',

280

/** Text to video */

281

T2V = 'T2V',

282

/** Reference to video */

283

R2V = 'R2V'

284

}

285

286

enum JobState {

287

JOB_STATE_UNSPECIFIED = 'JOB_STATE_UNSPECIFIED',

288

JOB_STATE_QUEUED = 'JOB_STATE_QUEUED',

289

JOB_STATE_PENDING = 'JOB_STATE_PENDING',

290

JOB_STATE_RUNNING = 'JOB_STATE_RUNNING',

291

JOB_STATE_SUCCEEDED = 'JOB_STATE_SUCCEEDED',

292

JOB_STATE_FAILED = 'JOB_STATE_FAILED',

293

JOB_STATE_CANCELLING = 'JOB_STATE_CANCELLING',

294

JOB_STATE_CANCELLED = 'JOB_STATE_CANCELLED'

295

}

296

```

297

298

## Complete Examples

299

300

### Basic Supervised Fine-Tuning

301

302

```typescript

303

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

304

import * as fs from 'fs';

305

306

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

307

308

// Load training data from JSONL file

309

const trainingData: TuningExample[] = fs

310

.readFileSync('./training-data.jsonl', 'utf-8')

311

.split('\n')

312

.filter(line => line.trim())

313

.map(line => JSON.parse(line));

314

315

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

316

317

// Create tuning job

318

const tuningJob = await client.tunings.tune({

319

baseModel: 'gemini-1.5-flash-001',

320

trainingDataset: {

321

examples: trainingData

322

},

323

config: {

324

tunedModelDisplayName: 'Customer Support Bot',

325

epochCount: 5,

326

learningRate: 0.001,

327

batchSize: 4

328

}

329

});

330

331

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

332

333

// Poll for completion

334

async function pollTuningJob(jobName: string): Promise<TuningJob> {

335

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

336

337

while (

338

job.state === JobState.JOB_STATE_RUNNING ||

339

job.state === JobState.JOB_STATE_PENDING ||

340

job.state === JobState.JOB_STATE_QUEUED

341

) {

342

console.log(`Status: ${job.state}`);

343

await new Promise(resolve => setTimeout(resolve, 60000)); // Wait 1 minute

344

345

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

346

}

347

348

return job;

349

}

350

351

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

352

353

if (completed.state === JobState.JOB_STATE_SUCCEEDED) {

354

console.log('Tuning completed successfully!');

355

console.log('Tuned model:', completed.tunedModel);

356

357

// Use the tuned model

358

const response = await client.models.generateContent({

359

model: completed.tunedModel!,

360

contents: 'Test input for tuned model'

361

});

362

363

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

364

} else {

365

console.error('Tuning failed:', completed.error);

366

}

367

```

368

369

### Tuning with Validation Dataset

370

371

```typescript

372

// Prepare training and validation data

373

const trainingExamples: TuningExample[] = [

374

// ... 80% of your data

375

];

376

377

const validationExamples: TuningExample[] = [

378

// ... 20% of your data

379

];

380

381

// Create tuning job with validation

382

const tuningJob = await client.tunings.tune({

383

baseModel: 'gemini-1.5-flash-001',

384

trainingDataset: {

385

examples: trainingExamples

386

},

387

validationDataset: {

388

examples: validationExamples

389

},

390

config: {

391

tunedModelDisplayName: 'Validated Custom Model',

392

epochCount: 10,

393

learningRate: 0.0005

394

}

395

});

396

397

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

398

```

399

400

### Prepare Training Data

401

402

```typescript

403

// Helper to create training examples

404

function createTrainingExample(

405

userInput: string,

406

modelOutput: string

407

): TuningExample {

408

return {

409

contents: [

410

{

411

role: 'user',

412

parts: [{ text: userInput }]

413

},

414

{

415

role: 'model',

416

parts: [{ text: modelOutput }]

417

}

418

]

419

};

420

}

421

422

// Create training dataset

423

const examples: TuningExample[] = [

424

createTrainingExample(

425

'What are your business hours?',

426

'We are open Monday to Friday, 9 AM to 5 PM EST.'

427

),

428

createTrainingExample(

429

'How do I track my order?',

430

'You can track your order using the tracking link sent to your email.'

431

),

432

createTrainingExample(

433

'What is your return policy?',

434

'Items can be returned within 30 days of purchase with original receipt.'

435

),

436

// ... more examples

437

];

438

439

// Save to JSONL format

440

const jsonl = examples.map(ex => JSON.stringify(ex)).join('\n');

441

fs.writeFileSync('./training-data.jsonl', jsonl);

442

443

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

444

```

445

446

### Manage Tuning Jobs

447

448

```typescript

449

// List all tuning jobs

450

const jobs = await client.tunings.list();

451

452

const activeJobs: TuningJob[] = [];

453

const completedJobs: TuningJob[] = [];

454

const failedJobs: TuningJob[] = [];

455

456

for await (const job of jobs) {

457

if (job.state === JobState.JOB_STATE_RUNNING ||

458

job.state === JobState.JOB_STATE_PENDING) {

459

activeJobs.push(job);

460

} else if (job.state === JobState.JOB_STATE_SUCCEEDED) {

461

completedJobs.push(job);

462

} else if (job.state === JobState.JOB_STATE_FAILED) {

463

failedJobs.push(job);

464

}

465

}

466

467

console.log(`Active jobs: ${activeJobs.length}`);

468

console.log(`Completed jobs: ${completedJobs.length}`);

469

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

470

471

// Display active jobs

472

if (activeJobs.length > 0) {

473

console.log('Active Tuning Jobs:');

474

activeJobs.forEach(job => {

475

console.log(` - ${job.tunedModelDisplayName}`);

476

console.log(` State: ${job.state}`);

477

console.log(` Started: ${job.startTime}`);

478

});

479

}

480

481

// Display completed models

482

if (completedJobs.length > 0) {

483

console.log('\nCompleted Tuned Models:');

484

completedJobs.forEach(job => {

485

console.log(` - ${job.tunedModelDisplayName}`);

486

console.log(` Model: ${job.tunedModel}`);

487

console.log(` Completed: ${job.endTime}`);

488

});

489

}

490

```

491

492

### Use Tuned Model

493

494

```typescript

495

// Get completed tuning job

496

const job = await client.tunings.get({

497

tuningJob: 'tunedModels/my-model-abc123/operations/xyz'

498

});

499

500

if (job.state === JobState.JOB_STATE_SUCCEEDED && job.tunedModel) {

501

console.log('Using tuned model:', job.tunedModel);

502

503

// Generate with tuned model

504

const response = await client.models.generateContent({

505

model: job.tunedModel,

506

contents: 'Input for tuned model'

507

});

508

509

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

510

511

// Create chat with tuned model

512

const chat = client.chats.create({

513

model: job.tunedModel,

514

config: {

515

temperature: 0.7

516

}

517

});

518

519

const chatResponse = await chat.sendMessage({

520

message: 'Hello!'

521

});

522

523

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

524

}

525

```

526

527

### Hyperparameter Tuning

528

529

```typescript

530

// Try different hyperparameter configurations

531

const configs = [

532

{ epochCount: 3, learningRate: 0.001, batchSize: 4 },

533

{ epochCount: 5, learningRate: 0.0005, batchSize: 8 },

534

{ epochCount: 10, learningRate: 0.0001, batchSize: 4 }

535

];

536

537

const tuningJobs = await Promise.all(

538

configs.map((config, index) =>

539

client.tunings.tune({

540

baseModel: 'gemini-1.5-flash-001',

541

trainingDataset: { examples: trainingData },

542

validationDataset: { examples: validationData },

543

config: {

544

tunedModelDisplayName: `Model Config ${index + 1}`,

545

...config

546

}

547

})

548

)

549

);

550

551

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

552

553

// Monitor all jobs

554

const results = await Promise.all(

555

tuningJobs.map(job => pollTuningJob(job.name!))

556

);

557

558

// Compare results

559

console.log('\nResults:');

560

results.forEach((result, index) => {

561

console.log(`Config ${index + 1}:`, configs[index]);

562

console.log(` State: ${result.state}`);

563

if (result.tunedModel) {

564

console.log(` Model: ${result.tunedModel}`);

565

}

566

});

567

```

568

569

### Error Handling and Retry

570

571

```typescript

572

async function tuneWithRetry(

573

params: CreateTuningJobParameters,

574

maxRetries: number = 3

575

): Promise<TuningJob> {

576

for (let attempt = 1; attempt <= maxRetries; attempt++) {

577

try {

578

console.log(`Attempt ${attempt}/${maxRetries}`);

579

580

const job = await client.tunings.tune(params);

581

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

582

583

if (completed.state === JobState.JOB_STATE_SUCCEEDED) {

584

console.log('Tuning succeeded');

585

return completed;

586

} else if (completed.state === JobState.JOB_STATE_FAILED) {

587

throw new Error(`Tuning failed: ${completed.error?.message}`);

588

}

589

} catch (error) {

590

console.error(`Attempt ${attempt} failed:`, error);

591

592

if (attempt === maxRetries) {

593

throw error;

594

}

595

596

// Exponential backoff

597

const backoffMs = Math.pow(2, attempt) * 60000; // Minutes

598

console.log(`Retrying in ${backoffMs / 60000} minutes...`);

599

await new Promise(resolve => setTimeout(resolve, backoffMs));

600

}

601

}

602

603

throw new Error('Max retries exceeded');

604

}

605

606

// Use with retry

607

try {

608

const result = await tuneWithRetry({

609

baseModel: 'gemini-1.5-flash-001',

610

trainingDataset: { examples: trainingData },

611

config: {

612

tunedModelDisplayName: 'Robust Model',

613

epochCount: 5

614

}

615

});

616

617

console.log('Final tuned model:', result.tunedModel);

618

} catch (error) {

619

console.error('Tuning failed after retries:', error);

620

}

621

```

622

623

### Data Validation

624

625

```typescript

626

function validateTrainingData(examples: TuningExample[]): boolean {

627

if (examples.length < 10) {

628

console.error('Need at least 10 training examples');

629

return false;

630

}

631

632

for (let i = 0; i < examples.length; i++) {

633

const example = examples[i];

634

635

if (!example.contents || example.contents.length !== 2) {

636

console.error(`Example ${i}: Must have exactly 2 content items (user and model)`);

637

return false;

638

}

639

640

const [userContent, modelContent] = example.contents;

641

642

if (userContent.role !== 'user') {

643

console.error(`Example ${i}: First content must be 'user' role`);

644

return false;

645

}

646

647

if (modelContent.role !== 'model') {

648

console.error(`Example ${i}: Second content must be 'model' role`);

649

return false;

650

}

651

652

if (!userContent.parts?.[0]?.text) {

653

console.error(`Example ${i}: User content must have text`);

654

return false;

655

}

656

657

if (!modelContent.parts?.[0]?.text) {

658

console.error(`Example ${i}: Model content must have text`);

659

return false;

660

}

661

}

662

663

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

664

return true;

665

}

666

667

// Validate before tuning

668

if (validateTrainingData(trainingExamples)) {

669

const job = await client.tunings.tune({

670

baseModel: 'gemini-1.5-flash-001',

671

trainingDataset: { examples: trainingExamples },

672

config: {

673

tunedModelDisplayName: 'Validated Model'

674

}

675

});

676

}

677

```

678

679

### Track Multiple Tuning Jobs

680

681

```typescript

682

class TuningJobTracker {

683

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

684

685

async startJob(params: CreateTuningJobParameters): Promise<string> {

686

const job = await client.tunings.tune(params);

687

this.jobs.set(job.name!, job);

688

console.log(`Started job: ${job.name}`);

689

return job.name!;

690

}

691

692

async checkAll(): Promise<void> {

693

console.log(`\nChecking ${this.jobs.size} jobs...`);

694

695

for (const [name, _] of this.jobs) {

696

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

697

this.jobs.set(name, updated);

698

699

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

700

701

if (updated.state === JobState.JOB_STATE_SUCCEEDED) {

702

console.log(` ✓ Model ready: ${updated.tunedModel}`);

703

} else if (updated.state === JobState.JOB_STATE_FAILED) {

704

console.log(` ✗ Failed: ${updated.error?.message}`);

705

}

706

}

707

}

708

709

getCompleted(): TuningJob[] {

710

return Array.from(this.jobs.values()).filter(

711

job => job.state === JobState.JOB_STATE_SUCCEEDED

712

);

713

}

714

715

getActive(): TuningJob[] {

716

return Array.from(this.jobs.values()).filter(

717

job => job.state === JobState.JOB_STATE_RUNNING ||

718

job.state === JobState.JOB_STATE_PENDING

719

);

720

}

721

}

722

723

// Use tracker

724

const tracker = new TuningJobTracker();

725

726

await tracker.startJob({

727

baseModel: 'gemini-1.5-flash-001',

728

trainingDataset: { examples: dataset1 },

729

config: { tunedModelDisplayName: 'Model 1' }

730

});

731

732

await tracker.startJob({

733

baseModel: 'gemini-1.5-flash-001',

734

trainingDataset: { examples: dataset2 },

735

config: { tunedModelDisplayName: 'Model 2' }

736

});

737

738

// Monitor progress

739

const checkInterval = setInterval(async () => {

740

await tracker.checkAll();

741

742

if (tracker.getActive().length === 0) {

743

clearInterval(checkInterval);

744

console.log('\nAll jobs completed');

745

746

const completed = tracker.getCompleted();

747

console.log(`${completed.length} models ready to use`);

748

}

749

}, 60000); // Check every minute

750

```

751