Una 3060 y cero presupuesto de cloud. Modelos de IA detrás de un solo endpoint: cinco proveedores cloud con nivel gratuito, cinco motores locales que corren en tu propio hardware, el resto por suscripción o pago por token como último recurso.
No en teoría. Ahora mismo. aigate es un stack de Docker detrás de un único puerto de nginx. Generación de texto, generación de imágenes, síntesis de voz, transcripción, búsqueda web, automatización de navegador, almacenamiento de objetos, ejecución agéntica de código, ejecución de código en sandbox y multilenguaje, una pasarela de correo, tu cuenta de Telegram como herramienta MCP, previsión de series temporales, producción de audio, una caja de herramientas de vídeo con lipsync, una cola de trabajos asíncrona y una interfaz web. Sobre hardware que cuesta menos que un solo mes de factura de la API de OpenAI.
Todo esto es compatible con OpenAI. Apunta cualquier cliente a http://localhost:4000 y funciona. Tu código de siempre, tus SDK de siempre, tus herramientas de siempre: todos le hablan como si fuera OpenAI. No lo es. Es tuyo.
Modelos, La Mayoría Gratis
Cinco proveedores, Groq, OpenRouter, HuggingFace, Mistral, Cohere, tienen nivel gratuito. Sin tarjeta para empezar. Pero seamos honestos con lo que significa “gratis”, porque las páginas de marketing no lo van a ser: gratis significa limitado por tasa y con tope, no ilimitado. Groq te da 30 RPM y entre 1K y 14,4K peticiones al día según el modelo. OpenRouter son 50 peticiones al día con 0 dólares, 1K al día si alguna vez metiste 10. HuggingFace te tiende 0,10 dólares al mes en créditos, o sea un presupuesto de evaluación, no un nivel. La prueba de Cohere son 1K llamadas al mes y se acaba rápido. El nivel “Experiment” de Mistral no publica límites exactos en ningún sitio. Cerebras estaba en esta lista. Ya no: en la última auditoría cada modelo suyo respondía “payment required”, así que está en el stack como proveedor de pago con tres modelos, no como nivel gratuito. Esa es la otra cosa de los niveles gratuitos, los retiran, y un stack montado sobre exactamente uno de ellos es un stack que se rompe el día que desaparece.
Así que no, no vas a sostener una empresa con tokens gratis. Pero sí corres tus propias cargas encima, y cuando uno se seca el siguiente toma el relevo. En eso consiste todo.
Otros tres, claudebox, pibox-zai y pibox, son containers de agente. Los dos primeros van por suscripción, que no es lo mismo que gratis: el cupo se cuenta igual, solo que lo pagas al mes en vez de por token. Anthropic y OpenAI están en el stack pero son el último recurso. Cinco motores locales corren en tu propio hardware: sin red, sin límites de tasa, sin coste alguno.
La filosofía de enrutado es simple: nunca pagues un token que podías tener gratis.
De eso se encarga LiteLLM. Pides groq-llama-3.3-70b. Groq te limita. LiteLLM cae en silencio a cerebras-gpt-oss-120b. Cerebras está caído. Cae a mistral-small. Mistral responde. Tú obtienes la respuesta. El cliente nunca supo que pasara nada. Cada modelo tiene su cadena de respaldo: primero cloud gratis, luego suscripción, luego pago por token, luego local. La cadena se reconstruye cada vez que arrancas el stack, filtrada solo a los proveedores que realmente has activado.
groq-llama-3.3-70b → 429 rate limited
↓ fallback
cerebras-gpt-oss-120b → 503 unavailable
↓ fallback
mistral-small → 200 ✓No escribiste lógica de reintentos. No escribiste lógica de respaldo. Mandaste una petición y recibiste una respuesta.
La Arquitectura
nginx :4000 ┌──────────── always on ────────────┐
├─► /claudebox/ → claudebox │ nginx, LiteLLM, PostgreSQL, Redis │
├─► /pibox-zai/ → pibox-zai │ proxq — everything else is opt-in │
├─► /pibox/ → pibox └───────────────────────────────────┘
├─► /stealthy-auto-browse/ → HAProxy → [×5]
├─► /storage/ → hybrids3
├─► /q/ → proxq → LiteLLM (async, returns job ID)
├─► /librechat/ → LibreChat (web UI, LIBRECHAT=1)
├─► /searxng/ → SearXNG (meta-search, SEARXNG=1)
├─► /telethon/ → Telethon (Telegram client, TELETHON=1)
├─► /mailbox/ → mailbox (IMAP+SMTP gateway, MAILBOX=1)
├─► /piston/ → piston (sandboxed code execution, PISTON=1)
├─► /predictalot/ → predictalot (forecasting + tabular ML, PREDICTALOT=1)
├─► /audiolla/ → audiolla (audio production, AUDIOLLA=1)
├─► /flickies/ → flickies (video toolkit, FLICKIES=1)
└─► / → LiteLLM (sync)
├─ Groq (free: 30 RPM, 1K-14.4K RPD per model, GROQ=1)
├─ Cerebras (paid plan, 3 models, CEREBRAS=1)
├─ OpenRouter (free: 50 RPD $0 / 1K RPD with $10+, OPENROUTER=1)
├─ HuggingFace (free: $0.10/mo credits — eval only, HUGGINGFACE=1)
├─ Mistral (free "Experiment" tier, MISTRAL=1)
├─ Cohere (trial: 1K calls/MONTH, COHERE=1)
├─ Ollama (local CPU + CUDA, OLLAMA=1 / OLLAMA_CUDA=1)
├─ Talkies (local ASR + TTS, TALKIES=1 / TALKIES_CUDA=1)
├─ sd.cpp (local image gen, SDCPP=1 / SDCPP_CUDA=1)
├─ vLLM (local text LLM + embeddings, VLLM=1 / VLLM_CUDA=1)
├─ llama.cpp (local GGUF + vision-VLM, LLAMACPP=1 / LLAMACPP_CUDA=1)
├─ claudebox (subscription, CLAUDEBOX=1)
├─ pibox-zai (subscription, PIBOX_ZAI=1)
├─ pibox (points back at this stack's LiteLLM, PIBOX=1)
├─ Anthropic (pay-per-token, ANTHROPIC=1)
└─ OpenAI (pay-per-token, OPENAI=1)
MCP servers (all optional):
├─ stealthy_auto_browse — run_script: multi-step browser automation (BROWSER=1)
├─ hybrids3 — upload, download, list, delete, presign (HYBRIDS3=1)
├─ claudebox — agentic Claude Code via OAuth or API key (CLAUDEBOX=1)
├─ pibox_zai — agentic pi-coding-agent via z.ai/GLM (PIBOX_ZAI=1)
├─ pibox — agentic pi-coding-agent on your own models (PIBOX=1)
├─ telethon — your Telegram account as a tool (TELETHON=1)
├─ mailbox — IMAP+SMTP across N accounts (MAILBOX=1)
├─ predictalot — time-series forecasting (PREDICTALOT=1)
├─ audiolla — audio production, MIR, mastering, MIDI (AUDIOLLA=1)
├─ flickies — lipsync, face restore, ffmpeg ops (FLICKIES=1)
└─ mcp_tools — generate_image + generate_tts + search_web
+ execute_code (auto-enabled)Todo es opt-in. Cambias flags en .env. ¿No tienes clave de Anthropic? No la pongas. ¿Solo tienes CPU? Sáltate los flags de CUDA. El stack se adapta a lo que tengas y reconstruye su config en consecuencia. El núcleo siempre encendido son cinco cosas: nginx, LiteLLM, PostgreSQL, Redis, proxq. Todo lo demás es un flag.
Herramientas Que Puede Llamar Cualquier Modelo
Esto es lo que hace de aigate algo más que un proxy con cadena de respaldo. Un montón entero de servidores MCP, decenas de herramientas. Cualquier modelo con function calling puede invocar cualquiera de ellas por su cuenta. Tú das el prompt. El modelo decide qué herramientas necesita. Tú recibes resultados.
El flujo concreto: mandas un prompt a Groq, gratis, rápido. El modelo decide que tiene que documentarse sobre algo. Llama a search_web, SearXNG consulta Google, Bing y DuckDuckGo a la vez y devuelve resultados. El modelo quiere más detalle sobre uno. Llama a la herramienta de navegador. Una instancia de Camoufox abre un Firefox de verdad, mueve un cursor de ratón de verdad, carga la página, extrae el contenido. El modelo lo lee y decide guardar el resultado. Llama a la herramienta de almacenamiento. hybrids3 escribe el fichero y devuelve una URL pública. El modelo decide que le hace falta una imagen para el informe. Llama a generate_image. stable-diffusion.cpp la renderiza en local, la sube al almacenamiento, devuelve una URL. El modelo te entrega una respuesta estructurada con enlaces a todo lo que produjo. Una sola llamada de API. Cero tokens pagados. El cliente vio una petición y una respuesta.
stealthy_auto_browse
Cinco réplicas de Camoufox detrás de un HAProxy. Camoufox es un Firefox endurecido: entrada real de ratón y teclado a nivel de sistema vía PyAutoGUI, cero exposición de CDP, huellas persistentes por sesión. Pasa Cloudflare. Pasa CreepJS. Pasa BrowserScan. Pasa Pixelscan. No “pasa casi siempre”, pasa de verdad, porque no es detectable como automatización por las vías que esos sistemas comprueban.
Una sola herramienta: run_script. Scripts de varios pasos: navegar, hacer clic, escribir, extraer, capturar pantalla, desplazar, esperar elementos, ejecutar JavaScript. El modelo escribe el script, el navegador lo ejecuta, tú recibes datos estructurados de la página en vivo.
hybrids3
Almacenamiento de objetos compatible con S3 corriendo en local. El bucket uploads es de lectura pública: los ficheros quedan accesibles por URL directa, sin firmar. URL PUT prefirmadas para subidas directas. Caducidad automática. Herramientas para put, get, list, delete, info, presign y listar buckets.
Esto resuelve un problema concreto de los flujos agénticos. Cuando un modelo produce algo grande, un conjunto de datos scrapeado, una imagen generada, un informe renderizado, no lo metes a presión en la ventana de contexto. Lo pones en el almacenamiento, coges una URL, pasas la URL. El siguiente paso puede ir a por ella. Tú también. El contexto se queda limpio.
Tres Agentes de Código: claudebox, pibox-zai y pibox
Tres agentes de código agénticos distintos, no tres copias del mismo. claudebox ejecuta Claude Code con tu suscripción o tu clave de API. pibox-zai ejecuta pi-coding-agent apuntado a z.ai para los modelos GLM (glm-5.3 y glm-5.3-flash). pibox es el mismo agente apuntado de vuelta al LiteLLM de este mismo stack, así que programa sobre lo que ya tengas activado: nombras los modelos con PIBOX_MODELS, eliges uno por defecto con PIBOX_DEFAULT_MODEL. Dos advertencias ahí, y muerden las dos: un modelo que listes tiene que soportar tool calling de verdad o el agente no tiene nada que conducir, y no le devuelvas a un agente su propio modelo en la lista salvo que disfrutes con la recursión. Los tres tienen acceso completo a shell, workspaces persistentes, I/O de ficheros y uso de herramientas, y los tres exponen una API REST, un endpoint compatible con OpenAI y un servidor MCP.
Estás usando Groq por velocidad. Groq se topa con algo que pide trabajo serio de código. Groq llama a la herramienta claudebox. Claude Code lo recoge, consigue un shell, escribe código, lanza tests, devuelve resultados estructurados. De vuelta al contexto de Groq. La orquestación ocurre dentro del bucle de function calling del modelo, y tú no escribiste nada de esa lógica.
piston: Ejecución de Código en Sandbox
Los LLM son catastróficamente malos con la aritmética, con los hashes y con el parseo. Así que no los hagas adivinar. execute_code ejecuta código real en un sandbox de nsjail, con su propio user namespace, chroot, filtro seccomp, límites de cgroup y sin red, y le entrega al modelo un resultado determinista.
La instalación por defecto es Python más Node. Añades Bash, Deno, Go, Rust, TypeScript u otros cuarenta y pico lenguajes vía PISTON_LANGUAGES y reconstruyes. ¿El modelo necesita un SHA-256, una diferencia entre fechas, una regex aplicada a 10K filas? Escribe código, piston lo ejecuta en la celda, y el número vuelve correcto en vez de alucinado.
mcp_tools
generate_image, generate_tts, search_web y execute_code. Se activan solas cuando el backend correspondiente está encendido. Todas devuelven JSON estructurado, y los ficheros generados suben automáticamente a hybrids3 con URL persistentes. Sin bloques de base64 en la ventana de contexto.
La generación de imágenes se enruta por FLUX, DALL-E o stable-diffusion.cpp según lo que esté activado. El TTS va por Kokoro (CPU más CUDA), Qwen3-TTS con clonado de voz, diseño de voz y control de emoción (CUDA), u OpenAI TTS. La búsqueda web consulta SearXNG. La ejecución de código va a piston. Las herramientas descubren dinámicamente desde LiteLLM qué modelos hay, así que siempre reflejan lo que está corriendo de verdad.
telethon
Tu cuenta real de Telegram, como herramienta. No la Bot API, sino MTProto completo, el mismo acceso que tienes desde el móvil. Leer mensajes, enviarlos, listar conversaciones, gestionar grupos, reenviar contenido, editar, borrar, marcar como leído, mandar ficheros. El modelo decide cuándo. El agente actúa como tú.
Un modelo de Groq en nivel gratuito que busca en la web, scrapea una página, genera una imagen y manda el resultado a tus Mensajes guardados: cero tokens pagados, una conversación, varias llamadas a herramientas. O un cron que te resume las últimas 24 horas del grupo del trabajo y te lo manda por privado cada mañana. Tu cuenta, programable.
Movido por telethon-plus. Cambias TELETHON=1, pones TELETHON_API_ID / TELETHON_API_HASH / TELETHON_SESSION en .env. La cadena de sesión es acceso completo a la cuenta, así que trátala como la contraseña que en la práctica es.
mailbox: El Correo Como Herramienta
IMAP más SMTP sin estado, sobre N cuentas, desde una sola config YAML. Bandeja unificada, list/search/CRUD por cuenta, envío por SMTP. API REST más un juego plano de herramientas MCP donde un parámetro mailbox elige la cuenta.
Lo que significa que un modelo puede leerte la bandeja, encontrar la factura, sacarle el total y responder, sin que escribas una sola línea de manejo de IMAP. MAILBOX=1, apuntas MAILBOX_CONFIG a tu YAML, listo.
predictalot: Previsión y ML Tabular
Cinco modelos fundacionales zero-shot para series temporales, chronos-2, timesfm-2.5, moirai-2, toto-1, sundial-base-128m, sobre seis tipos de previsión (univariante, multivariante, covariables pasadas, covariables futuras, muestras y ensembles ponderados por tipo) en /v1/timeseries/<type>/….
Y luego toda una familia hermana en /v1/tabular/*: nueve backends supervisados (lightgbm, xgboost, hist-gbt, random-forest, logistic, mlp, svm-rbf, knn, naive-bayes) y tres meta-aprendices (calibrated, stacking, diversified). 26 herramientas MCP cubren los modelos fundacionales; lo tabular es solo REST. CPU o CUDA.
Zero-shot significa sin entrenamiento previo. Le tiendes una serie y predice. Ya está.
audiolla: Producción de Audio
Este es absurdo en alcance. Separación de pistas (Demucs / UVR). Restauración: quitar reverb, quitar eco, quitar ruido. Masterización vía matchering y cadenas de pedalboard, con presets preparados como master-for-spotify, podcast-cleanup, vocal-cleanup. Análisis MIR: BPM, tonalidad, LUFS, tiempos, onsets, melodía, acordes, segmentos. Transformaciones DSP con sox y ffmpeg. Normalización de loudness. Mejora de voz (DeepFilterNet). VAD (silero). Diarización (pyannote). Embeddings CLAP y clasificación de audio zero-shot. Etiquetado AudioSet. Audio→MIDI vía basic-pitch, más componer / inspeccionar / transformar / renderizar MIDI con fluidsynth.
Más generación text-to-audio, stable-audio-open, musicgen, riffusion, audioldm2, solo en CUDA.
Trabajos asíncronos y webhooks por todas partes. El contrato desde la v1.0 es estricto: cuerpo JSON en cada endpoint de audio, bytes en crudo solo en PUT /v1/files/{path}, y output_path xor output_url obligatorio en cualquier cosa que produzca audio.
flickies: Vídeo y Lipsync
Lipsync vía LatentSync 1.5 (ByteDance, Apache-2.0, ~8 GB de VRAM, el de por defecto en CUDA) y Wav2Lip / Wav2Lip-GAN (LRS2, no comercial, con acceso restringido). Restauración de caras vía GFPGAN v1.4. Operaciones de ffmpeg: recortar, concatenar, transcodificar incluyendo cambios de gif/fps/códec, escalar, mezclar audio, extraer audio, rejilla de miniaturas. Info de ffprobe. Trabajos asíncronos y webhooks. 11 herramientas MCP, el mismo contrato de cuerpo JSON y output_path xor output_url que audiolla.
GFPGAN y LatentSync 1.5 son solo de CUDA. La imagen de CPU sigue haciendo las operaciones de ffmpeg y un Wav2Lip lentísimo.
Inferencia Local: Más Lenta, Pero Tuya
Cinco motores locales. Todos y cada uno tienen modo CPU.
Esta es la parte del “ordenador de pobre”. Tu portátil viejo con 16GB de RAM puede hacer generación de texto, generación de imágenes, transcripción y síntesis de voz. Sin clave de API. Sin red. Sin límite de tasa. Sin factura. Es más lento que el cloud. A veces mucho más lento. Pero es tuyo, es privado y funciona sin conexión.
Ollama: llama3.2:3b, qwen3:4b, smollm2:1.7b, qwen2.5-coder:1.5b, qwen2.5-coder:3b, phi4-mini (razonamiento, contexto de 128K), gemma4:e2b (visión), gemma3:4b (visión), nuextract-v1.5 (extracción de texto estructurado a JSON), dolphin-phi, más dos modelos de embeddings para RAG. Al más pequeño le basta 1GB de RAM. OLLAMA_CUDA=1 añade el lote pesado: qwen3:8b, gemma4:e4b (visión), deepseek-coder-v2:16b (MoE, contexto de 160K), deepseek-r1:8b (razonamiento), qwen3-abliterated:16b (sin censura), gemma4-abliterated:e4b (visión sin censura), qwen2.5-coder:7b, llama3.1:8b. Flash attention, caché KV cuantizada, almacenamiento de modelos compartido con el servicio de CPU, así que sin descargas duplicadas.
talkies: el servicio unificado de ASR más TTS, y el sustituto de lo que antes era Speaches en este stack. La CPU trae ahora 13 modelos: whisper-large-v3 y -turbo, canary-180m-flash, nemotron-3.5-asr-0.6b, cuatro variantes de Sherpa-ONNX Zipformer, Vosk small English, y dos reconocedores de fonemas que te devuelven un flujo crudo de fonos IPA con marca de tiempo por fono en vez de palabras; Kokoro para TTS. En CUDA se llega a 22, sumando parakeet-tdt-0.6b-v3, canary-1b-flash, canary-qwen-2.5b, Chatterbox Turbo y la familia Qwen3-TTS, 0.6B y 1.7B, con clonado de voz, diseño de voz y control de emoción mediante el campo instructions. Chatterbox es el único de todos que marca su salida: la marca de agua neuronal PerTh de ResembleAI, activada por defecto, y TALKIES_CHATTERBOX_WATERMARK=false la apaga para dejar el audio limpio, mientras que Kokoro y Qwen3-TTS no incrustan nada nunca. Endpoints compatibles con OpenAI, así que tus llamadas a Whisper de siempre funcionan sin tocar nada. TALKIES=1 / TALKIES_CUDA=1.
Las incorporaciones de Sherpa y Vosk aterrizan como diez alias nuevos de transcripción: los cinco modelos bajo local-talkies-, y luego los mismos cinco otra vez bajo local-talkies-cuda-. Las builds int8 están cuantizadas (más pequeñas y rápidas, con algo menos de precisión); left-64 frente a left-128 fija la ventana de contexto izquierdo de la atención. Los cinco hacen ASR en vivo de forma nativa sobre el WebSocket de streaming además del POST /v1/audio/transcriptions de siempre, y la imagen de CUDA instala una wheel de Sherpa CUDA de upstream verificada por hash, para que usen de verdad su execution provider de CUDA en lugar de caer en silencio a CPU dentro de un container con GPU.
Una sutileza de respaldo que merece la pena robar: seis cadenas de fallbacks.json listaban antes un modelo talkies hermano en primer lugar, whisper-large-v3 → whisper-large-v3-turbo, y los equivalentes para la variante de CUDA y para las dos entradas de TTS. Eso no puede funcionar nunca. Cada container de talkies sirve un modelo a la vez y desaloja el anterior al admitir, así que un salto a un hermano no encuentra capacidad libre, fuerza un cambio de modelo, y bajo reintentos eso es puro desalojo en bucle. Ahora las cadenas van primero al otro container de talkies, y después salen a los proveedores cloud. Los saltos CPU↔CUDA se quedan, porque esos sí son procesos independientes.
stable-diffusion.cpp: generación de imágenes en local. La CPU corre sd-turbo y sdxl-turbo de serie. SDCPP_CUDA=1 para aceleración por hardware y el juego completo: sd-turbo, sdxl-turbo, sdxl-lightning, flux-schnell, juggernaut-xi. Los modelos se descargan al primer uso y se cachean en local. El endpoint compatible con OpenAI /images/generations hace que tu código de siempre funcione tal cual.
vLLM: LLM de texto en local más embeddings. qwen3-0.6b para generación, nomic-embed-v2 para embeddings. VLLM=1 / VLLM_CUDA=1.
llama.cpp: modelos GGUF y VLM de visión, incluido Surya OCR 2 para comprensión de documentos. LLAMACPP=1 / LLAMACPP_CUDA=1.
Los modelos locales están al final de la cadena de respaldo por defecto. ¿Se cae el cloud? Lo recoge lo local. O los apuntas directamente: "model": "local-ollama-cpu-llama3.2-3b". Cero red. Cero coste. Más lento, pero responde.
Una Sola GPU, Todo
Aquí está el problema de ingeniería: tienes una sola GPU. Ollama quiere VRAM para el LLM. sd.cpp la quiere para generar imágenes. talkies la quiere para transcripción y voz. audiolla la quiere para separar pistas. flickies quiere unos 8GB para LatentSync. Cárgalos todos y te vas a OOM.
El gestor de recursos resuelve esto solo. Un callback de LiteLLM impone exclusión mutua por hardware: un trabajo de CUDA cada vez. Cuando llega una petición de generación de imágenes con un LLM cargado, el gestor toma el semáforo, descarga el LLM y luego deja pasar la generación. Cuando después llega una petición de TTS, descarga primero el generador de imágenes. La misma lógica en CPU.
Cada servicio tiene su propia API de descarga y el gestor las conoce todas: Ollama lleva keep_alive: 0, sd.cpp tiene POST /sdcpp/v1/unload, talkies / vllm-cuda / llamacpp-cuda llevan DELETE /api/ps/{model_id} por modelo o POST /unload para matar lo que haya cargado, y audiolla tiene POST /v1/unload para desalojar de golpe todos los motores cargados.
También hay endpoints para el operador, cuando quieres limpiarlo todo a mano: POST /v1/unload/cuda se reparte en paralelo hacia ollama-cuda, sdcpp-cuda, talkies-cuda, vllm-cuda, llamacpp-cuda, audiolla-cuda y flickies-cuda. POST /v1/unload/cpu hace lo mismo con esos siete en el lado CPU. POST /v1/unload ejecuta ambos en orden y te devuelve un informe por servicio de qué se desalojó realmente.
Tú no gestionas nada de esto. Mandas peticiones. La plataforma hace malabares con la VRAM sola. El único coste es la latencia: la primera petición después de un cambio incluye el tiempo de carga del modelo. Después va rápido, hasta que el timeout de inactividad descarga el modelo para liberar memoria para lo siguiente.
Búsqueda Web
SearXNG en /searxng/. Metabuscador autoalojado: consulta Google, Bing, DuckDuckGo y Wikipedia a la vez. Sin clave de API. Corre entero en local.
Arregla tu secret_key si desplegaste esto pronto. La de SearXNG estaba a fuego en el searxng/settings.yml versionado. Ahora se genera por despliegue y se lee de SEARXNG_SECRET_KEY en .env: ponla con openssl rand -hex 32 cuando actives SEARXNG=1, o SearXNG arranca con el placeholder de upstream. El settings.yml versionado ha desaparecido del todo; los ajustes se renderizan desde una entrada searxng_config del bloque configs:, igual que proxq_config ya sacaba ${REDIS_PASSWORD}. La exposición era limitada, /searxng/ va detrás de la auth de admin de nginx, el container no publica puertos en el host, y limiter: false significaba que la clave no guardaba ningún límite de tasa, pero el valor viejo sigue ahí en el historial de git, y esa parte ya no se des-hace.
La herramienta MCP search_web hace que cualquier modelo con function calling pueda buscar en la web por su cuenta. El modelo decide que tiene que consultar algo, llama a la herramienta, recibe resultados y sigue razonando. Tú no construiste una integración de búsqueda. Activaste SEARXNG=1.
LibreChat: El Del Día a Día
Todo lo de arriba funciona desde la API. Pero para el uso diario está LibreChat en /librechat/.
Todos los modelos en el desplegable. Todas las herramientas MCP conectadas. Eliges modelo y te pones a hablar. El modelo sigue pudiendo invocar por su cuenta el navegador, el almacenamiento, los agentes de código, la generación de imágenes, el TTS y la búsqueda web: todo lo que hay en la API está en la interfaz. El historial de conversaciones va sobre MongoDB. Subida de ficheros. Streaming por WebSocket.
El primer usuario registrado se convierte en admin. Pon LIBRECHAT_ALLOW_REGISTRATION=false después y eres el único dentro.
Lo activas: LIBRECHAT=1 en .env.
Cola Asíncrona
Las peticiones largas de inferencia dan timeout. Pega en /q/ en vez de / y la petición entra en una cola sobre Redis. Recibes un ID de trabajo al instante. La inferencia de verdad corre en segundo plano. Consultas el estado y recoges el resultado cuando esté.
# submit — returns 202 immediately
curl http://localhost:4000/q/v1/chat/completions
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-d '{"model": "cerebras-gpt-oss-120b", "messages": [{"role":"user","content":"write a novel"}]}'
# → {"jobId": "550e8400-e29b-41d4-a716-446655440000"}
# check status
curl http://localhost:4000/q/__jobs/550e8400-e29b-41d4-a716-446655440000
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
# get the result
curl http://localhost:4000/q/__jobs/550e8400-e29b-41d4-a716-446655440000/content
-H "Authorization: Bearer $LITELLM_MASTER_KEY"Concurrencia, retención, timeouts, reintentos y caché de respuestas, todo configurable. Solo las rutas de la API de OpenAI pasan por la cola; los health checks y las peticiones de admin van directas.
Viene Con Su Propio Agent Skill
El repo lleva .agents/skills/aigate/, un agent skill publicado en ClawHub que le enseña a un agente de código cómo manejar el stack. Así que en vez de explicarle tu propia infraestructura a un asistente en cada sesión, instalas el skill y ya se sabe los endpoints, los flags y los contratos de las herramientas.
Seguridad
Los servicios internos, PostgreSQL, MongoDB, Redis, el clúster de navegadores, el backend de almacenamiento, no tienen puertos en el host. Están en redes de Docker aisladas. Nada llega a ellos desde fuera del stack. La única superficie expuesta es nginx en el puerto 4000, y esa pide autenticación por bearer token.
Los containers de aplicación corren con no-new-privileges:true. Dos excepciones, ambas deliberadas y ambas documentadas en el fichero de compose: piston necesita privileged: true porque nsjail tiene que construir user namespaces y chroots en cada ejecución, el aislamiento real vive dentro del subproceso de nsjail, y el container privilegiado es justo lo que nsjail necesita para levantar esa celda. tailscale necesita NET_ADMIN para su dispositivo tun en espacio de usuario. Todo lo demás suelta privilegios. make run valida que las rutas de fichero que haya en .env existan de verdad antes de arrancar, así que nada de volúmenes rotos en silencio.
¿Lo quieres accesible desde fuera sin abrir un puerto en el firewall? CLOUDFLARED=1, o sea Cloudflare Tunnel. Protección DDoS, terminación TLS, sin puertos abiertos, sin IP que escanear. Túnel rápido para una URL *.trycloudflare.com aleatoria, o túnel con nombre para un dominio fijo.
¿No lo quieres público en absoluto, pero sí llegar a él desde el portátil, el móvil u otra máquina? TAILSCALE=1 con TS_AUTHKEY=tskey-auth-... y un TS_HOSTNAME. Un sidecar de Tailscale se une a tu tailnet y ejecuta tailscale serve en modo de reenvío TCP L4 directo a nginx:4000: sin emparejar por cabecera Host, sin configurar FQDN del lado de tailscale, sin autocertificado HTTPS (la terminación TLS, si la quieres, vive en nginx). nginx recibe los bytes originales de la petición tal cual y los enruta por su lógica de vhost y ruta de siempre. Acceso por http://<TS_HOSTNAME>.<tailnet>.ts.net, y aquí el HTTP a secas vale porque WireGuard ya cifra cada byte dentro del tailnet. Funciona con Tailscale alojado o con Headscale autoalojado (usas TS_EXTRA_ARGS=--login-server=...). El estado persiste en .data/tailscale/, así que los reinicios reaprovechan la sesión existente. Combínalo con la auth por bearer token y tienes dos capas de control de acceso completamente independientes.
Eso es el tráfico que entra. El tráfico que sale es otra cosa, y ahora la puedes encender: salida por tailnet para los agentes de código, para que claudebox, pibox-zai y pibox puedan llegar a máquinas de tu tailnet y no solo a internet. Viene como overlay de compose (docker-compose.tailscale.yml) y pide dos valores más, TS_MAGICDNS_SUFFIX (el sufijo MagicDNS de tu tailnet, sacado tal cual de tailscale status) y TS_FALLBACK_DNS (por defecto 1.1.1.1). El segundo existe porque el DNS acaba partido: MagicDNS responde por los nombres del tailnet y devuelve SERVFAIL para todo lo demás, así que a los nombres públicos les hace falta un resolver al que caer.
Cientos de tests. Health checks, enrutado, auth, validación de herramientas MCP, CRUD de almacenamiento, automatización de navegador, ejecuciones agénticas de código, ciclo de vida de trabajos asíncronos, ida y vuelta de TTS/STT local, verificación del gestor de recursos de CUDA, generación local de imágenes, tool calling de punta a punta de LLM a MCP, búsqueda en SearXNG, ida y vuelta de MTProto con Telethon contra una cuenta real. Más seguridad: aislamiento entre tokens, intentos de secuestro de sesión, HTTP request smuggling (CL.TE/TE.CL), smuggling h2c, SSRF vía navegador y vía MCP hacia servicios internos, extracción de claves por prompt injection, path traversal, abuso de presign de S3, XSS almacenado, inyección de nombre de modelo, inyección de cabeceras, aislamiento del socket de Docker. Esta no es la suite de tests de un proyecto de fin de semana. Esto es la paranoia como funcionalidad.
Instalación
git clone https://github.com/psyb0t/aigate && cd aigate
make bootstrap # seeds .env; then edit it: add keys, flip flags
make run-bgCada variable está documentada en .env.example. Activa lo que tengas, ignora lo que no. Tampoco hace falta ya que copies ese fichero a mano: make bootstrap siembra el .env, y cualquier otro target lo siembra primero, así que make run sobre un clon recién hecho simplemente funciona.
Cuando quieras cambiar algo del stack en sí y no un flag, ponlo en docker-compose.override.yml. Esa es la costura soportada ahora: el Makefile arma COMPOSE_FILE con el fichero base, el overlay de tailscale cuando lo has activado, y tu override al final. Edita el compose base directamente y la siguiente actualización se te come los cambios; el override sobrevive.
Si los recursos importan, y en un ordenador normal importan, make limits lee la RAM y la CPU que tienes y escribe límites recomendados para cada servicio. MAXUSE=80 make limits topa el stack entero al 80% de los recursos del sistema si compartes la máquina con otras cargas. Los servicios de CUDA conocen al gestor de recursos, así que el presupuesto cuenta el mayor de ellos, no cada servicio de GPU a plena asignación a la vez.
# free tier, auto-fallback
curl http://localhost:4000/chat/completions
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-d '{"model": "cerebras-gpt-oss-120b", "messages": [{"role":"user","content":"hello"}]}'
# local, no network, no limits
curl http://localhost:4000/chat/completions
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-d '{"model": "local-ollama-cpu-llama3.2-3b", "messages": [{"role":"user","content":"hello"}]}'
# image generation
curl http://localhost:4000/images/generations
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-d '{"model": "hf-flux-schnell", "prompt": "a cat riding a skateboard"}'
# local image generation (no network, no cost)
curl http://localhost:4000/images/generations
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-d '{"model": "local-sdcpp-cpu-sd-turbo", "prompt": "a red panda in a forest", "size": "512x512"}'
# transcription (local, CPU)
curl http://localhost:4000/audio/transcriptions
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-F "model=local-talkies-whisper-large-v3-turbo" -F "[email protected]"
# text-to-speech (local, multiple voices)
curl http://localhost:4000/audio/speech
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-d '{"model": "local-talkies-kokoro-tts", "input": "Hello world", "voice": "af_heart"}'
-o speech.mp3
# web search (no API key, self-hosted)
curl http://localhost:4000/chat/completions
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-d '{"model": "groq-qwen3-32b", "messages": [{"role":"user","content":"search the web for latest rust release notes"}]}'
# async — submit and poll
curl http://localhost:4000/q/v1/chat/completions
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
-d '{"model": "cerebras-gpt-oss-120b", "messages": [{"role":"user","content":"write a novel"}]}'Cinco proveedores con nivel gratuito, cinco motores locales, el resto como respaldo. Más lento en un ordenador normal, pero corre, es privado, y nadie puede echarte de tu propia infraestructura con un límite de tasa.
github.com/psyb0t/aigate
Cómo Instalarlo en Tu Agente
Ese skill ya no es solo para OpenClaw. Todo lo que hay bajo .agents/ está catalogado en un único marketplace, así que son dos comandos:
claude plugin marketplace add psyb0t/agents
claude plugin install aigate@psyb0tCodex usa el mismo marketplace con otro verbo, codex plugin add aigate@psyb0t, porque codex plugin install no existe. Además encuentra el skill él solo en un checkout del repo, ya que escanea .agents/skills/ de forma nativa sin tener nada instalado.