Aviso: GPT Image 2.6 Flare y Sunburst ya están disponibles con un 20 % de descuento por tiempo limitado, pruébalo ahora
HiAPI
Blog

Tutorial

Cómo llamar a kimi-k3.1-pro mediante la API de HiAPI: curl, Python y solicitudes listas para ejecutar

Una guía práctica de integración que cubre el endpoint, los parámetros de solicitud, el streaming, las llamadas a herramientas y la resolución de errores

Nov 12, 2026
封面图:深墨绿底色上,两组扁平缎带呈经纬交错编织成规整的开放式网格,缎带为克制的黄铜色与暗绿色。
En esta página

Por qué llamar a kimi-k3.1-pro a través de una API agregada

Cada integración de modelo conlleva el mismo costo oculto: el primer día es divertido, el segundo mes es mantenimiento. Cuando conectas kimi-k3.1-pro directamente a tu aplicación, heredas el esquema de autenticación del proveedor, la semántica de errores, el modelo de cuotas y el ritmo de lanzamientos. Para un prototipo de un solo modelo no hay problema. Pero en cuanto quieres un segundo modelo, un segundo entorno o una ruta de degradación cuando un endpoint falla, se convierte en fricción.

Una API agregada reduce esas diferencias a un solo contrato. HiAPI expone kimi-k3.1-pro con una forma de solicitud compatible con OpenAI, lo que significa que el código cliente que escribas aquí no es desechable. Cambia el identificador del modelo y la misma estructura de solicitud se traslada a otros modelos de la plataforma: las mismas cabeceras, el mismo arreglo de mensajes, el mismo envoltorio de streaming.

En concreto para kimi-k3.1-pro, esto tiene tres implicaciones prácticas:

  • Una sola superficie de credenciales. Gestionas una única API Key y una única URL base, en lugar de un conjunto creciente de cuentas de proveedores.
  • Cargas predecibles. Los esquemas de solicitud y respuesta se mantienen estables entre modelos, así que tu capa de análisis, reintentos y registro se escribe una sola vez.
  • Bajo costo de migración. Si más adelante otro modelo encaja mejor con cierto tipo de carga, el cambio es una cadena en la carga útil, no una reescritura de la capa de transporte.

El resto de esta guía es la integración en sí: anatomía de la solicitud, llamada curl lista para copiar, cliente Python equivalente, después las dos características que suelen dar más problemas en producción —streaming y llamadas a herramientas— y por último una lista de verificación para la resolución de errores.

Lo que necesitas antes de empezar

  • Una API Key de HiAPI, guardada donde tu proyecto almacene los secretos.
  • La URL base de la API de tu cuenta, obtenida desde la consola de HiAPI. Todos los ejemplos siguientes usan https://api.hiapi.ai/v1 como URL base de marcador de posición; antes de salir a producción, confirma el host real en la consola.
  • La cadena del identificador de modelo de kimi-k3.1-pro, copiada tal cual desde la lista de modelos de la consola, porque el identificador distingue mayúsculas y minúsculas.
  • curl para la primera prueba, y Python 3.9+ con la biblioteca requests para el ejemplo de cliente.

Forma de la solicitud: endpoint, cabeceras y parámetros del modelo

Cada llamada de conversación sigue la misma anatomía. Entiende cada parte una vez y luego no tendrás que depurar campo por campo.

Endpoint

La completación de conversación está en una única ruta bajo la URL base:

POST {BASE_URL}/chat/completions

Este es el único endpoint necesario para todos los ejemplos de esta guía. El streaming y las llamadas a herramientas no son endpoints independientes: son opciones sobre el mismo cuerpo de solicitud.

Cabeceras

Solo dos cabeceras importan realmente:

Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json

La clave va en la cabecera Authorization, con el prefijo Bearer. No la pongas en la URL, en parámetros de consulta ni en el cuerpo de la solicitud: esas tres prácticas la filtran a los registros y a los informes de errores. Establece Content-Type explícitamente; algunos clientes HTTP no lo infieren por ti.

Los campos del cuerpo de solicitud que realmente importan

