Course EN
← back to chapter

Router

Un agent clasifica la solicitud; un especialista elegido por esa clasificación la responde. Escala un asistente con un router barato más especialistas enfocados en vez de un solo prompt gigante. La respuesta muestra qué especialista la manejó.

Showcase — Router

Un agent clasifica la solicitud; un especialista elegido por esa clasificación la responde. Escala un asistente con un router barato más especialistas enfocados en vez de un solo prompt gigante. La respuesta muestra qué especialista la manejó.

Córrelo

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

Abre http://localhost:3000. Gemini: PROVIDER=gemini docker compose up --build.

Qué hay aquí

  • backend/ai_openai.py / backend/ai_gemini.py — un router agent + cuatro especialistas.
  • frontend/app/page.tsx — caja de mensaje, respuesta ruteada.

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 router.zip

unzip router.zip
cd router
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

"""Showcase 2 (OpenAI): a router with specialist agents.

One agent classifies the request; another, chosen by that classification, answers
it. This is how you scale an assistant without one giant prompt: a cheap router
plus focused specialists, each expert at one thing. The reply shows which
specialist handled it.
"""
from openai import OpenAI

_client = OpenAI()

_MODEL = "gpt-5.4-nano"

_SPECIALISTS = {
    "billing": "You are a billing specialist. Help with payments, invoices, refunds, and plan changes. Be precise about money.",
    "technical": "You are a technical support engineer. Help debug errors and explain how-tos clearly, with steps.",
    "sales": "You are a friendly sales rep. Explain plans and features and gently encourage the right upgrade.",
    "general": "You are a helpful general assistant.",
}


def _agent(system: str, user: str) -> str:
    return _client.responses.create(model=_MODEL, instructions=system, input=[{"role": "user", "content": user}]).output_text


def run(message: str) -> str:
    m = message.strip()
    if not m:
        return "Send a message to route (a billing, technical, sales, or general question)."
    route = _agent(
        "You are a router. Classify the user's message into exactly one of: billing, technical, "
        "sales, general. Reply with ONLY that one word.", m,
    ).strip().lower()
    route = route if route in _SPECIALISTS else "general"
    answer = _agent(_SPECIALISTS[route], m)
    return f"[routed to: {route}]\n\n{answer}"

backend/ai_gemini.py

"""Showcase 2 (Gemini): a router with specialist agents.

Same classify-then-dispatch, on Gemini.
"""
import os

from google import genai
from google.genai import types

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

_MODEL = "gemini-3.1-flash-lite"

_SPECIALISTS = {
    "billing": "You are a billing specialist. Help with payments, invoices, refunds, and plan changes. Be precise about money.",
    "technical": "You are a technical support engineer. Help debug errors and explain how-tos clearly, with steps.",
    "sales": "You are a friendly sales rep. Explain plans and features and gently encourage the right upgrade.",
    "general": "You are a helpful general assistant.",
}


def _agent(system: str, user: str) -> str:
    r = _client.models.generate_content(
        model=_MODEL,
        contents=[types.Content(role="user", parts=[types.Part(text=user)])],
        config=types.GenerateContentConfig(system_instruction=system),
    )
    return r.text or ""


def run(message: str) -> str:
    m = message.strip()
    if not m:
        return "Send a message to route (a billing, technical, sales, or general question)."
    route = _agent(
        "You are a router. Classify the user's message into exactly one of: billing, technical, "
        "sales, general. Reply with ONLY that one word.", m,
    ).strip().lower()
    route = route if route in _SPECIALISTS else "general"
    answer = _agent(_SPECIALISTS[route], m)
    return f"[routed to: {route}]\n\n{answer}"

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