Ir al contenido principal

Tutorial de la API de Claude Opus 4.8: cómo ajustar el parámetro effort

Crea una app en Streamlit que ejecute Claude Opus 4.8 con pensamiento adaptativo, puntúe automáticamente cada respuesta con Haiku 4.5 y grafique la relación coste‑calidad.
Actualizado 17 sept 2026  · 11 min leer

Explorar con IA

ChatGPTClaudePerplexity

La mayoría de los benchmarks comparan modelos entre sí. Pero cuando construyes un pipeline de IA para producción, la pregunta útil suele ser más simple: ¿cuánto debe esforzarse el mismo modelo en una tarea concreta y cuánto cuesta eso?

Claude Opus 4.8 introduce un parámetro effort con varios niveles que controla directamente cuánta capacidad de razonamiento aplica el modelo. Un effort más alto implica más tokens de pensamiento, mejor cobertura de casos límite y respuestas más largas. También supone mayor latencia y coste.

En este tutorial, crearemos una app en Streamlit que haga tangible y medible ese equilibrio. La app ejecuta tres llamadas a la API (una por nivel de effort) sobre el mismo prompt, puntúa automáticamente cada respuesta usando Claude Haiku 4.5 como juez basado en rúbrica y muestra una curva interactiva de proyección de costes para que veas qué nivel de effort encaja con tu volumen de tareas.

Al finalizar, sabrás cómo:

  • Pasar el parámetro effort en la API de Claude Opus 4.8

  • Usar thinking: {type: "adaptive"} como indicador complementario obligatorio

  • Puntuar salidas del modelo de forma programática con un modelo juez más económico

  • Construir una interfaz de proyección de costes con Streamlit

¿Qué es Claude Opus 4.8?

Claude Opus 4.8 es el buque insignia de Anthropic en modelos de lenguaje grandes (LLM). Está diseñado para razonamiento complejo, codificación agente a largo plazo y tareas de alta autonomía, donde el modelo debe mantenerse coherente a lo largo de muchos pasos, manejar contextos amplios y reducir errores por compactación.

Algunas novedades que diferencian Opus 4.8 de versiones anteriores de Claude:

  • Ventana de contexto de 1M de tokens: Disponible por defecto en la API de Claude, Amazon Bedrock y Vertex AI

  • 128k tokens máximos de salida: Permite generar textos largos sin truncado

  • Pensamiento adaptativo: El modelo decide en cada turno si necesita razonamiento profundo, en lugar de consumir siempre un presupuesto fijo

  • Parámetro effort: Un dial para controlar la profundidad del razonamiento y el coste por solicitud

  • Mínimo de caché de prompt más bajo:  El umbral de prompts cacheables baja de ~2.048 a 1.024 tokens, por lo que más prompts de sistema obtienen aciertos de caché sin cambiar código

Si estás comparando Opus 4.8 con la otra opción de frontera, nuestra comparativa Claude Opus 4.8 vs. GPT-5.5 explica dónde destaca cada modelo en codificación y razonamiento.

Opus 4.8 también ajusta algunas restricciones de la API heredadas de Opus 4.7: temperature, top_p y top_k no pueden establecerse en valores distintos al predeterminado, y ya no se admiten presupuestos de pensamiento ampliados mediante budget_tokens. Cualquiera de ellos devuelve un error 400 si se envía. 

El parámetro effort y el pensamiento adaptativo los sustituyen como los principales controles del comportamiento de razonamiento.

Introducción a los modelos Claude

Aprende a trabajar con Claude utilizando la API de Anthropic para resolver tareas del mundo real y crear aplicaciones basadas en inteligencia artificial.
Explora El Curso

¿Qué es el parámetro effort?

Claude Opus 4.8 añadió un parámetro effort que te permite controlar la profundidad de razonamiento por solicitud. Piénsalo como un dial con tres posiciones:

  • low: El modelo responde de forma más directa, usando menos tokens de pensamiento. Adecuado para tareas bien acotadas, factuales o estructuradas.

  • medium: Un punto intermedio: el modelo razona con más cuidado, pero sin explorar a fondo todos los casos límite.

  • high: Es el valor predeterminado del modelo. Aumenta la profundidad de pensamiento y es ideal para razonamiento complejo, problemas de diseño multi‑paso y tareas donde pasar por alto un caso límite sale caro.

  • xhigh: Diseñado para tareas de agencia y codificación de largo recorrido que exigen coherencia sostenida a lo largo de muchos pasos.

  • max: El nivel de capacidad máximo, reservando todo el presupuesto de cómputo para las tareas más exigentes.