Un cuerpo de solicitud mínimo tiene cuatro campos significativos:

  • model — el identificador de kimi-k3.1-pro. Obligatorio. Es el campo que más se escribe mal en el primer intento, porque debe coincidir exactamente.
  • messages — arreglo ordenado de objetos, cada uno con role (system, user o assistant) y content. Obligatorio y no vacío. El orden es tu historial de conversación; el modelo ve exactamente este arreglo, nada más.
  • stream — booleano, por defecto false. Cuando es true, la respuesta llega como eventos enviados por el servidor en lugar de un único cuerpo JSON. Hay una sección dedicada más adelante.
  • temperature — control de muestreo opcional. Valores bajos producen salidas más deterministas; valores altos producen más variación. Elige un valor una vez por caso de uso y déjalo quieto, no lo ajustes en cada solicitud.

Campos opcionales que puedes añadir a medida que madura la integración:

  • max_tokens — límite superior de la longitud generada. Sirve como barrera de costo y latencia. Ten en cuenta que limita la salida, no la entrada.
  • tools — arreglo de definiciones de herramientas, detallado más adelante.
  • tool_choice — controla si el modelo llama a tus herramientas y cómo lo hace.
  • stop — una o más secuencias que terminan la generación.

La respuesta que deberías esperar

Una respuesta no streaming devuelve un objeto JSON cuyo arreglo choices contiene al menos un elemento. En ese elemento encontrarás un objeto message con role y content, además de un finish_reason que indica por qué se detuvo la generación. Ramifica siempre según finish_reason en lugar de suponer que el contenido está completo: una respuesta truncada tiene contenido, pero no es la respuesta completa.

Escribe el analizador contra esa estructura, no contra la respuesta convertida en cadena. Así sobrevivirá sin importar cómo cambies de modelo en la plataforma.

Una solicitud curl ejecutable

Empieza aquí. Si devuelve una respuesta válida, tu clave, URL base e identificador de modelo son correctos, y cualquier problema posterior estará en el código, no en las credenciales.

curl -sS "$HIAPI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kimi-k3.1-pro",
    "messages": [
      {"role": "system", "content": "Eres un asistente técnico conciso."},
      {"role": "user", "content": "Explica qué es una clave de idempotencia en dos frases."}
    ],
    "temperature": 0.3,
    "max_tokens": 256
  }'

Explicación de cada campo

  • -sS hace que curl no muestre el progreso, pero sí exponga los errores. Sin la segunda S, una solicitud fallida puede salir en silencio y hacerte perder una ronda de depuración.
  • Las variables de entorno mantienen la clave fuera del historial del shell y del búfer de desplazamiento de la terminal. Exporta HIAPI_BASE_URL y HIAPI_API_KEY en el archivo de configuración de tu shell o en un .env ya cargado.
  • El cuerpo entre comillas simples es correcto para un shell POSIX, siempre que la carga útil no contenga comillas simples. En cuanto necesites comillas simples, mueve el cuerpo a un archivo y pásalo con -d @body.json: así evitas una clase de errores de comillas que parecen errores de formato JSON.
  • El mensaje system es opcional, pero vale la pena incluirlo. Es el lugar más sencillo para fijar el tono y el formato de salida.
  • max_tokens es deliberadamente conservador en este ejemplo. Limita a la vez la latencia y el gasto de la prueba de humo.

Interpretar el resultado

Una llamada exitosa devuelve HTTP 200 y un cuerpo JSON. Antes de continuar confirma tres cosas:

  1. choices es un arreglo no vacío.
  2. choices[0].message.content contiene una respuesta real.
  3. choices[0].finish_reason es un valor de finalización normal, no un truncamiento por longitud.

Si el cuerpo de la respuesta es un objeto de error, salta a la sección de resolución de problemas: el mensaje de error suele señalar el campo concreto que falla.

Consejo de reproducibilidad

Guarda esa llamada curl como un script de shell en el repositorio. Un comando que hace una prueba de humo contra la API en vivo es la forma más rápida de distinguir entre «mi integración está rota» y «mi cuenta o mi clave cambiaron». Ejecútalo siempre que algo parezca ir mal.

