Saltar al contenido principal

Documentation Index

Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt

Use this file to discover all available pages before exploring further.

Hemos mejorado la interfaz compatible con OpenAI con optimizaciones más profundas específicamente para los modelos de la serie Claude. Ahora puedes controlar el razonamiento y el caching con mayor precisión y comodidad, especialmente el razonamiento intercalado (interleaved thinking) en conversaciones multiturno, que hemos hecho más fácil de usar y permite una integración sin fricciones sin parámetros adicionales. También admite la activación de las funciones beta ofrecidas por Anthropic.

1. Razonamiento del modelo (Extended Thinking)

1.1 Ventajas del razonamiento intercalado

Cuando el razonamiento intercalado no está habilitado, el modelo realiza el razonamiento solo una vez al inicio del turno del asistente; las respuestas posteriores se generan directamente tras recibir los resultados de las herramientas, sin producir nuevos bloques de razonamiento:
User → [Thinking] → Tool Call → Tool Result → Response
Cuando el razonamiento intercalado está habilitado, el modelo inserta un nuevo bloque de razonamiento cada vez que recibe el resultado de una herramienta, formando una cadena de razonamiento:
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
                                                ↑ Interleaved Thinking
Esto permite al modelo:
  • Realizar razonamiento secundario basado en los resultados de la herramienta, en lugar de concatenar simplemente las salidas.
  • Encadenar el razonamiento entre múltiples llamadas a herramientas, donde cada decisión se basa en el análisis del paso anterior.
Referencia: Anthropic Interleaved Thinking

1.2 Habilitar el razonamiento

Puedes habilitar el razonamiento de cuatro formas; elige cualquiera de ellas:
MétodoEjemploDescripció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 razonamiento
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 razonamiento

El mensaje de respuesta incluirá dos nuevos campos:
  • reasoning_content: Contenido del razonamiento (cadena), para facilitar su visualización.
  • reasoning_details: Información estructurada completa sobre el razonamiento, que debe devolverse tal cual en conversaciones multiturno; la estructura interna puede diferir entre proveedores.
Ejemplo sin 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 razonamiento se enviará por fragmentos mediante 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 Conservar el razonamiento en conversaciones multiturno (El razonamiento intercalado está integrado, no se necesitan parámetros adicionales)

Para permitir que el modelo continúe sus capacidades de razonamiento en conversaciones multiturno, simplemente coloca el reasoning_details previamente devuelto 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 habilitará automáticamente el razonamiento intercalado cuando detecte información histórica de razonamiento en la solicitud, permitiendo que el modelo continúe el razonamiento profundo tras recibir los resultados de las llamadas a herramientas sin necesidad de parámetros adicionales.

1.5 Ejemplo completo

Los siguientes dos ejemplos muestran el proceso completo de Tool Call multiturno + razonamiento intercalado: consulta del usuario → el modelo piensa y llama a una herramienta → se inyectan los resultados de la herramienta (preservando reasoning_details) → el razonamiento intercalado del modelo da la respuesta final. Sin streaming · Razonamiento 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})
Streaming · Razonamiento 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 mapeo de la intensidad del razonamiento

Modo Effort:
  • Opus 4.6 / Sonnet 4.6 y superiores: se mapea al nivel de esfuerzo nativo de Adaptive Thinking de Anthropic.
  • Otros modelos: se calcula usando la fórmula para budget_tokens:
budget_tokens = max(min(max_tokens × effort_ratio, 128000), 1024)
efforteffort_ratio
xhigh0.95
high0.80
medium0.50
low0.20
minimal0.10
Mapeo del Adaptive Thinking Effort:
Effort entranteOpus 4.6Sonnet 4.6
xhighmaxhigh
highhighhigh
mediummediummedium
lowlowlow
minimallowlow
Modo max_tokens: Se asigna directamente como el budget_tokens de Anthropic. Sufijo -think: Opus/Sonnet 4.6+ usa el razonamiento adaptativo (effort=medium); otros modelos establecen budget_tokens = min(10240, max_tokens - 1), con un max_tokens predeterminado de 4096.

2. Caché de prompts (Prompt Caching)

Puedes utilizar Prompt Caching al realizar solicitudes al modelo Claude a través de la interfaz Chat. Estableciendo puntos de corte cache_control en los mensajes, los bloques grandes de texto (como tarjetas de rol, datos de RAG, capítulos de libros, etc.) pueden almacenarse en caché para su reutilización, lo que permite que las solicitudes posteriores acierten directamente en la caché y reduzcan significativamente los costos.
Documentación oficial de Claude: Prompt Caching

2.1 Costos de caché

OperaciónMultiplicador de precio (relativo al precio de entrada original)
Escritura de caché (TTL 5 min)1,25x
Escritura de caché (TTL 1 hora)2x
Lectura de caché0,1x

2.2 Modelos admitidos y longitud mínima de caché

ModeloCantidad mínima de tokens en caché
Claude Opus 4.6 / Opus 4.54096
Claude Sonnet 4.6 / Sonnet 4.5 / Opus 4.1 / Opus 4 / Sonnet 4 / Sonnet 3.7 (obsoleto)1024
Claude Haiku 4.54096
Claude Haiku 3.5 (obsoleto) / Haiku 32048
Límite de cantidad de puntos de corte: Un máximo de 4 puntos de corte cache_control por solicitud.

2.3 TTL de la caché

TTLSintaxisEscenarios aplicables
5 minutos (predeterminado)"cache_control": {"type": "ephemeral"}Sesiones cortas, solicitudes habituales
1 hora"cache_control": {"type": "ephemeral", "ttl": "1h"}Sesiones largas, para evitar reescrituras de caché
Los costos de escritura para el TTL de 1 hora son mayores, pero pueden ahorrar gastos totales al reducir las reescrituras en sesiones extensas. Todos los modelos de Claude 4.5 y posteriores, de todos los proveedores (incluidos Anthropic, Amazon Bedrock y Google Vertex AI), admiten el TTL de 1 hora.

2.4 Uso

Puedes establecer puntos de corte de caché usando el campo cache_control en system, user (incluidas imágenes) y tools. Los siguientes ejemplos solo muestran la estructura clave, omitiendo grandes bloques 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 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": "What's this?"}
  ]
}
Caché de la definición de herramientas: 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": "Get current weather for a location",
      "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"]
      }
    },
    "cache_control": {"type": "ephemeral", "ttl": "1h"}
  }]
}

2.5 Consultar el estado de la caché

El campo usage de la respuesta devolverá claude_cache_tokens_details, que registra información detallada de la caché: Primera solicitud (creando la 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
    }
  }
}
CampoSignificado
cache_creation_input_tokensNúmero de tokens escritos en la caché en esta solicitud
cache_read_input_tokensNúmero de tokens leídos desde la caché en esta solicitud
cache_write_5_minutes_input_tokensNúmero de tokens escritos en la caché con TTL de 5 minutos
cache_write_1_hour_input_tokensNúmero de tokens escritos en la caché con TTL de 1 hora
prompt_tokens_details.cached_tokensNúmero de tokens en caché cuando se acierta la caché, compatible con el formato de OpenAI

3. Cabecera de solicitud para anthropic-beta

Puedes habilitar las funciones beta del modelo Claude mediante la cabecera HTTP anthropic-beta, que AihubMix reenviará a la API de Anthropic.

Uso

Añade anthropic-beta a la cabecera de la solicitud, con el valor del identificador de la función beta correspondiente:
curl "https://aihubmix.com/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -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 identificadores beta específicos disponibles, consulta la documentación de la API de Anthropic.

Última actualización: 2026-06-01