El parámetro effort solo funciona junto con thinking: {type: "adaptive"}. El pensamiento adaptativo deja que el modelo decida en cada turno si necesita razonamiento profundo. Combinados, te dan un control real sobre cómo gasta el modelo su presupuesto de cómputo.

Este tutorial se centra en low, medium y high, los tres niveles más relevantes para cargas de trabajo generales en producción, pero la misma estructura de app sirve si quieres ampliarla a xhigh o max.

Los niveles superiores están pensados para trabajo agente sostenido: justo el tipo que recorremos en nuestro tutorial Spec-Driven Development with Claude Code.

Crear un dial de effort para medir el equilibrio calidad–coste de Claude Opus 4.8

La app es un único archivo de Python. Al ejecutarla, verás una barra lateral con un campo de prompt y un control deslizante de tareas por día, y un panel principal con cuatro pestañas: 

  • Diagrama de dispersión calidad vs coste
  • Gráficas de proyección por volumen
  • Respuestas en bruto
  • Una tabla de resultados descargable

El flujo en cada ejecución es:

  1. Lanzar tres llamadas secuenciales a la API claude-opus-4-8 con effort low, medium y high, respectivamente
  2. Pasar cada respuesta a claude-haiku-4-5 como juez con rúbrica
  3. Renderizar todos los resultados en la UI de Streamlit con deslizadores ajustables para correcciones manuales

El prompt predeterminado es una pregunta de diseño de sistemas distribuidos que escala de forma natural con el nivel de effort.

Demo

Paso 0: requisitos previos

Para seguir este tutorial, necesitarás:

  • Python 3.10 o posterior

  • Una clave de la API de Anthropic con acceso a claude-opus-4-8

  • Conocimientos básicos de Streamlit

Paso 1: instalar dependencias

Crea un entorno virtual e instala los paquetes necesarios:

bashpython -m venv .venv
source .venv/bin/activate
pip install anthropic streamlit plotly pandas python-dotenv

En Windows, usa .venv\Scripts\activate en lugar de source .venv/bin/activate.

Añade tu clave de la API de Anthropic a un archivo .env en la raíz del proyecto:

.env
ANTHROPIC_API_KEY=sk-ant-...

Una vez configurado el entorno, definiremos el esquema effort_dial para la interfaz.

Paso 2: definir las constantes del proyecto

Crea un archivo llamado effort_dial.py y añade el bloque de configuración al inicio:

import os
import time
import json
import re
import anthropic
import pandas as pd
import plotly.graph_objects as go
import streamlit as st
from dotenv import load_dotenv

load_dotenv()
st.set_page_config(
    page_title="Opus 4.8 Effort Dial — Claude Opus 4.8",
    layout="wide",
)
MODEL              = "claude-opus-4-8"
SCORER_MODEL       = "claude-haiku-4-5"
MAX_OUTPUT_TOKENS  = 16000
SCORER_MAX_TOKENS  = 500
PRICE_OUT_PER_TOK        = 25 / 1_000_000
PRICE_IN_PER_TOK         = 5  / 1_000_000
SCORER_PRICE_OUT_PER_TOK = 5  / 1_000_000
SCORER_PRICE_IN_PER_TOK  = 1  / 1_000_000
EFFORT_ORDER  = ["low", "medium", "high"]
EFFORT_COLORS = {"low": "#185FA5", "medium": "#639922", "high": "#EF9F27"}
DEFAULT_QUALITY = {"low": 68, "medium": 82, "high": 91}

Establecemos MAX_OUTPUT_TOKENS en 16.000 en lugar del valor por defecto (4.096). Esto importa porque, con un tope de 4.096 tokens, medium y high quedarían truncados al mismo punto y desaparecería la diferencia entre ambos. Necesitas margen suficiente para que las respuestas se separen de forma natural. 

El motivo de parada end_turn en la salida final, en lugar de max_tokens, también confirma que el modelo terminó por su cuenta.

Paso 3: establecer el prompt por defecto

Un prompt simple como «explica la recursión» produce respuestas parecidas en los tres niveles de effort porque no hay nada lo bastante difícil como para activar razonamiento profundo. Por eso usamos una pregunta de diseño de sistemas con varias partes:

DEFAULT_PROMPT = """\
Design a production-ready rate-limiting system for a distributed API gateway
handling 100k requests/second. Cover:
1. Algorithm choice (token bucket vs sliding window vs leaky bucket) with tradeoffs
2. Redis data structure design and TTL strategy
3. Race condition handling across 50 pods
4. Failure mode behavior when Redis is unavailable
5. How you'd test this under load
Be specific about implementation details, not just concepts.
"""