La misma solicitud escrita en Python

La versión en Python debería parecer aburrida: ese es el objetivo. Todas las decisiones interesantes (identificador de modelo, URL base, tiempo de espera) deben estar en la configuración, no dispersas por los puntos de llamada.

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]
MODEL = os.environ.get("HIAPI_MODEL", "kimi-k3.1-pro")

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}


def chat(messages, temperature=0.3, max_tokens=512, timeout=60):
    payload = {
        "model": MODEL,
        "messages": messages,
        "temperature": temperature,
        "max_tokens": max_tokens,
    }
    resp = requests.post(
        f"{BASE_URL}/chat/completions",
        headers=HEADERS,
        json=payload,
        timeout=timeout,
    )
    resp.raise_for_status()
    data = resp.json()
    choice = data["choices"][0]
    return choice["message"]["content"], choice.get("finish_reason")


if __name__ == "__main__":
    text, reason = chat([
        {"role": "system", "content": "Eres un asistente técnico conciso."},
        {"role": "user", "content": "Explica qué es una clave de idempotencia en dos frases."},
    ])
    print(reason)
    print(text)

Por qué está organizado así

  • Usar json= en lugar de data= — la biblioteca requests serializa el diccionario y establece el tipo de contenido por ti. Serializar a mano introduce fácilmente errores de escape.
  • Siempre timeout=60 — no establecer un tiempo de espera es la causa más común de que un proceso de trabajo quede colgado hasta que el gestor lo mata. Toda llamada de red en un servicio debe tener tiempo de espera.
  • raise_for_status() antes de analizar — convierte los fallos de la capa HTTP en excepciones en el punto de llamada, en lugar de dejar que un cuerpo de respuesta mal formado fluya aguas abajo.
  • MODEL desde el entorno — al cambiar de modelo, el identificador es lo único que cambia. Tenerlo en la configuración hace que el cambio sea una variable de despliegue y no una modificación de código.
  • Devolver finish_reason — quien llama casi siempre necesita saber si la respuesta fue truncada.

Mantenerlo reutilizable entre modelos

La firma de chat(messages, ...) evita deliberadamente exponer cualquier cosa específica de un modelo. Si más adelante enrutas cargas más baratas a otros modelos, pasa un parámetro explícito de anulación de modelo o construye un segundo objeto cliente con un MODEL distinto. El transporte, las cabeceras, la política de reintentos y el manejo de errores se mantienen iguales.

Nota sobre reintentos

No reintentes a ciegas dentro de chat(). Reintenta en la capa que sabe si la operación es segura de repetir: una completación fallida suele serlo, pero una solicitud que ya cambió estado aguas abajo no lo es. Reintenta solo fallos transitorios de transporte y respuestas de límite de velocidad, y solo con retroceso exponencial acotado.

Streaming de respuestas sin romper el cliente

El streaming es la diferencia entre una interfaz de chat que se siente instantánea y una que se queda en blanco diez segundos. También introduce la mayor cantidad de errores de integración, porque la respuesta ya no es un único documento JSON.

Cómo activarlo

Añade "stream": true al cuerpo de la solicitud. El resto de la solicitud no cambia.

with requests.post(
    f"{BASE_URL}/chat/completions",
    headers=HEADERS,
    json={"model": MODEL, "messages": messages, "stream": True},
    stream=True,
    timeout=120,
) as resp:
    resp.raise_for_status()
    for line in resp.iter_lines(decode_unicode=True):
        if not line or not line.startswith("data:"):
            continue
        chunk = line[len("data:"):].strip()
        if chunk == "[DONE]":
            break
        # Analizar chunk como JSON y leer choices[0].delta.content

Lo que llega realmente

El cuerpo de la respuesta es una serie de eventos enviados por el servidor. Cada evento es una línea data: que lleva un pequeño objeto JSON. En choices[0] hay un objeto delta en lugar de un objeto message: el delta normalmente contiene un fragmento de content, y puede que nada. El flujo termina con la línea centinela data: [DONE].

