Volver al inicio

Benchmark de servidores LLM para Qwen 3.5 en Mac — Resultados 2026

Comparación de ocho servidores LLM locales para ejecutar Qwen 3.5 35B MoE en MacBook Pro M2 Max. Análisis de rendimiento en escenarios de un solo usuario y multiusuario. Recomendaciones clave para elegir un framework para desarrolladores.

Qwen 3.5 en Mac: ¿qué servidor LLM es más rápido en 2026?
Advertisement 728x90

# # Comparativa de 8 servidores LLM locales para Qwen 3.5 en Mac: Resultados sorprendentes en 2026

Se realizó una comparativa detallada de ocho servidores LLM locales para ejecutar Qwen 3.5 35B MoE en un MacBook Pro con M2 Max. Con un solo usuario, la diferencia de velocidad fue de solo el 2 %, pero con dos solicitudes paralelas, un framework ofreció una aceleración de 2,17× mientras que otro cayó al 0,85×. El análisis reveló matices críticos en el batching continuo, métricas de velocidad fantasma y problemas de gestión de memoria.

Por qué ejecutar LLMs de forma local: Tres razones técnicas

Para desarrolladores e ingenieros, ejecutar modelos de forma local resuelve tres desafíos clave:

  • Privacidad de datos. Procesa contratos, especificaciones y chats de clientes sin enviarlos a APIs en la nube. Un modelo local anonimiza datos personales (nombres, credenciales) en tiempo real.
  • Agentes de codificación autónomos. Herramientas como OpenCode y Aider necesitan un endpoint compatible con OpenAI. Configurar base_url: http://mac.local:8000/v1 te permite ejecutar agentes sin telemetría ni límites de tasa, ahorrando tokens en la nube.
  • Sin latencia de red. Un modelo de 35B en cuantización de 4 bits en M2 Max genera respuestas más rápido que las APIs en la nube gracias a un tiempo de ida y vuelta cero. En 64 GB de memoria unificada, el modelo ocupa ~20 GB, dejando espacio para el KV cache.

Estos factores convierten a un servidor local en Mac en una alternativa viable para uso profesional, especialmente con datos sensibles.

Google AdInline article slot

Por qué MLX supera a llama.cpp en Apple Silicon

Elegir MLX sobre llama.cpp se debe a la arquitectura de Apple Silicon:

  • Memoria unificada. En las series M, CPU y GPU comparten un único pool de memoria. El modelo de 35B reside en 20 GB sin copias entre RAM y VRAM (a diferencia de NVIDIA).
  • Rendimiento. MLX es consistentemente un 10-30 % más rápido que llama.cpp gracias a la compilación nativa en Metal. M2 Max ofrece ~400 GB/s de ancho de banda de memoria, permitiendo 50-80 tokens/seg en tiempo real.
  • Batching continuo nativo. El ecosistema MLX soporta el manejo de solicitudes paralelas de fábrica, mientras que llama.cpp requiere configuración extra.

Importante: Metal no soporta el intercambio de contexto de GPU entre procesos. Todas las pruebas usaron un solo servidor para evitar conflictos de recursos.

Frameworks comparados: Selección y criterios

La comparativa incluyó seis servidores del ecosistema MLX (dos se descartaron por incompatibilidad con Qwen 3.5 35B MoE):

Google AdInline article slot
  • mlx-openai-server (Python 3.11) — soporte para batching continuo, multi-modelo vía YAML, salida estructurada.
  • mlx-omni-server (Python 3.11+) — API dual (OpenAI + Anthropic), TTS/STT.
  • Rapid-MLX (Python 3.10+) — despliegue fácil, +1900 pruebas, integración con Cursor/Aider.
  • vllm-mlx (Python 3.10+) — KV cache paginado, multimodalidad, pero con un error crítico en el parser SSE.
  • omlx (Python) — KV cache escalonado (RAM + SSD), panel web, pero límite duro de 32768 tokens.
  • mlx-vlm (Python 3.10+) — soporte para +40 arquitecturas, pero ralentización patológica en prompts largos.

Excluidos:

  • higgs (Rust) — no soporta qwen3_5_moe.
  • mlx-serve (Zig) — requiere macOS 15 (Sequoia).

Criterio clave de selección: compatibilidad nativa con formato MLX de Qwen 3.5 35B MoE, sin necesidad de conversión.

Metodología de la comparativa: Cómo se midió el rendimiento

Las pruebas se ejecutaron en un MacBook Pro de 16" con M2 Max (64 GB de memoria unificada) usando mlx-community/Qwen3.5-35B-A3B-4bit. El arnés de pruebas en Python incluyó:

Google AdInline article slot
  • Escenarios de carga:

* run_single — procesamiento secuencial de 8 prompts (100 a 53000 tokens).

* run_double_batch — dos solicitudes paralelas vía barrera asyncio:

gate = asyncio.Event()
task_a = create_task(chat_stream(..., start_gate=gate))
task_b = create_task(chat_stream(..., start_gate=gate))
await asyncio.sleep(0.05)
gate.set()
res_a, res_b = await gather(task_a, task_b)
  • Métricas:

* wall_tps_p50 — tokens/seg mediana por reloj real (métrica principal).

* ttft_p50 — tiempo hasta el primer token (TTFT).

* speedup — eficiencia de batching (relación wall_tps para dos vs. una solicitud).

Se usó la mediana en lugar de la media para evitar valores atípicos por variación en la longitud de prompts. Cada prueba se repitió 5 veces.

Resultados: Un solo usuario vs. procesamiento paralelo

El rendimiento con un solo usuario fue similar entre servidores (dentro del 2 %). Las diferencias surgieron con dos solicitudes paralelas:

  • mlx-openai-server alcanzó 2,17× de aceleración — el único framework con batching continuo efectivo.
  • vllm-mlx mostró 14000 tokens/seg fantasma debido a un error en el parser SSE que sesgaba gen_tps.
  • Rapid-MLX carece de generación en streaming, por lo que TTFT equivale al tiempo total de respuesta.
  • mlx-omni-server se degradó a 0,85× de aceleración sin --workers 2.
  • omlx devolvió HTTP 400 en prompts >32768 tokens.
  • mlx-vlm tuvo caídas cíclicas de velocidad (790 → 3,5 tok/s) por problemas de GC.

Destacable: la complejidad cuadrática de la atención en algunas implementaciones hizo que los prefills de 52k tokens tomaran 31 minutos en lugar de 2-3.

Lecciones clave para desarrolladores

  • El batching continuo es crucial para escenarios multiusuario. Solo mlx-openai-server ofreció aceleración real en solicitudes paralelas. Los demás no las procesaron en paralelo o necesitaron ajustes manuales de workers.
  • Valida métricas con datos reales. Los 14000 tok/s fantasma de vllm-mlx provenían de errores en el manejo de streams SSE, haciendo gen_tps poco fiable.
  • La memoria unificada es una ventaja, pero no lo resuelve todo. A pesar de los pools compartidos, el KV cache escalonado (como en omlx) importa para contextos muy largos.
  • Prueba prompts largos. La ralentización patológica de mlx-vlm en prompts >30k tokens puede hacerlo inutilizable para tareas de contexto grande.
  • La versión de Python afecta la estabilidad. Rapid-MLX con +1900 pruebas fue el más robusto, pero perdió en velocidad de batching.

— Editorial Team

Advertisement 728x90

Leer después