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
/infernodedel 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/modelsresponde401con"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:
| Tarea | Modelo | Parámetros |
|---|---|---|
| Clasificar, extraer, reformatear | El más pequeño con json-mode | temperature: 0, max_tokens bajo |
| Responder con documentos | Uno de instrucción de 27B o más | temperature: 0.2 |
| Analizar imágenes o PDF escaneados | Uno con vision | Envía la imagen en content como en OpenAI |
| Búsqueda semántica | Uno de tipo Embeddings | Mismo 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ámetro | Qué hace |
|---|---|
top_k, min_p, repetition_penalty | Controles de muestreo de los modelos locales. |
guard: true | Evalúa la conversación con las guardas de contenido después de responder; el resultado queda en GET /v1/guard/events. |
metadata | Etiquetas 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, leeRetry-After(segundos) oX-RateLimit-Reset-Requests/-Tokensy espera hasta entonces; el cuerpo indica endetails.dimensionqué límite se superó (rpm,rpd,tpm,tpdoipmpara imágenes). No reintentes en bucle. - Ante
502, reintenta con espera exponencial (1 s, 2 s, 4 s) hasta tres veces. - Guarda
X-Request-Iden 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-Attrae la fecha. Si usaste un alias,X-Alias-Ofindica el modelo real que respondió. Planifica el cambio antes de la fecha.