kiln-ai 0.14.0__py3-none-any.whl → 0.15.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kiln-ai might be problematic. Click here for more details.

@@ -0,0 +1,217 @@
1
+ import logging
2
+ import time
3
+
4
+ import vertexai
5
+ from google.cloud import storage
6
+ from google.cloud.aiplatform_v1beta1 import types as gca_types
7
+ from vertexai.tuning import sft
8
+
9
+ from kiln_ai.adapters.fine_tune.base_finetune import (
10
+ BaseFinetuneAdapter,
11
+ FineTuneParameter,
12
+ FineTuneStatus,
13
+ FineTuneStatusType,
14
+ )
15
+ from kiln_ai.adapters.fine_tune.dataset_formatter import DatasetFormat, DatasetFormatter
16
+ from kiln_ai.datamodel import DatasetSplit, StructuredOutputMode, Task
17
+ from kiln_ai.utils.config import Config
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class VertexFinetune(BaseFinetuneAdapter):
23
+ """
24
+ A fine-tuning adapter for Vertex AI.
25
+ """
26
+
27
+ async def status(self) -> FineTuneStatus:
28
+ """
29
+ Get the status of the fine-tune.
30
+ """
31
+
32
+ # Update the datamodel with the latest status if it has changed
33
+ status = await self._status()
34
+ if status.status != self.datamodel.latest_status:
35
+ self.datamodel.latest_status = status.status
36
+ if self.datamodel.path:
37
+ self.datamodel.save_to_file()
38
+ return status
39
+
40
+ async def _status(self) -> FineTuneStatus:
41
+ if not self.datamodel or not self.datamodel.provider_id:
42
+ return FineTuneStatus(
43
+ status=FineTuneStatusType.pending,
44
+ message="This fine-tune has not been started or has not been assigned a provider ID.",
45
+ )
46
+
47
+ response = sft.SupervisedTuningJob(self.datamodel.provider_id)
48
+ # If the fine-tuned model ID has been updated, update the datamodel
49
+ try:
50
+ if self.datamodel.fine_tune_model_id != response.tuned_model_endpoint_name:
51
+ self.datamodel.fine_tune_model_id = response.tuned_model_endpoint_name
52
+ if self.datamodel.path:
53
+ self.datamodel.save_to_file()
54
+ except Exception as e:
55
+ # Don't let this error crash the status call
56
+ logger.warning(f"Error updating fine-tune model ID: {e}")
57
+ pass
58
+
59
+ error = response.error
60
+ if error and error.code != 0:
61
+ return FineTuneStatus(
62
+ status=FineTuneStatusType.failed,
63
+ message=f"Fine Tune Job Error: {error.message} [{error.code}]",
64
+ )
65
+ state = response.state
66
+ if state in [
67
+ gca_types.JobState.JOB_STATE_FAILED,
68
+ gca_types.JobState.JOB_STATE_EXPIRED,
69
+ ]:
70
+ return FineTuneStatus(
71
+ status=FineTuneStatusType.failed,
72
+ message="Fine Tune Job Failed",
73
+ )
74
+ if state in [
75
+ gca_types.JobState.JOB_STATE_CANCELLED,
76
+ gca_types.JobState.JOB_STATE_CANCELLING,
77
+ ]:
78
+ return FineTuneStatus(
79
+ status=FineTuneStatusType.failed, message="Fine Tune Job Cancelled"
80
+ )
81
+ if state in [
82
+ gca_types.JobState.JOB_STATE_PENDING,
83
+ gca_types.JobState.JOB_STATE_QUEUED,
84
+ ]:
85
+ return FineTuneStatus(
86
+ status=FineTuneStatusType.pending, message="Fine Tune Job Pending"
87
+ )
88
+ if state in [
89
+ gca_types.JobState.JOB_STATE_RUNNING,
90
+ ]:
91
+ return FineTuneStatus(
92
+ status=FineTuneStatusType.running,
93
+ message="Fine Tune Job Running",
94
+ )
95
+ if state in [
96
+ gca_types.JobState.JOB_STATE_SUCCEEDED,
97
+ gca_types.JobState.JOB_STATE_PARTIALLY_SUCCEEDED,
98
+ ]:
99
+ return FineTuneStatus(
100
+ status=FineTuneStatusType.completed, message="Fine Tune Job Completed"
101
+ )
102
+
103
+ if state not in [
104
+ gca_types.JobState.JOB_STATE_UPDATING,
105
+ gca_types.JobState.JOB_STATE_UNSPECIFIED,
106
+ gca_types.JobState.JOB_STATE_PAUSED,
107
+ ]:
108
+ # While the above states map to "unknown", they are expected unknowns. Log if some new state appears we aren't expecting
109
+ logger.warning(f"Unknown Vertex AI Fine Tune Status: [{state}]")
110
+
111
+ return FineTuneStatus(
112
+ status=FineTuneStatusType.unknown, message=f"Unknown state: [{state}]"
113
+ )
114
+
115
+ async def _start(self, dataset: DatasetSplit) -> None:
116
+ task = self.datamodel.parent_task()
117
+ if not task:
118
+ raise ValueError("Task is required to start a fine-tune")
119
+
120
+ # Use chat format for unstructured output, and JSON for formatted output
121
+ format = DatasetFormat.VERTEX_GEMINI
122
+ if task.output_json_schema:
123
+ self.datamodel.structured_output_mode = StructuredOutputMode.json_mode
124
+ train_file_id = await self.generate_and_upload_jsonl(
125
+ dataset, self.datamodel.train_split_name, task, format
126
+ )
127
+ validation_file_id = None
128
+ if self.datamodel.validation_split_name:
129
+ validation_file_id = await self.generate_and_upload_jsonl(
130
+ dataset, self.datamodel.validation_split_name, task, format
131
+ )
132
+
133
+ hyperparameters = self.datamodel.parameters
134
+
135
+ project, location = self.get_vertex_provider_location()
136
+ vertexai.init(project=project, location=location)
137
+
138
+ sft_tuning_job = sft.train(
139
+ source_model=self.datamodel.base_model_id,
140
+ train_dataset=train_file_id,
141
+ validation_dataset=validation_file_id,
142
+ tuned_model_display_name=f"kiln_finetune_{self.datamodel.id}",
143
+ # It is recommended to use auto-selection and leave them unset
144
+ epochs=hyperparameters.get("epochs", None), # type: ignore
145
+ adapter_size=hyperparameters.get("adapter_size", None), # type: ignore
146
+ learning_rate_multiplier=hyperparameters.get(
147
+ "learning_rate_multiplier", None
148
+ ), # type: ignore
149
+ labels={
150
+ "source": "kiln",
151
+ "kiln_finetune_id": str(self.datamodel.id),
152
+ "kiln_task_id": str(task.id),
153
+ },
154
+ )
155
+ self.datamodel.provider_id = sft_tuning_job.resource_name
156
+
157
+ return None
158
+
159
+ async def generate_and_upload_jsonl(
160
+ self, dataset: DatasetSplit, split_name: str, task: Task, format: DatasetFormat
161
+ ) -> str:
162
+ formatter = DatasetFormatter(
163
+ dataset, self.datamodel.system_message, self.datamodel.thinking_instructions
164
+ )
165
+ path = formatter.dump_to_file(split_name, format, self.datamodel.data_strategy)
166
+
167
+ project, location = self.get_vertex_provider_location()
168
+ storage_client = storage.Client(project=project)
169
+
170
+ bucket_name = "kiln-ai-data"
171
+
172
+ # Check if bucket exists and create it if it doesn't
173
+ if not storage_client.lookup_bucket(bucket_name):
174
+ bucket = storage_client.create_bucket(bucket_name, location=location)
175
+ else:
176
+ bucket = storage_client.bucket(bucket_name)
177
+
178
+ # Create a blob and upload
179
+ epoch_timestamp = int(time.time())
180
+ blob_name = f"{epoch_timestamp}/{path.name}"
181
+ blob = bucket.blob(blob_name)
182
+ blob.upload_from_filename(path)
183
+
184
+ return f"gs://{bucket.name}/{blob.name}"
185
+
186
+ @classmethod
187
+ def available_parameters(cls) -> list[FineTuneParameter]:
188
+ return [
189
+ FineTuneParameter(
190
+ name="learning_rate_multiplier",
191
+ type="float",
192
+ description="Scaling factor for the learning rate. A smaller learning rate may be useful to avoid overfitting. Defaults to 1.0 (don't scale vertex's learning rate).",
193
+ optional=True,
194
+ ),
195
+ FineTuneParameter(
196
+ name="epochs",
197
+ type="int",
198
+ description="The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset. Defaults to 'auto'",
199
+ optional=True,
200
+ ),
201
+ FineTuneParameter(
202
+ name="adapter_size",
203
+ type="int",
204
+ description="The size of the adapter to use for the fine-tune. One of 1, 4, 8, or 16. By default Vertex will auto-select a size.",
205
+ optional=True,
206
+ ),
207
+ ]
208
+
209
+ @classmethod
210
+ def get_vertex_provider_location(cls) -> tuple[str, str]:
211
+ project = Config.shared().vertex_project_id
212
+ location = Config.shared().vertex_location
213
+ if not project or not location:
214
+ raise ValueError(
215
+ "Google Vertex project and location must be set in Kiln settings to fine tune."
216
+ )
217
+ return project, location
@@ -70,9 +70,18 @@ class ModelName(str, Enum):
70
70
  llama_3_3_70b = "llama_3_3_70b"
