Hemos actualizado la interfaz compatible con OpenAI con optimizaciones más profundas específicamente para los modelos de la serie Claude. Ahora puede controlar el pensamiento y la caché de forma más precisa y cómoda. El pensamiento intercalado en conversaciones de varios turnos es ahora más fácil de usar, lo que permite una integración fluida sin parámetros adicionales. También admite la activación de las funciones beta ofrecidas por Anthropic.
1. Pensamiento del modelo (Extended Thinking)
1.1 Ventajas del pensamiento intercalado
Cuando el pensamiento intercalado no está activado, el modelo realiza el pensamiento solo una vez al principio de un turno del asistente; las respuestas posteriores se generan directamente después de recibir los resultados de las herramientas, sin producir nuevos bloques de pensamiento:
User → [Thinking] → Tool Call → Tool Result → Response
Cuando el pensamiento intercalado está activado, el modelo inserta un nuevo bloque de pensamiento cada vez que recibe un resultado de herramienta, formando una cadena de razonamiento:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Interleaved Thinking
Esto permite que el modelo:
- realice un razonamiento secundario basado en los resultados de las herramientas, en lugar de simplemente concatenar las salidas.
- encadene el razonamiento entre varias llamadas a herramientas, donde cada decisión se basa en el análisis del paso anterior.
Referencia: Pensamiento intercalado de Anthropic
1.2 Activar el pensamiento
Puede activar el pensamiento de cuatro formas, 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 reasoning |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Controla con precisión 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 usan varios métodos):reasoning_effort>reasoning.max_tokens>reasoning.effort> sufijo-think
Valores posibles para effort: minimal / low / medium / high / xhigh
1.3 Retorno del pensamiento
El mensaje de respuesta incluirá dos campos nuevos:
reasoning_content: contenido del pensamiento (cadena), para mostrarlo fácilmente.reasoning_details: información estructurada completa sobre el pensamiento, que debe devolverse tal cual en conversaciones de varios turnos; la estructura interna puede diferir entre proveedores.
Ejemplo de respuesta no streaming (omitiendo campos no relacionados):
{
"choices": [{
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?",
"reasoning_content": "The user is just saying hello...",
"reasoning_details": {
"type": "thinking",
"thinking": "The user is just saying hello...",
"signature": "Er8CCkYI..."
}
}
}]
}
En las respuestas en streaming, el contenido del pensamiento se envía por fragmentos mediante delta.reasoning_content y delta.reasoning_details. Para la lógica completa de concatenación en streaming, consulte el ejemplo completo a continuación.
1.4 Conservar el pensamiento en conversaciones de varios turnos (El pensamiento intercalado está integrado, no se necesitan parámetros adicionales)
Para que el modelo pueda seguir usando sus capacidades de razonamiento en conversaciones de varios turnos, basta con colocar los reasoning_details devueltos previamente tal cual en el mensaje del asistente de la siguiente ronda:
messages = [
{"role": "user", "content": "What's the weather like in 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 activará automáticamente el pensamiento intercalado cuando detecte información de pensamiento histórica en la solicitud, permitiendo que el modelo continúe con el razonamiento profundo tras recibir los resultados de las llamadas a herramientas, sin necesidad de parámetros adicionales.
1.5 Ejemplo completo
Los dos ejemplos siguientes muestran el proceso completo de llamadas a herramientas + pensamiento intercalado en varios turnos: consulta del usuario → el modelo piensa y llama a una herramienta → se inyectan los resultados de la herramienta (conservando reasoning_details) → el modelo, con pensamiento intercalado, da la respuesta final.
Sin streaming · Pensamiento intercalado
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-***"),
)
# ── Tool definition ───────────────────────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "City name"}},
"required": ["location"]
}
}
}]
# ── Mock tool execution ───────────────────────────────────────
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 "{}"
# ── Multi-turn conversation loop ─────────────────────────────
messages = [
{"role": "user", "content": "What's the weather like in Boston? Then recommend what to wear."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turn {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
# Print thinking process
if msg.reasoning_content:
label = "Interleaved Thinking" if turn > 1 else "Thinking"
print(f"[{label}] {msg.reasoning_content}")
# Print response content
if msg.content:
print(f"[Response] {msg.content}")
# Print tool calls
if msg.tool_calls:
for tc in msg.tool_calls:
print(f"[Tool Call: {tc.function.name}] {tc.function.arguments}")
# Build assistant message, preserve reasoning_details (critical!)
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 # pass back unmodified
messages.append(assistant_msg)
# No tool_calls means conversation is done
if not msg.tool_calls:
break
# Execute tools and append results to messages
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = execute_tool(tc.function.name, args)
print(f"[Tool Result: {tc.function.name}] {result}")
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
Con streaming · Pensamiento intercalado
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-***"),
)
# ── Tool definition & mock execution ─────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "City name"}},
"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 "{}"
# ── Stream response collector ────────────────────────────────
def stream_and_collect(turn: int, **kwargs):
"""Stream response, print thinking/content in real-time, accumulate reasoning_details/tool_calls."""
rd = {} # accumulated reasoning_details
content = "" # accumulated response text
tc_map = {} # accumulated tool_calls (by index)
cur = "none" # current output section: 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
# ── Handle thinking ──
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
# Print thinking chunks in real-time
thinking_chunk = rd_delta.get("thinking", "")
if thinking_chunk:
if cur != "thinking":
cur = "thinking"
label = "Interleaved Thinking" if turn > 1 else "Thinking"
sys.stdout.write(f"\n[{label}] ")
sys.stdout.write(thinking_chunk)
sys.stdout.flush()
# ── Handle content ──
if delta.content:
if cur != "content":
if cur == "thinking":
sys.stdout.write("\n")
cur = "content"
sys.stdout.write("\n[Response] ")
sys.stdout.write(delta.content)
sys.stdout.flush()
content += delta.content
# ── Handle 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 ""
# End current output section
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,
}
# ── Multi-turn conversation loop ─────────────────────────────
messages = [
{"role": "user", "content": "What's the weather like in Boston? Then recommend what to wear."}
]
turn = 0
while True:
turn += 1
print(f"\n── Turn {turn} ──")
result = stream_and_collect(
turn,
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
# Print tool calls
if result["tool_calls"]:
for tc in result["tool_calls"]:
print(f"[Tool Call: {tc['function']['name']}] {tc['function']['arguments']}")
# Build assistant message, preserve reasoning_details (critical!)
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"] # pass back unmodified
messages.append(assistant_msg)
# No tool_calls means conversation is done
if not result["tool_calls"]:
break
# Execute tools and append results to messages
for tc in result["tool_calls"]:
args = json.loads(tc["function"]["arguments"])
tool_result = execute_tool(tc["function"]["name"], args)
print(f"[Tool Result: {tc['function']['name']}] {tool_result}")
messages.append({"role": "tool", "tool_call_id": tc["id"], "content": tool_result})
1.6 Reglas de asignación de la intensidad del pensamiento
Modo effort:
- Opus 4.6 / Sonnet 4.6 y posteriores: se asigna al nivel de esfuerzo nativo de Adaptive Thinking de Anthropic.
- Otros modelos: se calcula con la fórmula de
budget_tokens:
budget_tokens = max(min(max_tokens × effort_ratio, 128000), 1024)
| effort | effort_ratio |
|---|---|
| xhigh | 0.95 |
| high | 0.80 |
| medium | 0.50 |
| low | 0.20 |
| minimal | 0.10 |
Asignación del esfuerzo de Adaptive Thinking:
| Effort entrante | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | max | high |
| high | high | high |
| medium | medium | medium |
| low | low | low |
| minimal | low | low |
Modo max_tokens: se asigna directamente como budget_tokens de Anthropic.
-think sufijo: Opus/Sonnet 4.6+ utiliza el pensamiento adaptativo (effort=medium); los demás modelos establecen budget_tokens = min(10240, max_tokens - 1), con un valor predeterminado de max_tokens de 4096.
2. Caché de prompts
Puede usar la caché de prompts al realizar solicitudes al modelo Claude a través de la interfaz Chat. Al establecer puntos de interrupción cache_control en los mensajes, los bloques grandes de texto (como tarjetas de rol, datos de RAG, capítulos de libros, etc.) pueden guardarse en caché para su reutilización, de modo que las solicitudes posteriores accedan directamente a la caché y se reduzcan significativamente los costos.
Documentación oficial de Claude: Caché de prompts
2.1 Costos de la caché
| Operación | Multiplicador de precio (en relación con el precio de entrada original) |
|---|---|
| Escritura en caché (TTL de 5 minutos) | 1.25x |
| Escritura en caché (TTL de 1 hora) | 2x |
| Lectura de caché | 0.1x |
2.2 Modelos compatibles y longitud mínima de caché
| Modelo | Número mínimo de tokens para la 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 puntos de interrupción: un máximo de 4 puntos de interrupción cache_control por solicitud.2.3 TTL de la 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 la caché |
Los costos de escritura con TTL de 1 hora son más altos, pero pueden ahorrar gastos totales al reducir las escrituras repetidas en sesiones largas. Todos los modelos de Claude 4.5 y posteriores de todos los proveedores (incluidos Anthropic, Amazon Bedrock y Google Vertex AI) admiten TTL de 1 hora.
2.4 Uso
Puede establecer puntos de interrupción de caché mediante el campo cache_control en system, user (incluidas las imágenes) y tools. Los ejemplos siguientes solo muestran la estructura clave, omitiendo bloques grandes de texto.
Caché de mensajes del sistema (TTL predeterminado de 5 minutos):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "You are an AI assistant"},
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral"}
}
]
},
{
"role": "user",
"content": [{"type": "text", "text": "Hello"}]
}
]
}
Caché de mensajes del usuario (TTL de 1 hora):
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [{"type": "text", "text": "You are an AI assistant"}]
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
},
{"type": "text", "text": "Hello"}
]
}
]
}
Caché de mensajes con imágenes:
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"detail": "auto", "url": "data:image/jpeg;base64,/9j/4AAQ..."},
"cache_control": {"type": "ephemeral"}
},
{"type": "text", "text": "What's this?"}
]
}
Caché de definiciones de herramientas:
cache_control se coloca en el nivel superior del objeto de la herramienta (junto con type y function):
{
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
},
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}]
}
2.5 Consulta del estado de la caché
La respuesta usage devolverá claude_cache_tokens_details, que registra la información detallada de la caché:
Primera solicitud (creación de 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 posteriores (acierto de caché):
{
"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 la 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é con TTL de 5 minutos |
cache_write_1_hour_input_tokens |
Número de tokens escritos en la caché con TTL de 1 hora |
prompt_tokens_details.cached_tokens |
Número de tokens en caché cuando se produce un acierto, compatible con el formato de OpenAI |
3. Cabecera de solicitud para anthropic-beta
Puede activar las funciones beta del modelo Claude mediante la cabecera HTTP anthropic-beta, que AIHubMix pasará directamente a la API de Anthropic.
Uso
Añada anthropic-beta a la cabecera de la solicitud, con como valor 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": "You are an AI assistant"},
{
"type": "text",
"text": "(long context)",
"cache_control": {"type": "ephemeral"}
}
]
},
{"role": "user", "content": [{"type": "text", "text": "hello"}]}
]
}'
Para conocer los identificadores beta disponibles, consulte la documentación de la API de Anthropic.
Última actualización: 2026-06-01



