or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assistants.mdaudio.mdbatches.mdchat-completions.mdchatkit.mdclient-initialization.mdcompletions.mdcontainers.mdconversations.mdembeddings.mdevals.mdfiles.mdfine-tuning.mdimages.mdindex.mdmodels.mdmoderations.mdrealtime.mdresponses.mdruns.mdthreads-messages.mduploads.mdvector-stores.mdvideos.mdwebhooks.md
KNOWN_ISSUES.md

fine-tuning.mddocs/

0

# Fine-tuning

1

2

Create and manage fine-tuning jobs to customize models on your own data. Fine-tune base models to improve performance on specific tasks, add domain knowledge, or adjust model behavior.

3

4

## Capabilities

5

6

### Create Fine-tuning Job

7

8

Start a fine-tuning job to train a custom model.

9

10

```python { .api }

11

def create(

12

self,

13

*,

14

model: str,

15

training_file: str,

16

hyperparameters: dict | Omit = omit,

17

method: dict | Omit = omit,

18

integrations: list[dict] | Omit = omit,

19

metadata: dict[str, str] | Omit = omit,

20

seed: int | Omit = omit,

21

suffix: str | Omit = omit,

22

validation_file: str | Omit = omit,

23

extra_headers: dict[str, str] | None = None,

24

extra_query: dict[str, object] | None = None,

25

extra_body: dict[str, object] | None = None,

26

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

27

) -> FineTuningJob:

28

"""

29

Create a fine-tuning job to train a custom model.

30

31

Args:

32

model: Base model to fine-tune. Supported models:

33

- "gpt-4o-2024-08-06"

34

- "gpt-4o-mini-2024-07-18"

35

- "gpt-3.5-turbo"

36

- "babbage-002", "davinci-002"

37

38

training_file: ID of uploaded training file (JSONL format).

39

Each line: {"messages": [...], "response": ...}

40

41

hyperparameters: Training hyperparameters. Options:

42

- n_epochs: Number of training epochs (auto or 1-50)

43

- batch_size: Batch size (auto or specific value)

44

- learning_rate_multiplier: Learning rate multiplier (auto or 0.02-2)

45

46

method: Fine-tuning method configuration. Options:

47

- {"type": "supervised"}: Standard supervised fine-tuning

48

- {"type": "dpo"}: Direct Preference Optimization

49

- {"type": "reinforcement"}: Reinforcement learning

50

51

integrations: External tool integrations. Options:

52

- Weights & Biases: [{"type": "wandb", "wandb": {"project": "..."}}]

53

54

metadata: Key-value pairs for storing additional information (max 16 pairs).

55

Keys max 64 chars, values max 512 chars.

56

57

seed: Random seed for reproducibility.

58

59

suffix: Custom suffix for fine-tuned model name (max 18 chars).

60

Final model name: ft:{base_model}:{suffix}:{job_id}

61

62

validation_file: ID of validation file for evaluation during training.

63

64

extra_headers: Additional HTTP headers.

65

extra_query: Additional query parameters.

66

extra_body: Additional JSON fields.

67

timeout: Request timeout in seconds.

68

69

Returns:

70

FineTuningJob: Created job with status "created" or "validating_files".

71

72

Raises:

73

BadRequestError: Invalid parameters or file format

74

NotFoundError: Training file not found

75

"""

76

```

77

78

Usage examples:

79

80

```python

81

from openai import OpenAI

82

83

client = OpenAI()

84

85

# Upload training data first

86

with open("training_data.jsonl", "rb") as f:

87

training_file = client.files.create(file=f, purpose="fine-tune")

88

89

# Create fine-tuning job

90

job = client.fine_tuning.jobs.create(

91

model="gpt-3.5-turbo",

92

training_file=training_file.id

93

)

94

95

print(f"Job ID: {job.id}")

96

print(f"Status: {job.status}")

97

98

# With hyperparameters

99

job = client.fine_tuning.jobs.create(

100

model="gpt-3.5-turbo",

101

training_file=training_file.id,

102

hyperparameters={

103

"n_epochs": 3,

104

"batch_size": 4,

105

"learning_rate_multiplier": 0.1

106

}

107

)

108

109

# With validation file

110

with open("validation_data.jsonl", "rb") as f:

111

validation_file = client.files.create(file=f, purpose="fine-tune")

112

113

job = client.fine_tuning.jobs.create(

114

model="gpt-3.5-turbo",

115

training_file=training_file.id,

116

validation_file=validation_file.id,

117

suffix="my-custom-model"

118

)

119

120

# With Weights & Biases integration

121

job = client.fine_tuning.jobs.create(

122

model="gpt-3.5-turbo",

123

training_file=training_file.id,

124

integrations=[{

125

"type": "wandb",

126

"wandb": {

127

"project": "my-fine-tuning",

128

"name": "experiment-1"

129

}

130

}]

131

)

132

133

# Using DPO method

134

job = client.fine_tuning.jobs.create(

135

model="gpt-3.5-turbo",

136

training_file=training_file.id,

137

method={"type": "dpo"}

138

)

139

```