71
71
  gpt_4o_mini = "gpt_4o_mini"
72
72
  gpt_4o = "gpt_4o"
73
+ gpt_4_1 = "gpt_4_1"
74
+ gpt_4_1_mini = "gpt_4_1_mini"
75
+ gpt_4_1_nano = "gpt_4_1_nano"
76
+ gpt_o3_low = "gpt_o3_low"
77
+ gpt_o3_medium = "gpt_o3_medium"
78
+ gpt_o3_high = "gpt_o3_high"
73
79
  gpt_o1_low = "gpt_o1_low"
74
80
  gpt_o1_medium = "gpt_o1_medium"
75
81
  gpt_o1_high = "gpt_o1_high"
82
+ gpt_o4_mini_low = "gpt_o4_mini_low"
83
+ gpt_o4_mini_medium = "gpt_o4_mini_medium"
84
+ gpt_o4_mini_high = "gpt_o4_mini_high"
76
85
  gpt_o3_mini_low = "gpt_o3_mini_low"
77
86
  gpt_o3_mini_medium = "gpt_o3_mini_medium"
78
87
  gpt_o3_mini_high = "gpt_o3_mini_high"
@@ -97,6 +106,9 @@ class ModelName(str, Enum):
97
106
  gemini_1_5_flash_8b = "gemini_1_5_flash_8b"
