ES ▾
NSFW Video Generator

API sin censura para pipelines de video para adultos

LLMs gratuitos para Python: modelos locales frente a una API alojada

Los LLMs gratuitos para Python se dividen en dos tipos: modelos de pesos abiertos que ejecutas en tu propia máquina, y endpoints alojados que cuestan unos céntimos. Esta guía los compara y te ofrece código funcional para la ruta alojada.

Actualizado

Ilustración isométrica de una máquina local conectada a un clúster de servidores alojados, comparando LLMs locales y alojados

Puntos clave

  1. Los modelos locales de pesos abiertos no cuestan nada por token pero requieren memoria, tiempo de configuración y mantenimiento.
  2. La API alojada es compatible con OpenAI: instala el paquete openai, configura la URL base y usa el ID de modelo uncensored.
  3. El streaming, las llamadas a funciones y el modo JSON funcionan a través de la llamada estándar de chat completions.
  4. Una clave de prueba otorga $0.50 de crédito durante 7 días, con 2 solicitudes concurrentes y 60 solicitudes por minuto.

Dos formas de integrar un LLM gratuito en un script de Python

Cuando la gente busca llms gratuitos para python, generalmente se refiere a una de dos cosas. La primera es un modelo de pesos abiertos que descargas y ejecutas tú mismo, usando algo como Ollama, llama.cpp o la biblioteca transformers de Hugging Face. La segunda es un endpoint alojado que cuesta tan poco, o viene con suficiente crédito de prueba, que parece gratuito para un prototipo. Ambas son legítimas y se adaptan a diferentes tareas.

Ejecutar localmente significa no pagar por token y que tus datos no salgan de tu máquina. También significa que necesitas suficiente RAM o memoria de GPU para el modelo que elijas, esperas a que se descarguen los archivos y los modelos pequeños que caben en un portátil responden peor que los grandes. Una API alojada elimina la necesidad de hardware, pero pagas por token una vez que se agota la prueba. Esta página cubre ambos honestamente y luego muestra el código de Python para la opción alojada en este sitio, que es compatible con OpenAI y funciona con el paquete estándar openai.

Modelos locales y API alojada lado a lado

PreguntaEjecútalo tú mismoAPI alojada prepago
Costo por tokenNinguno, pero pagas por hardware y electricidad$0,15 por 1M de entrada, $0,50 por 1M de salida
Tiempo de configuraciónInstala el entorno de ejecución, descarga los pesos y ajusta la configuraciónInstala un paquete, pega una clave
Longitud del contextoLimitado por tu memoria100.000 tokens, prompt más completación
ConcurrenciaLo que tu máquina pueda manejar8 peticiones a la vez con una clave completa, 2 con una clave de prueba
RechazosDepende de los pesos que elijasAjustado para responder sin rechazos de contenido para uso adulto legal
Uso sin conexiónSíNo

Si tienes una GPU capaz y tu trabajo es privado o sin conexión, lo local es una buena solución y puedes dejar de leer aquí. Si quieres un modelo más grande sin poseer la máquina, o quieres que tu script se comporte igual en un portátil, un servidor y un runner de CI, la ruta alojada es más sencilla. Muchos proyectos usan ambos: un modelo local pequeño durante el desarrollo y el alojado en producción, cambiando solo la URL base.

Configura el endpoint alojado en cinco minutos

Primero necesitas una clave. Regístrate con Google o con un correo electrónico y contraseña, luego reclama los $0.50 de crédito de prueba con un clic en la página de claves de API. La prueba es válida por 7 días, una por persona y no requiere pago. Luego instala el SDK y mantén la clave fuera de tu código fuente.

pip install openai
export NOTRACK_API_KEY="sk-your-key-here"

El cliente necesita dos cambios respecto a una configuración estándar de OpenAI: la URL base y la clave. El ID del modelo es uncensored y solo se ofrece un modelo.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.nsfwvideogenerator.cc/v1",
    api_key=os.environ["NOTRACK_API_KEY"],
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "You are a concise writing assistant."},
        {"role": "user", "content": "Give me three title ideas for a noir short story."},
    ],
    temperature=0.8,
)

print(resp.choices[0].message.content)
print(resp.usage)

