Course EN
← back to chapter

Few-shot

Classify a support message into one label — billing, bug, feature_request,

Showcase — Few-shot

Classify a support message into one label — billing, bug, feature_request, praise, other. A checkbox flips the few-shot examples on and off. With the examples in the prompt, the label set and the one-line format stay put. Turn them off and the model starts inventing labels and wrapping them in prose.

Run

bash bootstrap-secrets.sh              # reads ../../../../.env, writes secrets/
docker compose up --build              # default: PROVIDER=openai

Open http://localhost:3000.

To run against Gemini instead:

PROVIDER=gemini docker compose up --build

What's where

  • backend/ai_openai.py — the INSTRUCTION + EXAMPLES block (the lesson) and the OpenAI call
  • backend/ai_gemini.py — same prompt, Gemini call
  • backend/main.py — identical FastAPI loader; reads PROVIDER and dispatches
  • frontend/app/page.tsx — textarea + few-shot checkbox + result
  • docker-compose.yml — two services, secrets mounted from ./secrets/

The frontend encodes <mode>\n---\n<message> (mode is zeroshot or fewshot) into the single-string input, keeping the def run(input: str) -> str contract identical across the week's showcases.

Stop

docker compose down

Ejecútalo en tu máquina

Descarga el proyecto como ZIP y córrelo con Docker. Levanta un backend FastAPI y un frontend Next.js en localhost:3000.

Descargar few-shot.zip

unzip few-shot.zip
cd few-shot
bash bootstrap-secrets.sh   # one-time: pulls API keys into ./secrets
docker compose up --build   # default provider: openai
# or:  PROVIDER=gemini docker compose up --build

Escribe algo, elige un proveedor y ejecuta el mismo código de Código contra la API real. Requiere iniciar sesión.


  

Los mismos módulos que ejecuta el botón Run. El proyecto completo (frontend, Dockerfile, compose) está en el ZIP, pestaña README.

backend/ai_openai.py

"""Week 2 - Showcase 2 (OpenAI): zero-shot vs few-shot, side by side.

Same classification task, same instruction. The only thing the toggle
changes is whether a handful of worked examples ride along in the prompt.
Zero-shot drifts on the label set and the format; few-shot locks both.
The frontend encodes "<mode>\\n---\\n<text>" where mode is zeroshot|fewshot.
"""
from openai import OpenAI

_client = OpenAI()

LABELS = "billing, bug, feature_request, praise, other"

INSTRUCTION = (
    "Classify the support message into exactly one of these labels: "
    f"{LABELS}. Respond with only `label: <one label>` and nothing else."
)

# The few-shot block: three worked examples that pin the label vocabulary
# and the output line. This is the entire difference the toggle makes.
EXAMPLES = """
Message: My card got charged twice this month.
label: billing

Message: The export button does nothing when I click it.
label: bug

Message: Any chance you could add dark mode?
label: feature_request
""".strip()


def run(payload: str) -> str:
    mode, _, text = payload.partition("\n---\n")
    mode = (mode or "fewshot").strip()
    text = (text or payload).strip()

    if mode == "zeroshot":
        prompt = f"{INSTRUCTION}\n\nMessage: {text}"
    else:
        prompt = f"{INSTRUCTION}\n\n{EXAMPLES}\n\nMessage: {text}"

    response = _client.responses.create(
        model="gpt-5.4-nano", input=prompt, max_output_tokens=20,
    )
    return response.output_text

backend/ai_gemini.py

"""Week 2 - Showcase 2 (Gemini): zero-shot vs few-shot, side by side."""
import os

from google import genai
from google.genai import types

_client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

LABELS = "billing, bug, feature_request, praise, other"

INSTRUCTION = (
    "Classify the support message into exactly one of these labels: "
    f"{LABELS}. Respond with only `label: <one label>` and nothing else."
)

EXAMPLES = """
Message: My card got charged twice this month.
label: billing

Message: The export button does nothing when I click it.
label: bug

Message: Any chance you could add dark mode?
label: feature_request
""".strip()


def run(payload: str) -> str:
    mode, _, text = payload.partition("\n---\n")
    mode = (mode or "fewshot").strip()
    text = (text or payload).strip()

    if mode == "zeroshot":
        prompt = f"{INSTRUCTION}\n\nMessage: {text}"
    else:
        prompt = f"{INSTRUCTION}\n\n{EXAMPLES}\n\nMessage: {text}"

    response = _client.models.generate_content(
        model="gemini-3.1-flash-lite",
        contents=prompt,
        config=types.GenerateContentConfig(max_output_tokens=20),
    )
    return response.text

Archivos del proyecto

  • .gitignore
  • README.md
  • backend/Dockerfile
  • backend/ai_gemini.py
  • backend/ai_openai.py
  • backend/main.py
  • backend/requirements.txt
  • bootstrap-secrets.sh
  • docker-compose.yml
  • frontend/Dockerfile
  • frontend/app/layout.tsx
  • frontend/app/page.tsx
  • frontend/next.config.ts
  • frontend/package.json
  • frontend/tsconfig.json