98
107
  gemini_1_5_pro = "gemini_1_5_pro"
99
108
  gemini_2_0_flash = "gemini_2_0_flash"
109
+ gemini_2_0_flash_lite = "gemini_2_0_flash_lite"
110
+ gemini_2_5_pro = "gemini_2_5_pro"
111
+ gemini_2_5_flash = "gemini_2_5_flash"
100
112
  nemotron_70b = "nemotron_70b"
101
113
  mixtral_8x7b = "mixtral_8x7b"
102
114
  qwen_2p5_7b = "qwen_2p5_7b"
@@ -181,29 +193,77 @@ class KilnModel(BaseModel):
181
193
 
182
194
 
183
195
  built_in_models: List[KilnModel] = [
184
- # GPT 4o Mini
196
+ # GPT 4.1
185
197
  KilnModel(
186
198
  family=ModelFamily.gpt,
187
- name=ModelName.gpt_4o_mini,
188
- friendly_name="GPT 4o Mini",
199
+ name=ModelName.gpt_4_1,
200
+ friendly_name="GPT 4.1",
189
201
  providers=[
190
202
  KilnModelProvider(
191
203
  name=ModelProviderName.openai,
192
- model_id="gpt-4o-mini",
193
- provider_finetune_id="gpt-4o-mini-2024-07-18",
204
+ model_id="gpt-4.1",
205
+ provider_finetune_id="gpt-4.1-2025-04-14",
194
206
  structured_output_mode=StructuredOutputMode.json_schema,
195
207
  supports_logprobs=True,
196
208
  ),
197
209
  KilnModelProvider(
198
210
  name=ModelProviderName.openrouter,
199
- model_id="openai/gpt-4o-mini",
211
+ model_id="openai/gpt-4.1",
200
212
  structured_output_mode=StructuredOutputMode.json_schema,
201
213
  supports_logprobs=True,
202
- logprobs_openrouter_options=True,
203
214
  ),
204
215
  KilnModelProvider(
205
216
  name=ModelProviderName.azure_openai,
206
- model_id="gpt-4o-mini",
217
+ model_id="gpt-4.1",
218
+ ),
219
+ ],
220
+ ),
221
+ # GPT 4.1 Mini
222
+ KilnModel(
223
+ family=ModelFamily.gpt,
224
+ name=ModelName.gpt_4_1_mini,
225
+ friendly_name="GPT 4.1 Mini",
226
+ providers=[
227
+ KilnModelProvider(
228
+ name=ModelProviderName.openai,
229
+ model_id="gpt-4.1-mini",
230
+ provider_finetune_id="gpt-4.1-mini-2025-04-14",
231
+ structured_output_mode=StructuredOutputMode.json_schema,
232
+ supports_logprobs=True,
233
+ ),
234
+ KilnModelProvider(
235
+ name=ModelProviderName.openrouter,
236
+ model_id="openai/gpt-4.1-mini",
237
+ structured_output_mode=StructuredOutputMode.json_schema,
238
+ supports_logprobs=True,
239
+ ),
240
+ KilnModelProvider(
241
+ name=ModelProviderName.azure_openai,
242
+ model_id="gpt-4.1-mini",
243
+ ),
244
+ ],
245
+ ),
246
+ # GPT 4.1 Nano
247
+ KilnModel(
248
+ family=ModelFamily.gpt,
249
+ name=ModelName.gpt_4_1_nano,
250
+ friendly_name="GPT 4.1 Nano",
251
+ providers=[
252
+ KilnModelProvider(
253
+ name=ModelProviderName.openai,
254
+ model_id="gpt-4.1-nano",
255
+ structured_output_mode=StructuredOutputMode.json_schema,
256
+ supports_logprobs=True,
257
+ ),
258
+ KilnModelProvider(
259
+ name=ModelProviderName.openrouter,
260
+ model_id="openai/gpt-4.1-nano",
261
+ structured_output_mode=StructuredOutputMode.json_schema,
262
+ supports_logprobs=True,
263
+ ),
264
+ KilnModelProvider(
265
+ name=ModelProviderName.azure_openai,
266
+ model_id="gpt-4.1-nano",
207
267
  ),
208
268
  ],
209
269
  ),
@@ -233,6 +293,102 @@ built_in_models: List[KilnModel] = [
233
293
  ),
234
294
  ],
