Course EN
← back to chapter

Few-shot

Clasifica un mensaje de soporte en una sola etiqueta — billing, bug,

Showcase — Few-shot

Clasifica un mensaje de soporte en una sola etiqueta — billing, bug, feature_request, praise, other. Un checkbox prende y apaga los ejemplos de few-shot. Con los ejemplos en el prompt, el conjunto de etiquetas y el formato de una línea se quedan fijos. Apágalos y el modelo empieza a inventar etiquetas y a envolverlas en prosa.

Córrelo

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

Abre http://localhost:3000.

Para correrlo contra Gemini en su lugar:

PROVIDER=gemini docker compose up --build

Qué hay aquí

  • backend/ai_openai.py — el bloque INSTRUCTION + EXAMPLES (la lección) y la llamada a OpenAI
  • backend/ai_gemini.py — el mismo prompt, llamada a Gemini
  • backend/main.py — loader de FastAPI idéntico; lee PROVIDER y despacha
  • frontend/app/page.tsx — textarea + checkbox de few-shot + resultado
  • docker-compose.yml — dos servicios, secrets montados desde ./secrets/

El frontend codifica <mode>\n---\n<message> (mode es zeroshot o fewshot) en el input de un solo string, manteniendo el contrato def run(input: str) -> str idéntico en los showcases de la semana.

Detenlo

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.es.md
  • 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