Instalación y tu primer request
Instalación y tu primer request
En el capítulo anterior vimos qué es Bifrost y por qué un AI gateway resuelve el problema de hablar con decenas de proveedores de modelos detrás de una sola puerta. Ahora toca lo divertido: ponerlo en marcha en tu máquina y enviar tu primera petición de chat. La promesa de Bifrost es agresiva (arrancar en menos de un minuto, sin escribir una sola línea de configuración), y en este capítulo vamos a comprobar que esa promesa es real.
Verás dos caminos para levantar el gateway —NPX y Docker—, añadirás tu primera clave de un proveedor (usaremos OpenAI como ejemplo) y harás un curl contra el endpoint compatible con la API de OpenAI. Al terminar tendrás Bifrost corriendo, una respuesta de un modelo real en tu terminal y el log de esa petición visible en la Web UI. No necesitas saber Go ni tocar ningún archivo todavía: este es el modo zero-config, y es el punto de partida perfecto.
¿Qué vamos a montar?
Antes de teclear, conviene tener el mapa mental de lo que ocurre. Tu cliente (un curl, un SDK, un agente) habla con Bifrost en http://localhost:8080. Bifrost recibe la petición en un endpoint compatible con OpenAI, identifica a qué proveedor y modelo va dirigida gracias a la sintaxis provider/model, usa la clave que le diste y reenvía la llamada al proveedor real. La respuesta vuelve por el mismo camino y, de paso, queda registrada para que la veas en la interfaz web.
flowchart LR
A["Cliente<br/>curl / SDK / agente"] -->|"POST /v1/chat/completions<br/>model: openai/gpt-4o-mini"| B["Bifrost Gateway<br/>localhost:8080"]
B -->|"usa OPENAI_API_KEY"| C["OpenAI API"]
C -->|"respuesta"| B
B -->|"chat completion + log"| A
B -.->|"registra la peticion"| D["Web UI<br/>localhost:8080"]
Fíjate en un detalle clave que repetiremos a lo largo del tutorial: el puerto 8080 sirve a la vez la API (en /v1/...) y la Web UI (en la raíz). Misma dirección, dos caras.
Requisitos previos
Bifrost es deliberadamente ligero en dependencias. Para el camino NPX necesitas Node.js 18 o superior (es lo que pide npx). Para el camino Docker solo necesitas Docker instalado. Y para que la primera petición devuelva algo útil, necesitas una clave de API de algún proveedor; en los ejemplos usaremos OPENAI_API_KEY, pero cualquier proveedor soportado sirve.
No hace falta clonar el repositorio ni compilar nada. Bifrost se distribuye como binario empaquetado tanto en npm como en imagen de Docker.
Camino 1: arrancar con NPX
La vía más rápida si ya tienes Node es NPX. Un único comando descarga y ejecuta el gateway:
npx -y @maximhq/bifrost
El flag -y (de npx) evita la pregunta interactiva de confirmación de descarga, así que el comando arranca sin interrupciones. Cuando termine de inicializar, Bifrost queda escuchando en http://localhost:8080.
Flags útiles del gateway
El gateway acepta varios flags para ajustar cómo arranca. Estos son los que vas a usar más a menudo:
# Cambiar el puerto (por defecto 8080)
npx -y @maximhq/bifrost -port 8080
# Escuchar en todas las interfaces (util en contenedores o LAN)
npx -y @maximhq/bifrost -host 0.0.0.0
# Ajustar el nivel de log
npx -y @maximhq/bifrost -log-level info
# Elegir el directorio de datos/configuracion
npx -y @maximhq/bifrost -app-dir ./my-bifrost-data
El flag -app-dir merece atención especial: es el directorio donde Bifrost guarda su estado (incluyendo el config.json si lo hubiera y el almacén por defecto). Apuntar a una carpeta propia te permite tener configuraciones separadas por proyecto. Profundizaremos en el app-dir y el config.json en el capítulo 3.
También puedes fijar la versión del transporte si necesitas reproducibilidad exacta:
npx -y @maximhq/bifrost --transport-version v1.3.9
Un apunte sobre los agentes de CLI
Además de servir requests, Bifrost está pensado para funcionar como gateway de agentes de código (Claude Code, Codex CLI, Gemini CLI, Opencode). La integración no requiere instalar ningún paquete adicional: basta con apuntar cada agente a la base URL del gateway mediante las variables de entorno que ese agente ya entiende. El agente consume el gateway, no lo reemplaza.
Por ejemplo, para que Claude Code envíe sus peticiones a través de Bifrost, defines su base URL y su token de autenticación (en ~/.claude/settings.json o como variables de entorno):
export ANTHROPIC_BASE_URL="http://localhost:8080/anthropic"
export ANTHROPIC_AUTH_TOKEN="tu-virtual-key"
Y requiere un gateway ya corriendo (el que acabas de levantar). Otros agentes siguen el mismo patrón apuntando a su base URL correspondiente (por ejemplo, Codex CLI espera una API base que termine en /v1, como http://localhost:8080/openai/v1).
Para este capítulo nos centramos en el gateway, que es lo que necesitas para hacer requests. Los agentes de CLI y su configuración los retomaremos cuando lleguemos a integraciones.
Camino 2: arrancar con Docker
Si prefieres no depender de Node, o vas directo a pensar en producción, Docker es la opción natural. Primero baja la imagen oficial y luego ejecútala publicando el puerto 8080:
docker pull maximhq/bifrost
docker run -p 8080:8080 maximhq/bifrost
-p 8080:8080 mapea el puerto del contenedor al de tu máquina. Igual que con NPX, la Web UI y la API quedan disponibles en http://localhost:8080.
Persistir los datos con un volumen
El comando anterior funciona, pero cuando el contenedor desaparece se lleva consigo su estado (claves añadidas por la UI, logs, configuración). Para conservarlo entre reinicios, monta un volumen sobre el directorio de datos del contenedor (/app/data):
docker run -p 8080:8080 -v $(pwd)/data:/app/data maximhq/bifrost
Con -v $(pwd)/data:/app/data, todo lo que Bifrost escriba en /app/data aterriza en la carpeta data/ de tu directorio actual. Así puedes parar y volver a levantar el contenedor sin perder nada. Esta es la forma recomendada incluso para desarrollo local, porque te ahorra reconfigurar cada vez.
Equivalencias de flags en Docker
En Docker, los ajustes que en NPX pasabas como flags se controlan con variables de entorno:
docker run \
-e APP_PORT=8080 \
-e APP_HOST=0.0.0.0 \
-e LOG_LEVEL=info \
-e OPENAI_API_KEY="sk-tu-clave-aqui" \
-p 8080:8080 \
-v $(pwd)/data:/app/data \
maximhq/bifrost
Observa que ahí también pasamos OPENAI_API_KEY. Ese es uno de los dos métodos para darle credenciales a Bifrost, que vemos justo ahora.
Añadir tu primera clave de proveedor
Bifrost necesita una clave del proveedor para poder hablar con el modelo real. Tienes dos caminos, y ambos son válidos en zero-config.
Opción A: por variable de entorno
La vía más directa. Exporta la clave antes de arrancar el gateway (o pásala con -e en Docker, como vimos):
export OPENAI_API_KEY="sk-tu-clave-aqui"
npx -y @maximhq/bifrost
Bifrost reconoce la convención env.OPENAI_API_KEY para leer secretos desde el entorno sin escribirlos jamás en disco. Esa es exactamente la sintaxis que verás en el config.json cuando lleguemos a él: el valor de la clave se referencia como "value": "env.OPENAI_API_KEY", de modo que el secreto vive en el entorno y el archivo solo guarda el puntero. Lo desarrollaremos en el capítulo 4.
Opción B: por la Web UI
Si prefieres no tocar la terminal, abre http://localhost:8080 en el navegador. La Web UI te permite añadir proveedores y sus claves desde un formulario, sin reiniciar nada. Este método es cómodo para empezar y para probar varios proveedores rápido; la pega es que las claves quedan en el almacén por defecto de Bifrost (un SQLite local), no en tu entorno. Para equipos y producción, la variable de entorno suele ser preferible. Comparamos los dos enfoques a fondo en el capítulo 3.
flowchart TD
Start["Arranco Bifrost en zero-config"] --> Q{"¿Como doy la clave?"}
Q -->|"Rapido y reproducible"| Env["export OPENAI_API_KEY=...<br/>(o -e en Docker)"]
Q -->|"Sin tocar terminal"| UI["Web UI en localhost:8080<br/>formulario de proveedor"]
Env --> Ready["Gateway listo para requests"]
UI --> Ready
Tu primer request
Con el gateway arriba y la clave configurada, ya puedes enviar tu primera petición. Bifrost expone un endpoint compatible con la API de OpenAI en /v1/chat/completions, así que el curl te resultará familiar si alguna vez llamaste a OpenAI directamente:
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello, Bifrost!"}]
}'
Si todo está en orden, recibirás una respuesta JSON con la estructura típica de un chat completion, donde el texto del modelo aparece dentro de choices[0].message.content.
La sintaxis provider/model, el corazón de Bifrost
Para entrar en héroe, hay que entender el campo model. En lugar de escribir solo gpt-4o-mini, escribimos openai/gpt-4o-mini. Ese prefijo antes de la barra es el proveedor, y lo que va después es el modelo dentro de ese proveedor.
flowchart LR
M["model: openai/gpt-4o-mini"] --> P["openai<br/>(proveedor)"]
M --> N["gpt-4o-mini<br/>(modelo)"]
P --> R["Bifrost enruta al proveedor correcto<br/>con la clave correcta"]
N --> R
Esta convención es lo que permite a Bifrost ser un único punto de entrada para todos tus modelos: cambiar de proveedor es tan simple como cambiar el prefijo. Por ejemplo, para llamar a un modelo de Anthropic en lugar de OpenAI:
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4-5-20250929",
"messages": [{"role": "user", "content": "Hola desde Bifrost"}]
}'
La forma del request no cambia: misma URL, mismas cabeceras, mismo cuerpo. Solo el valor de model decide a dónde va. Esa uniformidad es la base del drop-in replacement que veremos en el capítulo 5.
Verificar que funciona
Hay tres señales de que tu instalación está sana.
1. La respuesta en la terminal. El curl devuelve un JSON con content no vacío. Si quieres aislar solo el texto, puedes encadenar con jq:
curl -s -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o-mini",
"messages": [{"role": "user", "content": "Di hola en una palabra"}]
}' | jq -r '.choices[0].message.content'
2. La Web UI responde. Abre http://localhost:8080 en el navegador. Si ves el dashboard de Bifrost, el servicio está vivo.
3. El log de la petición. Cada request que pasa por Bifrost queda registrado. En la Web UI encontrarás la petición que acabas de hacer, con su proveedor, su modelo y su estado. Ver tu primer curl aparecer en esa lista es la confirmación definitiva de que el gateway está haciendo su trabajo. La observabilidad completa (logs estructurados, Prometheus, OpenTelemetry) la cubriremos en el capítulo 11.
sequenceDiagram
participant T as Terminal (curl)
participant B as Bifrost (localhost:8080)
participant O as OpenAI
participant U as Web UI
T->>B: POST /v1/chat/completions<br/>model: openai/gpt-4o-mini
B->>O: reenvia con OPENAI_API_KEY
O-->>B: chat completion
B-->>T: JSON con choices[0].message.content
B->>U: registra la peticion en el log
Note over U: Abres localhost:8080 y la ves listada
Zero-config vs config.json
Llegados aquí es importante nombrar el modo en el que has estado trabajando. Todo lo anterior ha sido zero-config: arrancaste el gateway sin ningún archivo de configuración, le diste una clave (por entorno o por la UI) e hiciste requests. Cuando no hay config.json, Bifrost crea por defecto un almacén SQLite local y habilita la edición desde la Web UI. Es el modo ideal para empezar, prototipar y aprender.
El otro modo es arrancar con un config.json, un archivo donde declaras de forma explícita tus proveedores, claves, modelos y muchas opciones avanzadas. Un ejemplo mínimo de cómo se ve esa declaración de proveedor:
{
"$schema": "https://www.getbifrost.ai/schema",
"providers": {
"openai": {
"keys": [
{
"name": "openai-key-1",
"value": "env.OPENAI_API_KEY",
"models": ["gpt-4o-mini", "gpt-4o"],
"weight": 1.0
}
]
}
}
}
Fíjate en "value": "env.OPENAI_API_KEY": el archivo nunca contiene el secreto, solo la referencia al entorno. La diferencia práctica entre ambos modos es el control: zero-config prioriza la rapidez y la edición en caliente desde la UI; el config.json prioriza la reproducibilidad y el versionado en git, especialmente cuando combinas con config_store.enabled: false para un modo “file-only” donde la configuración se carga en memoria al arrancar.
No necesitas decidir ahora. Para tu primer request, zero-config es más que suficiente. La estructura completa del config.json —todos sus campos, la interpolación de variables de entorno y cuándo conviene cada modo— es justo el tema del siguiente capítulo.
Resumen
- Bifrost arranca en menos de un minuto con NPX (
npx -y @maximhq/bifrost) o con Docker (docker run -p 8080:8080 maximhq/bifrost), y para persistir datos basta montar un volumen con-v $(pwd)/data:/app/data. - Tanto la API como la Web UI viven en
http://localhost:8080; los flags útiles del gateway por NPX incluyen-port,-host,-log-levely-app-dir, con sus equivalentes Docker como variables de entorno (APP_PORT,APP_HOST,LOG_LEVEL). - La primera clave de proveedor se añade por variable de entorno (
OPENAI_API_KEY, referenciada comoenv.OPENAI_API_KEY) o por la Web UI. - El primer request es un
POSTa/v1/chat/completionscon la sintaxisprovider/model(openai/gpt-4o-mini); cambiar de proveedor es cambiar el prefijo. - Verificas el funcionamiento leyendo la respuesta en la terminal, abriendo la Web UI y viendo el log de tu petición listado en ella.
- Has trabajado en modo zero-config; el modo con
config.jsonaporta reproducibilidad y versionado, y es lo que veremos a continuación.
Siguiente: Configuración: Web UI, config.json y variables de entorno