235
295
  ),
296
+ # GPT 4o Mini
297
+ KilnModel(
298
+ family=ModelFamily.gpt,
299
+ name=ModelName.gpt_4o_mini,
300
+ friendly_name="GPT 4o Mini",
301
+ providers=[
302
+ KilnModelProvider(
303
+ name=ModelProviderName.openai,
304
+ model_id="gpt-4o-mini",
305
+ provider_finetune_id="gpt-4o-mini-2024-07-18",
306
+ structured_output_mode=StructuredOutputMode.json_schema,
307
+ supports_logprobs=True,
308
+ ),
309
+ KilnModelProvider(
310
+ name=ModelProviderName.openrouter,
311
+ model_id="openai/gpt-4o-mini",
312
+ structured_output_mode=StructuredOutputMode.json_schema,
313
+ supports_logprobs=True,
314
+ logprobs_openrouter_options=True,
315
+ ),
316
+ KilnModelProvider(
317
+ name=ModelProviderName.azure_openai,
318
+ model_id="gpt-4o-mini",
319
+ ),
320
+ ],
321
+ ),
322
+ # GPT o4 Mini Low
323
+ KilnModel(
324
+ family=ModelFamily.gpt,
325
+ name=ModelName.gpt_o4_mini_low,
326
+ friendly_name="GPT o4 Mini - Low",
327
+ providers=[
328
+ KilnModelProvider(
329
+ name=ModelProviderName.openai,
330
+ model_id="o4-mini",
331
+ thinking_level="low",
332
+ structured_output_mode=StructuredOutputMode.json_schema,
333
+ ),
334
+ KilnModelProvider(
335
+ name=ModelProviderName.azure_openai,
336
+ model_id="o4-mini",
337
+ structured_output_mode=StructuredOutputMode.json_schema,
338
+ thinking_level="low",
339
+ ),
340
+ ],
341
+ ),
342
+ # GPT o4 Mini Medium
343
+ KilnModel(
344
+ family=ModelFamily.gpt,
345
+ name=ModelName.gpt_o4_mini_medium,
346
+ friendly_name="GPT o4 Mini - Medium",
347
+ providers=[
348
+ KilnModelProvider(
349
+ name=ModelProviderName.openai,
350
+ model_id="o4-mini",
351
+ thinking_level="medium",
352
+ structured_output_mode=StructuredOutputMode.json_schema,
353
+ ),
354
+ KilnModelProvider(
355
+ name=ModelProviderName.azure_openai,
356
+ model_id="o4-mini",
357
+ structured_output_mode=StructuredOutputMode.json_schema,
358
+ thinking_level="medium",
359
+ ),
360
+ KilnModelProvider(
361
+ name=ModelProviderName.openrouter,
362
+ model_id="openai/o4-mini",
363
+ structured_output_mode=StructuredOutputMode.json_schema,
364
+ ),
365
+ ],
366
+ ),
367
+ # GPT o4 Mini High
368
+ KilnModel(
369
+ family=ModelFamily.gpt,
370
+ name=ModelName.gpt_o4_mini_high,
371
+ friendly_name="GPT o4 Mini - High",
372
+ providers=[
373
+ KilnModelProvider(
374
+ name=ModelProviderName.openai,
375
+ model_id="o4-mini",
376
+ thinking_level="high",
377
+ structured_output_mode=StructuredOutputMode.json_schema,
378
+ ),
379
+ KilnModelProvider(
380
+ name=ModelProviderName.azure_openai,
381
+ model_id="o4-mini",
382
+ structured_output_mode=StructuredOutputMode.json_schema,
383
+ thinking_level="high",
384
+ ),
385
+ KilnModelProvider(
386
+ name=ModelProviderName.openrouter,
387
+ model_id="openai/o4-mini-high",
388
+ structured_output_mode=StructuredOutputMode.json_schema,
389
+ ),
390
+ ],
391
+ ),
236
392
  # GPT o3 Mini Low
