Saltar al contenido
AI•4 min de lectura

Tu primer modelo local en 10 minutos (Ollama)

Antes de alquilar una sola GPU, vamos a correr un modelo en tu propia máquina. Gratis, sin cuenta, en 10 minutos. El objetivo no es producción: es que entiendas el ciclo completo de request a tokens, que es lo mismo que hará vLLM después con hardware serio.

Ollama es la puerta de entrada estándar a los modelos locales: descarga pesos, los cuantiza y los sirve con una API OpenAI-compatible en localhost:11434. No es para producción, y en el capítulo 4 verás por qué. Es tu laboratorio.

"Ollama... Get up and running with large language models locally." - Source: Ollama en GitHub

Instalar y correr tu primer modelo

# macOS
brew install ollama

# Linux
curl -fsSL https://ollama.com/install.sh | sh

ollama --version

Ahora el primer modelo. La regla de tamaño es simple: el modelo debe caber en la mitad de tu RAM. Empieza por uno diminuto:

# terminal
ollama run qwen2.5:0.5b

Eso descarga ~400 MB y abre un chat en tu terminal. Pregúntale algo, mira la velocidad, y sal con /bye.

El sufijo es la escala: 0.5b = 500 millones de parámetros, 7b = 7.000 millones. Ahora el grande:

# terminal
ollama run qwen2.5:7b

Descarga ~4,7 GB. Los pesos ya vienen cuantizados a 4 bits (formato GGUF), por eso un modelo de 7B cabe en ~5 GB y no en los 14 GB que le tocan en FP16. La matemática de cuantización la hice con números en Cuantización con números.

El mismo idioma del capítulo 1

Ollama ya está sirviendo una API en el puerto 11434. Y no cualquier API: la OpenAI-compatible. Reconoce este comando:

# terminal
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen2.5:7b",
    "messages": [
      { "role": "user", "content": "Explica en una frase que es un token" }
    ],
    "max_tokens": 60
  }'

Mismo endpoint, mismo formato de messages, mismo usage que el curl de OpenRouter del capítulo 1. Cambió el backend y tu cliente no se enteró. Ese desacople es exactamente el que explotaremos con vLLM.

Streaming: ver los tokens llegar

Corre el mismo request con "stream": true y -N (desactiva el buffering de curl):

# terminal
curl -N http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen2.5:7b","messages":[{"role":"user","content":"Cuenta del 1 al 10"}],"stream":true,"max_tokens":60}'

No ves un JSON al final: ves decenas de fragmentos data: {...}, uno por token. Cada fragmento trae un delta con el pedacito nuevo de texto. Eso es lo que hace ChatGPT cuando "escribe". En el capítulo 4 vamos a medir cuándo llega el primero.

Mide tus primeros tiempos

Guardar tiempos en la memoria no sirve. Este script mide TTFT (tiempo hasta el primer token) y tokens/s contra cualquier endpoint OpenAI-compatible:

# measure.py
import json, sys, time
import requests

URL = "http://localhost:11434/v1/chat/completions"
MODEL = sys.argv[1] if len(sys.argv) > 2 else "qwen2.5:7b"
PROMPT = sys.argv[2] if len(sys.argv) > 2 else sys.argv[1]

def measure(prompt: str) -> None:
    start = time.perf_counter()
    ttft = None
    tokens = 0

    with requests.post(URL, json={
        "model": MODEL,
        "messages": [{"role": "user", "content": prompt}],
        "stream": True,
        "max_tokens": 200,
    }, stream=True) as r:
        for line in r.iter_lines():
            if not line or not line.startswith(b"data: "):
                continue
            payload = line[6:]
            if payload == b"[DONE]":
                break
            chunk = json.loads(payload)
            delta = chunk["choices"][0]["delta"].get("content")
            if delta:
                if ttft is None:
                    ttft = time.perf_counter() - start
                tokens += 1

    total = time.perf_counter() - start
    print(f"TTFT: {ttft*1000:6.0f} ms | tokens: {tokens:3d} | tok/s: {tokens/total:6.1f} | total: {total:.2f}s")

if __name__ == "__main__":
    measure(PROMPT)

Nota que cuento fragmentos, no tokens exactos: casi siempre es 1 delta = 1 token, y para comparar modelos es suficiente. Correlo con los dos modelos:

# terminal
pip install requests
python measure.py qwen2.5:0.5b "Explica que es la cuantizacion en 3 frases"
python measure.py qwen2.5:7b  "Explica que es la cuantizacion en 3 frases"

Mis números en un MacBook Pro M4 Max, para que compares contra algo real:

ModeloTTFTDecode
qwen2.5:0.5b~1.000-1.200 ms308-326 tok/s
qwen2.5:7b~2.700-3.200 ms72-79 tok/s
qwen3-coder:30b4.007 ms frío / 34,9 ms caliente91-93 tok/s

Dos lecturas: el decode se vuelve ~4× más lento al multiplicar por 14 los parámetros, y el TTFT depende de si el modelo ya está caliente en memoria (34,9 ms contra 4 segundos). El primer request paga la carga; los siguientes vuelan.

Qué NO esperar de Ollama

Ollama atiende un request a la vez y vive en tu laptop. Para ti solo, perfecto. Para un equipo, no: sin batching, sin gestión de memoria de contexto, sin llaves. Cuando quieras que 10 personas trabajen a la vez, ese es el trabajo de vLLM en una GPU de verdad.

Checkpoint y el error típico

Checkpoint: $0, ~15 minutos. Tienes un modelo corriendo, un streaming entendido y tus primeras 2 mediciones.

El error típico: pedirle a una laptop de 8 GB un modelo de 7B. La RAM se llena, el sistema entra en swap y todo se congela. Respeta la regla de la mitad; si tu máquina es chica, quédate con 0.5b o 3b y sigue con la guía igual.

Si quieres ver el camino local completo (LM Studio, MLX, cuándo vLLM en Mac), lo cubrí en Inferencia local en 2026. Y para no engañarte con benchmarks, medir inferencia sin engañarte.

Siguiente capítulo

Alquilamos tu primera GPU: cuenta RunPod, la L40S correcta (y por qué NO una A100), discos, SSH y la regla de oro para no quemar dinero con el pod encendido.

¿Qué números te dieron tus dos modelos? Déjalos en los comentarios: comparar hardware real es la mejor parte.


> Más posts