La autenticación es un encabezado estándar Authorization: Bearer, que el SDK añade por ti. Existen dos métodos: POST /v1/chat/completions y GET /v1/models. Puedes confirmar la conexión con client.models.list(), que devuelve el ID del modelo disponible. La lista completa de parámetros está en la página de documentación.

Respuestas en streaming

Para cualquier salida visible, activa stream=True e itera sobre los chunks al llegar los eventos enviados por el servidor. El uso se reporta al final del stream, así que puedes registrar los conteos de tokens.

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Write a four-line poem about rain on a tin roof."}],
    stream=True,
)

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    usage = getattr(chunk, "usage", None)
    if usage:
        print("\n", usage)

Un detalle que suele sorprender: una petición en streaming mantiene su slot de concurrencia hasta que el stream termina. Con una clave de prueba de 2 slots, dos streams abiertos significan que una tercera llamada obtendrá un 429 con el código concurrency. Siempre consume o cierra el stream.

Llamadas a herramientas y modo JSON

El endpoint soporta tools, tool_choice, tool_calls en streaming y resultados devueltos como role: "tool". Aquí tienes un ciclo de ida y vuelta completo con una función.

import json

tools = [{
    "type": "function",
    "function": {
        "name": "word_count",
        "description": "Count the words in a piece of text.",
        "parameters": {
            "type": "object",
            "properties": {"text": {"type": "string"}},
            "required": ["text"],
        },
    },
}]

messages = [{"role": "user", "content": "How many words are in: the quick brown fox jumps"}]
first = client.chat.completions.create(
    model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = first.choices[0].message

if msg.tool_calls:
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = len(args["text"].split())
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": str(result),
        })
    final = client.chat.completions.create(model="uncensored", messages=messages, tools=tools)
    print(final.choices[0].message.content)

Analiza siempre arguments de forma defensiva; el modelo lo devuelve como una cadena JSON y cualquier modelo puede producir ocasionalmente uno mal formado. Para salida estructurada sin herramientas, usa el modo JSON.

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "Reply with a JSON object with keys title and tags (list of strings)."},
        {"role": "user", "content": "Describe a lighthouse keeper's diary."},
    ],
    response_format={"type": "json_object"},
    temperature=0.2,
)
data = json.loads(resp.choices[0].message.content)
print(data["title"], data["tags"])

Menciona la palabra JSON y nombra las claves en tu prompt, y mantén la temperatura baja. Envuelve json.loads en un bloque try para código de producción.

Límites de peticiones, errores y reintentos

Una clave completa permite 8 solicitudes concurrentes y 300 solicitudes por minuto. Una clave de prueba permite 2 concurrentes y 60 por minuto. Si excedes, obtienes HTTP 429 con código rate_limited (demasiadas por minuto) o concurrency (demasiadas a la vez). En sobrecarga temporal, la API devuelve 429 con cabecera Retry-After: 5. El SDK reintenta algunos errores; para scripts con fan-out, un wrapper explícito es más claro.

import time
from concurrent.futures import ThreadPoolExecutor
from openai import RateLimitError

def ask(prompt, tries=4):
    for attempt in range(tries):
        try:
            r = client.chat.completions.create(
                model="uncensored",
                messages=[{"role": "user", "content": prompt}],
                max_tokens=300,
            )
            return r.choices[0].message.content
        except RateLimitError:
            time.sleep(5 * (attempt + 1))
    raise RuntimeError("still rate limited")

prompts = [f"Summarize idea number {i} in one sentence." for i in range(20)]
with ThreadPoolExecutor(max_workers=2) as pool:   # 8 on a full key
    results = list(pool.map(ask, prompts))

Ajustar max_workers al límite de concurrencia de tu clave evita la mayoría de los 429s antes de que ocurran. Cada respuesta también incluye X-Request-Id, X-Balance-USD y dos encabezados de límite de tasa, que puedes leer a través de client.chat.completions.with_raw_response.create(...) cuando los necesites para depuración o soporte.

Cómo elegir entre local y alojado