140

141

### Retrieve Fine-tuning Job

142

143

Get status and details of a fine-tuning job.

144

145

```python { .api }

146

def retrieve(

147

self,

148

fine_tuning_job_id: str,

149

*,

150

extra_headers: dict[str, str] | None = None,

151

extra_query: dict[str, object] | None = None,

152

extra_body: dict[str, object] | None = None,

153

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

154

) -> FineTuningJob:

155

"""

156

Retrieve fine-tuning job details.

157

158

Args:

159

fine_tuning_job_id: The ID of the fine-tuning job.

160

extra_headers: Additional HTTP headers.

161

extra_query: Additional query parameters.

162

extra_body: Additional JSON fields.

163

timeout: Request timeout in seconds.

164

165

Returns:

166

FineTuningJob: Job details including current status.

167

168

Raises:

169

NotFoundError: Job not found

170

"""

171

```

172

173

Usage example:

174

175

```python

176

# Check job status

177

job = client.fine_tuning.jobs.retrieve("ftjob-abc123")

178

179

print(f"Status: {job.status}")

180

print(f"Model: {job.fine_tuned_model}")

181

print(f"Trained tokens: {job.trained_tokens}")

182

183

if job.status == "succeeded":

184

print(f"Fine-tuned model ready: {job.fine_tuned_model}")

185

elif job.status == "failed":

186

print(f"Error: {job.error}")

187

```

188

189

### List Fine-tuning Jobs

190

191

List fine-tuning jobs with optional filtering and pagination.

192

193

```python { .api }

194

def list(

195

self,

196

*,

197

after: str | Omit = omit,

198

limit: int | Omit = omit,

199

metadata: dict[str, str] | Omit = omit,

200

extra_headers: dict[str, str] | None = None,

201

extra_query: dict[str, object] | None = None,

202

extra_body: dict[str, object] | None = None,

203

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

204

) -> SyncCursorPage[FineTuningJob]:

205

"""

206

List fine-tuning jobs with pagination.

207

208

Args:

209

after: Cursor for pagination. Return jobs after this job ID.

210

limit: Number of jobs to retrieve (max 100). Default 20.

211

metadata: Optional metadata filter. To filter, use the syntax `metadata[k]=v`.

212

Alternatively, set `metadata=null` to indicate no metadata.

213

extra_headers: Additional HTTP headers.

214

extra_query: Additional query parameters.

215

extra_body: Additional JSON fields.

216

timeout: Request timeout in seconds.

217

218

Returns:

219

SyncCursorPage[FineTuningJob]: Paginated list of jobs.

220

"""

221

```

222

223

Usage example:

224

225

```python

226

# List all jobs

227

jobs = client.fine_tuning.jobs.list()

228

229

for job in jobs:

230

print(f"{job.id}: {job.status}")

231

232

# Pagination

233

page1 = client.fine_tuning.jobs.list(limit=10)

234

page2 = client.fine_tuning.jobs.list(limit=10, after=page1.data[-1].id)

235

236

# Filter by status

237

succeeded_jobs = [

238

job for job in client.fine_tuning.jobs.list()

239

if job.status == "succeeded"

240

]

241

```

242

243

### Cancel Fine-tuning Job

244

245

Cancel an in-progress fine-tuning job.

246

247

```python { .api }

248

def cancel(

249

self,

250

fine_tuning_job_id: str,

251

*,

252

extra_headers: dict[str, str] | None = None,

253

extra_query: dict[str, object] | None = None,

254

extra_body: dict[str, object] | None = None,

255

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

256

) -> FineTuningJob:

257

"""

258

Cancel a running fine-tuning job.

259

260

Args:

261

fine_tuning_job_id: The ID of the job to cancel.

262

extra_headers: Additional HTTP headers.

263

extra_query: Additional query parameters.

264

extra_body: Additional JSON fields.

265

timeout: Request timeout in seconds.

266

267

Returns:

268

FineTuningJob: Job with status "cancelled".

269

270

Raises:

271

NotFoundError: Job not found

272

BadRequestError: Job not in cancellable state

273

"""

274

```