Cuatro reglas cubren casi todos los errores:

  1. Acumula, no reemplaces. Cada delta es un fragmento. Añade delta.content al búfer; la respuesta completa es la concatenación en orden de cada fragmento.
  2. Omite los deltas vacíos. El primer y el último evento a menudo no traen contenido. Evita añadir None.
  3. Trata [DONE] como terminador, no como dato. Deja de leer ahí; lo que venga después no forma parte de la respuesta.
  4. Lee finish_reason del último evento que lo traiga. En modo streaming, el estado de finalización aparece en deltas tardíos, no en un campo de nivel superior.

Errores que vale la pena nombrar

  • Olvidar stream=True en la llamada del cliente. Recibirás todo el flujo como un único cuerpo en búfer, lo que anula el propósito y parece una solicitud no streaming muy lenta.
  • Configurar el tiempo de espera como si fuera no streaming. Un flujo de una generación larga dura más que una solicitud corta. Da a la ruta de streaming un tiempo de lectura más holgado y considera un temporizador de inactividad que aborte si no llegan bytes en un intervalo elegido.
  • Analizar línea por línea sin comprobar el prefijo. No todas las líneas son datos. Las líneas vacías separan eventos; ignóralas.
  • Suponer que el delta tiene la clave content. El streaming de llamadas a herramientas pone otras claves en el delta. Lee siempre de forma defensiva.
  • Olvidar al consumidor del cliente. Un servidor que escribe el flujo en un búfer y solo lo muestra al final es técnicamente streaming, pero no en la práctica. Asegúrate de que el consumidor aguas abajo renderiza los fragmentos a medida que llegan.

Cuándo no hacer streaming

Las tareas por lotes, los resúmenes en segundo plano y cualquier cosa cuya salida consuma un programa en lugar de mostrarse a un humano suelen ser más sencillas sin streaming. Una respuesta no streaming se analiza una sola vez, es más fácil de registrar y más fácil de validar contra un esquema. Usa streaming donde la latencia sea visible para el usuario; no lo uses por defecto.

Añadir llamadas a herramientas al flujo

Las llamadas a herramientas permiten que el modelo pida a tu código ejecutar acciones en lugar de inventar respuestas. El protocolo es una conversación de dos turnos: declaras las herramientas, el modelo puede responder con una solicitud de llamada, tú la ejecutas y luego envías el resultado de vuelta.

Declarar herramientas

Añade un arreglo tools a la solicitud. Cada entrada envuelve la descripción de una función:

{
  "model": "kimi-k3.1-pro",
  "messages": [{"role": "user", "content": "¿Qué tiempo hace en Lisboa?"}],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Devuelve el tiempo actual de la ciudad indicada.",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "Nombre de la ciudad"}
          },
          "required": ["city"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}

La description de la función y de cada uno de sus parámetros no es decorativa: es la única guía que tiene el modelo para decidir cuándo y cómo llamar a la herramienta. Escríbela como si le explicaras la tarea a un compañero nuevo.

El bucle de respuesta

  1. Envía la solicitud.
  2. Si choices[0].finish_reason indica una llamada a herramienta, lee choices[0].message.tool_calls. Cada entrada tiene id, el name de la función y arguments, una cadena codificada en JSON, no un objeto. Analízala.
  3. Ejecuta la función en tu código. Valida los argumentos antes de hacer cualquier cosa con ellos; el modelo puede generar cargas que parecen razonables pero carecen de campos o tienen tipos erróneos.
  4. Añade el mensaje del asistente —incluyendo sus tool_calls— a tu arreglo messages.
  5. Añade un nuevo mensaje con rol tool, el tool_call_id correspondiente y el resultado como content.
  6. Envía la solicitud de nuevo. El modelo ahora compone la respuesta final usando la salida de la herramienta.

El paso 4 es el que la gente omite, y es justo el que rompe las cosas. Si solo devuelves el resultado de la herramienta sin el turno de llamada a herramienta del asistente, la conversación tiene una referencia colgante y el modelo no tiene registro de lo que pidió.