Este prompt tiene cinco subproblemas diferenciados. Los enfoques de bajo effort suelen cubrirlos por encima, citando conceptos clave pero sin detalles de implementación. Con high se abordan condiciones de borde, se incluyen ejemplos en Lua, se comenta la atomicidad de EVALSHA y se añade un plan de pruebas de carga con umbrales concretos.

Paso 4: llamar a Claude Opus 4.8 con el parámetro effort

Ahora define la función central que invoca el modelo. Los dos detalles críticos son thinking={"type": "adaptive"} y output_config={"effort": effort}:

def call_opus(client: anthropic.Anthropic, effort: str, prompt: str) -> dict:
    t0 = time.perf_counter()
    response = client.messages.create(
        model=MODEL,
        max_tokens=MAX_OUTPUT_TOKENS,
        thinking={"type": "adaptive"},
        output_config={"effort": effort},
        # Do NOT set temperature, top_p, or top_k — those 400-error on Opus 4.8
        messages=[{"role": "user", "content": prompt}],
    )
    latency_ms = (time.perf_counter() - t0) * 1000
    in_tok  = response.usage.input_tokens
    out_tok = response.usage.output_tokens
    text = next(
        (b.text for b in response.content if b.type == "text"), "(no text block)"
    )
    return {
        "effort":        effort,
        "in_tokens":     in_tok,
        "out_tokens":    out_tok,
        "latency_ms":    latency_ms,
        "cost_usd":      in_tok * PRICE_IN_PER_TOK + out_tok * PRICE_OUT_PER_TOK,
        "response":      text,
        "stop_reason":   response.stop_reason,
        "hit_token_cap": out_tok >= MAX_OUTPUT_TOKENS,
    }

Repasemos las decisiones clave de esta función.

  • thinking={"type": "adaptive"}: Es obligatorio para que effort tenga efecto. Sin ello, las tres llamadas se comportan de forma idéntica uses el valor de effort que uses. El pensamiento adaptativo decide por turno si hace falta razonamiento profundo y cuánto presupuesto dedicar.

  • output_config={"effort": effort}: Así permite el SDK de Anthropic en Python pasar parámetros aún no expuestos como argumentos con nombre. Internamente, fusiona el diccionario en el cuerpo bruto de la solicitud antes de enviarla.

  • time.perf_counter(): Se usa para medir latencia real en vez de time.time() porque perf_counter tiene mayor resolución y no se ve afectado por ajustes del reloj del sistema. 

  • response.content: Opus 4.8 con pensamiento adaptativo puede devolver varios bloques, incluido uno de thinking con la cadena de razonamiento interna y otro de texto con la respuesta final. Para mostrar solo queremos el bloque de texto. La llamada a next() omite el bloque de thinking y extrae la respuesta para el usuario.

  • hit_token_cap: Es una marca diagnóstica que se pone en True cuando out_tokens alcanza MAX_OUTPUT_TOKENS. Si es True en medium o high, la respuesta se cortó a mitad. 

Paso 5: puntuar automáticamente con Claude Haiku 4.5

Puntuar manualmente tres respuestas largas en cada ejecución es lento y subjetivo. En su lugar, pasa cada respuesta a Claude Haiku 4.5 con una rúbrica y haz que devuelva una puntuación JSON estructurada.

Usar un modelo para evaluar a otro es una forma de evaluación LLM-as-a-judge; en nuestra guía de evaluación de LLM explicamos cómo diseñar rúbricas fiables.

La rúbrica descompone la calidad en cuatro subpuntuaciones:

  • integralidad, 
  • corrección, 
  • cobertura de casos límite, y 
  • especificidad de implementación 

Esto encaja directamente con lo que diferencia los niveles de effort en un prompt de diseño de sistemas:

