On this page
- What exactly is OpenAI ending, and when?
- Should you re-fine-tune at all, or prompt a newer model?
- What should you export before the deadlines?
- How do you choose the open-weight replacement and its licence?
- How do you convert OpenAI training data for open-weight SFT?
- How do you reproduce the fine-tune with LoRA SFT?
- How do you prove parity before cutover?
- How do you cut over and roll back safely?
- What does a realistic timeline look like from today?
- Frequently asked questions
- Sources
OpenAI is shutting down fine-tuning in stages: existing customers can create fine-tuning jobs only until January 6, 2027, and fine-tuned GPT-4o, GPT-4o mini, GPT-4.1 and GPT-4.1 mini models stop serving on January 14, 2027. To migrate, export your data and evals, decide whether prompting a newer model is enough, and otherwise retrain an open-weight model with LoRA and prove parity before cutover.
This playbook is dated. Every OpenAI date below was checked on OpenAI’s own deprecations page and fine-tuning guide on November 13, 2026. Re-check both before you plan around them.
What exactly is OpenAI ending, and when?
Three separate things are ending: the ability to train new fine-tunes, the ability to call existing fine-tunes, and the hosted Evals product many teams used to test them.
| Date | What happens | Who is affected |
|---|---|---|
| May 7, 2026 (past) | Fine-tuning closed to organizations that had never run it | New users |
| July 2, 2026 (past) | No new jobs for organizations with no fine-tuned-model inference in the prior 60 days | Inactive customers |
| October 23, 2026 (past) | Fine-tunes of gpt-4.1-nano-2025-04-14, gpt-3.5-turbo-0125, gpt-4-0613, gpt-4o-2024-05-13 and o4-mini (including ft-o4-mini-2025-04-16) stopped serving with their base models |
Anyone still on those snapshots |
| November 30, 2026 | Evals dashboard, API and graders shut down; they are read-only until then | Anyone with evals stored on OpenAI |
| January 6, 2027 | “Active existing customers will no longer be able to create new fine-tuning jobs” | All remaining fine-tuning customers |
| January 14, 2027 | gpt-4o-2024-08-06, gpt-4o-2024-11-20, gpt-4o-mini-2024-07-18, gpt-4.1-2025-04-14 and gpt-4.1-mini-2025-04-14 shut down, and fine-tunes built on them stop serving |
Most production fine-tunes |
The rule that ties these together is in the fine-tuning guide: “Fine-tuned models remain available for inference until their base model shuts down.” The deprecations page says the same thing from the other side: fine-tuned versions “follow the same shutdown schedule as their underlying base models.” Your model ID tells you which date applies, because it embeds the base snapshot, as in ft:gpt-4.1-mini-2025-04-14:your-org::abc123.
The base models OpenAI’s guide lists for supervised fine-tuning are GPT-4.1, GPT-4.1 mini and GPT-4.1 nano. Nano is already gone and the other two shut down on January 14, 2027. So the January 6 job cutoff matters less than it looks: a job you start in December produces a model that serves for a few weeks at most.
The real deadline: January 14, 2027 is the last day you can call most OpenAI fine-tunes, which also makes it the last day you can measure them. Everything in this playbook that needs the old model, from reference outputs to a rollback path, has to happen before then.
Should you re-fine-tune at all, or prompt a newer model?
Re-fine-tuning is not the default answer. Many OpenAI fine-tunes were trained in 2024 or 2025 to make a weaker model follow a format, a tone or a narrow policy. Newer models follow instructions and schemas better, and OpenAI lists gpt-6-luna as the replacement for the January 2027 snapshots. For some workloads, a good system prompt, a few examples and structured outputs on a newer model will match the old fine-tune. That migration is cheaper to build and has no training pipeline to maintain.
| Signal | Prompt a newer model | Re-fine-tune an open-weight model |
|---|---|---|
| What the fine-tune taught | Output format, tone, a short policy | Behavior that needs hundreds of examples to specify, a domain style, tool-calling habits |
| Volume | Low or moderate | High and steady, where per-token price dominates |
| Latency and footprint | Hosted API latency is acceptable | You need a small model, a tight p95 or on-premises serving |
| Data constraints | Prompts may leave your boundary | Data residency or contractual limits on where inference runs |
| Lifecycle | Acceptable to re-validate at each vendor retirement | You want weights no vendor can retire |
The honest test is empirical: put the newer prompted model in the same parity test as your open-weight candidate (see the parity section below) and let the numbers decide. If the prompted model passes and its cost works at your volume, stop there. The broader trade-off is covered in fine-tuning vs RAG vs prompt engineering, and the long-term ownership question in open-weight vs proprietary LLMs.
What should you export before the deadlines?
Start with an inventory: every ft: model ID called in production, the base snapshot embedded in each, the service that calls it, the system prompt it runs with, request volume and the owner. Then export, in this order of urgency.
- Evals, before November 30, 2026. Eval definitions (data source configuration and testing criteria), every run and every run’s output items. These hold your graders and the labelled cases you trusted. OpenAI’s deprecations entry points to Promptfoo as the replacement; wherever you move them, store cases, rubrics and results in plain files you own.
- Fine-tuning job metadata. For each job: base model, training and validation file IDs,
methodand hyperparameters (n_epochs,batch_size,learning_rate_multiplier), seed, result file IDs and checkpoint metrics. This is your record of what was trained and how. - Result files. The Files API serves
GET /v1/files/{file_id}/content, and job result files are downloadable. - Training and validation files. Try to download them, but do not count on it. In a 2021 developer-forum thread, a reply speaking for OpenAI said “we only allow downloads on the results of fine-tuning runs and not the input files,” after a user hit the error “Not allowed to download files of purpose: fine-tune.” Test this on your account now. Your upstream copy of the dataset is the real source of truth; if it is lost, rebuild from production logs and human labels.
- Reference outputs from the old model. Run each production fine-tune on your frozen test set (built in the parity section) and save every output. After January 14, 2027 this is the only record of how the old model behaved.
This script exports the fine-tuning and eval records with the official Python SDK. It needs an API key for the organization that owns the jobs.
import json
import pathlib
from openai import APIError, OpenAI
client = OpenAI()
out = pathlib.Path("openai_export")
out.mkdir(exist_ok=True)
# Fine-tuning jobs, checkpoints and files
jobs = []
for job in client.fine_tuning.jobs.list(limit=100): # the SDK paginates automatically
record = job.model_dump()
record["checkpoints"] = [c.model_dump() for c in client.fine_tuning.jobs.checkpoints.list(job.id)]
jobs.append(record)
for file_id in [job.training_file, job.validation_file, *(job.result_files or [])]:
if not file_id or (out / file_id).exists():
continue
try:
(out / file_id).write_bytes(client.files.content(file_id).content)
except APIError as err: # input files may be refused; record which ones
print(f"{job.id}: could not download {file_id}: {err}")
(out / "fine_tuning_jobs.json").write_text(json.dumps(jobs, indent=2, default=str))
# Evals, runs and per-item results (read-only until November 30, 2026)
evals = []
for ev in client.evals.list(limit=100):
runs = []
for run in client.evals.runs.list(ev.id, limit=100):
items = [item.model_dump() for item in client.evals.runs.output_items.list(run.id, eval_id=ev.id, limit=100)]
runs.append({"run": run.model_dump(), "output_items": items})
evals.append({"eval": ev.model_dump(), "runs": runs})
(out / "evals.json").write_text(json.dumps(evals, indent=2, default=str))
Two cautions. Exports can contain customer data, so store them under the same access controls as production data. And if you plan to train on the old model’s outputs rather than on your own labels, have counsel read the OpenAI agreement that governs your account first; the distillation guide explains why provider terms matter for that.
How do you choose the open-weight replacement and its licence?
OpenAI does not publish parameter counts, so there is no reliable “GPT-4.1 mini equals N billion parameters” mapping. Shortlist by constraints, then let evaluation pick.
- Licence first. Apache 2.0 and MIT carry the fewest conditions. Several 2026 releases add model-as-a-service or attribution clauses; the per-model detail is in open-weight vs proprietary LLMs.
- Capabilities your fine-tune relied on. Tool calling, JSON output, context length, languages, images.
- Serving footprint. The smallest model that passes is usually the cheapest to run and the fastest to retrain.
- Ecosystem support. Check that your training stack and your inference server support the architecture and its chat template.
Candidates with permissive licences, verified on their model cards on November 13, 2026:
| Model | Size | Context | Licence | Note |
|---|---|---|---|---|
| Gemma 4 (Google) | E2B to 31B, incl. 26B-A4B MoE | 128K (E2B, E4B), 256K (12B and up) | Apache 2.0 | Wide size range for small, cheap targets |
| Qwen3.8-27B (Alibaba) | 27B | 262,144 native | Apache 2.0 | Thinking mode on by default; can be disabled per request |
| Muse Glimmer 30B (Meta) | 29.6B incl. vision encoder | 131,072+ | Apache 2.0 | August 2026 release |
| gpt-oss-20b (OpenAI) | 21B total, 3.6B active | 131,072 (config) | Apache 2.0 | Must use the harmony format; runs within 16GB with MXFP4 |
Run two or three shortlisted bases, untuned, with your production system prompt on the test set before training anything. The untuned score tells you how much work the fine-tune has to do, and sometimes shows that a base model plus a prompt already passes. The models page lists the supported bases.
How do you convert OpenAI training data for open-weight SFT?
OpenAI’s format is JSONL in the chat completions format, one example per line with a messages array. Hugging Face TRL’s SFTTrainer accepts the same conversational shape, so most rows convert unchanged. Three details need attention.
- Tool-call arguments. OpenAI encodes
argumentsas a JSON string. TRL’s tool-calling format passes them as an object, which is what most chat templates expect. Parse them. - The tools list. Keep it in a
toolscolumn; the chat template uses it to build the prompt. - The system prompt. If production calls added a system prompt that the training rows lack, add it, so training matches inference.
import json
from datasets import Dataset
def convert(line: str) -> dict:
row = json.loads(line)
messages = []
for message in row["messages"]:
message = dict(message)
if message.get("tool_calls"):
message["tool_calls"] = [
{
"type": "function",
"function": {
"name": call["function"]["name"],
"arguments": json.loads(call["function"]["arguments"]),
},
}
for call in message["tool_calls"]
]
messages.append(message)
converted = {"messages": messages}
if row.get("tools"):
converted["tools"] = row["tools"]
return converted
with open("train.jsonl") as handle:
rows = [convert(line) for line in handle if line.strip()]
dataset = Dataset.from_list(rows, on_mixed_types="use_json") # Json() type needs datasets >= 4.7
Then render a few examples with the new model’s tokenizer (apply_chat_template) and read them. A template that drops tool messages, mishandles a None content field or appends a thinking block you did not train on fails silently as a worse model. Deduplicate, and make sure no test-set prompt appears in training.
How do you reproduce the fine-tune with LoRA SFT?
LoRA is the practical default. Thinking Machines’ LoRA Without Regret (John Schulman and Thinking Machines Lab, 2025) found that on small-to-medium instruction and reasoning datasets “LoRA performs the same as full fine-tuning”, provided it is applied to all weight matrices, especially the MLP layers; attention-only LoRA underperformed. Its other findings translate directly into settings:
- The optimal LoRA learning rate was “consistently 10x” the full fine-tuning rate; preliminary evidence put it nearer 15x for short runs of under about 100 steps.
- LoRA was “less tolerant of large batch sizes,” so keep the effective batch modest.
- On datasets that exceed the adapter’s capacity, LoRA trains less efficiently than full fine-tuning; if training loss falls noticeably slower than expected, raise the rank.
Do not copy OpenAI’s hyperparameters literally. n_epochs is a reasonable starting point, but learning_rate_multiplier scales a base rate OpenAI never published, so it does not transfer.
import torch
from peft import LoraConfig
from trl import SFTConfig, SFTTrainer
BASE_MODEL = "org/your-shortlisted-base" # the base that won the untuned comparison
# train_dataset and validation_dataset: your converted training and validation files (see above)
args = SFTConfig(
output_dir="adapter-v1",
num_train_epochs=3, # start from the epoch count recorded on the OpenAI job
learning_rate=1e-4, # roughly 10x a typical full fine-tuning rate
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # effective batch of 16 per device
max_length=4096, # set from your longest example, not a guess
assistant_only_loss=True, # needs a chat template with generation markers
eval_strategy="epoch",
save_strategy="epoch",
model_init_kwargs={"dtype": torch.bfloat16},
)
peft_config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules="all-linear", # all layers, including the MLP
task_type="CAUSAL_LM",
)
trainer = SFTTrainer(
model=BASE_MODEL,
args=args,
train_dataset=train_dataset,
eval_dataset=validation_dataset,
peft_config=peft_config,
)
trainer.train()
trainer.save_model("adapter-v1")
assistant_only_loss=True computes loss only on assistant turns. TRL’s documentation notes that it needs {% generation %} markers in the chat template, which TRL adds automatically for known families such as Qwen3; check this for other models. Memory planning, QLoRA and hyperparameter choices are covered step by step in the LoRA and QLoRA tutorial. If you would rather not run this pipeline, Attempts runs managed LoRA SFT and reports the result against your current model as the baseline.
How do you prove parity before cutover?
Parity means the new model is not meaningfully worse than the old one on your task, by a margin you set before you look at results. It does not mean the new model reproduces the old one’s outputs; agreement with a model that was sometimes wrong is a diagnostic, not the goal.
- Freeze a held-out test set. Draw it from recent production traffic, cover your important slices (customer tier, language, document type, tool-calling paths) and label it with the correct answer. None of it may appear in training. OpenAI’s own guide recommends holdout data with “roughly the same diversity” of inputs as training.
- Run every arm on the same items. The old fine-tune (before January 14, 2027), each open-weight candidate, and the newer prompted model if you are considering that route. Same scorer, same rubric.
- Pin the judge. If an LLM judge scores the outputs, make sure it is a model that will outlive the evaluation.
gpt-5ando3, including their dated snapshots, shut down on December 11, 2026, so a judge built on them needs replacing and re-validating against human labels. - Set the decision rule in advance. For example: the candidate passes if the lower bound of a 95% paired bootstrap confidence interval on (candidate score − old score) is above −2 points, no critical slice drops by more than its own margin, and format validity is at least as high as the old model’s.
- Add the operational checks. p95 latency at your production concurrency, cost per 1,000 requests at expected volume, refusal rate and the safety cases you care about.
How many examples do you need? It depends on how often the two models disagree. Worked example (assumptions, not data): with a pass/fail metric on 400 items, if the models disagree on 10% of items in roughly equal numbers each way, the standard error of the paired difference is about √(0.10 / 400) ≈ 1.6 points, so the 95% interval is about ±3.1 points. That is too wide to show non-inferiority at a −2 point margin even if the models are equal. At about 1,000 items the half-width shrinks to 2 points, but a truly equal candidate would then pass only about half the time; for roughly 80% power you need about 2,000 items, or a lower disagreement rate. Do this arithmetic before labelling, not after. The statistics, including paired bootstrap and McNemar’s test, are in how to measure whether fine-tuning actually improved your model.
Rule of thumb: if you cannot run the old model on the test set before it shuts down, you cannot claim parity, only that the new model meets a fixed bar. Decide which of the two you are promising the business before January.
How do you cut over and roll back safely?
Plan the cutover so the client change is small. vLLM serves LoRA adapters behind an OpenAI-compatible API, and clients select an adapter by name in the model field, so the change can be a base URL and a model name:
vllm serve org/your-shortlisted-base \
--enable-lora \
--lora-modules support-v1=./adapter-v1 \
--max-lora-rank 16
Requests then use "model": "support-v1", per the vLLM LoRA documentation. Whatever serves the model, keep the switch in configuration, not code.
- Shadow. Send a copy of live traffic to the new model, log both outputs and score them offline. Production users still see the old model. Apply your normal data-retention rules to the shadow logs.
- Canary. Route a small share of real traffic, for example 5%, then 25%, then 50%, holding each step long enough to see your slowest-moving metric. Watch format errors, tool-call failures, escalations, user corrections and p95 latency.
- Full cutover, with the old path still configured.
- Rollback triggers written down before the canary: which metric, which threshold, who flips the flag.
The rollback target changes on January 14, 2027. Until then, you can roll back to the old fine-tune. After it, the old model no longer exists, so your fallback must be something that does: the previous adapter version, the untuned base with your production prompt, or a newer prompted model that you already tested in the parity run. Keep every adapter version, its training data snapshot and its evaluation results, so the next base-model change is a retrain and a re-test, not another migration.
What does a realistic timeline look like from today?
Working back from the January 14, 2027 shutdown, as of November 13, 2026:
| By | Do this |
|---|---|
| November 20 | Inventory every ft: model, its base snapshot and caller; start the exports |
| November 27 | Evals exported, ahead of the November 30 shutdown; test set frozen and labelled |
| December 11 | Any judge or baseline on gpt-5 or o3 replaced and re-validated |
| Mid-December | Old fine-tunes run on the test set and outputs saved; untuned shortlist scored; first adapters trained |
| Late December | Parity decision made; shadow traffic running |
| Early January | Canary and full cutover, with the old model still available as a rollback |
| January 14, 2027 | Old fine-tunes stop serving; rollback now points to your own fallback |
This leaves little slack. If you have several fine-tunes, rank them by traffic and business risk and migrate the most important first; a fine-tune with little traffic may be a candidate for the prompted route or for retirement.
Frequently asked questions
When does OpenAI fine-tuning shut down?
OpenAI is winding down its fine-tuning platform in stages. Organizations that had never fine-tuned lost access on May 7, 2026, and organizations without fine-tuned-model inference in the prior 60 days lost job creation on July 2, 2026. On January 6, 2027, active existing customers can no longer create fine-tuning jobs. Existing fine-tuned models keep serving until their base model shuts down.
Will my existing OpenAI fine-tuned model keep working after January 6, 2027?
Yes, until its base model shuts down. OpenAI says fine-tuned models remain available for inference until the base model shuts down. For fine-tunes of gpt-4o-2024-08-06, gpt-4o-mini-2024-07-18, gpt-4.1-2025-04-14 and gpt-4.1-mini-2025-04-14, that is January 14, 2027. Fine-tunes of gpt-4.1-nano, gpt-3.5-turbo-0125 and several other legacy snapshots already stopped on October 23, 2026.
Can I download the weights of my OpenAI fine-tuned model?
No. An OpenAI fine-tuning job produces a model ID such as ft:gpt-4.1-mini-2025-04-14:org::id that you call through the API, not a set of weights you can export. To keep the behavior, you need the data that produced it, then retrain on a model whose weights you control, or match it with prompting on a newer model.
Can I download my fine-tuning training files from OpenAI?
You can download job result files through the Files API. Downloading the input training files was refused in 2021 developer-forum reports, with the error 'Not allowed to download files of purpose: fine-tune', so test it on your account today and treat your own upstream copy of the data as the source of truth. If that copy is gone, rebuild the dataset from production logs and labels.
Should I re-fine-tune an open-weight model or just prompt a newer OpenAI model?
Test both on the same held-out set. Prompting a newer model is often enough when the old fine-tune mainly enforced format or tone, volume is modest, and the newer model's cost and latency fit. Re-fine-tuning an open-weight model makes more sense at high volume, for strict latency or data-residency requirements, or when you want weights that no vendor can retire.
How do I prove an open-weight model is as good as my OpenAI fine-tune?
Freeze a held-out test set that neither model trained on, run the old fine-tuned model on it before it shuts down, then score the candidate on the same items with the same scorer. Decide a non-inferiority margin in advance and require the lower bound of a paired confidence interval on the score difference to stay above it, overall and on critical slices.
Sources
- Deprecations — OpenAI, 2026
- Supervised fine-tuning — OpenAI, 2026
- API reference: Files — OpenAI, 2026
- API reference: Fine-tuning — OpenAI, 2026
- API reference: Evals — OpenAI, 2026
- Retrieve file content API is not allowing to retrieve content — OpenAI Developer Community, 2021
- LoRA Without Regret — Thinking Machines Lab, 2025
- SFT Trainer — Hugging Face TRL, 2026
- Dataset formats and types: tool calling — Hugging Face TRL, 2026
- LoRA adapters — vLLM, 2026
- Qwen3.8-27B model card — Qwen (Hugging Face), 2026
- Gemma 4 31B IT model card — Google (Hugging Face), 2026
- gpt-oss-20b model card — OpenAI (Hugging Face), 2025
- Muse Glimmer 30B model card — Meta (Hugging Face), 2026