Manejar múltiples llamadas

Una respuesta puede contener varias llamadas a herramientas en el mismo turno. Ejecútalas una por una y devuelve un mensaje tool por cada llamada, cada uno con su propio tool_call_id. No las fusiones.

Controlar las llamadas

tool_choice es tu palanca de política: auto deja decidir al modelo, exigir una herramienta concreta fuerza su llamada, y deshabilitar herramientas le dice que responda directamente. Mantén un presupuesto: si una herramienta falla repetidamente y el modelo sigue reintentando, el bucle de herramientas puede alargarse mucho. Limita el número de iteraciones en tu propio bucle y devuelve un mensaje claro al alcanzar el límite, en lugar de dejar que la solicitud se eternice.

Tratar la salida de herramientas como no confiable

El modelo lee el resultado de la herramienta como texto. Mantenlo pequeño, estructurado y sin instrucciones, y valida los argumentos de tu lado. Una herramienta que devuelve texto sin límite es tanto un problema de costo como un riesgo de corrección.

Diagnosticar errores comunes

La mayoría de los fallos de integración caen en cinco categorías. Recorre esta lista antes de tocar los prompts.

1. Autenticación y autorización

  • Síntoma: estado HTTP en el rango 401/403.
  • Comprueba: que la clave existe, que se pegó sin espacios antes ni después y que lleva exactamente el prefijo Bearer .
  • Comprueba: que la URL base coincide con la que muestra la consola de HiAPI; un host obsoleto o pegado mal produce errores de autenticación confusos.
  • Arregla: vuelve a exportar las variables de entorno y luego ejecuta de nuevo la prueba de humo con curl antes de tocar el código.

2. Cargas mal formadas

  • Síntoma: un error de validación de solicitud que nombra un campo, o un cuerpo de respuesta que no se puede analizar.
  • Comprueba: que el cuerpo es JSON válido. Si lo construyes a mano, valídalo con un rápido json.tool; si lo construyes con código, asegúrate de que el diccionario no quedó anidado un nivel de más por accidente.
  • Comprueba: que messages no está vacío y que cada entrada tiene role y content.
  • Comprueba: que los valores de role pertenecen al conjunto admitido. Un error tipográfico como role: "human" es silencioso en algunos clientes en lugar de obvio.
  • Comprueba: que las entradas de tools tienen type: "function" y un objeto function anidado. Las definiciones aplanadas son el error de llamada a herramienta más común.

3. Identificador del modelo

  • Síntoma: errores del tipo «no encontrado», o un mensaje de que el modelo no está disponible para tu cuenta.
  • Comprueba: que el identificador se copió tal cual desde la consola. Tanto las mayúsculas y minúsculas como los separadores importan.
  • Comprueba: que el modelo está habilitado para tu clave. Aunque el identificador sea válido, un modelo que tu cuenta no puede invocar seguirá fallando.

4. Límites de contexto y longitud

  • Síntoma: un error de que la solicitud excede el contexto máximo, o una respuesta que termina con un finish_reason relacionado con la longitud.
  • Comprueba: la suma de tu prompt de sistema, el historial de mensajes y cualquier definición de herramienta. Los esquemas de herramientas cuentan para el presupuesto y se olvidan fácilmente.
  • Arregla: recorta el historial, resume turnos anteriores o divide la tarea. Para el truncamiento de salida, aumenta max_tokens si la carga realmente necesita más; de lo contrario, mantenlo acotado.

5. Límites de velocidad y tiempos de espera

  • Síntoma: estados de límite de velocidad bajo carga, o tiempos de espera de lectura en el cliente.
  • Comprueba: si los reintentos se lanzan sin ningún retroceso. Un bucle de reintentos ajustado convierte un límite transitorio en un límite persistente.
  • Arregla: respeta la señal de límite de velocidad indicada en la respuesta, usa retroceso exponencial acotado con jitter y controla la concurrencia por clave. Para los tiempos de espera, revisa primero el valor del cliente: un límite del cliente más corto que el tiempo de generación del modelo produce exactamente este síntoma.