237
393
  KilnModel(
238
394
  family=ModelFamily.gpt,
@@ -293,6 +449,66 @@ built_in_models: List[KilnModel] = [
293
449
  ),
294
450
  ],
295
451
  ),
452
+ # GPT o3 Low
453
+ KilnModel(
454
+ family=ModelFamily.gpt,
455
+ name=ModelName.gpt_o3_low,
456
+ friendly_name="GPT o3 - Low",
457
+ providers=[
458
+ KilnModelProvider(
459
+ name=ModelProviderName.openai,
460
+ model_id="o3",
461
+ thinking_level="low",
462
+ structured_output_mode=StructuredOutputMode.json_schema,
463
+ ),
464
+ KilnModelProvider(
465
+ name=ModelProviderName.azure_openai,
466
+ model_id="o3",
467
+ structured_output_mode=StructuredOutputMode.json_schema,
468
+ thinking_level="low",
469
+ ),
470
+ ],
471
+ ),
472
+ # GPT o3 Medium
473
+ KilnModel(
474
+ family=ModelFamily.gpt,
475
+ name=ModelName.gpt_o3_medium,
476
+ friendly_name="GPT o3 - Medium",
477
+ providers=[
478
+ KilnModelProvider(
479
+ name=ModelProviderName.openai,
480
+ model_id="o3",
481
+ thinking_level="medium",
482
+ structured_output_mode=StructuredOutputMode.json_schema,
483
+ ),
484
+ KilnModelProvider(
485
+ name=ModelProviderName.azure_openai,
486
+ model_id="o3",
487
+ structured_output_mode=StructuredOutputMode.json_schema,
488
+ thinking_level="medium",
489
+ ),
490
+ ],
491
+ ),
492
+ # GPT o3 High
493
+ KilnModel(
494
+ family=ModelFamily.gpt,
495
+ name=ModelName.gpt_o3_high,
496
+ friendly_name="GPT o3 - High",
497
+ providers=[
498
+ KilnModelProvider(
499
+ name=ModelProviderName.openai,
500
+ model_id="o3",
501
+ thinking_level="high",
502
+ structured_output_mode=StructuredOutputMode.json_schema,
503
+ ),
504
+ KilnModelProvider(
505
+ name=ModelProviderName.azure_openai,
506
+ model_id="o3",
507
+ structured_output_mode=StructuredOutputMode.json_schema,
508
+ thinking_level="high",
509
+ ),
510
+ ],
511
+ ),
296
512
  # GPT o1 Low
297
513
  KilnModel(
298
514
  family=ModelFamily.gpt,
@@ -440,6 +656,100 @@ built_in_models: List[KilnModel] = [
440
656
  ),
441
657
  ],
442
658
  ),
