Buenas prácticas de la API de Mensajes
Un conjunto recopilado de prácticas para estructurar roles, turnos, bloques de contenido y prompts del sistema de forma fiable al trabajar con la API de Mensajes.
Trata esto como una referencia activa para verificar tu código, no como una lectura única.
Cómo usar esta lista
- Lee primero los encabezados de las categorías, luego profundiza en la sección relevante para lo que estás construyendo.
- Cada regla expone la práctica de forma positiva: haz esto, junto con por qué es importante.
- Vuelve a consultar esta lista siempre que estés depurando un error 400, una respuesta inconsistente o costes de tokens inesperados: la mayoría de los problemas se remontan a uno de estos puntos.
A - Roles y Turnos
- Siempre empieza el array de mensajes con un rol de "user". La API rechaza cualquier array que comience con
assistant, así que construye las conversaciones a partir de la primera entrada del usuario. - Mantén los roles estrictamente alternados. Nunca envíes dos turnos consecutivos de
useroassistant; combina varias piezas de entrada del usuario en el contenido de un solo turno en lugar de dividirlas en entradas de array separadas. - Añade el
response.contentcompleto, no solo el texto extraído, como el siguiente turno del asistente. Esto preserva los bloquestool_usey cualquier otro contenido estructurado necesario para que la conversación continúe correctamente. - Trata la API como completamente sin estado. Nunca asumas que Claude recuerda una llamada anterior; reenvía el historial relevante completo en cada solicitud.
- Limita una lista de mensajes por conversación. Nunca compartas una única lista mutable entre usuarios o sesiones concurrentes; los turnos intercalados de diferentes conversaciones romperán la alternancia.
B - Prompts del Sistema
- Mantén el prompt del sistema como una cadena separada y estable. No integres instrucciones permanentes en un turno de
user;systemes el lugar correcto para la persona, el alcance y las restricciones que se aplican a toda la conversación. - Estructura los prompts del sistema largos en secciones claras. La persona, el alcance, las restricciones y el formato de salida como secciones distintas son más fáciles de auditar y actualizar que un solo párrafo indiferenciado.
- Evita interpolar valores dinámicos en el prompt del sistema. Las marcas de tiempo, los IDs de solicitud o los IDs de usuario incrustados en
systemhacen que sea una cadena diferente en cada solicitud, rompiendo silenciosamente el caché del prompt. - Reenvía el mismo prompt del sistema en cada solicitud de una conversación. A diferencia de
messages,systemno es acumulativo; pasa el valor idéntico cada vez que desees un comportamiento consistente. - Usa mensajes del sistema a mitad de conversación para actualizaciones, donde sea compatible. En modelos que lo admiten, añadir un mensaje
role: "system"preserva mejor tu prefijo en caché que reescribir el camposystemde nivel superior a mitad de conversación.
C - Bloques de Contenido
- Haz coincidir el tipo de bloque de contenido con el tipo de contenido. Usa
textpara prosa,imagepara entrada visual,tool_usepara una llamada a herramienta iniciada por el modelo ytool_resultpara la respuesta a una de ellas; no fuerces todo a cadenas de texto plano. - Siempre analiza la entrada
tool_usecomo datos estructurados. Leeblock.inputcomo el objeto analizado que es; nunca compares con una cadena el JSON serializado, ya que el escape exacto puede variar. - Devuelve todos los
tool_resultjuntos en un solo turno de usuario cuando un turno de asistente solicitó múltiples herramientas. Dividirlos en turnos separados rompe la correspondencia esperada y puede suprimir futuras llamadas paralelas a herramientas. - Empareja cada
tool_usecon sutool_resultportool_use_id. Nunca omitas un resultado para una llamada a herramienta pendiente, incluso una fallida; usais_error: trueen lugar de omitirlo. - Comprueba el tipo de un bloque de contenido antes de acceder a los campos específicos del tipo. No asumas que cada bloque en una respuesta es
text; ramifica primero segúnblock.type, ya que los turnos deassistantpueden incluirtool_usejunto con o en lugar de texto.
D - Estado y Contexto de la Conversación
- Mide el uso de tokens con
count_tokens(), no con estimaciones de recuento de caracteres. Los recuentos de tokens no se mapean linealmente a la longitud de la cadena, especialmente para código o texto no inglés. - Recorta o resume de forma proactiva, antes de alcanzar un fallo de ventana de contexto. Comprueba el uso frente a un umbral de seguridad por debajo del límite real en lugar de reaccionar a un error en producción.
- Recorta en pares coincidentes. Si omites un turno de asistente que contiene
tool_use, omite también el turno del usuario correspondiente detool_result; nunca dejes huérfana la mitad de un par. - Usa un modelo más barato y rápido para los pasos de resumen. Resumir turnos antiguos no necesita la capacidad completa de tu modelo principal; Claude Haiku 4.5 suele ser suficiente y reduce el coste.
- Verifica que un array recortado o resumido todavía comience con "user" y alterne correctamente. Cortar un array puede dejarlo comenzando con
assistanto con turnos adyacentes del mismo rol; arréglalo antes de enviarlo.
E - Errores y Fiabilidad
- Captura las excepciones tipadas del SDK, de la más específica a la menos específica. Distingue
RateLimitError,NotFoundErroryAuthenticationErrorde la más generalAPIStatusErroren lugar de capturar una única clase de excepción genérica. - Siempre comprueba
stop_reasonantes de confiar en que una respuesta está completa. Unstop_reasondemax_tokenssignifica que la respuesta se cortó, no que terminó de forma natural. - Confía en el comportamiento de reintento integrado del SDK para errores 429 y 5xx. No implementes lógica de reintento manual para fallos transitorios que el cliente ya reintenta con retroceso por defecto.
- Transmite las solicitudes con un
max_tokensgrande. Las solicitudes no streaming con un alto límite de tokens corren el riesgo de alcanzar tiempos de espera HTTP del lado del cliente; la transmisión evita ese modo de fallo. - Establece
max_tokensdeliberadamente, no como una ocurrencia tardía. Demasiado bajo trunca la salida a mitad de pensamiento y fuerza un reintento; ajústalo a la tarea, con margen para pensar o llamar a herramientas cuando sea relevante.
Preguntas frecuentes
¿Cuál es la causa más común de un error 400 en la API de Mensajes?
Alternancia de roles rota: o bien el array no empieza con user, o aparecen dos turnos del mismo rol uno detrás de otro. Comprueba la estructura antes de comprobar el contenido.
¿Por qué es importante reenviar el prompt del sistema en cada solicitud?
Porque system no es acumulativo como messages; cada solicitud se evalúa de forma independiente, por lo que omitirlo o cambiarlo rompe silenciosamente el comportamiento y puede invalidar una caché de prompt construida sobre el texto anterior.
¿Debo omitir alguna vez la adición de un `tool_result` para un bloque `tool_use`?
No, cada bloque tool_use necesita un tool_result correspondiente, incluso si la llamada a la herramienta falló. Usa is_error: true para una llamada fallida en lugar de omitir el resultado por completo.
¿Es seguro estimar el uso de tokens a partir de la longitud de la cadena en lugar de llamar a count_tokens?
No, los recuentos de tokens no se mapean linealmente a los recuentos de caracteres o palabras, especialmente para código o texto no inglés, por lo que las estimaciones pueden ser significativamente erróneas en cualquier dirección.
¿Por qué usar un modelo más barato para resumir giros de conversación antiguos?
Porque la summarización es una tarea comparativamente simple que no necesita la capacidad de razonamiento completa de tu modelo principal; un modelo más rápido y barato reduce el coste de recortar sin una pérdida de calidad significativa.
¿Qué debo comprobar antes de confiar en que una respuesta está completa?
El campo stop_reason; si es max_tokens en lugar de end_turn, la respuesta se cortó y puede faltar contenido que esperas que esté ahí.
¿Cuándo debo cambiar a la transmisión en lugar de una solicitud normal?
Siempre que max_tokens se establezca lo suficientemente alto como para que una solicitud no streaming corra el riesgo de un tiempo de espera HTTP del lado del cliente; la transmisión evita completamente ese modo de fallo.
¿Por qué mezclar la coincidencia de cadenas y el análisis de entrada de `tool_use` causa errores?
Porque la serialización JSON exacta de la entrada de la herramienta puede variar en el escape entre solicitudes o modelos; siempre analiza block.input como datos estructurados en lugar de buscar patrones en el texto sin procesar.
¿Está bien compartir una lista de mensajes entre las conversaciones de varios usuarios?
No, una lista compartida y mutable utilizada por conversaciones concurrentes intercalará turnos de diferentes usuarios y romperá la alternancia de roles requerida para todos ellos.
¿Cuál es el riesgo de interpolar una marca de tiempo en el prompt del sistema?
Convierte el prompt del sistema en una cadena diferente en cada solicitud, lo que rompe silenciosamente el caché del prompt, ya que el caché depende de un prefijo estable y sin cambios.
¿Necesito implementar manualmente la lógica de reintento para los límites de tasa?
Generalmente no; el SDK oficial reintenta las respuestas 429 y 5xx automáticamente con retroceso por defecto, por lo que la lógica de reintento manual suele ser innecesaria a menos que necesites un comportamiento personalizado.
Relacionado
- Comprender los roles y turnos en la API de Mensajes - la base conceptual detrás de las prácticas de roles y turnos aquí.
- Construir conversaciones multi-turno con el array de mensajes - la mecánica detallada detrás de las prácticas de estado de la conversación.
- Gestionar el historial de conversaciones y el recorte para la ventana de contexto - las estrategias completas de recorte y resumen a las que se hace referencia en la categoría D.
- Manejar bloques de contenido mixto: texto, imagen y resultados de herramientas en un solo turno - ejemplos prácticos detrás de las prácticas de bloques de contenido en la categoría C.
Versiones de la pila: Escrito contra la línea de modelos 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
anthropic(última versión 0.x). Los nombres de los modelos, las versiones del SDK y los precios cambian rápidamente; verifica los detalles actuales en platform.claude.com/docs antes de confiar en ellos.