def score_response_with_haiku(client: anthropic.Anthropic, original_prompt: str,
                               response_text: str, effort: str) -> dict:
    rubric = (
        "You are grading an answer to a difficult systems design prompt. "
        "Score the response from 0 to 100 using this rubric: "
        "completeness 30 points, technical correctness 30 points, "
        "edge-case coverage 20 points, implementation specificity 20 points. "
        "Return strict JSON only with keys: score, rationale, completeness, "
        "correctness, edge_cases, specificity. "
        "The rationale must be concise, concrete, and no more than 80 words."
    )
    grader_prompt = (
        f"{rubric}\n\n"
        f"Original prompt:\n{original_prompt}\n\n"
        f"Effort level being graded: {effort}\n\n"
        f"Candidate response:\n{response_text}"
    )
    result = client.messages.create(
        model=SCORER_MODEL,
        max_tokens=SCORER_MAX_TOKENS,
        messages=[{"role": "user", "content": grader_prompt}],
    )
    raw    = next((b.text for b in result.content if b.type == "text"), "")
    parsed = extract_json_object(raw)
    in_tok  = result.usage.input_tokens
    out_tok = result.usage.output_tokens
    score = max(0, min(100, int(round(float(parsed["score"])))))
    return {
        "score":     score,
        "rationale": str(parsed.get("rationale", "")).strip(),
        "subscores": {
            "completeness": parsed.get("completeness"),
            "correctness":  parsed.get("correctness"),
            "edge_cases":   parsed.get("edge_cases"),
            "specificity":  parsed.get("specificity"),
        },
        "scorer_model":      SCORER_MODEL,
        "scorer_cost_usd":   in_tok * SCORER_PRICE_IN_PER_TOK + out_tok * SCORER_PRICE_OUT_PER_TOK,
        "scorer_in_tokens":  in_tok,
        "scorer_out_tokens": out_tok,
    }

El helper extract_json gestiona los casos en los que Haiku envuelve ocasionalmente su JSON en fences de Markdown. Es un modo de fallo común al trabajar con modelos más pequeños. 

El coste total de puntuación de las tres respuestas suele ser inferior a 0,002 $. Es un sobrecoste despreciable que sustituye un paso manual y subjetivo por una rúbrica repetible.

Paso 6: construir las gráficas con Plotly

La app tiene tres gráficas:

  • Un diagrama de dispersión de la calidad frente al coste por llamada, que muestra la forma de la frontera coste‑calidad. 
  • Un gráfico de barras agrupadas que compara tokens de salida y coste diario con un volumen de tareas configurable. 
  • Un gráfico de líneas con el coste diario acumulado entre 100 y 5.000 tareas por día.

Construyamos cada una:

def quality_tradeoff_chart(results: list[dict], scores: dict) -> go.Figure:
    fig = go.Figure()
    for r in results:
        effort = r["effort"]
        fig.add_trace(go.Scatter(
            x=[r["cost_usd"]],
            y=[scores[effort]],
            mode="markers+text",
            name=effort.capitalize(),
            text=[effort.capitalize()],
            textposition="top center",
            marker=dict(size=18, color=EFFORT_COLORS[effort],
                        line=dict(color="white", width=2)),
            hovertemplate=(
                "<b>%{text}</b><br>"
                "Cost / call: $%{x:.5f}<br>"
                "Quality: %{y}<extra></extra>"
            ),
        ))
    fig.update_layout(
        plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
        margin=dict(t=20, b=20, l=0, r=0),
        xaxis=dict(title="Cost / call (USD)", gridcolor="rgba(128,128,128,0.15)"),
        yaxis=dict(title="Quality score", range=[0, 100],
                   gridcolor="rgba(128,128,128,0.15)"),
        legend=dict(orientation="h", yanchor="bottom", y=1.02, x=0),
    )
    return fig

def projection_chart(results: list[dict], tasks: int) -> go.Figure:
    fig = go.Figure()
    fig.add_traces([
        go.Bar(
            name="Output tokens", x=[r["effort"] for r in results],
            y=[r["out_tokens"] for r in results],
            marker_color=[EFFORT_COLORS[r["effort"]] for r in results],
            yaxis="y1", text=[f"{r['out_tokens']:,}" for r in results],
            textposition="outside", width=0.35, offset=-0.2,
        ),
        go.Bar(
            name=f"Daily cost ({tasks:,} tasks)",
            x=[r["effort"] for r in results],
            y=[r["cost_usd"] * tasks for r in results],
            marker_color=[EFFORT_COLORS[r["effort"]] for r in results],
            marker_opacity=0.45, yaxis="y2",
            text=[f"${r['cost_usd']*tasks:.4f}" for r in results],
            textposition="outside", width=0.35, offset=0.2,
        ),
    ])
    fig.update_layout(
        barmode="group", plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
        margin=dict(t=20, b=20, l=0, r=0),
        yaxis=dict(title="Output tokens", gridcolor="rgba(128,128,128,0.15)"),
        yaxis2=dict(title="Daily cost (USD)", overlaying="y", side="right"),
        legend=dict(orientation="h", yanchor="bottom", y=1.02, x=0),
    )
    return fig

