Lección 1.2 · 25 min · Gratis

Tu primera llamada con Python

En la lección anterior dejaste lista tu cuenta en la Claude Console y un workspace de desarrollo con límite de gasto. Ahora toca escribir código. Al final de esta lección tendrás un proyecto de Python que le hace una pregunta a Claude en nombre de Viajes Kukulcán y te muestra la respuesta, cuántos tokens usó y cuánto costó.

Al terminar podrás:

  • crear una clave de API y guardarla fuera de tu código;
  • montar un proyecto de Python con uv e instalar el SDK oficial;
  • hacer una llamada con messages.create usando una constante MODELO;
  • recorrer los bloques de content y leer usage, stop_reason y el identificador de la solicitud.

Paso 1: crea tu clave

En la consola entra a Settings > API keys y pulsa Create key. Ponle un nombre que diga para qué es, por ejemplo curso-api-laptop-mariana, elige una expiración (para un curso, 30 días es razonable) y asígnala al workspace de desarrollo que creaste. La clave empieza con sk-ant-api y solo se muestra completa una vez: cópiala en ese momento.

Tres reglas que vamos a seguir desde ya:

  1. La clave nunca va dentro de un archivo .py.
  2. La clave nunca se sube a Git, ni a un chat, ni a una captura de pantalla.
  3. Si sospechas que se filtró, la desactivas o la borras en la misma página y creas otra.

Paso 2: crea el proyecto con uv

uv es un gestor de proyectos y paquetes de Python muy rápido. Si no lo tienes, instálalo siguiendo su documentación. El SDK de Anthropic requiere Python 3.10 o superior, y uv puede descargar la versión adecuada por ti.

En una terminal:

uv init kukulcan-asistente
cd kukulcan-asistente
uv add anthropic python-dotenv

uv init crea la carpeta con un pyproject.toml; uv add instala el SDK oficial (anthropic) y python-dotenv, que usaremos para leer la clave desde un archivo .env. Ambas dependencias quedan registradas en pyproject.toml y fijadas en uv.lock, así que cualquiera que clone el proyecto obtiene las mismas versiones con uv sync.

Paso 3: guarda la clave en un archivo .env

Dentro de kukulcan-asistente crea un archivo llamado .env con una sola línea:

ANTHROPIC_API_KEY=sk-ant-api...tu-clave-completa...

Después abre .gitignore (créalo si no existe) y agrega:

.env

El SDK busca la clave en la variable de entorno ANTHROPIC_API_KEY. python-dotenv carga el archivo .env en las variables de entorno al iniciar el script. Si prefieres no usar archivo, también puedes definir la variable en la terminal:

# macOS o Linux
export ANTHROPIC_API_KEY="sk-ant-api..."
# Windows PowerShell, solo para la sesión actual
$env:ANTHROPIC_API_KEY = "sk-ant-api..."

Paso 4: la primera llamada

Crea primera_llamada.py:

# primera_llamada.py
import anthropic
from dotenv import load_dotenv

MODELO = "claude-opus-5-5"

load_dotenv()  # carga ANTHROPIC_API_KEY desde .env
cliente = anthropic.Anthropic()  # lee la clave de la variable de entorno

respuesta = cliente.messages.create(
    model=MODELO,
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": (
                "Soy cliente de una agencia en Mérida. En dos párrafos cortos, "
                "¿qué debo llevar a un tour de un día a Chichén Itzá y un cenote?"
            ),
        }
    ],
)

for bloque in respuesta.content:
    if bloque.type == "text":
        print(bloque.text)

print("---")
print("stop_reason:", respuesta.stop_reason)
print("tokens de entrada:", respuesta.usage.input_tokens)
print("tokens de salida:", respuesta.usage.output_tokens)
print("id de solicitud:", respuesta._request_id)

Ejecútalo:

uv run primera_llamada.py

uv run usa el entorno del proyecto automáticamente; no necesitas activar nada.

Los tres parámetros obligatorios

  • model: el identificador del modelo. Lo guardamos en la constante MODELO al inicio de cada script de este curso para cambiarlo en un solo lugar. Usamos claude-opus-5-5 porque la página de modelos de Anthropic lo recomienda como punto de partida en octubre de 2026; en la lección 1.3 aprenderás a elegir otro.
  • max_tokens: el máximo de tokens que el modelo puede generar en esta respuesta. Es un tope duro: si se alcanza, la respuesta se corta. Lo vemos a fondo en la lección 1.5.
  • messages: la lista de mensajes de la conversación. Cada mensaje tiene un role ("user" o "assistant") y un content. Aquí solo hay uno, la pregunta.

Paso 5: entiende la respuesta

messages.create devuelve un objeto Message. Si imprimes respuesta.to_json() verás algo parecido a esto (recortado):

