Saltar al contenido
Lección 11 de 12

Despliegue e Inferencia

6 min read

Del Modelo Entrenado a una API en Produccion

Tu modelo esta fine-tuned, evaluado, fusionado y exportado. Ahora necesitas servirlo a los usuarios. El motor de inferencia que elijas determina tu latencia, rendimiento, costo y complejidad operacional. Esta leccion cubre las cuatro rutas principales de despliegue y te ayuda a elegir la correcta para tu caso de uso.

Comparacion de Motores de Inferencia

| Motor | Ideal Para | Rendimiento | Facilidad | GPU Requerida | |-------|-----------|-------------|-----------|--------------| | vLLM | Produccion alto rendimiento | El mas alto | Medio | Si | | TGI (HuggingFace) | Integracion ecosistema HF | Alto | Medio | Si | | Ollama | Desarrollo local / pequena escala | Medio | El mas facil | Opcional | | llama.cpp | Edge / inferencia CPU | Bajo-Medio | Medio | No |

vLLM: Produccion de Alto Rendimiento

vLLM usa PagedAttention y batching continuo para lograr el mayor rendimiento entre los motores de inferencia de codigo abierto. Es la opcion preferida para despliegues en produccion que manejan muchas solicitudes concurrentes.

Instalacion y Servicio Basico

pip install vllm
# Servir tu modelo fine-tuned
vllm serve ./output/merged-model \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 4096 \
    --gpu-memory-utilization 0.90 \
    --dtype auto

Esto inicia un servidor API compatible con OpenAI. Tu codigo existente que llama a GPT-4 puede cambiar a tu modelo fine-tuned solo cambiando la URL base:

import openai

client = openai.OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="not-needed",  # vLLM no requiere autenticacion por defecto
)

response = client.chat.completions.create(
    model="./output/merged-model",
    messages=[
        {"role": "system", "content": "Eres un analista de documentos legales."},
        {"role": "user", "content": "Resume esta clausula del contrato..."},
    ],
    temperature=0.7,
    max_tokens=512,
)

print(response.choices[0].message.content)

Modelos AWQ con vLLM

Para maxima eficiencia, sirve modelos cuantizados con AWQ:

vllm serve ./output/merged-model-awq \
    --quantization awq \
    --max-model-len 4096 \
    --gpu-memory-utilization 0.90

Configuracion Clave de vLLM

vllm serve ./output/merged-model \
    --tensor-parallel-size 2 \        # Dividir entre 2 GPUs
    --max-num-seqs 256 \              # Max secuencias concurrentes
    --max-num-batched-tokens 8192 \   # Max tokens por batch
    --enable-prefix-caching \         # Cachear prefijos comunes
    --gpu-memory-utilization 0.90     # Usar 90% de memoria GPU

Text-Generation-Inference (TGI)

El servidor de inferencia de produccion de Hugging Face. Excelente integracion con el ecosistema HF y despliegue nativo con Docker.

# Usando Docker (recomendado)
docker run --gpus all -p 8080:80 \
    -v ./output/merged-model:/data \
    ghcr.io/huggingface/text-generation-inference:latest \
    --model-id /data \
    --max-input-length 2048 \
    --max-total-tokens 4096 \
    --max-batch-prefill-tokens 4096
# Uso del cliente
import requests

response = requests.post(
    "http://localhost:8080/generate",
    json={
        "inputs": "Resume esta clausula del contrato: ...",
        "parameters": {
            "max_new_tokens": 256,
            "temperature": 0.7,
        }
    }
)
print(response.json()["generated_text"])

Ollama: Despliegue Local y de Pequena Escala

Ollama es la forma mas facil de ejecutar modelos localmente. Maneja la gestion de modelos, cuantizacion y servicio a traves de una CLI simple.

Creando un Modelo Personalizado

# Crear un Modelfile
cat > Modelfile << 'EOF'
FROM ./output/gguf/model-q4_k_m.gguf

TEMPLATE """{{ if .System }}<|start_header_id|>system<|end_header_id|>

{{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|>

{{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|>

{{ .Response }}<|eot_id|>"""

SYSTEM "Eres un analista de documentos legales especializado en revision de contratos."

PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER stop "<|eot_id|>"
EOF

# Crear el modelo
ollama create legal-assistant -f Modelfile

# Ejecutarlo
ollama run legal-assistant "Resume esta clausula de NDA..."