275

276

Usage example:

277

278

```python

279

# Cancel job

280

job = client.fine_tuning.jobs.cancel("ftjob-abc123")

281

282

print(f"Status: {job.status}") # "cancelled"

283

```

284

285

### Pause Fine-tuning Job

286

287

Temporarily pause a running fine-tuning job to save costs.

288

289

```python { .api }

290

def pause(

291

self,

292

fine_tuning_job_id: str,

293

*,

294

extra_headers: dict[str, str] | None = None,

295

extra_query: dict[str, object] | None = None,

296

extra_body: dict[str, object] | None = None,

297

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

298

) -> FineTuningJob:

299

"""

300

Pause a running fine-tuning job.

301

302

Args:

303

fine_tuning_job_id: The ID of the job to pause.

304

extra_headers: Additional HTTP headers.

305

extra_query: Additional query parameters.

306

extra_body: Additional JSON fields.

307

timeout: Request timeout in seconds.

308

309

Returns:

310

FineTuningJob: Job with status "paused".

311

312

Raises:

313

NotFoundError: Job not found

314

BadRequestError: Job not in pauseable state

315

"""

316

```

317

318

### Resume Fine-tuning Job

319

320

Resume a previously paused fine-tuning job.

321

322

```python { .api }

323

def resume(

324

self,

325

fine_tuning_job_id: str,

326

*,

327

extra_headers: dict[str, str] | None = None,

328

extra_query: dict[str, object] | None = None,

329

extra_body: dict[str, object] | None = None,

330

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

331

) -> FineTuningJob:

332

"""

333

Resume a paused fine-tuning job.

334

335

Args:

336

fine_tuning_job_id: The ID of the job to resume.

337

extra_headers: Additional HTTP headers.

338

extra_query: Additional query parameters.

339

extra_body: Additional JSON fields.

340

timeout: Request timeout in seconds.

341

342

Returns:

343

FineTuningJob: Job with status "running".

344

345

Raises:

346

NotFoundError: Job not found

347

BadRequestError: Job not in resumeable state

348

"""

349

```

350

351

Usage example:

352

353

```python

354

# Pause job to save costs

355

job = client.fine_tuning.jobs.pause("ftjob-abc123")

356

print(f"Status: {job.status}") # "paused"

357

358

# Resume later

359

job = client.fine_tuning.jobs.resume("ftjob-abc123")

360

print(f"Status: {job.status}") # "running"

361

```

362

363

### List Job Events

364

365

Stream events and training metrics from a fine-tuning job.

366

367

```python { .api }

368

def list_events(

369

self,

370

fine_tuning_job_id: str,

371

*,

372

after: str | Omit = omit,

373

limit: int | Omit = omit,

374

extra_headers: dict[str, str] | None = None,

375

extra_query: dict[str, object] | None = None,

376

extra_body: dict[str, object] | None = None,

377

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

378

) -> SyncCursorPage[FineTuningJobEvent]:

379

"""

380

List events for a fine-tuning job (training logs, metrics).

381

382

Args:

383

fine_tuning_job_id: The job ID.

384

after: Return events after this event ID.

385

limit: Number of events to retrieve (max 100). Default 20.

386

extra_headers: Additional HTTP headers.

387

extra_query: Additional query parameters.

388

extra_body: Additional JSON fields.

389

timeout: Request timeout in seconds.

390

391

Returns:

392

SyncCursorPage[FineTuningJobEvent]: Job events and logs.

393

"""

394

```

395

396

Usage example:

397

398

```python

399

# Get training events

400

events = client.fine_tuning.jobs.list_events("ftjob-abc123")

401

402

for event in events:

403

print(f"[{event.created_at}] {event.message}")

404

if event.data:

405

print(f" Metrics: {event.data}")

406

407

# Monitor training progress

408

import time

409

410

job_id = "ftjob-abc123"

411

while True:

412

job = client.fine_tuning.jobs.retrieve(job_id)

413

414

if job.status in ["succeeded", "failed", "cancelled"]:

415

break

416

417

events = client.fine_tuning.jobs.list_events(job_id, limit=5)

418

for event in events:

419

print(event.message)

420

421

time.sleep(10)

422

```

