Model chooser  /  Classify, tag or extract data  /  Recurring

To classify or extract at volume, use GPT-5.6 Luna.

Tagging every inbound lead or ticket is a high-volume, low-difficulty job where cost per call decides the model. OpenAI built Luna for exactly that, it is in the lowest cost tier of any current flagship family, and strict JSON schemas keep the output machine-readable.

Why GPT-5.6 Luna

The reasons it wins for this job.

  • OpenAI positions Luna for "cost-sensitive, high-volume workloads". It replaces the old nano tier in the GPT-5.6 family released 9 July 2026.
  • It keeps the family's 1.05M-token context, so long inputs such as a whole email thread or a scraped page do not need chunking.
  • The Responses API's json_schema format with strict: true guarantees every response matches your schema, so no row breaks the import.
  • For classification, the gap between a small and a frontier model is small and measurable. Measure it on your own labelled rows before you pay for the bigger one.

How to use it

4 steps to a first result.

  1. 1Label 200 real rows by handThis is your test set. Without it you are choosing a model on vibes.
  2. 2Put the label definitions in the promptSame definitions as the humans used. Use an enum in the schema so it cannot invent a label.
  3. 3Compare two models on the setRun Luna and one stronger model. If Luna's agreement with your labels is within a point or two, ship Luna.
  4. 4Send low-confidence rows to a personAdd a confidence field and route anything below your threshold to a review queue.

OpenAI Responses API, TypeScript

Start from this.

Edit the parts in capitals, then run it.

import OpenAI from "openai";

const openai = new OpenAI(); // reads OPENAI_API_KEY

export async function tagLead(lead: string) {
  const res = await openai.responses.create({
    model: "gpt-5.6-luna",
    input: [
      { role: "system", content: "Classify the lead. Industry definitions: SaaS = sells software on subscription; ADD THE REST. Use only facts in the input." },
      { role: "user", content: lead },
    ],
    text: {
      format: {
        type: "json_schema",
        name: "lead_tags",
        strict: true,
        schema: {
          type: "object",
          properties: {
            industry: { type: "string", enum: ["SaaS", "Fintech", "Healthcare", "Ecommerce", "Agency", "Other"] },
            company_size: { type: "string", enum: ["1-10", "11-50", "51-200", "201-1000", "1000+", "unknown"] },
            confidence: { type: "string", enum: ["high", "low"] },
          },
          required: ["industry", "company_size", "confidence"],
          additionalProperties: false,
        },
      },
    },
  });
  return JSON.parse(res.output_text);
}
Nothing is sent anywhere. It copies to your clipboard.

Alternatives that also work

If GPT-5.6 Luna is not an option.

Gemini 3.8 FlashOfficial page →

Google · closed · cost: low

Pick it when the inputs are images, PDFs or audio, or the rows need more reasoning than a label. It is also in the low cost tier.

DeepSeek V4.1 FlashHugging Face →

DeepSeek · open weights · cost: low · 391K HF downloads/mo

Pick it when you want the lowest price on a hosted API and can batch work into off-peak hours, when DeepSeek charges half.

Gemma 4 26B A4BHugging Face →

Google · open weights · cost: free weights; you pay for the hardware · 9.6M HF downloads/mo

Pick it when data must stay in your cloud account. Apache 2.0, only 3.8B parameters active per token, so it is fast on one GPU.

Watch out for

Doing this just once? To tag or clean one list, paste it into Claude Sonnet 5. A one-off cleanup of a few hundred rows does not need an API. Sonnet 5 is available to everyone in the Claude app, reads the CSV you upload, and is fast enough to iterate on the labels with you.

Sources

Checked . Models change monthly; we re-check this page when they do.

Picking the model is the easy part.

Wiring it into a workflow that runs every week, with evals, fallbacks and a cost you can predict, is the work. Fifteen minutes, no deck.

Book fifteen minutes →