Saltar al contenido principal

Usar la API desde código

InferNode es compatible con el SDK de OpenAI: cambia la URL base y usa tu llave de InferNode.

Antes de empezar

  • Una llave de API de InferNode (empieza por sk-saptiva-). La obtienes en API > API Keys de Studio (si tu Cliente tiene la sección) o de tu administrador.
  • La URL base de tu instalación. InferNode se sirve bajo la ruta /infernode del dominio de la API: https://api.<tu-dominio>/infernode/v1 (en la instalación de referencia, https://api.laboratorioia.ibero.mx/infernode/v1). Sin llave, GET /v1/models responde 401 con "code": "identity.invalid_token" (verificado el 2026-08-25 en la instalación de referencia); con una llave mal escrita o revocada, identity.unauthorized. Es la forma de comprobar que la URL es correcta antes de pedir una llave.

Python

from openai import OpenAI

client = OpenAI(
base_url="https://api.<tu-dominio>/infernode/v1",
api_key="sk-saptiva-...",
)

resp = client.chat.completions.create(
model="Qwen/Qwen3-8B",
messages=[{"role": "user", "content": "Resume este texto en tres líneas: ..."}],
temperature=0.2,
)
print(resp.choices[0].message.content)

Con streaming:

for chunk in client.chat.completions.create(model="Qwen/Qwen3-8B", messages=msgs, stream=True):
print(chunk.choices[0].delta.content or "", end="")

Herramientas (function calling)

Los modelos con la capacidad tool-use aceptan tools con el mismo formato de OpenAI. El modelo devuelve tool_calls; tu código ejecuta la función y responde con un mensaje role: "tool".

tools = [{
"type": "function",
"function": {
"name": "buscar_alumno",
"description": "Busca un alumno por matrícula",
"parameters": {"type": "object", "properties": {"matricula": {"type": "string"}}, "required": ["matricula"]},
},
}]
resp = client.chat.completions.create(model="Qwen/Qwen3.6-27B-FP8", messages=msgs, tools=tools)
call = resp.choices[0].message.tool_calls[0]
# ejecuta buscar_alumno(**json.loads(call.function.arguments)) y añade el resultado:
msgs += [resp.choices[0].message, {"role": "tool", "tool_call_id": call.id, "content": "..."}]

Salida en JSON

Con response_format={"type": "json_object"} y una instrucción que describa el esquema, un modelo con json-mode devuelve JSON válido. Es la forma de usar InferNode para extraer datos sin un agente.

Embeddings

vec = client.embeddings.create(model="Qwen/Qwen3-Embedding-8B", input=["texto uno", "texto dos"])
print(len(vec.data[0].embedding))

Usa el mismo modelo para indexar y para consultar; vectores de modelos distintos no son comparables.

curl

curl https://api.<tu-dominio>/infernode/v1/chat/completions \
-H "Authorization: Bearer sk-saptiva-..." \
-H "Content-Type: application/json" \
-d '{"model":"Qwen/Qwen3-8B","messages":[{"role":"user","content":"Hola"}]}' -i

La opción -i muestra las cabeceras X-RateLimit-* y X-Request-Cost.

Qué modelo usar

GET /v1/models devuelve los nombres válidos para tu llave. Son los mismos identificadores que ves en el Catálogo de modelos (administradores).

Elegir modelo y esfuerzo

GET /v1/models devuelve los nombres válidos para tu llave; GET /v1/models/{name} añade contexto máximo, precio por token, capacidades y estado de retiro. Reglas rápidas:

TareaModeloParámetros
Clasificar, extraer, reformatearEl más pequeño con json-modetemperature: 0, max_tokens bajo
Responder con documentosUno de instrucción de 27B o mástemperature: 0.2
Analizar imágenes o PDF escaneadosUno con visionEnvía la imagen en content como en OpenAI
Búsqueda semánticaUno de tipo EmbeddingsMismo modelo para indexar y consultar

Parámetros que acepta chat/completions

Además de los de OpenAI (messages, max_tokens o max_completion_tokens, temperature 0-2, top_p, n hasta 8, stream y stream_options.include_usage, stop, presence_penalty, frequency_penalty, logit_bias, seed, response_format, tools, tool_choice, parallel_tool_calls, logprobs, top_logprobs hasta 20, user), InferNode acepta:

ParámetroQué hace
top_k, min_p, repetition_penaltyControles de muestreo de los modelos locales.
guard: trueEvalúa la conversación con las guardas de contenido después de responder; el resultado queda en GET /v1/guard/events.
metadataEtiquetas libres que se guardan con el evento de consumo (por ejemplo {"proyecto": "becas"}), para desglosar el gasto después. No se envía al modelo.

Las claves que InferNode no reconoce se reenvían al modelo tal cual y se listan en la cabecera X-Saptiva-Passthrough; los valores por defecto que el administrador fijó para ese modelo aparecen en X-Saptiva-Model-Defaults. Con modelos de razonamiento, la respuesta incluye reasoning_content en el mensaje del asistente.

Manejo de límites

  • Ante 429, lee Retry-After (segundos) o X-RateLimit-Reset-Requests / -Tokens y espera hasta entonces; el cuerpo indica en details.dimension qué límite se superó (rpm, rpd, tpm, tpd o ipm para imágenes). No reintentes en bucle.
  • Ante 502, reintenta con espera exponencial (1 s, 2 s, 4 s) hasta tres veces.
  • Guarda X-Request-Id en tus logs: es lo que Saptiva necesita para investigar una llamada.
  • Si aparece X-Model-Deprecated: true, el modelo está en retiro; X-Model-Retires-At trae la fecha. Si usaste un alias, X-Alias-Of indica el modelo real que respondió. Planifica el cambio antes de la fecha.

Siguiente paso