def breakeven_chart(results: list[dict]) -> go.Figure:
    volumes = list(range(100, 5001, 100))
    fig = go.Figure()
    for r in results:
        fig.add_trace(go.Scatter(
            x=volumes, y=[r["cost_usd"] * v for v in volumes],
            mode="lines", name=r["effort"].capitalize(),
            line=dict(color=EFFORT_COLORS[r["effort"]], width=2.5),
        ))
    fig.update_layout(
        plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
        margin=dict(t=20, b=20, l=0, r=0),
        xaxis=dict(title="Tasks / day", gridcolor="rgba(128,128,128,0.15)"),
        yaxis=dict(title="Daily cost (USD)", gridcolor="rgba(128,128,128,0.15)"),
        legend=dict(orientation="h", yanchor="bottom", y=1.02, x=0),
    )
    return fig

Cada gráfica responde a una pregunta distinta con los mismos tres puntos de datos.

  • quality_tradeoff_chart dibuja el coste en el eje x y la calidad en el eje y, de modo que la forma de la frontera se ve de inmediato. 

  • projection_chart toma el coste por llamada basado en la API y lo multiplica por el valor del control de tareas por día, así que cada barra refleja un recuento de tokens real, no una estimación. 

  • breakeven_chart recorre de 100 a 5.000 tareas diarias usando los mismos anclajes de coste reales, de forma que las líneas divergen a un ritmo sustentado por respuestas de la API. Un equipo con 500 tareas al día ve un coste muy distinto al de uno con 5.000, y esta gráfica lo hace evidente.

En el siguiente paso conectaremos estas tres funciones de gráfica con la UI de Streamlit y con los resultados en vivo de la API.

Paso 7: construir la interfaz en Streamlit

La última pieza es la interfaz de Streamlit. La barra lateral gestiona la clave, el prompt y el control de tareas diarias. El panel principal ejecuta las llamadas secuencialmente y actualiza tarjetas de progreso según terminan.

