El modelo mental del SDK de Python de Anthropic
El paquete oficial anthropic de Python es más pequeño de lo que parece desde fuera.
Debajo de cada llamada a método, decorador y gestor de contexto de transmisión se encuentra un único endpoint HTTP: POST /v1/messages.
El trabajo del SDK es hacer que la llamada a ese endpoint sea segura, tipada y ergonómica desde Python, tanto en scripts bloqueantes como en servicios concurrentes.
Una vez que veas el paquete de esta manera, el resto de su superficie, los clientes síncronos frente a asíncronos, la configuración de reintentos y la transmisión, dejarán de parecer una pila de características no relacionadas y comenzarán a parecer un pequeño número de decisiones superpuestas a una única solicitud.
Resumen
- Idea Central: El paquete
anthropices un cliente HTTP tipado para la API de Mensajes, ofrecido como dos clases de cliente paralelas que solo difieren en el modelo de concurrencia. - Por qué Importa: Hablar directamente con la API con
requestsohttpxsignifica reimplementar reintentos, análisis de transmisión y tipado de respuestas por ti mismo; el SDK te proporciona los tres de forma gratuita. - Conceptos Clave: cliente, síncrono vs asíncrono, política de reintentos, tiempo de espera, transmisión, modelo de respuesta.
- Cuándo Usar: Cualquier código Python que llame a Claude, desde un script único hasta un servicio FastAPI de producción que maneje cientos de solicitudes concurrentes.
- Limitaciones / Compensaciones: El SDK no oculta la forma de la API subyacente. Todavía necesitas entender los mensajes, tokens y razones de parada; el SDK simplemente elimina la plomería a su alrededor.
- Temas Relacionados: Forma de solicitud/respuesta de la API de Mensajes, configuración de reintentos y tiempos de espera, eventos de transmisión, modelos de respuesta con sugerencias de tipo.
Fundamentos
Un endpoint, dos puertas
Cada llamada que realizas con el paquete anthropic, ya sea que parezca client.messages.create(...) o client.messages.stream(...), en última instancia envía una solicitud POST al endpoint /v1/messages con un cuerpo JSON que contiene un model, max_tokens y una lista de messages.
El SDK te proporciona dos clases de cliente como puntos de entrada a ese mismo endpoint:
anthropic.Anthropic()es el cliente síncrono. Llamarlo bloquea el hilo actual hasta que llega una respuesta (o el primer fragmento transmitido).anthropic.AsyncAnthropic()es el cliente asíncrono. Llamarlo devuelve una corrutina queawait, para que tu programa pueda hacer otro trabajo mientras la solicitud está en curso.
Ambas clases exponen los mismos métodos, los mismos parámetros y los mismos tipos de respuesta. Elegir una u otra no cambia lo que puedes pedirle a Claude que haga. Cambia cómo se comporta tu programa Python mientras espera la respuesta.
El cliente como un objeto pequeño y reutilizable
Una instancia de cliente no es una solicitud única. Es un punto de entrada configurado que construyes una vez y reutilizas.
import anthropic
client = anthropic.Anthropic() # lee ANTHROPIC_API_KEY del entornoLa construcción es donde configuras cosas que deben aplicarse a cada solicitud realizada a través de ese cliente: la clave API, una base_url personalizada, un timeout predeterminado y max_retries predeterminado. Luego, llamas a client.messages.create(...) o client.messages.stream(...) muchas veces contra el mismo cliente, en lugar de construir uno nuevo por solicitud.
Esto es importante porque los reintentos, la agrupación de conexiones y el comportamiento del tiempo de espera son propiedades del cliente, no de una llamada individual. Un cliente que construyes una vez al inicio de la aplicación y reutilizas es el patrón normal; construir un cliente nuevo dentro de un bucle de manejo de solicitudes activo solo descarta esa reutilización sin ningún beneficio.
Mecánica e Interacciones
Síncrono y asíncrono son el mismo contrato, diferentes tiempos de ejecución
Dado que Anthropic() y AsyncAnthropic() comparten los mismos nombres de método y parámetros, mover código entre ellos es principalmente mecánico: agrega async a la firma de la función, await la llamada y usa async with en lugar de with para el gestor de contexto de transmisión.
# Síncrono
response = client.messages.create(model="claude-sonnet-5", max_tokens=1024, messages=[...])
# Asíncrono
response = await async_client.messages.create(model="claude-sonnet-5", max_tokens=1024, messages=[...])Lo que difiere es lo que sucede en tu programa mientras la solicitud está pendiente. El cliente síncrono detiene el hilo que llama. El cliente asíncrono cede el control al bucle de eventos, por lo que otras corrutinas, otras llamadas API en curso, consultas a bases de datos, solicitudes web entrantes, pueden progresar al mismo tiempo.
Esta es la razón por la que la decisión entre los dos clientes es realmente una decisión sobre el modelo de concurrencia de tu programa, no sobre la API de Claude en sí. Un script que realiza una solicitud y muestra la respuesta no tiene nada que ganar con async. Un servicio web que atiende muchas solicitudes simultáneas, cada una de las cuales necesita llamar a Claude, se beneficia enormemente de ello, porque un único bucle de eventos puede gestionar cientos de llamadas API pendientes sin cientos de hilos del sistema operativo.
Los reintentos se sitúan entre tú y la red
Las redes reales fallan de maneras que no tienen nada que ver con tu prompt: se cae una conexión, la API devuelve un 529 porque está temporalmente sobrecargada, llega un 429 porque excediste brevemente un límite de tasa. La capa de reintentos del SDK existe para absorber exactamente esta clase de fallos sin que tengas que escribir un bucle de reintentos manualmente.
Por defecto, ambos clientes reintentan una solicitud automáticamente un pequeño número de veces, con un retraso de retroceso entre intentos, siempre que el fallo parezca transitorio (errores de red, 408, 409, 429 y respuestas 5xx). Los fallos que no son transitorios, como una solicitud mal formada, una clave API inválida, un modelo que no existe, no se reintentan, porque reintentarlos solo reproduciría el mismo error.
Este comportamiento es configurable por cliente (max_retries=... en la construcción) y por solicitud (with_options(...)), lo que te permite ajustar los reintentos para llamadas sensibles a la latencia y ampliarlos para trabajos en segundo plano. La referencia completa de parámetros se encuentra en una página dedicada (ver Relacionados).
La transmisión convierte una respuesta en muchos eventos
Una llamada no transmitida espera la respuesta completa antes de devolver algo. Para respuestas cortas, esto está bien. Para las largas, una explicación de varios párrafos, una generación de código grande, esperar la respuesta completa antes de mostrar algo al usuario hace que una aplicación parezca lenta incluso cuando el modelo está trabajando a un ritmo normal.
La transmisión cambia la forma de la interacción de "una solicitud, una respuesta" a "una solicitud, muchos eventos incrementales". En lugar de devolver un objeto Message completo, client.messages.stream(...) devuelve un gestor de contexto que expone un iterador, comúnmente consumido a través de su helper text_stream, que produce texto a medida que el modelo lo genera.
No transmisión: solicitud ──────────────────► [ respuesta completa ]
Transmisión: solicitud ─► fragmento ─► fragmento ─► fragmento ─► [ fin ]
Conceptualmente, la transmisión no cambia lo que produce el modelo. Cambia cuándo puedes ver partes de ello. El mismo mensaje final, el mismo uso de tokens, la misma razón de parada siguen estando disponibles al final de la transmisión; simplemente se te ha dado la opción de renderizar la salida a medida que llega en lugar de esperar.
Consideraciones Avanzadas y Aplicaciones
Dónde se encuentran los tres conceptos
La razón por la que síncrono/asíncrono, reintentos y transmisión pertenecen a un solo modelo mental es que interactúan.
Una solicitud reintentada durante la transmisión, por ejemplo, es más sutil que una solicitud no transmitida reintentada: si una conexión se cae a mitad de la transmisión después de que ya se haya mostrado algo de texto a un usuario, simplemente reintentar la solicitud desde cero corre el riesgo de duplicar la salida que el usuario ya vio. El SDK maneja los casos comunes de fallos transitorios aquí, pero debes entender esta interacción antes de construir una función de transmisión de producción, en lugar de descubrirla durante un incidente.
Async y streaming también se componen directamente: el gestor de contexto de transmisión de un cliente AsyncAnthropic es un gestor de contexto asíncrono, iterado con async for, lo que permite que una única aplicación asíncrona transmita respuestas a muchos clientes concurrentes (por ejemplo, muchas conexiones WebSocket abiertas) sin dedicar un hilo a cada una.
| Enfoque | Fortaleza | Debilidad | Mejor Ajuste |
|---|---|---|---|
| Síncrono, no transmitido | Código más simple, más fácil de razonar | Bloquea hasta que llega la respuesta completa | Scripts únicos, trabajos por lotes, notebooks |
| Síncrono, transmitido | Renderiza la salida incrementalmente con un flujo de control simple | Todavía bloquea el hilo entre fragmentos | Herramientas CLI, aplicaciones de escritorio para un solo usuario |
| Asíncrono, no transmitido | Libera el bucle de eventos mientras espera | Añade complejidad async/await | Servicios backend que manejan muchas solicitudes independientes |
| Asíncrono, transmitido | Renderiza incrementalmente y maneja muchos usuarios concurrentes | Más complejo de razonar y depurar | Interfaces de chat, servicios web multiusuario, bucles de agentes |
Elegir un punto de partida
Un valor predeterminado razonable: recurre primero a Anthropic(), porque es lo más simple que funciona, y pasa a AsyncAnthropic() solo una vez que tengas un requisito de concurrencia concreto, típicamente un framework web (como FastAPI) que ya sea asíncrono, o una carga de trabajo que distribuya muchas llamadas simultáneas a Claude. Añade transmisión cuando la respuesta sea lo suficientemente larga, o la interacción sea lo suficientemente interactiva, como para que mostrar una salida parcial mejore mediblemente la experiencia.
Ninguna de estas son puertas de un solo sentido. Dado que la superficie de métodos se comparte entre las dos clases de cliente, el código escrito contra el cliente síncrono se traduce al cliente asíncrono con cambios mecánicos y de bajo riesgo en lugar de una reescritura.
Conceptos Erróneos Comunes
- "AsyncAnthropic() es más rápido." No es más rápido por solicitud; una única llamada asíncrona a Claude tarda la misma cantidad de tiempo que la misma llamada realizada de forma síncrona. Lo que async te da es la capacidad de tener muchas solicitudes en curso a la vez sin un hilo por solicitud.
- "La transmisión te permite obtener una respuesta parcial si cancelas temprano." Cierto en un sentido estricto, pero la transmisión no cambia lo que calcula el modelo; cambia cuándo lo recibes. Cancelar una transmisión temprano todavía significa que pediste (y se te facturaron, hasta ese punto) trabajo que el modelo ya hizo.
- "Los reintentos significan que nunca necesito manejar errores." El SDK reintenta automáticamente los fallos transitorios, pero una solicitud que finalmente falla después de los reintentos todavía genera una excepción. Los reintentos reducen la frecuencia con la que ves errores transitorios; no eliminan el manejo de errores.
- "Siempre debo usar el cliente asíncrono para código de producción." Producción no es sinónimo de asíncrono. Un pipeline de lotes de producción que procesa documentos uno a la vez no tiene concurrencia que explotar, y el cliente síncrono es la opción más simple y igualmente correcta allí.
Preguntas Frecuentes
¿Soportan Anthropic() y AsyncAnthropic() características diferentes?
No.
Ambos clientes exponen los mismos métodos (messages.create, messages.stream, etc.) con los mismos parámetros y devuelven los mismos tipos de respuesta.
La única diferencia es que uno bloquea el hilo que llama y el otro se espera dentro de un bucle de eventos.
¿Puedo usar ambos clientes en la misma aplicación?
Sí, aunque es poco común.
Un caso típico es un servicio web mayormente asíncrono que también tiene un script de inicio o mantenimiento síncrono que usa Anthropic() directamente, fuera del bucle de eventos.
¿Cambia la transmisión el resultado final que obtengo del modelo?
No.
El mismo texto, uso de tokens y razón de parada se producen independientemente de si transmites o no; la transmisión solo cambia si ves la salida incrementalmente o toda a la vez al final.
¿Qué se considera un fallo "transitorio" que se reintenta automáticamente?
Errores de conexión a nivel de red y respuestas HTTP en los rangos 408, 409, 429 y 5xx.
Estos representan problemas en la red o en el lado del servidor que probablemente tendrán éxito si simplemente lo intentas de nuevo.
¿Reintentará el SDK una solicitud que falla debido a un prompt incorrecto o parámetros inválidos?
No.
Los errores del cliente como un nombre de modelo inválido o una solicitud mal formada devuelven un error 4xx (excluyendo 408/409/429) y no se reintentan, porque reintentar una solicitud mal formada sin cambios solo volvería a fallar.
¿Es el objeto cliente seguro para hilos y reutilizable entre solicitudes?
Sí, una única instancia de cliente está diseñada para ser construida una vez y reutilizada para muchas solicitudes, lo que también permite que la agrupación de conexiones y el comportamiento configurado de reintentos/tiempos de espera surtan efecto.
¿Por qué elegiría el cliente síncrono para una aplicación web?
Si tu framework web es en sí mismo síncrono (vistas clásicas de Flask o Django WSGI sin soporte async), el cliente síncrono es la opción natural. Conectar un cliente asíncrono a un framework síncrono añade complejidad sin un beneficio de concurrencia.
¿Requiere la transmisión el cliente asíncrono?
No.
Ambos clientes soportan la transmisión; Anthropic().messages.stream(...) y AsyncAnthropic().messages.stream(...) existen, iterados con for y async for respectivamente.
¿Qué sucede con el uso de tokens y la facturación cuando transmito?
No se ve afectado por la transmisión.
Se te factura por los tokens que el modelo genera realmente, ya sea que los recibas como una respuesta final o como muchos fragmentos incrementales.
Si cancelo una transmisión a mitad de camino, ¿eso detiene al modelo de generar más tokens?
Detiene a tu cliente de recibir más fragmentos, pero si la generación subyacente se detiene inmediatamente depende de cómo canceles (cerrando el contexto de transmisión vs. dejando que la conexión continúe). Considera la cancelación a mitad de transmisión como un mejor esfuerzo, no como una parada dura instantánea.
¿Necesito analizar JSON crudo de la respuesta de transmisión yo mismo?
No.
El SDK analiza los eventos enviados por el servidor subyacentes por ti y expone accesores tipados como text_stream, así como el mensaje final completamente ensamblado una vez que la transmisión se completa.
¿Es un cliente "más oficial" o más listo para producción que el otro?
No, ambos son partes totalmente soportadas y GA del mismo paquete.
Ninguno es una versión beta o de respaldo del otro; son dos interfaces a la misma API subyacente.
Relacionados
- Conceptos básicos del SDK de Python - instala el SDK, construye un cliente y envía tu primera solicitud.
- Elegir entre Anthropic() y AsyncAnthropic() en código de producción - una comparación más profunda y centrada en decisiones para servicios FastAPI y scripts.
- Transmisión de respuestas con el SDK de Python - código de trabajo para
client.messages.stream()ytext_stream. - Referencia de configuración de reintentos y tiempos de espera del SDK de Python - la referencia completa de
max_retries,timeoutywith_options().
Versiones de la pila: Escrito contra la línea de modelos de Claude actual a partir de ~junio de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (el predeterminado), y Claude Haiku 4.5 - y el SDK oficial de Python de
anthropic(última versión 0.x). Los nombres de modelos, versiones del SDK y precios cambian rápidamente; verifica los detalles actuales en platform.claude.com/docs antes de confiar en ellos.