Disciplina general de depuración

Registra cuatro cosas en cada fallo: el estado HTTP, el cuerpo de la respuesta, el identificador del modelo y si stream estaba activado. Estos cuatro datos explican la gran mayoría de incidentes. Y mantén actualizada la prueba de humo con curl: cuando pasa pero tu aplicación falla, sabes que el problema está en el código, no en las credenciales.

Leer los mensajes de error

La capa agregada normalmente indica con claridad qué campo provocó el rechazo. Resiste la tentación de reescribir el prompt. Lee el mensaje, corrige el campo señalado y reintenta una vez. Si el mismo error persiste, valida la solicitud contra la prueba de humo antes de profundizar.

Antes de salir a producción: lista de verificación

La diferencia entre «funciona en mi terminal» y «funciona en producción» es sobre todo una lista que nadie escribió. Aquí hay una que vale la pena copiar.

Configuración y secretos

  • La API Key está en un gestor de secretos, nunca en el control de código fuente ni en una URL o línea de registro. Confirma que tu cliente HTTP no puede imprimir la cabecera Authorization en nivel de depuración.
  • La URL base y el identificador del modelo son configuración, no constantes dispersas por el código. Confirma la URL base contra la consola.
  • Rota las claves según un calendario y tras la salida de cualquier miembro del equipo. Tu código cliente debería recoger la clave rotada sin cambios.

Higiene de las solicitudes

  • Cada llamada saliente tiene un tiempo de espera explícito, y la ruta de streaming tiene uno más holgado más una regla de aborto por inactividad.
  • Cada ruta de llamada establece max_tokens. Una generación sin límite es una factura sin límite.
  • Los ajustes de muestreo están fijados por caso de uso y documentados, para que los resultados sean reproducibles cuando haya que depurar.

Manejo de respuestas

  • Tu analizador ramifica según finish_reason y trata el truncamiento como un resultado aparte, no como una respuesta completa.
  • La acumulación de streaming se prueba tanto con respuestas cortas como largas, incluidas las que terminan antes de tiempo.
  • Los argumentos de las llamadas a herramientas se validan antes de usarlos, y el turno de llamada a herramienta del asistente siempre se devuelve al arreglo de mensajes.
  • El bucle de herramientas tiene un límite de iteraciones y un mensaje de fallo claro.

Comportamiento ante fallos

  • Los reintentos están acotados, usan retroceso exponencial con jitter y solo se aplican a operaciones seguras de repetir.
  • Las respuestas de límite de velocidad se respetan en lugar de saturarse con solicitudes.
  • Los fallos registran el estado, el cuerpo de la respuesta, el identificador del modelo y el indicador de stream: esos cuatro campos son los que realmente resuelven incidentes.
  • La prueba de humo con curl se ejecuta en CI o según un calendario, para que te enteres de un cambio de credenciales o de modelo desde el panel y no desde el cliente.

Costo y capacidad

  • Tienes claro cómo se factura el uso: la plataforma cobra por tokens procesados, así que tanto los prompts largos como las generaciones largas importan. Consulta las tarifas actuales en el panel de precios de la consola.
  • Sabes qué tipo de carga es el mayor consumidor y si necesita el modelo completo o uno más ligero.
  • Tienes una ruta de degradación: si una llamada falla repetidamente, la aplicación se degrada de forma visible en lugar de colgarse en silencio.

Una última pregunta

Pregúntate: ¿puede observarla alguien que no escribió esta integración? Si los desarrolladores de tu equipo pueden leer la prueba de humo, los campos de registro de errores y la configuración, y entienden cómo diagnosticar un fallo, has terminado. Si no, la lista aún no está completa.

Con una llamada curl ejecutable, un cliente Python reutilizable y esta lista, kimi-k3.1-pro queda realmente integrado, y no solo conectado.

Artículos relacionados

Ver todos los artículos →

Empieza a crear con artefactos de IA persistentes

Consigue tu API key y llama a modelos de imagen, vídeo y audio a través de una única API basada en tasks.

Leer la documentación de la API