def main():
    api_key = os.getenv("ANTHROPIC_API_KEY", "").strip()
    with st.sidebar:
        st.title("Opus 4.8 Effort Dial")
        st.divider()
        if api_key:
            st.success("Key loaded.")
        else:
            st.error("Missing ANTHROPIC_API_KEY. Set it in your .env file.")
        prompt = st.text_area(
            "Prompt (runs at all 3 effort levels)",
            value=DEFAULT_PROMPT, height=220,
        )
        run = st.button("▶ Run 3 calls", use_container_width=True, type="primary")
        st.divider()
        tasks = st.slider("Tasks / day", min_value=10, max_value=5000, value=500, step=10)
    if "results" not in st.session_state:
        st.session_state.results = []
    for effort, default in DEFAULT_QUALITY.items():
        if f"quality_{effort}" not in st.session_state:
            st.session_state[f"quality_{effort}"] = default
    if run:
        if not api_key:
            st.error("Set ANTHROPIC_API_KEY first.")
            st.stop()
        client = anthropic.Anthropic(api_key=api_key)
        collected = []
        progress   = st.progress(0, text="Starting calls…")
        cols       = st.columns(3)
        holders    = {e: cols[i].empty() for i, e in enumerate(EFFORT_ORDER)}
        for i, effort in enumerate(EFFORT_ORDER):
            holders[effort].info(f"**{effort.upper()}** — calling…")
            progress.progress(i / 3, text=f"Running {effort} effort…")
            try:
                result = call_opus(client, effort, prompt)
                try:
                    scored = score_response_with_haiku(
                        client, prompt, result["response"], effort
                    )
                    result.update(scored)
                    st.session_state[f"quality_{effort}"] = scored["score"]
                    score_line = f"auto-score: {scored['score']}/100"
                except Exception as e:
                    result["score_error"] = str(e)
                    score_line = "auto-score unavailable"
                collected.append(result)
                holders[effort].success(
                    f"**{effort.upper()}**\n\n"
                    f"{result['out_tokens']:,} output tokens\n\n"
                    f"{result['latency_ms']/1000:.2f}s\n\n"
                    f"${result['cost_usd']:.5f} / call\n\n"
                    f"{score_line}"
                )
            except Exception as exc:
                holders[effort].error(f"**{effort.upper()}** failed: {exc}")
            progress.progress((i + 1) / 3)
        st.session_state.results = sorted(
            collected, key=lambda r: EFFORT_ORDER.index(r["effort"])
        )
        progress.empty()
    st.header("Opus 4.8 Effort Dial: Quality vs. Cost Tradeoff")
    results = st.session_state.results
    if not results:
        st.info("Set your API key and click **▶ Run 3 calls** to start.")
        st.stop()
    if any(r.get("hit_token_cap") for r in results):
        st.warning(
            f"One or more calls hit the {MAX_OUTPUT_TOKENS:,}-token cap. "
            "Raise MAX_OUTPUT_TOKENS if medium and high still look similar."
        )
    scorer_spend = sum(r.get("scorer_cost_usd", 0) for r in results)
    if scorer_spend > 0:
        st.caption(
            f"Auto-scoring used {SCORER_MODEL} and added "
            f"${scorer_spend:.6f} across all three responses."
        )
    # Per-call metric cards
    st.subheader("Per-call results")
    scores = {e: int(st.session_state.get(f"quality_{e}", DEFAULT_QUALITY[e]))
              for e in EFFORT_ORDER}
    mcols = st.columns(3)
    for row, col in zip(results, mcols):
        effort = row["effort"]
        with col:
            st.metric(f"{effort.UPPER()} effort", f"{row['out_tokens']:,} output tokens")
            st.caption(
                f"Input: {row['in_tokens']:,} · "
                f"Latency: {row['latency_ms']/1000:.2f}s · "
                f"Cost: ${row['cost_usd']:.5f} · "
                f"Stop: {row.get('stop_reason', 'n/a')}"
            )
            st.slider(
                f"Quality score — {effort.UPPER()}",
                min_value=0, max_value=100,
                value=DEFAULT_QUALITY[effort],
                key=f"quality_{effort}",
            )
            if row.get("rationale"):
                st.caption(f"Auto-scored by {SCORER_MODEL}: {row['rationale']}")
    st.divider()
    # Tabs
    t1, t2, t3, t4 = st.tabs(
        ["Quality vs cost", "Volume projection", "Raw responses", "Raw data"]
    )
    with t1:
        left, right = st.columns([1.1, 1], gap="large")
        with left:
            st.plotly_chart(quality_tradeoff_chart(results, scores),
                            use_container_width=True)
        with right:
            low  = next((r for r in results if r["effort"] == "low"),  None)
            med  = next((r for r in results if r["effort"] == "medium"), None)
            high = next((r for r in results if r["effort"] == "high"), None)
            if low and med and high:
                st.markdown("#### Read on the current anchor set")
                st.write(
                    f"Low → medium adds **${med['cost_usd'] - low['cost_usd']:.5f}** per call "
                    f"for **{scores['medium'] - scores['low']}** quality points."
                )
                st.write(
                    f"Medium → high adds **${high['cost_usd'] - med['cost_usd']:.5f}** per call "
                    f"for **{scores['high'] - scores['medium']}** more quality points."
                )
                st.write(
                    f"High vs low: **${high['cost_usd'] - low['cost_usd']:.5f}** "
                    f"total per-call delta."
                )
                st.caption(
                    "Quality scores are auto-generated by Haiku 4.5 using a rubric, "
                    "but you can override them with the sliders above."
                )
    with t2:
        st.plotly_chart(projection_chart(results, tasks), use_container_width=True)
        st.plotly_chart(breakeven_chart(results), use_container_width=True)
        if low and high:
            daily_delta   = (high["cost_usd"] - low["cost_usd"]) * tasks
            monthly_delta = daily_delta * 30
            st.caption(
                f"High vs low at {tasks:,} tasks/day: "
                f"**+${daily_delta:.4f}/day** · **+${monthly_delta:.2f}/month**"
            )
    with t3:
        for row in results:
            with st.expander(
                f"{row['effort'].upper()} — {row['out_tokens']:,} tokens",
                expanded=True,
            ):
                if row.get("rationale"):
                    st.info(
                        f"Auto-score: **{scores[row['effort']]}/100**. "
                        f"{row['rationale']}"
                    )
                st.markdown(row["response"])
    with t4:
        df = pd.DataFrame([{
            "Effort":            r["effort"],
            "Quality score":     scores[r["effort"]],
            "Input tokens":      r["in_tokens"],
            "Output tokens":     r["out_tokens"],
            "Latency (s)":       round(r["latency_ms"] / 1000, 2),
            "Cost / call ($)":   round(r["cost_usd"], 6),
            "Auto-score cost ($)": round(r.get("scorer_cost_usd", 0), 6),
            f"Daily @ {tasks} tasks ($)": round(r["cost_usd"] * tasks, 4),
            f"Monthly @ {tasks} tasks/day ($)": round(r["cost_usd"] * tasks * 30, 2),
        } for r in results])
        st.dataframe(df, use_container_width=True, hide_index=True)
        st.download_button(
            "Download CSV",
            df.to_csv(index=False),
            file_name="effort_dial_results.csv",
            mime="text/csv",
        )
if __name__ == "__main__":
    main()

La barra lateral concentra toda la configuración (carga de la clave, prompt y tareas por día), manteniendo el panel principal limpio para los resultados. Este panel se organiza en cuatro pestañas para estructurar el flujo.