423

424

### List Checkpoints

425

426

List checkpoints saved during fine-tuning.

427

428

```python { .api }

429

def list(

430

self,

431

fine_tuning_job_id: str,

432

*,

433

after: str | Omit = omit,

434

limit: int | Omit = omit,

435

extra_headers: dict[str, str] | None = None,

436

extra_query: dict[str, object] | None = None,

437

extra_body: dict[str, object] | None = None,

438

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

439

) -> SyncCursorPage[FineTuningJobCheckpoint]:

440

"""

441

List checkpoints for a fine-tuning job.

442

443

Args:

444

fine_tuning_job_id: The job ID.

445

after: Return checkpoints after this checkpoint ID.

446

limit: Number of checkpoints to retrieve. Default 10.

447

extra_headers: Additional HTTP headers.

448

extra_query: Additional query parameters.

449

extra_body: Additional JSON fields.

450

timeout: Request timeout in seconds.

451

452

Returns:

453

SyncCursorPage[FineTuningJobCheckpoint]: Job checkpoints.

454

"""

455

```

456

457

Usage example:

458

459

```python

460

# List checkpoints

461

checkpoints = client.fine_tuning.jobs.checkpoints.list("ftjob-abc123")

462

463

for checkpoint in checkpoints:

464

print(f"Step {checkpoint.step_number}: {checkpoint.metrics}")

465

print(f" Model: {checkpoint.fine_tuned_model_checkpoint}")

466

```

467

468

### Checkpoint Permissions

469

470

Manage access permissions for fine-tuning checkpoints to enable sharing.

471

472

```python { .api }

473

# Accessed via: client.fine_tuning.checkpoints.permissions

474

def create(

475

self,

476

fine_tuned_model_checkpoint: str,

477

*,

478

project_ids: list[str],

479

extra_headers: dict[str, str] | None = None,

480

extra_query: dict[str, object] | None = None,

481

extra_body: dict[str, object] | None = None,

482

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

483

) -> SyncPage[PermissionCreateResponse]:

484

"""

485

Grant access permission to a checkpoint.

486

487

NOTE: Calling this endpoint requires an admin API key.

488

This enables organization owners to share fine-tuned models with other projects

489

in their organization.

490

491

Args:

492

fine_tuned_model_checkpoint: The checkpoint model ID (e.g., "ftckpt-xyz789").

493

project_ids: The project identifiers to grant access to (list of strings).

494

extra_headers: Additional HTTP headers.

495

extra_query: Additional query parameters.

496

extra_body: Additional JSON fields.

497

timeout: Request timeout in seconds.

498

499

Returns:

500

SyncPage[PermissionCreateResponse]: Paginated list of created permissions.

501

"""

502

503

def retrieve(

504

self,

505

fine_tuned_model_checkpoint: str,

506

*,

507

after: str | Omit = omit,

508

limit: int | Omit = omit,

509

order: Literal["ascending", "descending"] | Omit = omit,

510

project_id: str | Omit = omit,

511

extra_headers: dict[str, str] | None = None,

512

extra_query: dict[str, object] | None = None,

513

extra_body: dict[str, object] | None = None,

514

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

515

) -> PermissionRetrieveResponse:

516

"""

517

List all permissions for a checkpoint.

518

519

NOTE: This endpoint requires an admin API key.

520

Organization owners can use this endpoint to view all permissions for a

521

fine-tuned model checkpoint.

522

523

Args:

524

fine_tuned_model_checkpoint: The checkpoint model ID.

525

after: Identifier for the last permission ID from the previous pagination request.

526

limit: Number of permissions to retrieve.

527

order: The order in which to retrieve permissions ("ascending" or "descending").

528

project_id: The ID of the project to get permissions for (filter).

529

extra_headers: Additional HTTP headers.

530

extra_query: Additional query parameters.

531

extra_body: Additional JSON fields.

532

timeout: Request timeout in seconds.

533

534

Returns:

535

PermissionRetrieveResponse: Permissions list response.

536

"""

537

538

def delete(

539

self,

540

permission_id: str,

541

*,

542

fine_tuned_model_checkpoint: str,

543

extra_headers: dict[str, str] | None = None,

544

extra_query: dict[str, object] | None = None,

545

extra_body: dict[str, object] | None = None,

546

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

547

) -> PermissionDeleteResponse:

548

"""

549

Revoke a checkpoint permission.

550

551

NOTE: This endpoint requires an admin API key.

552

Organization owners can use this endpoint to delete a permission for a

553

fine-tuned model checkpoint.

554

555

Args:

556

permission_id: The ID of the permission to delete (positional parameter).

557

fine_tuned_model_checkpoint: The checkpoint model ID (keyword-only parameter).

558

extra_headers: Additional HTTP headers.

559

extra_query: Additional query parameters.

560

extra_body: Additional JSON fields.

561

timeout: Request timeout in seconds.

562

563

Returns:

564

PermissionDeleteResponse: Deletion confirmation.

565

"""

566

```

