Hemos actualizado la interfaz compatible con OpenAI con optimizaciones más profundas específicamente para los modelos de la serie Claude. Ahora puedes controlar el pensamiento y el almacenamiento en caché de manera más precisa y conveniente. El pensamiento entrelazado en conversaciones de múltiples turnos es ahora más fácil de usar, permitiendo una integración fluida sin parámetros adicionales. También admite la habilitación de las funciones beta ofrecidas por Anthropic.
1. Pensamiento del Modelo (Pensamiento Ampliado)
1.1 Ventajas del Pensamiento Entrelazado
Cuando el pensamiento entrelazado no está habilitado, el modelo realiza el pensamiento solo una vez al comienzo de un turno del asistente; las respuestas subsiguientes se generan directamente después de recibir los resultados de la herramienta, sin producir nuevos bloques de pensamiento:
Usuario → [Pensando] → Llamada a la Herramienta → Resultado de la Herramienta → Respuesta
Cuando el pensamiento entrelazado está habilitado, el modelo inserta un nuevo bloque de pensamiento cada vez que recibe un resultado de la herramienta, formando una cadena de razonamiento:
Usuario → [Pensando] → Llamada a la Herramienta → Resultado de la Herramienta → [Pensando] → Respuesta
↑ Pensamiento Entrelazado
Esto permite que el modelo:
- Realice razonamientos secundarios basados en los resultados de la herramienta, en lugar de simplemente concatenar salidas.
- Encadene razonamientos entre múltiples llamadas a herramientas, donde cada decisión se basa en el análisis del paso anterior.
Referencia: Pensamiento Entrelazado de Anthropic
1.2 Habilitando el Pensamiento
Puedes habilitar el pensamiento de cuatro maneras, eligiendo cualquiera de ellas:
| Método | Ejemplo | Descripción |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
Parámetro estándar de OpenAI, colocado en el nivel superior del cuerpo de la solicitud |
reasoning.effort |
"reasoning": {"effort": "low"} |
Equivalente al método anterior, colocado dentro del objeto de razonamiento |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Controla de manera precisa el número máximo de tokens para el pensamiento |
Nombre del modelo con -think |
"model": "claude-sonnet-4-5-think" |
La forma más sencilla, no requiere parámetros adicionales |
Prioridad (cuando se utilizan múltiples métodos):reasoning_effort>reasoning.max_tokens>reasoning.effort>-thinksufijo
Valores posibles para el esfuerzo: minimal / low / medium / high / xhigh
1.3 Retorno del Pensamiento
El mensaje de respuesta incluirá dos nuevos campos:
reasoning_content: Contenido del pensamiento (cadena), para una fácil visualización.reasoning_details: Información estructurada completa sobre el pensamiento, que debe ser devuelta tal cual en conversaciones de múltiples turnos; la estructura interna puede diferir entre proveedores.
Ejemplo no en streaming (omitindo campos no relacionados):
{
"choices": [{
"message": {
"role": "assistant",
"content": "¡Hola! ¿Cómo puedo ayudarte hoy?",
"reasoning_content": "El usuario solo está diciendo hola...",
"reasoning_details": {
"type": "thinking",
"thinking": "El usuario solo está diciendo hola...",
"signature": "Er8CCkYI..."
}
}
}]
}
En respuestas en streaming, el contenido del pensamiento se enviará en fragmentos a través de delta.reasoning_content y delta.reasoning_details. Para la lógica completa de concatenación en streaming, consulta el ejemplo completo a continuación.
1.4 Retener el Pensamiento en Conversaciones de Múltiples Turnos (El Pensamiento Entrelazado está integrado, no se necesitan parámetros adicionales)
Para permitir que el modelo continúe con sus capacidades de razonamiento en conversaciones de múltiples turnos, simplemente coloca el reasoning_details devuelto anteriormente tal cual en el mensaje del asistente de la siguiente ronda:
messages = [
{"role": "user", "content": "¿Cómo está el clima en Boston?"},
{
"role": "assistant",
"content": response.choices[0].message.content,
"tool_calls": response.choices[0].message.tool_calls,
"reasoning_details": response.choices[0].message.reasoning_details,
},
{
"role": "tool",
"tool_call_id": "toolu_xxx",
"content": '{"temperature": 45, "condition": "rainy"}',
}
]
AIHubMix habilitará automáticamente el pensamiento entrelazado cuando detecte información histórica de pensamiento en la solicitud, permitiendo que el modelo continúe razonando profundamente después de recibir los resultados de la llamada a la herramienta sin requerir parámetros adicionales.
1.5 Ejemplo Completo
Los siguientes dos ejemplos demuestran el proceso completo de llamada a la herramienta de múltiples turnos + pensamiento entrelazado: consulta del usuario → el modelo piensa y llama a una herramienta → inyectar resultados de la herramienta (preservando reasoning_details) → el modelo pensamiento entrelazado da la respuesta final.
No en streaming · Pensamiento Entrelazado
import os
import json
from openai import OpenAI
client = OpenAI(
base_url="https://aihubmix.com/v1",
api_key=os.environ.get("AIHUBMIX_API_KEY", "sk-***"),
)
# ── Definición de la herramienta ───────────────────────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtener el clima actual para una ubicación",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "Nombre de la ciudad"}},
"required": ["location"]
}
}
}]
# ── Ejecución simulada de la herramienta ─────────────────────────────────────
WEATHER_DB = {
"boston": {"temperature": "45°F (7°C)", "condition": "rainy", "humidity": "85%", "wind": "15 mph NE"},
"tokyo": {"temperature": "72°F (22°C)", "condition": "sunny", "humidity": "45%", "wind": "5 mph S"},
}
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
key = next((k for k in WEATHER_DB if k in args.get("location", "").lower()), None)
return json.dumps(WEATHER_DB.get(key, {"temperature": "65°F", "condition": "clear"}))
return "{}"
# ── Bucle de conversación de múltiples turnos ─────────────────────────────
messages = [
{"role": "user", "content": "¿Cómo está el clima en Boston? Luego recomienda qué usar."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turno {turn} ──")
response = client.chat.completions.create(
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
msg = response.choices[0].message
# Imprimir proceso de pensamiento
if msg.reasoning_content:
label = "Pensamiento Entrelazado" if turn > 1 else "Pensando"
print(f"[{label}] {msg.reasoning_content}")
# Imprimir contenido de respuesta
if msg.content:
print(f"[Respuesta] {msg.content}")
# Imprimir llamadas a herramientas
if msg.tool_calls:
for tc in msg.tool_calls:
print(f"[Llamada a la Herramienta: {tc.function.name}] {tc.function.arguments}")
# Construir mensaje del asistente, preservar reasoning_details (¡crítico!)
assistant_msg = {"role": "assistant", "content": msg.content}
if msg.tool_calls:
assistant_msg["tool_calls"] = msg.tool_calls
if msg.reasoning_details:
assistant_msg["reasoning_details"] = msg.reasoning_details # pasar de vuelta sin modificar
messages.append(assistant_msg)
# Sin tool_calls significa que la conversación ha terminado
if not msg.tool_calls:
break
# Ejecutar herramientas y agregar resultados a los mensajes
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = execute_tool(tc.function.name, args)
print(f"[Resultado de la Herramienta: {tc.function.name}] {result}")
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
Streaming · Pensamiento Entrelazado
import os
import sys
import json
from openai import OpenAI
client = OpenAI(
base_url="https://aihubmix.com/v1",
api_key=os.environ.get("AIHUBMIX_API_KEY", "sk-***"),
)
# ── Definición de la herramienta y ejecución simulada ─────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtener el clima actual para una ubicación",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "Nombre de la ciudad"}},
"required": ["location"]
}
}
}]
WEATHER_DB = {
"boston": {"temperature": "45°F (7°C)", "condition": "rainy", "humidity": "85%", "wind": "15 mph NE"},
"tokyo": {"temperature": "72°F (22°C)", "condition": "sunny", "humidity": "45%", "wind": "5 mph S"},
}
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
key = next((k for k in WEATHER_DB if k in args.get("location", "").lower()), None)
return json.dumps(WEATHER_DB.get(key, {"temperature": "65°F", "condition": "clear"}))
return "{}"
# ── Recolector de respuestas en streaming ────────────────────────────────
def stream_and_collect(turn: int, **kwargs):
"""Transmitir respuesta, imprimir pensamiento/contenido en tiempo real, acumular reasoning_details/tool_calls."""
rd = {} # reasoning_details acumulados
content = "" # texto de respuesta acumulado
tc_map = {} # llamadas a herramientas acumuladas (por índice)
cur = "none" # sección de salida actual: none / thinking / content
stream = client.chat.completions.create(stream=True, **kwargs)
for chunk in stream:
if not chunk.choices:
continue
delta = chunk.choices[0].delta
# ── Manejar pensamiento ──
rd_delta = getattr(delta, "reasoning_details", None)
if rd_delta and isinstance(rd_delta, dict):
for k, v in rd_delta.items():
if k == "type":
rd[k] = v
elif isinstance(v, str):
rd[k] = rd.get(k, "") + v
elif v is not None:
rd[k] = v
# Imprimir fragmentos de pensamiento en tiempo real
thinking_chunk = rd_delta.get("thinking", "")
if thinking_chunk:
if cur != "thinking":
cur = "thinking"
label = "Pensamiento Entrelazado" if turn > 1 else "Pensando"
sys.stdout.write(f"\n[{label}] ")
sys.stdout.write(thinking_chunk)
sys.stdout.flush()
# ── Manejar contenido ──
if delta.content:
if cur != "content":
if cur == "thinking":
sys.stdout.write("\n")
cur = "content"
sys.stdout.write("\n[Respuesta] ")
sys.stdout.write(delta.content)
sys.stdout.flush()
content += delta.content
# ── Manejar tool_calls ──
for tc in delta.tool_calls or []:
i = tc.index
if i not in tc_map:
tc_map[i] = {"id": "", "type": "function",
"function": {"name": "", "arguments": ""}}
if tc.id:
tc_map[i]["id"] = tc.id
if tc.function:
tc_map[i]["function"]["name"] += tc.function.name or ""
tc_map[i]["function"]["arguments"] += tc.function.arguments or ""
# Finalizar la sección de salida actual
if cur in ("thinking", "content"):
sys.stdout.write("\n")
tool_calls = [tc_map[i] for i in sorted(tc_map)] if tc_map else None
return {
"content": content or None,
"reasoning_details": rd or None,
"tool_calls": tool_calls,
}
# ── Bucle de conversación de múltiples turnos ─────────────────────────────
messages = [
{"role": "user", "content": "¿Cómo está el clima en Boston? Luego recomienda qué usar."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turno {turn} ──")
result = stream_and_collect(
turn,
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
# Imprimir llamadas a herramientas
if result["tool_calls"]:
for tc in result["tool_calls"]:
print(f"[Llamada a la Herramienta: {tc['function']['name']}] {tc['function']['arguments']}")
# Construir mensaje del asistente, preservar reasoning_details (¡crítico!)
assistant_msg = {"role": "assistant", "content": result["content"]}
if result["tool_calls"]:
assistant_msg["tool_calls"] = result["tool_calls"]
if result["reasoning_details"]:
assistant_msg["reasoning_details"] = result["reasoning_details"] # pasar de vuelta sin modificar
messages.append(assistant_msg)
# Sin tool_calls significa que la conversación ha terminado
if not result["tool_calls"]:
break
# Ejecutar herramientas y agregar resultados a los mensajes
for tc in result["tool_calls"]:
args = json.loads(tc["function"]["arguments"])
tool_result = execute_tool(tc["function"]["name"], args)
print(f"[Resultado de la Herramienta: {tc['function']['name']}] {tool_result}")
messages.append({"role": "tool", "tool_call_id": tc["id"], "content": tool_result})
1.6 Reglas de Mapeo de Intensidad de Pensamiento
Modo de Esfuerzo:
- Opus 4.6 / Sonnet 4.6 y superiores: se mapea al nivel de esfuerzo nativo de Pensamiento Adaptativo de Anthropic.
- Otros modelos: calculado utilizando la fórmula para
budget_tokens:
budget_tokens = max(min(max_tokens × effort_ratio, 128000), 1024)
| esfuerzo | esfuerzo_ratio |
|---|---|
| xhigh | 0.95 |
| high | 0.80 |
| medium | 0.50 |
| low | 0.20 |
| minimal | 0.10 |
Mapeo de Esfuerzo de Pensamiento Adaptativo:
| Esfuerzo Entrante | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | máx | alto |
| high | alto | alto |
| medium | medio | medio |
| low | bajo | bajo |
| minimal | bajo | bajo |
Modo max_tokens: Asignado directamente como budget_tokens de Anthropic.
-think sufijo: Opus/Sonnet 4.6+ utiliza pensamiento adaptativo (esfuerzo=medio); otros modelos establecen budget_tokens = min(10240, max_tokens - 1), con un max_tokens predeterminado de 4096.
2. Almacenamiento en Caché de Prompts
Puedes utilizar el Almacenamiento en Caché de Prompts al realizar solicitudes al modelo Claude a través de la interfaz de Chat. Al establecer puntos de control cache_control en los mensajes, se pueden almacenar en caché grandes bloques de texto (como tarjetas de rol, datos RAG, capítulos de libros, etc.) para su reutilización, permitiendo que solicitudes posteriores accedan directamente a la caché y reduzcan significativamente los costos.
Documentación Oficial de Claude: Almacenamiento en Caché de Prompts
2.1 Costos de Almacenamiento en Caché
| Operación | Multiplicador de Precio (relativo al precio de entrada original) |
|---|---|
| Escritura en Caché (TTL de 5 minutos) | 1.25x |
| Escritura en Caché (TTL de 1 hora) | 2x |
| Lectura en Caché | 0.1x |
2.2 Modelos Soportados y Longitud Mínima de Caché
| Modelo | Conteo Mínimo de Tokens en Caché |
|---|---|
| Claude Opus 4.8 | 1024 |
| Claude Opus 4.7 | 2048 |
| Claude Opus 4.6 / Opus 4.5 | 4096 |
| Claude Sonnet 4.6 / Sonnet 4.5 / Opus 4.1 / Opus 4 / Sonnet 4 / Sonnet 3.7 (obsoleto) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5 (obsoleto) / Haiku 3 | 2048 |
Límite de Cantidad de Puntos de Control: Un máximo de 4 puntos de control cache_control por solicitud.2.3 TTL de Caché
| TTL | Sintaxis | Escenarios Aplicables |
|---|---|---|
| 5 minutos (predeterminado) | "cache_control": {"type": "ephemeral"} |
Sesiones cortas, solicitudes rutinarias |
| 1 hora | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
Sesiones largas, para evitar escrituras repetidas en caché |
Los costos de escritura para TTL de 1 hora son más altos, pero pueden ahorrar gastos totales al reducir escrituras repetidas en sesiones largas. Todos los modelos de Claude 4.5 y posteriores de todos los proveedores (incluyendo Anthropic, Amazon Bedrock, Google Vertex AI) admiten TTL de 1 hora.
2.4 Uso
Puedes establecer puntos de control de caché utilizando el campo cache_control en system, user (incluyendo imágenes), y tools. Los siguientes ejemplos solo muestran la estructura clave, omitiendo grandes bloques de texto.
Almacenamiento en Caché del Mensaje del Sistema (TTL predeterminado de 5 minutos):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "Eres un asistente de IA"},
{
"type": "text",
"text": "(contexto largo)",
"cache_control": {"type": "ephemeral"}
}
]
},
{
"role": "user",
"content": [{"type": "text", "text": "Hola"}]
}
]
}
Almacenamiento en Caché del Mensaje del Usuario (TTL de 1 hora):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [{"type": "text", "text": "Eres un asistente de IA"}]
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "(contexto largo)",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
},
{"type": "text", "text": "Hola"}
]
}
]
}
Almacenamiento en Caché del Mensaje de Imagen:
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"detail": "auto", "url": "data:image/jpeg;base64,/9j/4AAQ..."},
"cache_control": {"type": "ephemeral"}
},
{"type": "text", "text": "¿Qué es esto?"}
]
}
Almacenamiento en Caché de la Definición de la Herramienta:
cache_control se coloca en el nivel superior del objeto de la herramienta (junto a type y function):
{
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtener el clima actual para una ubicación",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
},
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}]
}
2.5 Visualización del Estado de la Caché
El usage de la respuesta devolverá claude_cache_tokens_details, registrando información detallada de la caché:
Primera Solicitud (Creando Caché):
{
"usage": {
"prompt_tokens": 22,
"completion_tokens": 890,
"total_tokens": 912,
"claude_cache_tokens_details": {
"cache_creation_input_tokens": 6266,
"cache_read_input_tokens": 0,
"cache_write_5_minutes_input_tokens": 6266,
"cache_write_1_hour_input_tokens": 0
}
}
}
Solicitudes Subsiguientes (Cache Hit):
{
"usage": {
"prompt_tokens": 22,
"completion_tokens": 810,
"total_tokens": 832,
"prompt_tokens_details": {
"cached_tokens": 6266
},
"claude_cache_tokens_details": {
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 6266,
"cache_write_5_minutes_input_tokens": 0,
"cache_write_1_hour_input_tokens": 0
}
}
}
| Campo | Significado |
|---|---|
cache_creation_input_tokens |
Número de tokens escritos en caché en esta solicitud |
cache_read_input_tokens |
Número de tokens leídos de la caché en esta solicitud |
cache_write_5_minutes_input_tokens |
Número de tokens escritos en la caché de TTL de 5 minutos |
cache_write_1_hour_input_tokens |
Número de tokens escritos en la caché de TTL de 1 hora |
prompt_tokens_details.cached_tokens |
Número de tokens en caché cuando se accede a la caché, compatible con el formato de OpenAI |
3. Encabezado de Solicitud para anthropic-beta
Puedes habilitar funciones beta del modelo Claude a través del Encabezado HTTP anthropic-beta, que AIHubMix pasará a la API de Anthropic.
Uso
Agrega anthropic-beta al encabezado de la solicitud, con el valor siendo el identificador de la función beta correspondiente:
curl "https://aihubmix.com/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AIHUBMIX_API_KEY" \
-H "anthropic-beta: context-1m-2025-08-07" \
-d '{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "Eres un asistente de IA"},
{
"type": "text",
"text": "(contexto largo)",
"cache_control": {"type": "ephemeral"}
}
]
},
{"role": "user", "content": [{"type": "text", "text": "hola"}]}
]
}'
Para identificadores beta específicos disponibles, consulta la Documentación de la API de Anthropic.
Última actualización: 2026-06-01