Quality vs cost

  • La pestaña de calidad vs coste es la vista principal. Dibuja el scatter con coste en el eje x y calidad en el y, junto a un resumen textual de los incrementos de coste y calidad entre pasos. 

Volume projection

  • La pestaña de proyección por volumen es la capa de ayuda a la decisión. Muestra el gráfico de barras agrupadas y la línea de punto de equilibrio, para que puedas proyectar el coste del trade‑off de effort con tu volumen real usando el control lateral.
  • La pestaña de respuestas en bruto muestra la salida completa del modelo en cada nivel de effort en secciones desplegables, con la justificación de la auto‑puntuación de Haiku fijada arriba. Aquí puedes leer las respuestas y calibrar si las puntuaciones te cuadran.

Raw data

  • La pestaña de datos en bruto muestra los resultados completos como un DataFrame, con un botón para descargar CSV: útil si quieres ejecutar la demo varias veces con distintos prompts y comparar ejecuciones fuera de la app.

Con el backend, las gráficas y la interfaz listos, la app está preparada para ejecutarse.

Paso 8: ejecutar la app

Inicia el servidor de Streamlit:

streamlit run effort_dial.py

Abre http://localhost:8501 y mantén el prompt por defecto o sustitúyelo por algo de tu propio pipeline y pulsa  Run 3 calls.

La app ejecuta cada nivel de effort de forma secuencial y muestra una tarjeta de estado al completar cada uno. Cuando finalizan los tres, lanza las tres llamadas de puntuación con Haiku y rellena las gráficas. El tiempo total suele ser de 2–3 minutos con el prompt por defecto, la mayor parte en la llamada de high.

Cómo leer los resultados

Aquí tienes las cifras de una ejecución representativa con el prompt de rate limiting:

Effort

Tokens de salida

Latencia

Coste/llamada

Auto‑score

Low

3,276

46s

$0.0827

72/100

Medium

5,109

70s

$0.1285

82/100

High

5,382

71s

$0.1354

92/100

Algunas observaciones destacables:

  • Los tokens de salida están ordenados (3.276 → 5.109 → 5.382) con end_turn como motivo de parada en los tres casos. Esto confirma que el parámetro de effort se está aplicando correctamente y que las respuestas terminan de forma natural.

  • El salto de calidad de low a medium (+10 puntos) cuesta 0,046 $ por llamada. El de medium a high (+10 puntos) cuesta solo 0,007 $. Medium capta la mayor parte de la ganancia de calidad con un coste incremental seis veces menor que el último paso a high.

  • El diagrama de dispersión hace visible esta asimetría al instante. Low queda abajo a la izquierda: barato pero menos completo. Medium está en el centro. High arriba a la derecha, pero solo ligeramente más caro que medium porque la diferencia de tokens entre esos dos niveles es pequeña en este prompt.

  • La justificación del evaluador Haiku también aporta contexto. Sobre la respuesta low señaló: «buena profundidad técnica en la selección de algoritmos y scripting en Lua, pero faltan detalles concretos de enrutado pod‑a‑shard y de cómo se coordina el sharding entre pods». Sobre high: «respuesta excepcional que cubre los cinco requisitos con nivel de producción, con scripts EVALSHA y ejemplos concretos de casos límite».

Conclusión

En este tutorial hemos creado una app en Streamlit que ejecuta tres llamadas reales a la API de Claude Opus 4.8 (una por nivel de effort), puntúa cada respuesta con Haiku 4.5 y proyecta el coste según tu volumen de tareas. 

Las ideas clave: effort y thinking: {type: "adaptive"} trabajan juntos para controlar la profundidad del razonamiento; y un modelo juez económico puede sustituir la puntuación manual con una rúbrica repetible a coste marginal. También vimos que la frontera coste‑calidad no es lineal: el nivel medium captura la mayor parte de la mejora de calidad por una fracción del coste incremental de high.

Con 1.000 tareas al día, pasar de high a medium ahorra aproximadamente 207 $/mes con una bajada de calidad de unos 10 puntos sobre una rúbrica de 100. Para tareas bien acotadas (clasificación, extracción o resumen), medium suele ser suficiente. Sin embargo, para tareas que requieren razonamiento técnico profundo o cobertura exhaustiva de casos límite (revisión de código, diseño de arquitecturas, análisis de políticas), el nivel high justifica su coste. 

Como extensiones, puedes añadir un segundo tipo de prompt para mostrar cómo el delta de effort se reduce cuando el problema no necesita razonamiento profundo, o incluir una vista comparativa que resalte exactamente dónde el nivel high aporta detalle concreto que medium omite.

Preguntas frecuentes sobre el tutorial de la API de Claude Opus 4.8

