Course EN

Capítulo 2 de 21 · básico

Primera llamada a la API

Qué cubre esta sesión

Llevo años viendo cómo el primer programa de IA de alguien muere por una key faltante o hardcodeada mucho antes de llegar al modelo. Por eso la semana uno es deliberadamente pequeña: al final de la hora habrás recibido una respuesta real de un modelo en tu propia máquina, dos veces — una con OpenAI y otra con Google Gemini. Eso es todo. Sin framework, sin agente, sin retrieval. Eso viene después, y todo lo que viene después asume que esta parte ya funciona y nunca la vuelve a mencionar.

Escribí los dos ejemplos con la misma forma a propósito. Mismo patrón de imports, misma verificación de la key, mismo flujo de un prompt y una respuesta. Léelos uno tras otro y lo único que cambia son las partes que de verdad difieren entre los SDKs. Esas diferencias son la lección. Todo lo demás es andamiaje que dejarás de notar para la semana tres.

OpenAI

El ejemplo de OpenAI pasa por la Responses API: le das a responses.create un modelo y un string input, y lees el texto de response.output_text. La key nunca aparece en el código — OpenAI() sin argumentos encuentra OPENAI_API_KEY en el entorno por sí solo. La línea de load_dotenv / find_dotenv es lo que hace que eso funcione sin que exportes nada a mano. Sube desde este archivo, encuentra el .env en la raíz del curso y lo carga antes de que se construya el cliente.

"""Week 1 - First API call (OpenAI).

The smallest program that does real work: read a key from the
environment, send one prompt, print one answer.
"""
import os
import sys

from dotenv import find_dotenv, load_dotenv
from openai import OpenAI

# Pull OPENAI_API_KEY from the course-root .env. find_dotenv walks up
# the directory tree, so this works no matter where you run it from.
load_dotenv(find_dotenv())

if not os.environ.get("OPENAI_API_KEY"):
    sys.exit("OPENAI_API_KEY is not set. Put it in the course-root .env file.")

# OpenAI() reads OPENAI_API_KEY from the environment by itself - you
# never pass the key in code.
client = OpenAI()

response = client.responses.create(
    model="gpt-5.4-nano",
    input="In one sentence, greet someone taking their first AI course.",
)

print(response.output_text)

El guard antes del cliente no es decoración. Sáltatelo y el SDK se construye sin problema, y luego muere en lo profundo de una llamada HTTP con un traceback que jamás dice "olvidaste tu key". Tres líneas convierten eso en una oración sobre la que puedes actuar. El código de cada semana en este libro hace lo mismo, y yo conservaría el hábito mucho más allá de este libro.

Gemini

Mismo esqueleto. Lo que vale la pena notar es en qué diverge: el import es from google import genai, la llamada es client.models.generate_content con contents en lugar de input, y el texto regresa en response.text en lugar de response.output_text. Lo único que cambié a propósito es la key. El cliente de OpenAI descubre OPENAI_API_KEY implícitamente; aquí la paso con api_key=.... El cliente de Gemini también autodescubriría GEMINI_API_KEY o GOOGLE_API_KEY, pero en el día uno prefiero ver de dónde viene la key que ahorrarme una línea.

"""Week 1 - First API call (Gemini).

Deliberately the same shape as the OpenAI example so you can read the
two SDKs side by side: key from the environment, one prompt, one answer.
"""
import os
import sys

from dotenv import find_dotenv, load_dotenv
from google import genai

# Same .env lookup as the OpenAI example.
load_dotenv(find_dotenv())

if not os.environ.get("GEMINI_API_KEY"):
    sys.exit("GEMINI_API_KEY is not set. Put it in the course-root .env file.")

# Unlike OpenAI(), we hand the key in explicitly here. The client also
# auto-discovers GEMINI_API_KEY / GOOGLE_API_KEY, but being explicit
# keeps the first lesson unambiguous.
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

response = client.models.generate_content(
    model="gemini-3.1-flash-lite",
    contents="In one sentence, greet someone taking their first AI course.",
)

print(response.text)

Dos SDKs haciendo el mismo trabajo, separados por tres diferencias de nombres y una decisión sobre el manejo de la key. Para una llamada así de simple, esa es toda la comparación. Esos mismos puntos — el nombre de la llamada, el campo de la respuesta, cómo encuentra el cliente las credenciales — son los que seguirás revisando conforme los dos proveedores se vayan distanciando en semanas posteriores.

Ponlo a trabajar

Una llamada de "hola, modelo" sirve como por diez minutos. Tres apps web pequeñas convierten esa misma API de dos líneas en algo que yo sí dejaría abierto en una pestaña. Cada una es su propio proyecto de docker-compose bajo code/showcase/<slug>/bash bootstrap-secrets.sh, docker compose up --build, abre http://localhost:3000. El capítulo imprime solo la pieza de IA de cada una, ai_openai.py y ai_gemini.py. El Dockerfile, el loader de FastAPI y el pequeño formulario de Next.js son andamiaje que simplemente ejecutas; el README de cada showcase los cubre si quieres el recorrido completo.

Showcase 1 — Explica un snippet

Pega código o un one-liner de shell; recibe de vuelta un párrafo de explicación en lenguaje llano. El truco está en el prompt, no en el SDK: "Explain in one short paragraph, prose only, do not include code" fija al modelo a una sola forma de respuesta, que es lo que convierte un juguete estilo chat en algo a lo que puedes hacer pipe. Pruébalo con un regex que olvidaste, con una invocación de find, con un query de SQL que heredaste.

Showcase 2 — Reescribe el tono

Pega un borrador de mensaje, elige un tono — neutral, amigable, formal, seco — y recíbelo reescrito conservando cada dato. El frontend codifica el tono dentro del input de un solo string como <tone>\n---\n<message>, que es como el contrato def run(input: str) -> str se mantiene igual en los tres showcases de la semana.

Showcase 3 — Redacta un README

Entra una descripción de proyecto de un párrafo, sale un esqueleto de README: What, Install, Usage, License. Suéltalo en un repo nuevo, corrige los placeholders y publícalo. Sigue siendo una sola llamada a la API.

El mismo backend/main.py vive en los tres proyectos, byte por byte. Lee PROVIDER del entorno y hace importlib de ai_openai o ai_gemini. ¿Quieres las respuestas de Gemini? PROVIDER=gemini docker compose up --build y refresca. El backend nunca se enteró de que había más de un SDK; el loader sí. Ninguna de estas tres es un juguete, y ninguna usó nada más allá de la única llamada a la API que escribiste al principio de este capítulo.

Córrelo

El README de esta carpeta tiene la versión de Python, el comando de instalación, las dos variables de entorno y el comando exacto para correr cada ejemplo. El código espera un .env sin trackear en la raíz del curso. Ese archivo está en el git-ignore, así que la key nunca cae en el control de versiones, que es justamente el punto de no hardcodearla.

Lo que te llevas

La llamada al modelo son dos líneas. Todo lo que la rodea — cargar el .env, verificar la key, elegir el nombre del modelo — es lo que de verdad decide si tu programa corre o muere con un traceback confuso, y es exactamente la parte que la mayoría de los tutoriales se salta. Yo no me la voy a saltar. Haz que este andamiaje se vuelva reflejo desde ahora: la key en el entorno, nunca en el código fuente; cárgala antes del cliente; falla fuerte y temprano cuando falte. Cada capítulo posterior se apoya en esto y no se va a detener a explicarlo de nuevo.