Text Classification with Claude API (Python)

Classify text with Claude in Python: single-label, multi-label, zero-shot, and batch classification. Working code examples with structured JSON output and accuracy tips.

💥 50p impulse-buy: Power Prompts PDF (first 10 buyers) 30 battle-tested Claude Code prompts · 8-page PDF · paste into CLAUDE.md and never re-type a prompt again · 50p impulse-buy, no commitment

Claude's instruction-following ability makes it an excellent zero-shot and few-shot text classifier. This guide covers single-label, multi-label, and batch classification with structured JSON output.

Installation

pip install anthropic

Single-label classification (zero-shot)

import anthropic
import json

client = anthropic.Anthropic()

LABELS = ["positive", "neutral", "negative"]

def classify_sentiment(text: str) -> str:
    system = f"""You are a sentiment classifier.
Return ONLY a JSON object with a single key "label".
The label must be one of: {LABELS}.
No explanation. No markdown. Raw JSON only."""

    response = client.messages.create(
        model="claude-haiku-4-5-20251001",  # fast + cheap for classification
        max_tokens=32,
        temperature=0,  # deterministic
        system=system,
        messages=[{"role": "user", "content": text}]
    )
    result = json.loads(response.content[0].text)
    return result["label"]

print(classify_sentiment("The new API is incredibly easy to use!"))
# → "positive"
print(classify_sentiment("The package arrived yesterday."))
# → "neutral"

Multi-label classification

TOPIC_LABELS = ["billing", "technical", "account", "feature-request", "bug", "general"]

def classify_support_ticket(ticket: str) -> list[str]:
    system = f"""You are a support ticket classifier.
Return ONLY a JSON object with key "labels" containing an array of applicable labels.
Labels must be from this list: {TOPIC_LABELS}.
Return an empty array if no category fits.
No explanation. Raw JSON only."""

    response = client.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=64,
        temperature=0,
        system=system,
        messages=[{"role": "user", "content": ticket}]
    )
    result = json.loads(response.content[0].text)
    # Validate against allowed labels
    return [l for l in result["labels"] if l in TOPIC_LABELS]

ticket = "I was charged twice this month and I can't log into my account."
print(classify_support_ticket(ticket))
# → ["billing", "account"]

Few-shot classification (higher accuracy)

def classify_with_examples(text: str, labels: list[str], examples: list[dict]) -> str:
    """
    examples: [{"text": "...", "label": "..."}, ...]
    Provide 2-5 examples per label for best accuracy.
    """
    examples_str = "
".join(
        f'Text: "{ex["text"]}"
Label: {ex["label"]}'
        for ex in examples
    )
    system = f"""You are a text classifier.
Allowed labels: {labels}
Return ONLY a JSON object with key "label".

Examples:
{examples_str}"""

    response = client.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=32,
        temperature=0,
        system=system,
        messages=[{"role": "user", "content": f'Text: "{text}"
Label:'}]
    )
    result = json.loads(response.content[0].text)
    return result["label"]

examples = [
    {"text": "App crashes on launch", "label": "bug"},
    {"text": "Please add dark mode", "label": "feature-request"},
    {"text": "Can't reset my password", "label": "account"},
]
print(classify_with_examples("Login page freezes after update", ["bug", "feature-request", "account"], examples))
# → "bug"

Batch classification (50% cost via Batch API)

def batch_classify(texts: list[str], labels: list[str]) -> str:
    """Submit up to 100K requests at 50% cost. Returns batch ID to poll."""
    system = f"""You are a text classifier.
Return ONLY a JSON object with key "label".
Allowed labels: {labels}
No explanation. Raw JSON only."""

    requests_list = [
        {
            "custom_id": f"item_{i}",
            "params": {
                "model": "claude-haiku-4-5-20251001",
                "max_tokens": 32,
                "temperature": 0,
                "system": system,
                "messages": [{"role": "user", "content": text}]
            }
        }
        for i, text in enumerate(texts)
    ]
    batch = client.beta.messages.batches.create(requests=requests_list)
    print(f"Batch submitted: {batch.id} — poll until processing_status == 'ended'")
    return batch.id

# batch_classify(my_texts, ["positive", "neutral", "negative"])

Classification approach comparison

ApproachLabeled data neededAccuracyCostLatency
Claude zero-shotNoneGood for common labelsMedium~1s / text
Claude few-shot (3-5 ex)~5 examples totalBetterMedium+~1s / text
Claude Batch APINoneSame as zero-shot50% lessAsync (minutes–hours)
Fine-tuned BERT500–5,000 per classBest at scaleVery low<100ms

For bulk classification jobs, estimate your costs with the Claude API Cost Calculator. For extracting structured fields (not just labels) from text, see the structured output guide. For sentiment + summarization in one call, see the summarization guide.

Frequently asked questions

Why use Claude for text classification instead of a fine-tuned model?
Claude handles zero-shot and few-shot classification without any labeled training data. This is ideal when you have new categories, limited data, or need human-readable explanations alongside labels. Fine-tuned models are faster and cheaper at scale once you have 1,000+ labeled examples per class.
How do I get Claude to return only a label and not prose?
Instruct Claude via the system prompt: 'Return only a JSON object with a `label` field. No explanation.' Set temperature to 0 for deterministic output. Wrap the call in a try/except and use `json.loads()` — Claude follows structured output instructions reliably when prompted correctly.
What is zero-shot classification?
Zero-shot classification means providing only the category names (no examples). Claude assigns the best-fitting label using its training knowledge. Add 1-3 examples per category (few-shot) when accuracy matters — each example roughly doubles classification precision for ambiguous cases.
How should I handle multi-label classification?
Ask Claude to return a JSON array of labels. Instruct it to return an empty array if no category fits. Validate the array against your allowed label set in Python before using the output downstream.
How much does it cost to classify 100,000 texts with Claude?
At ~100 input tokens per text + system prompt (~200 tokens) and ~10 output tokens per label, that is ~310 tokens × 100,000 = ~31M tokens. At Haiku 4.5 rates ($0.00025/1K input, $0.00125/1K output), cost is roughly $8.75 for inputs + $1.25 for outputs = ~$10. Use the Batch API for 50% off.

Free tools

Cost Calculator → API Cookbook → Diff Summarizer → Skills Browser →

More examples

Claude API Python QuickstartClaude API Node.js / TypeScript QuickstartClaude API Streaming in PythonClaude API Streaming in Node.js / TypeScriptClaude API Tool Use in PythonClaude API Tool Use in Node.js / TypeScript