¿Por qué no puedo ajustar la temperatura en Claude Opus 4.8?

Claude Opus 4.8 no permite sobrescribir parámetros de muestreo. Pasar un temperature, top_p o top_k distinto al valor por defecto devuelve un error 400. Usa técnicas de prompting para guiar el estilo de respuesta.

¿Qué pasa si omito thinking: {type: "adaptive"}?

El parámetro effort no tiene efecto sin activar el pensamiento adaptativo. Si lo omites, las tres llamadas se comportan igual independientemente del valor de effort que envíes.

¿Por qué no ejecutar las tres llamadas en paralelo?

Puedes hacerlo y reducirías el tiempo total a aproximadamente una tercera parte. El enfoque secuencial aquí es intencional porque permite que las tarjetas de progreso se actualicen una a una, haciendo el flujo más legible en una demo. Si quieres ejecución en paralelo en producción, envuelve las tres llamadas a call_opus en concurrent.futures.ThreadPoolExecutor().

¿Qué fiabilidad tiene el auto‑scorer de Haiku?

Con una rúbrica con dimensiones concretas y un prompt de evaluación claro, Haiku 4.5 es consistente entre ejecuciones sobre la misma respuesta. No sustituye a una evaluación humana en tareas críticas, pero es suficiente para anclar un scatter coste‑calidad y evitar leer manualmente tres respuestas largas en cada ejecución.

¿Cuál es el coste total de una ejecución de demo?

Con el prompt de rate limiting y MAX_OUTPUT_TOKENS=16000, una ejecución completa cuesta aproximadamente 0,35 $ en salida del modelo más menos de 0,002 $ por las tres llamadas de puntuación con Haiku; en total, alrededor de 0,35 $.


Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

Soy experta Google Developers en ML (Gen AI), triple experta en Kaggle y embajadora de Women Techmakers, con más de tres años de experiencia en el sector tecnológico. Cofundé una startup de salud en 2020 y actualmente curso un máster en informática en Georgia Tech, con especialización en aprendizaje automático.

Temas
Inteligencia Artificial
Grandes modelos lingüísticos

¡Aprende IA con DataCamp!

Curso

Introducción a los modelos Claude

3 h
14.4K
Aprende a trabajar con Claude utilizando la API de Anthropic para resolver tareas del mundo real y crear aplicaciones basadas en IA.
Ver detallesRight Arrow
Iniciar Curso
Ver másRight Arrow
Relacionado

Tutorial

Primeros pasos con Claude 3 y la API de Claude 3

Conozca los modelos Claude 3, las pruebas de rendimiento detalladas y cómo acceder a ellas. Además, descubra la nueva API Python de Claude 3 para generar texto, acceder a funciones de visión y streaming.
Abid Ali Awan's photo

Abid Ali Awan

Tutorial

Tutorial de Python: Streamlit

Este tutorial sobre Streamlit está pensado para ayudar a los científicos de datos o ingenieros de machine learning que no son desarrolladores web y no están interesados en pasar semanas aprendiendo a utilizar estos marcos para crear aplicaciones web.
Nadia mhadhbi's photo

Nadia mhadhbi

15 min

Tutorial

Tutorial Mistral 7B: Guía paso a paso para utilizar y ajustar Mistral 7B

El tutorial cubre el acceso, la cuantización, el ajuste fino, la fusión y el almacenamiento de este potente modelo lingüístico de código abierto con 7300 millones de parámetros.
Abid Ali Awan's photo

Abid Ali Awan

12 min

Tutorial

Tutorial de DeepSeek-Coder-V2: Ejemplos, instalación, puntos de referencia

DeepSeek-Coder-V2 es un modelo de lenguaje de código de código abierto que rivaliza con el rendimiento de GPT-4, Gemini 1.5 Pro, Claude 3 Opus, Llama 3 70B o Codestral.
Dimitri Didmanidze's photo

Dimitri Didmanidze

8 min

Tutorial

Ajuste fino de GPT-3 mediante la API OpenAI y Python

Libere todo el potencial de GPT-3 mediante el ajuste fino. Aprenda a utilizar la API de OpenAI y Python para mejorar este modelo de red neuronal avanzado para su caso de uso específico.
Zoumana Keita 's photo

Zoumana Keita

12 min

Tutorial

Ajuste fino de LLaMA 2: Guía paso a paso para personalizar el modelo de lenguaje grande

Aprende a ajustar Llama-2 en Colab utilizando nuevas técnicas para superar las limitaciones de memoria y computación y hacer más accesibles los grandes modelos lingüísticos de código abierto.
Abid Ali Awan's photo

Abid Ali Awan

12 min

Ver MásVer Más