API de Ollama

Ollama expone una API REST en el puerto 11434:

import requests

response = requests.post(
    "http://localhost:11434/api/chat",
    json={
        "model": "legal-assistant",
        "messages": [
            {"role": "user", "content": "Resume esta clausula..."}
        ],
        "stream": False,
    }
)
print(response.json()["message"]["content"])

Endpoint Compatible con OpenAI

Ollama tambien proporciona una API compatible con OpenAI:

import openai

client = openai.OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama",
)

response = client.chat.completions.create(
    model="legal-assistant",
    messages=[{"role": "user", "content": "Analiza este contrato..."}],
)

llama.cpp: Inferencia Edge y CPU

Para entornos sin GPUs o para despliegue en edge:

# Ejecutar el modelo GGUF directamente
./llama-cli -m model-q4_k_m.gguf \
    -p "Resume esta clausula legal:" \
    -n 256 \
    --temp 0.7 \
    -ngl 0  # 0 = solo CPU, aumentar para capas en GPU

Para una configuracion de servidor:

./llama-server -m model-q4_k_m.gguf \
    --host 0.0.0.0 \
    --port 8080 \
    -ngl 35 \
    -c 4096

Construyendo un Wrapper con FastAPI

Para logica de API personalizada, envuelve tu motor de inferencia en una aplicacion FastAPI:

from fastapi import FastAPI
from pydantic import BaseModel
import openai

app = FastAPI()

# Conectar a tu backend de inferencia (vLLM, Ollama, etc.)
client = openai.OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="not-needed",
)

class ChatRequest(BaseModel):
    message: str
    system_prompt: str = "Eres un asistente legal util."
    temperature: float = 0.7
    max_tokens: int = 512

class ChatResponse(BaseModel):
    response: str
    model: str
    tokens_used: int

@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    response = client.chat.completions.create(
        model="legal-assistant",
        messages=[
            {"role": "system", "content": request.system_prompt},
            {"role": "user", "content": request.message},
        ],
        temperature=request.temperature,
        max_tokens=request.max_tokens,
    )

    return ChatResponse(
        response=response.choices[0].message.content,
        model=response.model,
        tokens_used=response.usage.total_tokens,
    )
uvicorn api:app --host 0.0.0.0 --port 3000

Cuantizacion para Produccion

Elegir la cuantizacion correcta para despliegue:

  • GPU con VRAM abundante: Usa AWQ 4-bit con vLLM. Mejor rendimiento.
  • GPU con VRAM limitada: Usa GGUF Q4_K_M con Ollama o llama.cpp con descarga a GPU.
  • Solo CPU: Usa GGUF Q4_K_M con llama.cpp. Mas lento pero funcional.
  • Dispositivos edge: Usa GGUF Q4_0 o Q3_K_S para tamano minimo.

Monitoreando Latencia y Rendimiento

Rastrea estas metricas de produccion:

import time
import statistics

latencies = []

for prompt in test_prompts:
    start = time.time()
    response = client.chat.completions.create(
        model="legal-assistant",
        messages=[{"role": "user", "content": prompt}],
        max_tokens=256,
    )
    latency = time.time() - start
    latencies.append(latency)

print(f"Latencia mediana: {statistics.median(latencies):.2f}s")
print(f"Latencia P95: {sorted(latencies)[int(len(latencies)*0.95)]:.2f}s")
print(f"Rendimiento: {len(latencies)/sum(latencies):.1f} solicitudes/seg")

Optimizacion de Costos

Estrategias clave para reducir costos de inferencia:

  • Cuantiza agresivamente. Q4_K_M usualmente es suficiente y reduce memoria en 75%.
  • Usa system prompts mas cortos. El fine-tuning incorpora el comportamiento, asi que necesitas menos tokens de prompt.
  • Agrupa solicitudes. El batching continuo de vLLM lo maneja automaticamente.
  • Cachea prefijos comunes. El caching de prefijos de vLLM evita recomputar system prompts compartidos.
  • Dimensiona correctamente tu GPU. Una A10G (24GB, ~$0.75/hr en AWS) maneja un modelo de 7B en Q4 con espacio de sobra.
  • Usa instancias spot. Para cargas de trabajo no criticas en latencia, las instancias spot reducen costos en 60-70%.

En la leccion final, unimos todo en un proyecto capstone completo — desde la creacion del dataset hasta una API desplegada.