659
+ # Gemini 2.5 Pro
660
+ KilnModel(
661
+ family=ModelFamily.gemini,
662
+ name=ModelName.gemini_2_5_pro,
663
+ friendly_name="Gemini 2.5 Pro",
664
+ providers=[
665
+ KilnModelProvider(
666
+ name=ModelProviderName.openrouter,
667
+ model_id="google/gemini-2.5-pro-preview-03-25",
668
+ structured_output_mode=StructuredOutputMode.json_schema,
669
+ ),
670
+ KilnModelProvider(
671
+ name=ModelProviderName.gemini_api,
672
+ model_id="gemini-2.5-pro-preview-03-25",
673
+ structured_output_mode=StructuredOutputMode.json_schema,
674
+ ),
675
+ KilnModelProvider(
676
+ name=ModelProviderName.vertex,
677
+ model_id="gemini-2.5-pro-preview-03-25",
678
+ structured_output_mode=StructuredOutputMode.json_schema,
679
+ ),
680
+ ],
681
+ ),
682
+ # Gemini 2.5 Flash
683
+ KilnModel(
684
+ family=ModelFamily.gemini,
685
+ name=ModelName.gemini_2_5_flash,
686
+ friendly_name="Gemini 2.5 Flash",
687
+ providers=[
688
+ KilnModelProvider(
689
+ name=ModelProviderName.openrouter,
690
+ model_id="google/gemini-2.5-flash-preview",
691
+ structured_output_mode=StructuredOutputMode.json_schema,
692
+ ),
693
+ KilnModelProvider(
694
+ name=ModelProviderName.gemini_api,
695
+ model_id="gemini-2.5-flash-preview-04-17",
696
+ structured_output_mode=StructuredOutputMode.json_schema,
697
+ ),
698
+ KilnModelProvider(
699
+ name=ModelProviderName.vertex,
700
+ model_id="gemini-2.5-flash-preview-04-17",
701
+ structured_output_mode=StructuredOutputMode.json_schema,
702
+ ),
703
+ ],
704
+ ),
705
+ # Gemini 2.0 Flash
706
+ KilnModel(
707
+ family=ModelFamily.gemini,
708
+ name=ModelName.gemini_2_0_flash,
709
+ friendly_name="Gemini 2.0 Flash",
710
+ providers=[
711
+ KilnModelProvider(
712
+ name=ModelProviderName.openrouter,
713
+ model_id="google/gemini-2.0-flash-001",
714
+ structured_output_mode=StructuredOutputMode.json_instruction_and_object,
715
+ ),
716
+ KilnModelProvider(
717
+ name=ModelProviderName.gemini_api,
718
+ model_id="gemini-2.0-flash",
719
+ structured_output_mode=StructuredOutputMode.json_instruction_and_object,
720
+ ),
721
+ KilnModelProvider(
722
+ name=ModelProviderName.vertex,
723
+ model_id="gemini-2.0-flash",
724
+ structured_output_mode=StructuredOutputMode.json_instruction_and_object,
725
+ provider_finetune_id="gemini-2.0-flash-001",
726
+ ),
727
+ ],
728
+ ),
729
+ # Gemini 2.0 Flash Lite
730
+ KilnModel(
731
+ family=ModelFamily.gemini,
732
+ name=ModelName.gemini_2_0_flash_lite,
733
+ friendly_name="Gemini 2.0 Flash Lite",
734
+ providers=[
735
+ KilnModelProvider(
736
+ name=ModelProviderName.openrouter,
737
+ model_id="google/gemini-2.0-flash-lite-001",
738
+ structured_output_mode=StructuredOutputMode.json_instruction_and_object,
739
+ ),
740
+ KilnModelProvider(
741
+ name=ModelProviderName.gemini_api,
742
+ model_id="gemini-2.0-flash-lite",
743
+ structured_output_mode=StructuredOutputMode.json_instruction_and_object,
744
+ ),
745
+ KilnModelProvider(
746
+ name=ModelProviderName.vertex,
747
+ model_id="gemini-2.0-flash-lite",
748
+ structured_output_mode=StructuredOutputMode.json_instruction_and_object,
749
+ provider_finetune_id="gemini-2.0-flash-lite-001",
750
+ ),
751
+ ],
752
+ ),
443
753
  # Gemini 1.5 Pro
444
754
  KilnModel(
445
755
  family=ModelFamily.gemini,
@@ -506,29 +816,6 @@ built_in_models: List[KilnModel] = [
506
816
  ),
507
817
  ],
