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.createusando una constanteMODELO; - recorrer los bloques de
contenty leerusage,stop_reasony 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:
- La clave nunca va dentro de un archivo
.py. - La clave nunca se sube a Git, ni a un chat, ni a una captura de pantalla.
- 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 constanteMODELOal inicio de cada script de este curso para cambiarlo en un solo lugar. Usamosclaude-opus-5-5porque 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 unrole("user"o"assistant") y uncontent. 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 faltamax_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.
- Crea tu clave en el workspace de desarrollo con expiración de 30 días y guárdala en
.env. Confirma que.envestá en.gitignore. - Crea el proyecto con
uv inityuv add anthropic python-dotenv, y ejecutaprimera_llamada.py. - Imprime
respuesta.to_json()completo y localizacontent,stop_reasonyusage. Anota si hubo un bloquethinking. - Cambia
max_tokensa 50 y vuelve a ejecutar. Observa elstop_reasony cómo queda el texto. - 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
.envo 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 conuv addy se ejecuta conuv run. messages.createrequieremodel,max_tokensymessages; guardamos el modelo en la constanteMODELO.contentes una lista de bloques: filtra los de tipotext, porque puede haber un bloquethinkingantes.stop_reasonexplica por qué terminó la respuesta,usagedice cuántos tokens se cobraron y_request_idsirve para rastrear la solicitud.