docs
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