567

568

Usage example:

569

570

```python

571

# Grant checkpoint access to other projects

572

permissions = client.fine_tuning.checkpoints.permissions.create(

573

fine_tuned_model_checkpoint="ftckpt-xyz789",

574

project_ids=["proj-456", "proj-789"]

575

)

576

577

print(f"Created {len(permissions.data)} permissions")

578

for perm in permissions:

579

print(f" Permission ID: {perm.id}")

580

581

# Retrieve all permissions for a checkpoint

582

all_perms = client.fine_tuning.checkpoints.permissions.retrieve(

583

fine_tuned_model_checkpoint="ftckpt-xyz789"

584

)

585

586

print(f"Total permissions: {len(all_perms.data)}")

587

for perm in all_perms.data:

588

print(f" {perm.id}: Project {perm.project_id}")

589

590

# Filter permissions by project

591

project_perms = client.fine_tuning.checkpoints.permissions.retrieve(

592

fine_tuned_model_checkpoint="ftckpt-xyz789",

593

project_id="proj-456"

594

)

595

596

# Revoke a permission

597

deleted = client.fine_tuning.checkpoints.permissions.delete(

598

permission_id="perm-abc123",

599

fine_tuned_model_checkpoint="ftckpt-xyz789"

600

)

601

602

print(f"Deleted: {deleted.deleted}") # True

603

```

604

605

### Alpha Graders

606

607

Run graders to evaluate fine-tuning results (alpha feature).

608

609

```python { .api }

610

# Accessed via: client.fine_tuning.alpha.graders

611

def run(

612

self,

613

*,

614

grader: dict,

615

model_sample: str,

616

item: object | Omit = omit,

617

extra_headers: dict[str, str] | None = None,

618

extra_query: dict[str, object] | None = None,

619

extra_body: dict[str, object] | None = None,

620

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

621

) -> GraderRunResponse:

622

"""

623

Run a grader on a model sample.

624

625

Args:

626

grader: The grader used for the fine-tuning job (structured Grader object).

627

model_sample: The model sample to be evaluated. This value will be used to

628

populate the `sample` namespace. See the guide for more details.

629

The `output_json` variable will be populated if the model sample is

630

a valid JSON string.

631

item: The dataset item provided to the grader. This will be used to

632

populate the `item` namespace. See the guide for more details.

633

extra_headers: Additional HTTP headers.

634

extra_query: Additional query parameters.

635

extra_body: Additional JSON fields.

636

timeout: Request timeout in seconds.

637

638

Returns:

639

GraderRunResponse: Grading results with scores and analysis.

640

"""

641

642

def validate(

643

self,

644

*,

645

grader: dict,

646

extra_headers: dict[str, str] | None = None,

647

extra_query: dict[str, object] | None = None,

648

extra_body: dict[str, object] | None = None,

649

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

650

) -> GraderValidateResponse:

651

"""

652

Validate a grader configuration before running.

653

654

Args:

655

grader: Grader configuration to validate (structured Grader object).

656

extra_headers: Additional HTTP headers.

657

extra_query: Additional query parameters.

658

extra_body: Additional JSON fields.

659

timeout: Request timeout in seconds.

660

661

Returns:

662

ValidationResult: Validation status and any errors.

663

"""

664

```

665

666

Usage example:

667

668

```python

669

# Validate grader configuration

670

validation = client.fine_tuning.alpha.graders.validate(

671

grader_config={

672

"type": "model_grader",

673

"criteria": "accuracy",

674

"model": "gpt-4"

675

}

676

)

677

678

if validation.valid:

679

# Run grader on evaluation data

680

result = client.fine_tuning.alpha.graders.run(

681

grader_config={

682

"type": "model_grader",

683

"criteria": "accuracy"

684

},

685

evaluation_data=[

686

{

687

"input": "What is 2+2?",

688

"expected": "4",

689

"actual": "4"

690

}

691

],

692

model="ft:gpt-3.5-turbo:my-org:custom_suffix:id"

693

)

694

695

print(f"Score: {result.score}")

696

print(f"Analysis: {result.analysis}")

697

```