{
  "id": "msg_01...",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-5-5",
  "content": [
    {"type": "thinking", "thinking": "", "signature": "Eo..."},
    {"type": "text", "text": "Para un día entre ruinas y cenote, lleva..."}
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "stop_details": null,
  "usage": {"input_tokens": 41, "output_tokens": 312}
}

Vamos campo por campo.

content es una lista de bloques

El error más común de quien empieza es escribir respuesta.content[0].text. Funciona en muchos tutoriales viejos, pero content es una lista de bloques y cada bloque tiene un type. Puede haber bloques de texto, de llamadas a herramientas y de pensamiento.

En Claude Opus 5.5 el pensamiento adaptativo está siempre activo: el modelo decide en cada solicitud si razona antes de responder. Cuando lo hace, la respuesta incluye un bloque thinking antes del texto. En este modelo el texto del pensamiento viene vacío por defecto (el campo display está en "omitted"), pero el bloque existe. Si tomas content[0] a ciegas, puedes estar leyendo ese bloque y no la respuesta. Por eso recorremos la lista y nos quedamos con los bloques type == "text". Veremos el pensamiento a detalle en la lección 2.5.

Un ayudante que vas a reutilizar en todo el curso:

def texto_de(respuesta) -> str:
    """Une el texto de todos los bloques de tipo text."""
    return "".join(b.text for b in respuesta.content if b.type == "text")

stop_reason dice por qué terminó

"end_turn" significa que el modelo terminó de forma natural. Si ves "max_tokens", la respuesta se cortó porque llegó al tope que pusiste. Hay otros valores (stop_sequence, tool_use, refusal y más) que revisamos en la lección 1.5. Revisar este campo antes de usar el texto es un buen hábito desde la primera llamada.

usage dice cuánto cuesta

usage.input_tokens y usage.output_tokens son la base de tu factura. Los tokens de salida incluyen el razonamiento interno del modelo aunque no veas su texto, así que una respuesta corta puede tener más tokens de salida de los que esperas. Con los precios de Claude Opus 5.5 (4 USD por millón de tokens de entrada y 20 USD por millón de salida, según la página de precios en octubre de 2026) puedes calcular el costo de cada llamada:

PRECIO_ENTRADA = 4.00 / 1_000_000   # USD por token, Claude Opus 5.5
PRECIO_SALIDA = 20.00 / 1_000_000

costo = (respuesta.usage.input_tokens * PRECIO_ENTRADA
         + respuesta.usage.output_tokens * PRECIO_SALIDA)
print(f"costo aproximado: {costo:.6f} USD")

Cuando uses caché de prompts aparecerán campos adicionales en usage; los vemos en las lecciones 2.4 y 4.1.

_request_id sirve para rastrear

Cada respuesta trae un encabezado request-id y el SDK lo expone como respuesta._request_id, con un valor como req_018E.... Guárdalo en tus registros: si algo falla y necesitas soporte, es lo primero que te pedirán. A pesar del guion bajo, es una propiedad pública del SDK.

Si algo sale mal

Los errores más frecuentes en la primera llamada:

  • AuthenticationError (401): la clave es incorrecta, expiró o no se cargó. Revisa que el archivo se llame exactamente .env, que esté en la carpeta donde ejecutas el script y que no tenga comillas de más.
  • NotFoundError (404) o error de modelo: el identificador del modelo está mal escrito. Cópialo de la página de modelos.
  • BadRequestError (400): la solicitud tiene un problema de formato, por ejemplo falta max_tokens. Lee el mensaje del error: suele decir qué campo falla. También puede indicar que alcanzaste un límite de gasto que configuraste.
  • APIConnectionError: no hay conexión con la API. Revisa tu red o proxy.

Todas estas excepciones heredan de anthropic.APIError. En la lección 2.3 construimos un manejo de errores completo con reintentos.

Una versión reutilizable

Vamos a dejar una función que usaremos en las siguientes lecciones. Crea kukulcan.py:

# kukulcan.py
import anthropic
from dotenv import load_dotenv

MODELO = "claude-opus-5-5"

load_dotenv()
cliente = anthropic.Anthropic()


def texto_de(respuesta) -> str:
    return "".join(b.text for b in respuesta.content if b.type == "text")


def preguntar(pregunta: str, max_tokens: int = 1024) -> str:
    respuesta = cliente.messages.create(
        model=MODELO,
        max_tokens=max_tokens,
        messages=[{"role": "user", "content": pregunta}],
    )
    if respuesta.stop_reason == "max_tokens":
        print("Aviso: la respuesta se cortó por max_tokens")
    u = respuesta.usage
    print(f"[{respuesta._request_id}] entrada={u.input_tokens} salida={u.output_tokens}")
    return texto_de(respuesta)


if __name__ == "__main__":
    print(preguntar("¿Qué es un cenote? Responde en tres oraciones para un turista."))

Ejecuta uv run kukulcan.py. Ya tienes la base del asistente.

Práctica

Dedica 25 minutos.

  1. Crea tu clave en el workspace de desarrollo con expiración de 30 días y guárdala en .env. Confirma que .env está en .gitignore.
  2. Crea el proyecto con uv init y uv add anthropic python-dotenv, y ejecuta primera_llamada.py.
  3. Imprime respuesta.to_json() completo y localiza content, stop_reason y usage. Anota si hubo un bloque thinking.
  4. Cambia max_tokens a 50 y vuelve a ejecutar. Observa el stop_reason y cómo queda el texto.
  5. Con kukulcan.py, haz cinco preguntas reales de clientes de una agencia (horarios, precios, qué llevar, transporte, clima en mayo) y anota tokens de entrada, de salida y el costo aproximado de cada una.

Resumen

  • La clave se crea en Settings > API keys, se guarda en .env o en una variable de entorno y nunca entra al código ni a Git.
  • Un proyecto con uv se crea con uv init, se le agregan dependencias con uv add y se ejecuta con uv run.
  • messages.create requiere model, max_tokens y messages; guardamos el modelo en la constante MODELO.
  • content es una lista de bloques: filtra los de tipo text, porque puede haber un bloque thinking antes.
  • stop_reason explica por qué terminó la respuesta, usage dice cuántos tokens se cobraron y _request_id sirve para rastrear la solicitud.

Quiz

1. ¿Dónde debe estar tu clave de API en este proyecto?
2. ¿Por qué no conviene usar respuesta.content[0].text directamente?
3. Tu respuesta llegó con stop_reason igual a "max_tokens". ¿Qué significa?
4. ¿Para qué sirve respuesta._request_id?

Esta lección es gratuita. El curso completo incluye todos los módulos, quizzes, plantillas y un proyecto final con certificado. Ver precios