508
818
  ),
509
- # Gemini 2.0 Flash
510
- KilnModel(
511
- family=ModelFamily.gemini,
512
- name=ModelName.gemini_2_0_flash,
513
- friendly_name="Gemini 2.0 Flash",
514
- providers=[
515
- KilnModelProvider(
516
- name=ModelProviderName.openrouter,
517
- model_id="google/gemini-2.0-flash-001",
518
- structured_output_mode=StructuredOutputMode.json_instruction_and_object,
519
- ),
520
- KilnModelProvider(
521
- name=ModelProviderName.gemini_api,
522
- model_id="gemini-2.0-flash",
523
- structured_output_mode=StructuredOutputMode.json_instruction_and_object,
524
- ),
525
- KilnModelProvider(
526
- name=ModelProviderName.vertex,
527
- model_id="gemini-2.0-flash",
528
- structured_output_mode=StructuredOutputMode.json_instruction_and_object,
529
- ),
530
- ],
531
- ),
532
819
  # Nemotron 70B
533
820
  KilnModel(
534
821
  family=ModelFamily.llama,
@@ -760,12 +1047,6 @@ built_in_models: List[KilnModel] = [
760
1047
  supports_data_gen=False,
761
1048
  model_id="llama3.2",
762
1049
  ),
763
- KilnModelProvider(
764
- name=ModelProviderName.fireworks_ai,
765
- supports_structured_output=False,
766
- supports_data_gen=False,
767
- model_id="accounts/fireworks/models/llama-v3p2-3b-instruct",
768
- ),
769
1050
  KilnModelProvider(
770
1051
  name=ModelProviderName.huggingface,
771
1052
  model_id="meta-llama/Llama-3.2-3B-Instruct",
@@ -3,20 +3,16 @@ from abc import ABCMeta, abstractmethod
3
3
  from dataclasses import dataclass
4
4
  from typing import Dict, Literal, Tuple
5
5
 
6
+ import jsonschema
7
+
6
8
  from kiln_ai.adapters.ml_model_list import KilnModelProvider, StructuredOutputMode
7
9
  from kiln_ai.adapters.parsers.json_parser import parse_json_string
8
10
  from kiln_ai.adapters.parsers.parser_registry import model_parser_from_id
9
11
  from kiln_ai.adapters.prompt_builders import prompt_builder_from_id
10
12
  from kiln_ai.adapters.provider_tools import kiln_model_provider_from
11
13
  from kiln_ai.adapters.run_output import RunOutput
12
- from kiln_ai.datamodel import (
13
- DataSource,
14
- DataSourceType,
15
- Task,
16
- TaskOutput,
17
- TaskRun,
18
- )
19
- from kiln_ai.datamodel.json_schema import validate_schema
14
+ from kiln_ai.datamodel import DataSource, DataSourceType, Task, TaskOutput, TaskRun
15
+ from kiln_ai.datamodel.json_schema import validate_schema_with_value_error
20
16
  from kiln_ai.datamodel.task import RunConfig
21
17
  from kiln_ai.utils.config import Config
22
18
 
@@ -103,7 +99,12 @@ class BaseAdapter(metaclass=ABCMeta):
103
99
  if self.input_schema is not None:
104
100
  if not isinstance(input, dict):
105
101
  raise ValueError(f"structured input is not a dict: {input}")
106
- validate_schema(input, self.input_schema)
102
+
103
+ validate_schema_with_value_error(
104
+ input,
105
+ self.input_schema,
106
+ "This task requires a specific input schema. While the model produced JSON, that JSON didn't meet the schema. Search 'Troubleshooting Structured Data Issues' in our docs for more information.",
107
+ )
107
108
 
108
109
  # Run
109
110
  run_output = await self._run(input)
@@ -125,7 +126,11 @@ class BaseAdapter(metaclass=ABCMeta):
125
126
  raise RuntimeError(
126
127
  f"structured response is not a dict: {parsed_output.output}"
127
128
  )
128
- validate_schema(parsed_output.output, self.output_schema)
129
+ validate_schema_with_value_error(
130
+ parsed_output.output,
131
+ self.output_schema,
132
+ "This task requires a specific output schema. While the model produced JSON, that JSON didn't meet the schema. Search 'Troubleshooting Structured Data Issues' in our docs for more information.",
133
+ )
129
134
  else:
130
135
  if not isinstance(parsed_output.output, str):
131
136
  raise RuntimeError(