Omite la ideología y responde cuatro preguntas sobre tu proyecto.

  1. ¿Los datos deben permanecer en tu máquina? Si un contrato o un hábito lo exige, ejecútalo localmente. Los prompts alojados no se usan para entrenamiento aquí, pero sí viajan por la red.
  2. ¿Cuánta memoria tienes? El tamaño del modelo determina la calidad. Un portátil sin GPU dedicada te limita a modelos pequeños y las respuestas lo reflejarán. Un modelo alojado te da uno grande con una ventana de contexto de 100,000 tokens, difícil de igualar en casa.
  3. ¿Cuántas peticiones enviarás? Unas pocas cientos por semana es trivial en ambos lados. Cientos de miles al mes convierten la factura alojada en un número real, y una máquina local empieza a parecer atractiva si está inactiva de otra manera. Calcula la suma: 100,000 peticiones de 1,000 tokens de entrada y 500 de salida cuestan 100,000 x $0.0004 = $40.
  4. ¿Necesitas que las negativas se manejen de una manera específica? Muchos modelos de pesos abiertos vienen con comportamiento de negativa incorporado, y otros están ajustados para eliminarlo. El modelo alojado aquí está ajustado para responder sin negativas de contenido para uso adulto legal, así que no necesitas buscar los pesos correctos.

Si tus respuestas apuntan en ambas direcciones, empieza con la opción alojada durante la primera semana. La prueba no cuesta nada y aprenderás qué necesitan tus prompts antes de comprar hardware o descargar otro archivo de varios gigabytes.

Errores comunes en scripts de Python

La mayoría de los problemas que encuentran las personas son pequeños y solucionables.

  • URL base incorrecta. Debe terminar en /v1. La falta de sufijo devuelve un 404, no un mensaje útil. Imprime client.base_url si tienes dudas.
  • Clave en el código. Léela de una variable de entorno y añade tu archivo .env a .gitignore.
  • Nombre de modelo incorrecto. El único ID de modelo es uncensored. Los nombres de otros proveedores no funcionan; cámbialos al portar código.
  • Bucles sin límite. Un bucle de llamadas a herramientas que nunca termina es un error costoso. Límita a, por ejemplo, cinco rondas.
  • Ignorar el presupuesto de contexto. El prompt y la completación comparten los 100,000 tokens. Si añades cada turno para siempre, eventualmente alcanzarás el límite. Recorta o resume mensajes antiguos.
  • Asume que JSON es siempre válido. Incluso en modo JSON, verifica las claves que necesitas antes de usarlas.

Cuando algo se ve mal en el lado del servidor, cita el valor de X-Request-Id de la respuesta cuando escribas a support. Esto permite a los operadores encontrar tu llamada exacta.

Lo que cuesta la opción alojada para Python

Un script típico con 1.000 tokens de entrada y 500 de salida cuesta $0,00015 más $0,00025, es decir, $0,0004. El crédito de prueba de $0,50 cubre aproximadamente 1.250. Una recarga de $20, el mínimo, cubre 50.000. El crédito no caduca, las peticiones fallidas o rechazadas no se cobran y los prompts no se usan para entrenamiento. Las recargas van hasta $500 con un bono a partir de $50, y el pago es en cripto, USDT en TRC20 o USDC en Base. Consulta la página de precios para ver los detalles.

Es solo texto: sin imágenes, audio, video, embeddings ni fine-tuning. Y la regla estricta es que no hay contenido sexual con menores. Para un proyecto en Python que necesite generación de texto con menos rechazos, esa es toda la superficie.

Preguntas y respuestas

¿Qué paquete de Python necesito?

El paquete oficial openai. Establece base_url en https://api.nsfwvideogenerator.cc/v1, pasa tu clave como api_key y usa el ID de modelo uncensored.

¿Puedo usar LangChain u otros frameworks?

Cualquier cliente que te permita configurar una URL base compatible con OpenAI y una clave debería funcionar, ya que la API sigue el formato de chat completions. Configura la URL base y usa uncensored como nombre del modelo.

¿Son los modelos locales gratuitos tan buenos como uno alojado?

Depende del modelo y de tu hardware. Los modelos que caben en un portátil suelen ser más pequeños y menos potentes que un modelo alojado grande, pero no cuestan nada por token y funcionan sin conexión.

¿Cómo evito los errores 429 en Python?

Mantén los hilos de trabajo en o por debajo de tu límite de concurrencia (2 en una trial key, 8 en una clave completa) y reintenta después de una breve pausa cuando recibas rate_limited, concurrencia o una respuesta Retry-After: 5.

Tu clave está a un formulario de distancia

Crea una cuenta, copia la clave, cambia la URL base. Esa es toda la configuración.