Servir un endpoint compatible con OpenAI
Corre un motor una vez y háblale en una ventana de chat, y tienes un
juguete. Sírvelo por HTTP en la forma que todo el mundo ya habla, y tienes
infraestructura: editores, UIs, agentes y tus propios scripts pueden
conducir todos el mismo modelo local. Esta página levanta un endpoint
local y luego cubre streaming, SDKs, seguridad y la carga en caliente.
Por qué ganó la forma OpenAI
El formato de petición chat-completions — un nombre de modelo, una lista
de mensajes {role, content}, unos pocos controles — se volvió el
estándar de facto porque todo autor de herramientas escribió primero un
cliente para él. Opines lo que opines de la empresa, la forma es
neutral: es solo JSON sobre POST. Consecuencia práctica: cualquier
servidor local que la imite es instantáneamente compatible con una pila
enorme de software existente. Tu elección de motor y tu elección de
cliente se vuelven decisiones independientes (véase motores).
llama-server en un minuto
llama-server -m model.gguf -c 8192 --port 8080
# UI en http://127.0.0.1:8080 — API en /v1/chat/completions
Una petición anotada:
curl http://127.0.0.1:8080/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"model","messages":[{"role":"user","content":"Why run local? One sentence."}],"temperature":0.7,"max_tokens":60}'
model— llama-server sirve lo que hayas lanzado; el campo a menudo se
ignora, pero envía un nombre sensato.messages— toda la conversación, el prompt de sistema primero;
servidor sin estado, tú guardas el historial.max_tokens— limita la respuesta; te protege de generaciones
desbocadas.
La respuesta (recortada) trae la respuesta más la contabilidad de tokens
que querrás para depurar gratis:
{
"choices": [
{ "message": { "role": "assistant", "content": "No accounts, no rate limits, and your data never leaves the machine." } }
],
"usage": { "prompt_tokens": 14, "completion_tokens": 15 }
}
usage es cómo aprendes lo que cuestan de verdad tus prompts en
contexto — compruébalo antes de culpar a un modelo por «olvidar» (véase
tokens).
Streaming
Añade "stream": true y el servidor conmuta a server-sent events:
trozos data: delimitados por saltos de línea, cada uno cargando un
pequeño delta, terminados por un centinela.
data: {"choices":[{"delta":{"content":"No "}}]}
data: {"choices":[{"delta":{"content":"accounts"}}]}
data: [DONE]
Del lado cliente: acumula delta.content hasta la línea [DONE]. El
streaming no hace la generación más rápida — hace tolerable la espera,
que para el UX de chat es lo mismo (véase velocidad).
Ollama: un servicio, dos APIs
La API nativa de Ollama es algo más rica — opciones por petición y
control del ciclo de vida del modelo:
curl http://127.0.0.1:11434/api/chat -d '{"model":"qwen3:8b","messages":[{"role":"user","content":"hi"}],"stream":false,"keep_alive":-1}'
También sirve la ruta compatible con OpenAI en/v1/chat/completions, así que los clientes con forma OpenAI funcionan
contra Ollama sin cambios. Usa la API nativa cuando quieraskeep_alive u opciones de motor por petición; usa /v1 para todo lo
demás.
vLLM para servidores con GPU
vllm serve Qwen/Qwen3-8B --max-model-len 16384 --port 8000
vLLM baja los pesos safetensors, carga una vez, y sirve la misma forma
OpenAI con procesamiento por lotes continuo por debajo — la herramienta
correcta en cuanto aparecen usuarios concurrentes (véase
concurrencia). Quiere VRAM NVIDIA y una GPU de
verdad; no te molestes para un escritorio de un solo usuario.
Apunta los SDK oficiales a localhost
Las librerías oficiales de OpenAI son solo clientes HTTP; cambia la URL
base y el campo de la clave de API pasa a ser decorativo:
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8080/v1", api_key="local")
r = client.chat.completions.create(
model="qwen3-8b",
messages=[{"role": "user", "content": "Why run local?"}],
)
print(r.choices[0].message.content)
import OpenAI from "openai";
const client = new OpenAI({ baseURL: "http://127.0.0.1:11434/v1", apiKey: "ollama" });
const r = await client.chat.completions.create({
model: "qwen3:8b",
messages: [{ role: "user", content: "Why run local?" }],
});
Cualquier cadena sirve para la clave salvo que el servidor tenga una
configurada. Este cambio de URL base es todo el truco detrás de toda
herramienta «funciona con modelos locales».
Qué desbloquea esto
- Editores y UIs de chat — véase UIs e integraciones.
- Tus propias apps: un modelo local detrás de tu propio backend, coste
cero por token. - Tuberías scripteadas con esquema garantizado — véase
salida estructurada. - Bucles de agente que llaman herramientas e iteran — véase
agentes. - El rincón de juegos de este foro: los agentes de
ajedrez y janggi juegan golpeando un
endpoint local de chat-completions exactamente como el curl de arriba.
Cierra la puerta
Un servidor de modelos es un LLM gratis para cualquiera que alcance el
puerto. Los valores por omisión son seguros — llama-server y Ollama se
vinculan a 127.0.0.1 — así que mantenlo así en portátiles. Para exponer
en una LAN: pon una clave de API (--api-key en llama-server y vLLM, y
autenticación en cualquier UI delante), y prefiere un proxy inverso para
TLS. Nunca vincules 0.0.0.0 sin autenticar: cualquiera en la red puede
quemar tu GPU, llenar tu contexto y sonsacar tu instalación.
Mantenlo en caliente
La carga en frío — pesos del disco a la VRAM — cuesta de segundos a
decenas de segundos de TTFT. llama-server y vLLM cargan al arranque y
permanecen residentes, así que solo la primera petición paga. Ollama
descarga tras keep_alive (~5 minutos por omisión): envía"keep_alive": -1 para retener el modelo indefinidamente, o 0 para
liberar VRAM inmediatamente tras una ráfaga. Si tu instalación se siente
«lenta al principio, bien después», eso es una carga en frío, no un
modelo lento — y bajo carga, una tormenta de cargas es un modo de fallo
real (véase concurrencia).
Relacionados: Concurrencia · UIs e integraciones · Motores · Salida estructurada