698

699

## Types

700

701

```python { .api }

702

from typing import Literal

703

from pydantic import BaseModel

704

705

class FineTuningJob(BaseModel):

706

"""Fine-tuning job."""

707

id: str

708

created_at: int

709

error: dict | None

710

fine_tuned_model: str | None

711

finished_at: int | None

712

hyperparameters: dict

713

model: str

714

object: Literal["fine_tuning.job"]

715

organization_id: str

716

result_files: list[str]

717

seed: int

718

status: Literal[

719

"validating_files", "queued", "running",

720

"succeeded", "failed", "cancelled"

721

]

722

trained_tokens: int | None

723

training_file: str

724

validation_file: str | None

725

integrations: list[dict] | None

726

user_provided_suffix: str | None

727

728

class FineTuningJobEvent(BaseModel):

729

"""Job event/log entry."""

730

id: str

731

created_at: int

732

level: Literal["info", "warn", "error"]

733

message: str

734

object: Literal["fine_tuning.job.event"]

735

data: dict | None

736

type: str

737

738

class FineTuningJobCheckpoint(BaseModel):

739

"""Training checkpoint."""

740

id: str

741

created_at: int

742

fine_tuned_model_checkpoint: str

743

fine_tuning_job_id: str

744

metrics: dict

745

object: Literal["fine_tuning.job.checkpoint"]

746

step_number: int

747

748

# Pagination

749

class SyncCursorPage[T](BaseModel):

750

data: list[T]

751

object: str

752

has_more: bool

753

def __iter__(self) -> Iterator[T]: ...

754

```

755

756

## Training Data Format

757

758

Training data must be JSONL (JSON Lines) format:

759

760

```jsonl

761

{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What is 2+2?"}, {"role": "assistant", "content": "4"}]}

762

{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What is the capital of France?"}, {"role": "assistant", "content": "Paris"}]}

763

```

764

765

## Best Practices

766

767

```python

768

from openai import OpenAI

769

770

client = OpenAI()

771

772

# 1. Validate training data before upload

773

def validate_jsonl(file_path: str) -> bool:

774

import json

775

776

with open(file_path) as f:

777

for i, line in enumerate(f):

778

try:

779

data = json.loads(line)

780

assert "messages" in data

781

except Exception as e:

782

print(f"Line {i}: {e}")

783

return False

784

return True

785

786

# 2. Monitor job progress

787

def wait_for_job(job_id: str):

788

import time

789

790

while True:

791

job = client.fine_tuning.jobs.retrieve(job_id)

792

793

if job.status == "succeeded":

794

return job.fine_tuned_model

795

elif job.status in ["failed", "cancelled"]:

796

raise Exception(f"Job {job.status}: {job.error}")

797

798

print(f"Status: {job.status}")

799

time.sleep(30)

800

801

# 3. Use validation file for monitoring

802

with open("train.jsonl", "rb") as train_f, \

803

open("val.jsonl", "rb") as val_f:

804

805

train_file = client.files.create(file=train_f, purpose="fine-tune")

806

val_file = client.files.create(file=val_f, purpose="fine-tune")

807

808

job = client.fine_tuning.jobs.create(

809

model="gpt-3.5-turbo",

810

training_file=train_file.id,

811

validation_file=val_file.id

812

)

813

814

# 4. Clean up after completion

815

fine_tuned_model = wait_for_job(job.id)

816

817

# Use the model

818

response = client.chat.completions.create(

819

model=fine_tuned_model,

820

messages=[{"role": "user", "content": "Test"}]

821

)

822

823

# Later, delete if no longer needed

824

client.models.delete(fine_tuned_model)

825

```

826

827

## Async Usage

828

829

```python

830

import asyncio

831

from openai import AsyncOpenAI

832

833

async def create_fine_tune():

834

client = AsyncOpenAI()

835

836

job = await client.fine_tuning.jobs.create(

837

model="gpt-3.5-turbo",

838

training_file="file-abc123"

839

)

840

841

return job.id

842

843

job_id = asyncio.run(create_fine_tune())

844

```

845