laptop_mac macOS Sonoma
Intermediate
schedule 8 min read
by Alex Rivera • May 14, 2024
Step 1 ¿Qué es MLX y Por Qué es Relevante?
Si alguna vez has ejecutado un modelo de lenguaje de gran escala en un Mac y has observado cómo el ventilador del CPU se dispara mientras tu GPU permanece inactiva, ya entiendes el problema que MLX fue diseñado para resolver.
MLX es un framework de arrays de código abierto desarrollado por el equipo de investigación en machine learning de Apple, lanzado a finales de 2023. En su núcleo, MLX fue diseñado con un único propósito: hacer que el machine learning en Apple Silicon sea rápido. No simplemente "aceptablemente" rápido — genuinamente competitivo con estaciones de trabajo GPU dedicadas para cargas de trabajo de inferencia.
La Ventaja de la Memoria Unificada
La clave arquitectónica detrás de MLX es la arquitectura de memoria unificada (UMA) de Apple Silicon. En configuraciones de cómputo tradicionales, el CPU y el GPU mantienen bancos de memoria separados. Los datos deben copiarse explícitamente entre ellos — un cuello de botella que consume tanto tiempo como energía.
Apple Silicon elimina esto por completo:
Terminal
Traditional Architecture:
┌──────────┐ PCIe Bus ┌──────────┐
│ CPU RAM │ ◄────────────► │ GPU RAM │
│ (DDR5) │ ~50 GB/s │ (GDDR6) │
└──────────┘ └──────────┘
Apple Silicon (M-Series):
┌─────────────────────────────────────┐
│ Unified Memory Pool │
│ ┌──────────┐ ┌─────────────┐ │
│ │ CPU │ │ GPU Cores │ │
│ │ Cores │ │ (up to 76) │ │
│ └──────────┘ └─────────────┘ │
│ ~400 GB/s bandwidth │
└─────────────────────────────────────┘
MLX fue construido desde cero para explotar esta topología. Los tensores residen en un único espacio de direcciones accesible simultáneamente por cada unidad de cómputo — núcleos de CPU, núcleos de GPU y el Neural Engine — sin ningún costo adicional por copias.
Por Qué Esto Importa en la Inferencia con LLMs
Ejecutar un modelo de lenguaje de gran escala es fundamentalmente un problema de ancho de banda de memoria, no un problema de cómputo. El paso forward de un transformer tiene como cuello de botella la velocidad con la que se pueden cargar los pesos desde la memoria hacia las unidades de cómputo, no el conteo bruto de FLOPs.
| Hardware |
Ancho de Banda de Memoria |
TOPS Pico |
| MacBook Pro M4 Max |
~546 GB/s |
38.4 |
| RTX 4090 (discreta) |
1,008 GB/s |
165.6 |
| MacBook Pro M3 Pro |
~153 GB/s |
18 |
| MacBook Air M2 |
~100 GB/s |
15.8 |
Lo que la tabla anterior no captura es que una RTX 4090 requiere un sistema de escritorio con un TDP de 450W. Un MacBook Pro M4 Max consume aproximadamente 60W bajo carga total de ML. La historia de rendimiento por vatio es extraordinaria.
MLX vs. Las Alternativas
Antes de MLX, la solución dominante para ejecutar LLMs localmente en Mac era llama.cpp — una heroica implementación en C++ que ajustaba a mano kernels Metal y operaciones vectoriales de CPU. Funciona bien, pero es fundamentalmente una solución alternativa construida sobre hardware para el que no fue diseñada.
MLX, en contraste, fue diseñado por las mismas personas que diseñaron el hardware. Los ingenieros de Apple escribieron MLX con pleno conocimiento del subsistema de memoria de la serie M, la jerarquía de caché y la microarquitectura GPU. El resultado es un framework donde operaciones como matmul, quantized_matmul y los kernels de atención son ciudadanos de primera clase con compute shaders nativos de Metal, no elementos de segunda categoría.
Decisiones arquitectónicas adicionales que hacen a MLX excepcional:
- Evaluación diferida (lazy evaluation): Los cómputos no se ejecutan hasta que los resultados son explícitamente necesarios, habilitando fusión automática de kernels y optimización del grafo.
- Diferenciación automática: Soporte completo tanto para diferenciación en modo forward como reverse, haciendo a MLX apto para fine-tuning, no solo inferencia.
- API Pythónica: La interfaz es deliberadamente compatible con NumPy, reduciendo drásticamente la curva de aprendizaje para los profesionales de ML.
- Ecosistema
mlx-lm: Una biblioteca de alto nivel construida sobre MLX, específicamente para inferencia de modelos de lenguaje, cuantización y fine-tuning con LoRA.
La conclusión: Si posees hardware Apple Silicon y no estás usando MLX para inferencia local de IA, estás dejando sobre la mesa una cantidad sustancial de rendimiento. El resto de esta guía te mostrará exactamente cómo capturarlo.
Step 2 Prerrequisitos y Configuración del Entorno Python
Antes de adentrarte en MLX, asegúrate de que tu hardware y tu stack de software cumplan con los requisitos mínimos. MLX es exclusivo de Apple Silicon — esto es innegociable. El framework está arquitectónicamente diseñado desde cero para explotar la arquitectura de memoria unificada y el Neural Engine presentes únicamente en los chips de la serie M.
Requisitos de Hardware
| Componente |
Mínimo |
Recomendado |
| Chip |
Apple M1 |
Apple M2 Pro / M3 Max |
| RAM |
8 GB de memoria unificada |
32 GB+ de memoria unificada |
| Almacenamiento |
20 GB libres |
50 GB+ libres (para modelos) |
| macOS |
Ventura 13.5 |
Sonoma 14.x o posterior |
⚠️ Importante: MLX no se ejecutará en Macs basados en Intel. Si intentas la instalación en un Mac con x86_64, el paquete se instalará pero el backend Metal fallará al inicializarse en tiempo de ejecución.
Verificando tu Silicon
Antes de tocar un solo gestor de paquetes, confirma que estás en Apple Silicon:
Salida esperada:
También puedes obtener información detallada del chip:
Terminal
system_profiler SPHardwareDataType | grep "Chip"
Requisitos de Versión de Python
MLX requiere Python 3.9 o posterior. Python 3.11 es actualmente el punto óptimo — ofrece el mejor rendimiento con la menor sobrecarga del intérprete en Apple Silicon, y todas las dependencias principales de MLX mantienen wheels estables para esta versión.
Terminal
python3 --version
# Python 3.11.x preferred
Configurando un Entorno Virtual Dedicado
Nunca instales MLX en tu Python del sistema. Los conflictos de dependencias con el Python incluido en macOS pueden causar fallos sutiles y desesperantes. Utiliza un entorno virtual limpio.
Opción A: Usando venv (Ligero, Integrado)
Terminal
# Create the environment
python3.11 -m venv ~/envs/mlx-env
# Activate it
source ~/envs/mlx-env/bin/activate
# Confirm the Python path
which python
# ~/envs/mlx-env/bin/python
Opción B: Usando conda / miniforge (Recomendado para Flujos de Trabajo de ML)
Miniforge incluye conda nativo para ARM y es la opción preferida para el desarrollo serio de ML en Apple Silicon:
Terminal
# Install Miniforge (if not already installed)
brew install miniforge
# Create a dedicated MLX conda environment
conda create -n mlx-env python=3.11 -y
# Activate
conda activate mlx-env
Consejo Pro: Usa conda-forge como tu canal principal. Proporciona builds nativos para ARM64 de la mayoría de los paquetes de cómputo científico, evitando la sobrecarga de traducción de Rosetta 2 que puede degradar el rendimiento silenciosamente.
Actualizando pip y las Herramientas Principales
Una vez dentro de tu entorno activado, actualiza el toolchain base antes de instalar cualquier paquete de ML:
Terminal
pip install --upgrade pip setuptools wheel
Esto es particularmente importante porque MLX ocasionalmente distribuye wheels binarias que requieren una versión reciente de pip (≥23.x) para resolver correctamente la etiqueta de plataforma arm64.
MLX depende de la API GPU Metal de Apple y del framework Accelerate para operaciones BLAS. Estos vienen incluidos con macOS y no requieren instalación adicional, pero puedes verificar que Metal sea accesible vía Python:
Terminal
python3 -c "import subprocess; subprocess.run(['system_profiler', 'SPDisplaysDataType'])"
Alternativamente, después de instalar MLX en la siguiente sección, el siguiente one-liner confirmará que el backend Metal está activo:
Terminal
import mlx.core as mx
print(mx.default_device()) # Device(gpu, 0) — confirms Metal backend
Si ves Device(cpu, 0), tus drivers de Metal no están siendo detectados correctamente — esto típicamente indica una incompatibilidad de versión de macOS o una instalación corrupta de Xcode Command Line Tools.
Varias dependencias de MLX compilan extensiones nativas en tiempo de instalación. Asegúrate de que las Xcode Command Line Tools estén presentes:
Verifica la instalación:
Terminal
xcode-select -p
# /Library/Developer/CommandLineTools
Con tu entorno limpio, Python fijado a 3.11, Metal confirmado y pip actualizado, estás listo para instalar MLX.
Step 3 Paso 1: Instalando MLX y MLX-LM
Con tu entorno Python correctamente configurado, es momento de instalar las bibliotecas principales. MLX se distribuye como un paquete Python estándar, pero hay algunos matices que vale la pena entender antes de ejecutar pip install a ciegas y terminar con un entorno roto.
Estructura de Paquetes Principal
El ecosistema MLX de Apple está dividido en varios paquetes específicos. Para inferencia con LLMs, necesitas dos componentes principales:
| Paquete |
Propósito |
mlx |
Framework principal de cómputo de arrays (operaciones de memoria unificada GPU/CPU) |
mlx-lm |
Interfaz de alto nivel para LLMs — generación, cuantización, fine-tuning |
huggingface-hub |
Descarga de modelos y gestión de caché |
transformers |
Soporte de tokenizadores (incorporado como dependencia) |
El paquete mlx-lm no instala automáticamente mlx en la versión exacta con la que fue probado, por lo que fijar versiones es importante. Más sobre esto a continuación.
Instalación
Activa primero tu entorno virtual. Si omitiste la sección de Prerrequisitos, el requisito mínimo es Python 3.9+ en un Mac con Apple Silicon (serie M1/M2/M3/M4). MLX no se ejecutará en Macs Intel — el framework está arquitectónicamente acoplado a la Arquitectura de Memoria Unificada.
Terminal
# Upgrade pip first — older pip versions mishandle Apple's binary wheels
pip install --upgrade pip
# Install the core MLX framework
pip install mlx
# Install the LLM interface layer
pip install mlx-lm
Para usuarios que deseen los builds nightly de última generación (útil para probar soporte de modelos aún no lanzados):
Terminal
pip install mlx-nightly mlx-lm
⚠️ No mezcles mlx estable con mlx-nightly. La ABI entre ambos es incompatible y producirá errores de importación crípticos en tiempo de ejecución.
Verificando la Instalación
Ejecuta este bloque de verificación inmediatamente después de instalar. Si alguno de estos falla, tu entorno tiene problemas que se acumularán en errores más difíciles de depurar posteriormente.
Terminal
# verify_mlx.py
import mlx.core as mx
import mlx_lm
# Check MLX version
print(f"MLX version: {mx.__version__}")
# Confirm we're targeting the GPU (not CPU fallback)
print(f"Default device: {mx.default_device()}")
# Confirm mlx-lm loaded
print(f"mlx-lm version: {mlx_lm.__version__}")
# Quick tensor operation on GPU
a = mx.array([1.0, 2.0, 3.0])
b = mx.array([4.0, 5.0, 6.0])
print(f"Dot product (GPU): {mx.inner(a, b).item()}")
Salida esperada:
Terminal
MLX version: 0.16.x
Default device: Device(gpu, 0)
mlx-lm version: 0.19.x
Dot product (GPU): 32.0
Punto de control crítico: Si Default device devuelve Device(cpu, 0), MLX no está accediendo al backend GPU Metal. Esto típicamente significa que estás ejecutando un binario de Python no nativo (por ejemplo, Python x86 traducido por Rosetta). Verifica con:
Terminal
python -c "import platform; print(platform.machine())"
# Must output: arm64
Opcional: Instalación para Desarrollo
Si planeas contribuir a MLX o necesitas parchear los internos, instala desde el código fuente:
Terminal
git clone https://github.com/ml-explore/mlx.git
cd mlx
pip install -e .
git clone https://github.com/ml-explore/mlx-lm.git
cd mlx-lm
pip install -e .
Compilar desde el código fuente requiere Xcode Command Line Tools y CMake ≥ 3.26:
Terminal
xcode-select --install
brew install cmake
Snapshot de Dependencias
Aquí tienes un requirements.txt limpio para un entorno de inferencia reproducible a mediados de 2025:
Terminal
mlx>=0.16.0
mlx-lm>=0.19.0
huggingface-hub>=0.23.0
transformers>=4.41.0
sentencepiece>=0.2.0
protobuf>=3.20.0
Fija estas versiones en cargas de trabajo de producción. El equipo de MLX introduce cambios de API que rompen la compatibilidad con frecuencia dado el ritmo acelerado de desarrollo del framework, y una actualización silenciosa puede invalidar tus parámetros de generación o configuraciones de cuantización.
Con las bibliotecas confirmadas y operativas, el siguiente paso es descargar modelos MLX correctamente formateados desde HuggingFace — lo cual requiere comprender por qué no todos los modelos en formato GGUF o Safetensors son compatibles con MLX de manera inmediata.
Step 4 Paso 2: Descargando Modelos MLX Optimizados desde HuggingFace
Antes de poder ejecutar inferencia, necesitas modelos que estén específicamente formateados y cuantizados para el runtime de MLX. Aunque MLX puede convertir modelos estándar sobre la marcha, el camino de mayor rendimiento es descargar directamente modelos pre-convertidos y pre-cuantizados nativos de MLX desde HuggingFace. La comunidad de MLX — liderada en gran medida por la prolífica organización mlx-community en HuggingFace — ha realizado el arduo trabajo de convertir y cuantizar cientos de modelos populares.
Los modelos MLX se almacenan como archivos safetensors emparejados con un config.json y un tokenizer_config.json. Lo que los distingue es el formato de cuantización. A diferencia de GGUF (utilizado por llama.cpp), MLX usa su propio esquema interno de cuantización con las siguientes configuraciones comunes:
| Cuantización |
Bits por Peso |
Calidad |
Velocidad (Tok/s est.) |
Tamaño (modelo 7B) |
mlx-4bit |
4 bits |
Buena |
⚡⚡⚡⚡ |
~4 GB |
mlx-8bit |
8 bits |
Mejor |
⚡⚡⚡ |
~8 GB |
bf16 |
16 bits (bfloat) |
Óptima |
⚡⚡ |
~14 GB |
fp16 |
16 bits (float) |
Óptima |
⚡⚡ |
~14 GB |
Para la mayoría de los usuarios con máquinas M1/M2/M3, los modelos cuantizados a 4 bits ofrecen la mejor relación entre rendimiento y calidad.
Método 1: Usando el CLI de huggingface_hub (Recomendado)
El enfoque más limpio es usar el CLI de HuggingFace Hub, que maneja automáticamente la reanudación en caso de fallo, el caché y la verificación de integridad.
Terminal
# Install the hub CLI if you haven't already
pip install huggingface_hub
# Download a 4-bit quantized Llama 3.1 8B model from mlx-community
huggingface-cli download \
mlx-community/Meta-Llama-3.1-8B-Instruct-4bit \
--local-dir ./models/llama-3.1-8b-4bit \
--local-dir-use-symlinks False
Consejo Pro: El flag --local-dir-use-symlinks False garantiza que los archivos reales se escriban en tu directorio en lugar de enlaces simbólicos al caché de HuggingFace. Esto es crítico para la portabilidad y las referencias directas a rutas en tus scripts.
Método 2: Usando mlx_lm.convert para Conversión Personalizada
Si el modelo que necesitas no ha sido pre-convertido por la comunidad, puedes convertirlo tú mismo directamente desde un checkpoint estándar de HuggingFace:
Terminal
# Convert and quantize a standard model to MLX 4-bit format
python -m mlx_lm.convert \
--hf-path mistralai/Mistral-7B-Instruct-v0.3 \
--mlx-path ./models/mistral-7b-instruct-4bit \
-q \
--q-bits 4 \
--q-group-size 64
Explicación de los flags clave:
-q — Habilita la cuantización durante la conversión
--q-bits — Bits objetivo por peso (4 u 8)
--q-group-size — Tamaño de grupo para la cuantización por grupos; 64 es el estándar, 32 produce calidad ligeramente superior a un mayor tamaño
Método 3: Descarga por Snapshot vía Python
Para flujos de trabajo programáticos y pipelines de CI/CD, usa la API de Python:
Terminal
from huggingface_hub import snapshot_download
model_path = snapshot_download(
repo_id="mlx-community/Mistral-7B-Instruct-v0.3-4bit",
local_dir="./models/mistral-7b-4bit",
ignore_patterns=["*.md", "*.txt"] # Skip non-essential files
)
print(f"Model downloaded to: {model_path}")
Modelos Recomendados para Comenzar
Aquí tienes modelos MLX probados y de alto rendimiento disponibles en HuggingFace ahora mismo:
| Modelo |
Repositorio en HuggingFace |
VRAM Requerida |
Mejor Para |
| Llama 3.1 8B (4-bit) |
mlx-community/Meta-Llama-3.1-8B-Instruct-4bit |
~5 GB |
Uso general |
| Mistral 7B (4-bit) |
mlx-community/Mistral-7B-Instruct-v0.3-4bit |
~4.5 GB |
Inferencia rápida |
| Llama 3.1 70B (4-bit) |
mlx-community/Meta-Llama-3.1-70B-Instruct-4bit |
~38 GB |
Alta calidad |
| Phi-3.5 Mini (4-bit) |
mlx-community/Phi-3.5-mini-instruct-4bit |
~2.5 GB |
Macs con poca memoria |
| Qwen2.5 14B (4-bit) |
mlx-community/Qwen2.5-14B-Instruct-4bit |
~9 GB |
Tareas de codificación |
Verificando tu Modelo Descargado
Antes de ejecutar inferencia, valida que la estructura del modelo esté intacta:
Terminal
# List the expected files in a valid MLX model directory
ls -lh ./models/llama-3.1-8b-4bit/
# Expected output should include:
# config.json
# tokenizer.json
# tokenizer_config.json
# special_tokens_map.json
# model.safetensors (or sharded: model-00001-of-00004.safetensors, etc.)
Si ves archivos .safetensors junto con las configuraciones del tokenizador, estás listo. Un config.json o tokenizer_config.json faltante es la causa más común de fallos al cargar — vuelve a ejecutar el comando de descarga si alguno de estos está ausente.
Step 5 Paso 3: Ejecutando Inferencia vía CLI
Con tu modelo optimizado para MLX descargado y almacenado localmente, estás listo para ejecutar inferencia directamente desde el terminal. MLX-LM incluye un potente comando mlx_lm.generate que elimina por completo el código repetitivo de Python, ofreciéndote una interfaz limpia y reproducible para benchmarking y experimentación rápida.
Comando Básico de Generación
La llamada de inferencia más simple posible luce así:
Terminal
mlx_lm.generate \
--model mlx-community/Mistral-7B-Instruct-v0.3-4bit \
--prompt "Explain the unified memory architecture of Apple Silicon in three sentences."
MLX cargará los pesos del modelo directamente en el banco de memoria unificada, compilará el grafo de cómputo mediante su motor de evaluación diferida y transmitirá tokens a stdout. Típicamente verás el primer token en 1–2 segundos en chips de la serie M — una consecuencia directa de eliminar por completo la latencia de transferencia PCIe.
Desglose de los Flags Clave del CLI
Comprender los flags disponibles te permite llevar el framework al límite:
| Flag |
Tipo |
Valor por Defecto |
Descripción |
--model |
str |
requerido |
Ruta local o ID de repositorio en HuggingFace |
--prompt |
str |
requerido |
Cadena de texto del prompt de entrada |
--max-tokens |
int |
256 |
Número máximo de tokens a generar |
--temp |
float |
0.0 |
Temperatura de muestreo (0 = decodificación greedy) |
--top-p |
float |
1.0 |
Umbral de muestreo por núcleo |
--seed |
int |
None |
Semilla RNG para reproducibilidad |
--repetition-penalty |
float |
1.0 |
Penaliza la repetición de tokens |
--verbose |
bool |
True |
Imprime el rendimiento en token/seg y la latencia |
Comando de Inferencia de Nivel Producción
Para benchmarking serio o evaluación de prompts en producción, usa la forma completamente parametrizada:
Terminal
mlx_lm.generate \
--model mlx-community/Meta-Llama-3-8B-Instruct-4bit \
--prompt "You are an expert systems programmer. Write a zero-copy ring buffer implementation in Rust." \
--max-tokens 1024 \
--temp 0.7 \
--top-p 0.9 \
--repetition-penalty 1.1 \
--seed 42 \
--verbose
El flag --verbose genera un resumen de rendimiento similar a este al completarse:
Terminal
==========
Prompt: 47 tokens, 823.14 tokens-per-second
Generation: 1024 tokens, 68.42 tokens-per-second
Peak memory: 5.21 GB
Presta especial atención a los dos números de rendimiento distintos. El procesamiento del prompt (prefill) es una operación matricial altamente paralelizable y siempre será significativamente más rápida que la generación autorregresiva de tokens (decode). En un M3 Max con 128 GB de memoria unificada, puedes esperar un rendimiento de decode de 60–90 tokens/seg en modelos de 8B cuantizados a 4 bits — competitivo o superior a la inferencia acelerada por GPU en tarjetas NVIDIA discretas que cuestan muchas veces más.
Usando una Plantilla de Chat
Muchos modelos ajustados para instrucciones requieren una plantilla de chat estructurada para comportarse correctamente. MLX-LM maneja esto automáticamente cuando utilizas el flag --chat-template o invocas la interfaz de chat:
Terminal
mlx_lm.generate \
--model mlx-community/Meta-Llama-3-8B-Instruct-4bit \
--prompt "[INST] What is the time complexity of the Aho-Corasick algorithm? [/INST]" \
--max-tokens 512
Alternativamente, para modelos con plantillas de chat embebidas en tokenizer_config.json (como Llama 3 y Mistral v0.3), puedes usar el modo de chat interactivo directamente:
Terminal
mlx_lm.chat --model mlx-community/Meta-Llama-3-8B-Instruct-4bit
Esto lanza una interfaz estilo REPL con gestión completa del historial de conversación, aplicando automáticamente los tokens correctos <|begin_of_text|>, <|user|> y <|assistant|>. La sesión mantiene la caché KV en la memoria unificada entre turnos, lo que significa que las respuestas subsecuentes en una conversación larga se vuelven progresivamente más rápidas a medida que la caché se calienta.
Redireccionando Prompts desde Archivos
Para pipelines automatizados y arneses de evaluación, redirecciona prompts desde stdin o archivos:
Terminal
cat system_prompt.txt | mlx_lm.generate \
--model mlx-community/Mistral-7B-Instruct-v0.3-4bit \
--prompt "$(cat complex_query.txt)" \
--max-tokens 2048 \
>> outputs/results_$(date +%Y%m%d_%H%M%S).txt
Este patrón se integra limpiamente en frameworks de evaluación basados en shell, permitiéndote procesar por lotes suites de prompts sin levantar un intérprete Python para cada llamada. El punto de entrada del CLI es ligero y rápido de inicializar — típicamente en menos de 500ms antes de que comience la carga del modelo — haciéndolo práctico incluso en contextos de scripting con bucles intensivos.
Step 6 Benchmarking MLX vs Llama.cpp
Ahora viene la parte que realmente importa — números crudos. Pongamos a MLX frente a frente con Llama.cpp, el campeón reinante de la inferencia local de LLMs en dispositivo, y veamos dónde gana cada framework, dónde pierde y por qué.
Entorno de Prueba
Todos los benchmarks se ejecutaron en la siguiente configuración de hardware y software:
| Parámetro |
Valor |
| Dispositivo |
MacBook Pro M3 Max |
| RAM |
128 GB de memoria unificada |
| macOS |
Sonoma 14.5 |
| Python |
3.11.9 |
| MLX |
0.16.1 |
| mlx-lm |
0.16.1 |
| llama.cpp |
b3467 |
| Modelo |
Llama-3.1-8B-Instruct (Q4_K_M / MLX 4-bit) |
Metodología
A cada framework se le proporcionó el mismo input y se le pidió generar exactamente 512 tokens. Ejecutamos 5 pasadas de calentamiento antes de registrar mediciones para eliminar la sobrecarga de compilación JIT en arranque en frío. La métrica reportada es tokens por segundo (tok/s) promediada sobre 10 ejecuciones.
Comando de benchmark para MLX:
```bash
python -m mlx_lm.generate \
--model mlx-community/Meta-Llama-3.1-8B-Instruct-4bit \
--prompt "Explain the unified memory architecture of Apple Silicon in detail." \
--max-tokens 512 \