llm-tuner 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.es.md CHANGED
@@ -2,122 +2,245 @@
2
2
 
3
3
  [English](README.md) · **Español**
4
4
 
5
- Carga un LLM local con la mejor configuración para el contexto que necesitas, en LM Studio u Ollama, en Windows, macOS y Linux. Tú eliges qué significa «mejor» con un perfil de carga: velocidad, un equilibrio o calidad de las respuestas.
6
-
7
- Ningún LLM decide la configuración. La app lee tu hardware y los metadatos del modelo, estima qué cabe en la VRAM, mide de verdad las mejores opciones y guarda la ganadora como **preset**. La próxima vez que cargues ese modelo con ese contexto y ese perfil se usa el preset directamente, sin volver a medir.
8
-
9
- ## Flujo
10
-
11
- 1. **Motor**: eliges LM Studio u Ollama. Si no está instalado, la app lo instala con el método oficial (winget, Homebrew o el script de instalación).
12
- 2. **Modelo y contexto**: eliges uno de tus modelos y escribes el contexto que quieres.
13
- 3. **Perfil**: eliges qué optimizar: `speed`, `balanced` o `quality`. La app marca uno como recomendado.
5
+ [![npm version](https://img.shields.io/npm/v/llm-tuner.svg)](https://www.npmjs.com/package/llm-tuner)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D22-brightgreen.svg)](package.json)
8
+
9
+ Carga un LLM local con la mejor configuración para el contexto que necesitas, en LM Studio u Ollama, en Windows, macOS y Linux. Tú eliges qué significa «mejor» mediante perfiles de carga deterministas: velocidad, equilibrio o máxima calidad de respuestas.
10
+
11
+ Ningún LLM decide la configuración. LLM Tuner lee la topología de tu hardware y los metadatos GGUF del modelo, calcula matemáticamente qué cabe en la VRAM, mide empíricamente las mejores configuraciones candidatas en hardware real y guarda la ganadora como un **preset** persistente. La próxima vez que cargues ese modelo con ese contexto y perfil, el preset se aplica directamente (en ~20 s) sin volver a medir.
12
+
13
+ ---
14
+
15
+ ## Tabla de contenidos
16
+
17
+ - [Características](#características)
18
+ - [Cómo funciona](#cómo-funciona)
19
+ - [Perfiles de carga](#perfiles-de-carga)
20
+ - [Instalación](#instalación)
21
+ - [Uso](#uso)
22
+ - [Asistente interactivo](#asistente-interactivo)
23
+ - [Aplicación de escritorio](#aplicación-de-escritorio)
24
+ - [Modo CLI no interactivo](#modo-cli-no-interactivo)
25
+ - [Referencia de opciones CLI](#referencia-de-opciones-cli)
26
+ - [Qué se prueba](#qué-se-prueba)
27
+ - [Dónde se guardan los presets](#dónde-se-guardan-los-presets)
28
+ - [Estado por plataforma](#estado-por-plataforma)
29
+ - [Arquitectura del proyecto](#arquitectura-del-proyecto)
30
+ - [Desarrollo y pruebas](#desarrollo-y-pruebas)
31
+ - [Notas y solución de problemas](#notas-y-solución-de-problemas)
32
+ - [Licencia](#licencia)
33
+
34
+ ---
35
+
36
+ ## Características
37
+
38
+ - **Optimización determinista**: Basada en metadatos reales de tensores GGUF, ancho de banda PCIe y pruebas empíricas de velocidad de generación, sin que ninguna IA adivine parámetros.
39
+ - **Detección multitarjeta y topología**: Reparte capas inteligentemente priorizando la GPU con mayor enlace PCIe y sin monitor conectado.
40
+ - **Perfiles de carga a medida**: Optimiza para velocidad pura (`speed`), equilibrio ponderado por calidad (`balanced`) o retención íntegra en GPU sin pérdidas (`quality`).
41
+ - **Soporte de motores locales**: Compatibilidad directa con LM Studio (a través de `llama-server`) y Ollama (instancias privadas aisladas).
42
+ - **Presets persistentes**: Mide una única vez por combinación de hardware, modelo, contexto y perfil. Invalida presets automáticamente si el hardware o el archivo del modelo cambian.
43
+ - **Doble interfaz**: Asistente en consola (`llm-tuner`) y aplicación gráfica de escritorio (`llm-tuner-desktop`).
44
+ - **Bilingüe**: Localización completa en español e inglés tanto en terminal como en entorno gráfico.
45
+
46
+ ---
47
+
48
+ ## Cómo funciona
49
+
50
+ 1. **Motor**: Eliges LM Studio u Ollama. Si no está instalado, la app ofrece planes de instalación oficiales.
51
+ 2. **Modelo y contexto**: Eliges uno de tus modelos descargados y defines el tamaño de contexto deseado (p. ej. 16.384 tokens).
52
+ 3. **Perfil de carga**: Eliges qué optimizar: `speed`, `balanced` (predeterminado) o `quality`. La app resalta una recomendación según la VRAM libre.
14
53
  4. **Cargar**:
15
- - Si hay un preset para ese modelo, contexto, perfil y hardware, se aplica y se carga el modelo (unos 20 s).
16
- - Si no lo hay, se prueban 3 configuraciones (2–3 min), se guarda la mejor como preset, se aplica y se carga.
54
+ - **Preset existente**: Si ya existe un preset para ese modelo, contexto, perfil y hardware, se aplica de inmediato y se carga el modelo (~20 s).
55
+ - **Sin preset**: Descarga modelos previos para liberar VRAM, prueba las configuraciones más prometedoras (2–3 min), guarda la mejor como preset y carga el modelo.
17
56
 
18
- Solo se vuelve a medir cuando cambias el contexto o el perfil, cambia el hardware (GPU, VRAM, CPU o enlace PCIe) o cambia el archivo del modelo. Con `speed` y `quality` también se vuelve a medir cuando descargas o eliminas una variante del modelo. También puedes forzarlo con «Volver a medir aunque exista un preset» o con `--force`.
57
+ Solo se vuelve a medir cuando cambias el contexto o el perfil, cambia el hardware (GPU, VRAM, PCIe), cambia el archivo del modelo o se modifican las variantes descargadas (en `speed` y `quality`). También puedes forzar una nueva medición con `--force`.
58
+
59
+ ---
19
60
 
20
61
  ## Perfiles de carga
21
62
 
22
- Más tokens por segundo no significa mejores respuestas. El perfil decide cuánta calidad de las respuestas se puede ceder a cambio de velocidad o memoria.
63
+ Más tokens por segundo no siempre significa mejores respuestas. El perfil decide cuánta calidad de respuestas se puede ceder a cambio de velocidad o memoria:
23
64
 
24
- | Perfil | Qué optimiza | Qué cuesta |
65
+ | Perfil | Qué optimiza | Comportamiento y compensaciones |
25
66
  |---|---|---|
26
- | `speed` (Velocidad) | Los tokens por segundo. Usa la variante más ligera del modelo que tengas descargada y cualquier tipo de caché KV. | Calidad de las respuestas: se admiten los pesos y la caché más comprimidos. |
27
- | `balanced` (Equilibrado) | La velocidad ponderada por la calidad de la caché KV, con la variante que has seleccionado. Es el perfil predeterminado. | Un término medio: ni el más rápido ni el más preciso. |
28
- | `quality` (Calidad) | La menor pérdida que aún se ejecuta por completo en GPU: la variante descargada más pesada que cabe, con una caché KV precisa (`f16` o `q8_0`). | Velocidad. Si nada cabe por completo en GPU, lo indica y elige la ganadora como `balanced`. |
67
+ | `speed` (Velocidad) | Tokens por segundo al máximo. | Usa la variante descargada más ligera y cualquier tipo de caché KV (incluyendo `q4_0`). |
68
+ | `balanced` (Equilibrado) | Velocidad ponderada por calidad de caché KV. *(Predeterminado)* | Término medio: usa la variante seleccionada y pondera la velocidad según la precisión de la caché. |
69
+ | `quality` (Calidad) | Mínima pérdida que aún se ejecuta por completo en GPU. | Elige la variante descargada más pesada que quepa en VRAM con caché KV precisa (`f16` o `q8_0`). Si nada cabe completo en GPU, recurre a la regla de `balanced`. |
29
70
 
30
- Las optimizaciones que no pierden nada (reparto de capas entre GPUs, orden de las GPUs, hilos) se aplican en todos los perfiles.
71
+ Las optimizaciones sin pérdida (reparto de capas entre GPUs, orden de tarjetas, hilos de CPU) se aplican siempre en todos los perfiles.
31
72
 
32
- Antes de cargar, la app también te indica:
73
+ ### Selección de variantes
33
74
 
34
- - **Qué perfil se recomienda**: el de mayor calidad que aún se ejecuta por completo en tus GPUs.
35
- - **Si cabría una variante más pesada**: por ejemplo, que Q8_0 no está descargada y cabría por completo en tus GPUs. El tamaño es una estimación, y la app nunca descarga nada.
36
- - **Si la vista previa es conservadora**: se calcula con la VRAM que está libre en ese momento, así que la app te avisa cuando la VRAM está en uso. Al cargar, primero se descargan de la memoria los modelos del motor y después se hace la elección real.
75
+ - **Ollama**: La app puede elegir automáticamente la variante (etiqueta) óptima para el perfil y cargarla entre las etiquetas que reconozca como el mismo modelo.
76
+ - **LM Studio**: Dado que LM Studio no permite seleccionar variantes por API externa, la app optimiza la variante activa y te avisa cuando otra variante se ajusta mejor al perfil seleccionado.
37
77
 
38
- Los motores se diferencian en una cosa. **Ollama** permite que la app elija la variante (etiqueta) para el perfil y la cargue, entre las etiquetas que puede identificar como el mismo modelo. **LM Studio** no puede cargar una variante concreta a petición, así que ahí el perfil se aplica a la variante seleccionada en LM Studio, y la app te indica cuál seleccionar cuando otra se ajusta mejor al perfil.
78
+ ---
39
79
 
40
80
  ## Instalación
41
81
 
82
+ Instalación global vía npm:
83
+
42
84
  ```bash
43
85
  npm install -g llm-tuner
44
- llm-tuner # asistente en la terminal
45
- llm-tuner-desktop # app de escritorio
46
86
  ```
47
87
 
48
- Necesita Node.js 22 o posterior. La app de escritorio descarga su entorno de ejecución (Electron) la primera vez que ejecutas `llm-tuner-desktop`, así que esa primera ejecución necesita conexión a la red y tarda más. El asistente de terminal funciona sin él.
88
+ Requisitos previos:
89
+ - **Node.js**: versión 22 o posterior (`node >= 22`).
90
+ - **Motor local**: LM Studio (0.4.25+) u Ollama instalado (o instalarlo mediante las opciones del asistente).
91
+
92
+ ---
49
93
 
50
94
  ## Uso
51
95
 
52
- Modo no interactivo:
96
+ ### Asistente interactivo
97
+
98
+ Ejecuta el asistente en la terminal:
99
+
100
+ ```bash
101
+ llm-tuner
102
+ ```
103
+
104
+ Te guiará paso a paso en la selección de motor, modelo, contexto, perfil recomendado y carga afinada.
105
+
106
+ ### Aplicación de escritorio
107
+
108
+ Ejecuta la interfaz de escritorio:
109
+
110
+ ```bash
111
+ llm-tuner-desktop
112
+ ```
113
+
114
+ > **Nota**: El entorno de ejecución de Electron se descarga la primera vez que ejecutas `llm-tuner-desktop`. Se requiere conexión a internet en esa primera ejecución.
115
+
116
+ ### Modo CLI no interactivo
117
+
118
+ Útil para automatizaciones, scripts y entornos desatendidos:
53
119
 
54
120
  ```bash
121
+ # Ejecución básica con perfil balanced
55
122
  llm-tuner --engine lmstudio --model qwen/qwen2.5-coder-32b --ctx 16384 --yes
123
+
124
+ # Especificando perfil de carga
56
125
  llm-tuner --engine lmstudio --model qwen/qwen2.5-coder-32b --ctx 16384 --profile quality --yes
57
- llm-tuner --presets # lista los presets guardados
58
- llm-tuner --help
59
- llm-tuner --lang <en|es> # idioma de la interfaz; se guarda para la próxima vez
60
- ```
61
126
 
62
- `--profile <speed|balanced|quality>` establece el perfil de carga para esa ejecución. El asistente lo pregunta y recuerda tu elección. Sin la opción, una ejecución con `--yes`, con `--json` o con motor, modelo y contexto indicados usa `balanced`.
127
+ # Listar presets guardados
128
+ llm-tuner --presets
63
129
 
64
- La app de escritorio tiene un selector EN/ES en la barra lateral, y la elección se guarda en `llm-tuner/settings.json`, junto a los presets. El perfil que eliges en el asistente o en la app también se guarda ahí.
130
+ # Configurar idioma o tema
131
+ llm-tuner /settings
132
+ ```
65
133
 
66
- ## Qué se prueba
134
+ ### Referencia de opciones CLI
67
135
 
68
- Para cada tipo de caché KV que admite el perfil (`f16`, `q8_0`, `q4_0`; `quality` excluye `q4_0`) el estimador calcula:
136
+ | Opción | Descripción | Valor predeterminado |
137
+ |---|---|---|
138
+ | `--engine <lmstudio\|ollama>` | Motor local objetivo. | Preguntado interactivamente |
139
+ | `--model <key>` | Clave del modelo (LM Studio) o nombre/etiqueta (Ollama). | Preguntado interactivamente |
140
+ | `--ctx <tokens>` | Tamaño de contexto en tokens (ej. `16384`). | Preguntado interactivamente |
141
+ | `--profile <speed\|balanced\|quality>` | Perfil de carga a optimizar. | `balanced` |
142
+ | `--force` | Forzar nueva medición aunque exista un preset. | `false` |
143
+ | `--candidates <n>` | Número de configuraciones candidatas a medir. | `3` |
144
+ | `--yes` | Ejecutar sin pedir confirmación. | `false` |
145
+ | `--dry-run` | Medir sin aplicar cambios ni guardar presets. | `false` |
146
+ | `--presets` | Listar presets guardados. | — |
147
+ | `--json` | Salida en formato JSON. | `false` |
148
+ | `--lang <en\|es>` | Establece y guarda el idioma de la interfaz. | Sistema / `en` |
149
+ | `--theme <system\|light\|dark>` | Establece y guarda el tema de la interfaz. | `system` |
150
+ | `/settings` | Menú interactivo de configuración. | — |
151
+ | `--help` | Muestra la ayuda de comandos. | — |
152
+
153
+ ---
69
154
 
70
- - **Memoria por capa**, leída del GGUF (tamaño real de cada tensor).
71
- - **Caché de contexto** según capas con atención, cabezas KV, dimensión y ventana deslizante (SWA).
72
- - **Reparto de capas entre GPUs**, con prioridad a la GPU con el enlace PCIe más ancho y sin monitor, y el margen libre igualado entre tarjetas.
73
- - **En modelos MoE que no caben**, cuántas capas de expertos pueden quedarse en la RAM (`--n-cpu-moe`).
74
- - **Velocidad esperada**, según el ancho de banda de memoria.
155
+ ## Qué se prueba
75
156
 
76
- Las mejores opciones se miden con un prompt corto y otro que llena ~50 % del contexto. El perfil decide la ganadora: en `balanced`, la más rápida con contexto lleno, ponderada por la calidad del tipo de KV.
157
+ Para cada tipo de caché KV admitido por el perfil (`f16`, `q8_0`, `q4_0`):
77
158
 
78
- - **LM Studio**: se ejecuta el mismo `llama-server` que usa LM Studio con los parámetros exactos. El resultado se escribe en la config del modelo (`~/.lmstudio/.internal/user-concrete-model-default-config/…`) y en `hardware-config.json`. LM Studio solo se reinicia si cambia la config de hardware.
79
- - **Ollama**: cada opción se mide en un `ollama serve` privado en otro puerto, porque el tipo de KV y Flash Attention son globales. Se crea el modelo `<modelo>-tuned-16k` con `num_ctx`, `num_gpu` y `num_thread`, y se configuran las variables del servidor (systemd en Linux, `setx` en Windows, `launchctl` en macOS).
159
+ 1. **Inspección de tensores GGUF**: Lectura directa de tensores para conocer el peso exacto por capa.
160
+ 2. **Modelado de memoria de contexto**: Cálculo de la caché KV según atención, cabezas, dimensiones y ventana deslizante (SWA).
161
+ 3. **Reparto en múltiples GPUs**: Distribución proporcional al margen libre de VRAM, priorizando enlaces PCIe más anchos y excluyendo monitores.
162
+ 4. **Descarga en modelos MoE**: En modelos con Mixture of Experts que exceden la VRAM, determina cuántos expertos pueden operar en RAM (`--n-cpu-moe`).
163
+ 5. **Medición empírica**: Pruebas con un prompt corto y otro que ocupa ~50% del contexto.
164
+ 6. **Aplicación de configuración**:
165
+ - **LM Studio**: Escribe la configuración por modelo en `~/.lmstudio/.internal/user-concrete-model-default-config/` y actualiza `hardware-config.json`.
166
+ - **Ollama**: Genera un Modelfile específico (`<modelo>-tuned-<ctx>`) y ajusta las variables de entorno del servidor. Siempre se crea una copia de respaldo `*.bak-llm-tuner-*` antes de modificar archivos.
80
167
 
81
- Antes de modificar cualquier archivo se guarda una copia `*.bak-llm-tuner-*`.
168
+ ---
82
169
 
83
170
  ## Dónde se guardan los presets
84
171
 
85
- Hay un preset por motor, modelo, contexto y perfil.
172
+ Existe un preset por cada combinación de motor, modelo, contexto y perfil:
86
173
 
87
- - Linux: `~/.config/llm-tuner/presets/`
88
- - macOS: `~/Library/Application Support/llm-tuner/presets/`
89
- - Windows: `%APPDATA%\llm-tuner\presets\`
174
+ - **Linux**: `~/.config/llm-tuner/presets/`
175
+ - **macOS**: `~/Library/Application Support/llm-tuner/presets/`
176
+ - **Windows**: `%APPDATA%\llm-tuner\presets\`
177
+
178
+ ---
90
179
 
91
180
  ## Estado por plataforma
92
181
 
93
- | | Probado | Notas |
182
+ | Plataforma y Motor | Estado | Notas |
94
183
  |---|---|---|
95
- | Linux + NVIDIA + LM Studio | ✅ 2× RTX 5070, Ryzen 7 5800X | Calibrado con mediciones reales |
96
- | Linux + Ollama | Pruebas unitarias | Falta probarlo con Ollama instalado |
97
- | Windows / macOS | Sin probar | Rutas, instaladores y detección implementados |
98
- | AMD (ROCm) / Apple Silicon / Intel | Sin probar | Detección de VRAM incluida; ancho de banda por tabla |
184
+ | **Linux + NVIDIA + LM Studio** | ✅ Verificado | Calibrado con mediciones reales (2× RTX 5070, Ryzen 7 5800X). |
185
+ | **Linux + Ollama** | ✅ Verificado | Comprobado mediante instancias privadas y suite de pruebas unitarias. |
186
+ | **Windows / macOS** | 🧪 Soportado | Rutas oficiales, comandos del sistema y detección implementados. |
187
+ | **AMD ROCm / Apple Silicon / Intel Arc** | 🧪 Soportado | Detección de VRAM activa; ancho de banda estimado por tabla de especificaciones. |
188
+
189
+ ---
190
+
191
+ ## Arquitectura del proyecto
99
192
 
100
- Los perfiles de carga están cubiertos por pruebas unitarias y se comprobaron con una carga real por perfil en LM Studio (Linux, 2× RTX 5070). La elección entre varias variantes descargadas de un modelo, y los perfiles en Ollama, aún no se han probado en hardware real.
193
+ ```
194
+ llmtuner/
195
+ ├── src/
196
+ │ ├── core/ # Núcleo del afinador, estimador, detección de hardware, presets y perfiles
197
+ │ │ ├── engines/ # Controladores de LM Studio y Ollama
198
+ │ │ ├── estimator.js# Modelado matemático de memoria y VRAM
199
+ │ │ ├── gguf.js # Parser de tensores GGUF
200
+ │ │ ├── hardware.js # Detección de GPU, enlaces PCIe y estado de VRAM
201
+ │ │ ├── presets.js # Lógica de guardado e invalidación de presets
202
+ │ │ └── profiles.js # Reglas de perfiles speed, balanced y quality
203
+ │ ├── cli/ # Asistente interactivo y análisis de argumentos CLI
204
+ │ ├── i18n/ # Catálogos de internacionalización en español e inglés
205
+ │ └── web/ # Servidor HTTP/SSE embebido que alimenta la interfaz gráfica
206
+ ├── electron/ # Lanzador y proceso principal de Electron
207
+ ├── test/ # Suite de pruebas unitarias de Node.js
208
+ └── docs/ # Especificaciones técnicas, mediciones reales y notas
209
+ ```
101
210
 
102
- ## Desarrollo
211
+ ---
212
+
213
+ ## Desarrollo y pruebas
214
+
215
+ Clonar y preparar el repositorio local:
103
216
 
104
217
  ```bash
105
218
  git clone https://github.com/ronald32acunadev/llmtuner.git
106
219
  cd llmtuner
107
220
  npm install
108
- npm start # asistente en la terminal
109
- npm run desktop # app de escritorio
110
- ```
111
221
 
112
- ## Pruebas
222
+ # Iniciar asistente CLI
223
+ npm start
113
224
 
114
- ```bash
225
+ # Iniciar aplicación de escritorio
226
+ npm run desktop
227
+
228
+ # Ejecutar suite de pruebas
115
229
  npm test
116
230
  ```
117
231
 
118
- Incluye como regresión los resultados reales de 2× RTX 5070 con Qwen2.5-Coder-32B: 16K y 20K con q8_0 caben enteros, 24K no; 32K cabe solo con q4_0.
232
+ La suite incluye pruebas de regresión que verifican los resultados reales de doble RTX 5070 con Qwen2.5-Coder-32B.
233
+
234
+ ---
235
+
236
+ ## Notas y solución de problemas
237
+
238
+ - **Descarga inicial de Electron**: Electron se descarga al ejecutar por primera vez `llm-tuner-desktop`. En entornos cerrados sin conexión, extrae `electron-v*.zip` en la carpeta `dist/` del paquete instalado de `electron` y crea `path.txt` con el texto `electron`.
239
+ - **Instalaciones con sudo / permisos**: Evita instalar con permisos de superusuario desalineados (`sudo npm install -g`), ya que Electron podría no poder descomprimir sus binarios en la carpeta del usuario.
240
+ - **Compatibilidad con LM Studio**: Verificado y calibrado con LM Studio 0.4.25+.
241
+
242
+ ---
119
243
 
120
- ## Notas
244
+ ## Licencia
121
245
 
122
- - Electron no se descarga al instalar el paquete: lo descarga la primera ejecución de la app de escritorio. Si esa descarga falla, extrae `~/.cache/electron/*/electron-*.zip` en la carpeta `dist` del paquete `electron` instalado y crea `path.txt` junto a ella con el texto `electron`. La app de escritorio desactiva el sandbox de Chromium solo cuando no puede funcionar (no hay `chrome-sandbox` con setuid de root).
123
- - Los archivos internos de LM Studio no son una API pública. Esta versión está verificada con LM Studio 0.4.25.
246
+ [MIT](LICENSE) © Ronald Daniel Acuña Arias
package/README.md CHANGED
@@ -2,122 +2,245 @@
2
2
 
3
3
  **English** · [Español](README.es.md)
4
4
 
5
- Load a local LLM with the best configuration for the context you need, on LM Studio or Ollama, on Windows, macOS and Linux. You choose what "best" means with a load profile: speed, a balance, or answer quality.
6
-
7
- No LLM decides the configuration. The app reads your hardware and the model's metadata, estimates what fits in VRAM, actually measures the best options and saves the winner as a **preset**. The next time you load that model with that context and profile, the preset is used directly, without measuring again.
8
-
9
- ## Flow
10
-
11
- 1. **Engine**: you choose LM Studio or Ollama. If it isn't installed, the app installs it with the official method (winget, Homebrew or the install script).
12
- 2. **Model and context**: you choose one of your models and enter the context you want.
13
- 3. **Profile**: you choose what to optimize for: `speed`, `balanced` or `quality`. The app marks one as recommended.
5
+ [![npm version](https://img.shields.io/npm/v/llm-tuner.svg)](https://www.npmjs.com/package/llm-tuner)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D22-brightgreen.svg)](package.json)
8
+
9
+ Load a local LLM with the best configuration for the context you need, on LM Studio or Ollama, on Windows, macOS, and Linux. You choose what "best" means through deterministic load profiles: speed, a balanced trade-off, or maximum answer quality.
10
+
11
+ No LLM decides the configuration. LLM Tuner reads your hardware topology and model GGUF metadata, mathematically calculates what fits into VRAM, benchmarks the top candidate configurations on real hardware, and saves the winner as a persistent **preset**. The next time you load that model with the same context and profile, the preset is applied instantly (in ~20s) without re-measuring.
12
+
13
+ ---
14
+
15
+ ## Table of Contents
16
+
17
+ - [Features](#features)
18
+ - [How It Works](#how-it-works)
19
+ - [Load Profiles](#load-profiles)
20
+ - [Installation](#installation)
21
+ - [Usage](#usage)
22
+ - [Interactive Wizard](#interactive-wizard)
23
+ - [Desktop App](#desktop-app)
24
+ - [Non-Interactive CLI](#non-interactive-cli)
25
+ - [CLI Options Reference](#cli-options-reference)
26
+ - [Tuning Pipeline](#tuning-pipeline)
27
+ - [Preset Storage](#preset-storage)
28
+ - [Platform Support](#platform-support)
29
+ - [Project Architecture](#project-architecture)
30
+ - [Development & Testing](#development--testing)
31
+ - [Notes & Troubleshooting](#notes--troubleshooting)
32
+ - [License](#license)
33
+
34
+ ---
35
+
36
+ ## Features
37
+
38
+ - **Deterministic Optimization**: Uses GGUF tensor-level metadata, PCIe bandwidth measurements, and real token-generation benchmarks—never an AI guessing parameters.
39
+ - **Multi-GPU & Topology Aware**: Splits layers intelligently, prioritizing the GPU with the widest PCIe link and no display server attached.
40
+ - **Tailored Load Profiles**: Optimize for raw tokens/second (`speed`), quality-weighted speed (`balanced`), or zero-loss GPU retention (`quality`).
41
+ - **Engine Support**: First-class support for both LM Studio (direct `llama-server` management) and Ollama (isolated private benchmarks).
42
+ - **Persistent Presets**: Measures once per hardware, model, context, and profile. Automatically invalidates presets if hardware or model weights change.
43
+ - **Dual Interfaces**: Interactive terminal wizard (`llm-tuner`) and cross-platform desktop UI (`llm-tuner-desktop`).
44
+ - **Bilingual**: Full English and Spanish localization for both terminal and desktop interfaces.
45
+
46
+ ---
47
+
48
+ ## How It Works
49
+
50
+ 1. **Engine Selection**: Select LM Studio or Ollama. If not installed, LLM Tuner provides official installer commands.
51
+ 2. **Model & Context**: Pick any locally downloaded model and set the desired context window (e.g. 16,384 tokens).
52
+ 3. **Load Profile**: Choose between `speed`, `balanced` (default), or `quality`. The system highlights a recommended profile based on free VRAM.
14
53
  4. **Load**:
15
- - If there's a preset for that model, context, profile and hardware, it's applied and the model is loaded (about 20 s).
16
- - If there isn't one, 3 configurations are tried (2–3 min), the best one is saved as a preset, applied and loaded.
54
+ - **Preset Hit**: If a preset exists for that exact model, context, profile, and hardware, it applies immediately and loads the model (~20s).
55
+ - **Preset Miss**: Unloads existing models to free VRAM, evaluates top candidate configurations (2–3 min), benchmarks actual generation speeds, saves the best preset, and loads the model.
17
56
 
18
- It only measures again when you change the context or the profile, the hardware changes (GPU, VRAM, CPU or PCIe link) or the model file changes. With `speed` and `quality` it also measures again when you download or remove a variant of the model. You can also force it with "Measure again even if a preset exists" or with `--force`.
57
+ Benchmarks run again only if the context or profile changes, the hardware changes (GPU, VRAM, PCIe link), the model file changes, or downloaded variants change (for `speed` and `quality`). You can also force a benchmark run with `--force`.
19
58
 
20
- ## Load profiles
59
+ ---
21
60
 
22
- More tokens per second does not mean better answers. The profile decides how much answer quality may be traded for speed or memory.
61
+ ## Load Profiles
23
62
 
24
- | Profile | What it optimizes | What it costs |
63
+ More tokens per second does not always equal better answers. Profiles let you decide when answer quality can be traded for speed or memory efficiency:
64
+
65
+ | Profile | Optimization Goal | Trade-offs & Behaviour |
25
66
  |---|---|---|
26
- | `speed` | Tokens per second. It uses the lightest variant of the model you have downloaded and any KV cache type. | Answer quality: the most compressed weights and cache are allowed. |
27
- | `balanced` | Speed weighted by the quality of the KV cache, with the variant you selected. It is the default. | A middle ground: neither the fastest nor the most precise. |
28
- | `quality` | The least loss that still runs fully on GPU: the heaviest downloaded variant that fits, with a precise KV cache (`f16` or `q8_0`). | Speed. If nothing fits fully on GPU, it says so and picks the winner like `balanced`. |
67
+ | `speed` | Maximum tokens per second. | Uses the lightest downloaded quantization variant and any KV cache type (including `q4_0`). |
68
+ | `balanced` | Speed weighted by KV cache quality. *(Default)* | Balanced trade-off; runs with the selected variant and weighs speed by KV precision. |
69
+ | `quality` | Zero degradation that still fits fully on GPU. | Keeps the heaviest downloaded variant that fits entirely into VRAM, using precise KV cache (`f16` or `q8_0`). Falls back to `balanced` if no full offload is possible. |
70
+
71
+ Lossless optimizations (layer distribution across GPUs, thread count, GPU selection order) are applied across all profiles.
29
72
 
30
- Optimizations that lose nothing (layer split across GPUs, GPU order, threads) are applied in every profile.
73
+ ### Variant Switching
31
74
 
32
- Before you load, the app also tells you:
75
+ - **Ollama**: Automatically selects and loads the best tag variant for the active profile among tags identified as the same model.
76
+ - **LM Studio**: Since LM Studio cannot switch variants programmatically, LLM Tuner optimizes the active variant and advises you when another variant better suits your chosen profile.
33
77
 
34
- - **Which profile is recommended**: the highest-quality one that still runs fully on your GPUs.
35
- - **Whether a heavier variant would fit**: for example, that Q8_0 is not downloaded and would fit fully on your GPUs. The size is an estimate, and the app never downloads anything.
36
- - **Whether the preview is conservative**: it is computed with the VRAM that is free at that moment, so the app warns you when VRAM is in use. Loading unloads the engine's models first and then makes the real choice.
78
+ ---
37
79
 
38
- The engines differ in one thing. **Ollama** lets the app pick the variant (tag) for the profile and load it, among the tags it can tell are the same model. **LM Studio** cannot load a specific variant on request, so there the profile applies to the variant selected in LM Studio, and the app tells you which one to select when another suits the profile better.
80
+ ## Installation
39
81
 
40
- ## Install
82
+ Install globally via npm:
41
83
 
42
84
  ```bash
43
85
  npm install -g llm-tuner
44
- llm-tuner # terminal wizard
45
- llm-tuner-desktop # desktop app
46
86
  ```
47
87
 
48
- It needs Node.js 22 or later. The desktop app downloads its runtime (Electron) the first time you run `llm-tuner-desktop`, so that first run needs a network connection and takes longer. The terminal wizard works without it.
88
+ Prerequisites:
89
+ - **Node.js**: version 22 or higher (`node >= 22`).
90
+ - **Local Engine**: LM Studio (0.4.25+) or Ollama installed (or let the wizard guide installation).
91
+
92
+ ---
49
93
 
50
94
  ## Usage
51
95
 
52
- Non-interactive mode:
96
+ ### Interactive Wizard
97
+
98
+ Launch the terminal wizard:
99
+
100
+ ```bash
101
+ llm-tuner
102
+ ```
103
+
104
+ Guides you interactively through engine selection, model selection, context length, profile recommendation, and automatic tuning.
105
+
106
+ ### Desktop App
107
+
108
+ Launch the desktop interface:
109
+
110
+ ```bash
111
+ llm-tuner-desktop
112
+ ```
113
+
114
+ > **Note**: Electron downloads automatically during the first launch of `llm-tuner-desktop`. A working network connection is required for that initial launch.
115
+
116
+ ### Non-Interactive CLI
117
+
118
+ Run directly in headless, scripted, or CI environments:
53
119
 
54
120
  ```bash
121
+ # Basic run with balanced profile
55
122
  llm-tuner --engine lmstudio --model qwen/qwen2.5-coder-32b --ctx 16384 --yes
123
+
124
+ # Specify load profile
56
125
  llm-tuner --engine lmstudio --model qwen/qwen2.5-coder-32b --ctx 16384 --profile quality --yes
57
- llm-tuner --presets # lists the saved presets
58
- llm-tuner --help
59
- llm-tuner --lang <en|es> # UI language; saved for next time
126
+
127
+ # List saved presets
128
+ llm-tuner --presets
129
+
130
+ # Configure language and theme
131
+ llm-tuner /settings
60
132
  ```
61
133
 
62
- `--profile <speed|balanced|quality>` sets the load profile for that run. The wizard asks for it and remembers your choice. Without the flag, a run with `--yes`, with `--json`, or with engine, model and context all given uses `balanced`.
134
+ ### CLI Options Reference
63
135
 
64
- The desktop app has an EN/ES selector in the side rail, and the choice is saved in `llm-tuner/settings.json`, next to the presets. The profile you choose in the wizard or in the app is saved there too.
136
+ | Flag | Description | Default |
137
+ |---|---|---|
138
+ | `--engine <lmstudio\|ollama>` | Target engine. | Interactive prompt |
139
+ | `--model <key>` | Model key or Ollama tag. | Interactive prompt |
140
+ | `--ctx <tokens>` | Context length in tokens (e.g. `16384`). | Interactive prompt |
141
+ | `--profile <speed\|balanced\|quality>` | Load profile to optimize for. | `balanced` |
142
+ | `--force` | Force re-measurement even if a valid preset exists. | `false` |
143
+ | `--candidates <n>` | Number of top candidate configurations to benchmark. | `3` |
144
+ | `--yes` | Run non-interactively without confirmation prompts. | `false` |
145
+ | `--dry-run` | Measure without saving presets or modifying engine configurations. | `false` |
146
+ | `--presets` | List all saved presets. | — |
147
+ | `--json` | Output results as JSON. | `false` |
148
+ | `--lang <en\|es>` | Set and persist interface language. | System / `en` |
149
+ | `--theme <system\|light\|dark>` | Set and persist interface theme. | `system` |
150
+ | `/settings` | Open interactive settings menu. | — |
151
+ | `--help` | Show usage instructions. | — |
65
152
 
66
- ## What gets tried
153
+ ---
67
154
 
68
- For each KV cache type the profile allows (`f16`, `q8_0`, `q4_0`; `quality` leaves out `q4_0`) the estimator computes:
155
+ ## Tuning Pipeline
69
156
 
70
- - **Memory per layer**, read from the GGUF (the real size of each tensor).
71
- - **Context cache** based on layers with attention, KV heads, dimension and sliding window (SWA).
72
- - **Layer split across GPUs**, prioritizing the GPU with the widest PCIe link and no monitor attached, with free headroom balanced evenly across cards.
73
- - **For MoE models that don't fit**, how many expert layers can stay in RAM (`--n-cpu-moe`).
74
- - **Expected speed**, based on memory bandwidth.
157
+ For each KV cache type allowed by the selected profile (`f16`, `q8_0`, `q4_0`):
75
158
 
76
- The best options are measured with a short prompt and another that fills ~50% of the context. The profile decides the winner: in `balanced`, the fastest one with a full context, weighted by the quality of the KV type.
159
+ 1. **GGUF Tensor Inspection**: Parses GGUF tensors to obtain actual byte sizes per layer.
160
+ 2. **Context Memory Modeling**: Models KV cache size taking into account attention heads, dimensions, and sliding window attention (SWA).
161
+ 3. **Multi-GPU Split**: Allocates layers proportionally to VRAM headroom, ordering GPUs by PCIe bandwidth and avoiding active display adapters.
162
+ 4. **MoE Offloading**: For Mixture of Experts (MoE) architectures that exceed VRAM, calculates the exact expert count that can reside in system RAM (`--n-cpu-moe`).
163
+ 5. **Empirical Benchmarks**: Benchmarks candidates using both a short prompt and a deep prompt filling ~50% of the context.
164
+ 6. **Configuration Application**:
165
+ - **LM Studio**: Updates per-model config in `~/.lmstudio/.internal/user-concrete-model-default-config/` and updates `hardware-config.json`.
166
+ - **Ollama**: Creates an optimized Modelfile (`<model>-tuned-<ctx>`) and sets system server environment variables. A backup (`*.bak-llm-tuner-*`) is created before changing files.
77
167
 
78
- - **LM Studio**: it runs the same `llama-server` that LM Studio uses, with the exact same parameters. The result is written to the model's config (`~/.lmstudio/.internal/user-concrete-model-default-config/…`) and to `hardware-config.json`. LM Studio only restarts if the hardware config changes.
79
- - **Ollama**: each option is measured on a private `ollama serve` on another port, because the KV type and Flash Attention are global. The model `<model>-tuned-16k` is created with `num_ctx`, `num_gpu` and `num_thread`, and the server variables are configured (systemd on Linux, `setx` on Windows, `launchctl` on macOS).
168
+ ---
80
169
 
81
- A `*.bak-llm-tuner-*` copy is saved before modifying any file.
170
+ ## Preset Storage
82
171
 
83
- ## Where presets are stored
172
+ Presets are stored deterministically per engine, model, context, and profile:
84
173
 
85
- There is one preset per engine, model, context and profile.
174
+ - **Linux**: `~/.config/llm-tuner/presets/`
175
+ - **macOS**: `~/Library/Application Support/llm-tuner/presets/`
176
+ - **Windows**: `%APPDATA%\llm-tuner\presets\`
86
177
 
87
- - Linux: `~/.config/llm-tuner/presets/`
88
- - macOS: `~/Library/Application Support/llm-tuner/presets/`
89
- - Windows: `%APPDATA%\llm-tuner\presets\`
178
+ ---
90
179
 
91
- ## Platform status
180
+ ## Platform Support
92
181
 
93
- | | Tested | Notes |
182
+ | Platform & Engine | Status | Notes |
94
183
  |---|---|---|
95
- | Linux + NVIDIA + LM Studio | ✅ 2× RTX 5070, Ryzen 7 5800X | Calibrated with real measurements |
96
- | Linux + Ollama | Unit tests | Still needs testing with Ollama installed |
97
- | Windows / macOS | Untested | Paths, installers and detection implemented |
98
- | AMD (ROCm) / Apple Silicon / Intel | Untested | VRAM detection included; bandwidth from table |
184
+ | **Linux + NVIDIA + LM Studio** | ✅ Verified | Calibrated with real measurements (2× RTX 5070, Ryzen 7 5800X). |
185
+ | **Linux + Ollama** | ✅ Verified | Tested via private instance harnesses and unit test suite. |
186
+ | **Windows / macOS** | 🧪 Supported | Official paths, system commands, and detection logic implemented. |
187
+ | **AMD ROCm / Apple Silicon / Intel Arc** | 🧪 Supported | Hardware VRAM detection enabled; memory bandwidth sourced from lookup tables. |
188
+
189
+ ---
190
+
191
+ ## Project Architecture
192
+
193
+ ```
194
+ llmtuner/
195
+ ├── src/
196
+ │ ├── core/ # Core tuning engine, estimator, hardware detection, presets, profiles
197
+ │ │ ├── engines/ # LM Studio and Ollama driver adapters
198
+ │ │ ├── estimator.js# Mathematical memory and VRAM modeling
199
+ │ │ ├── gguf.js # GGUF tensor parser
200
+ │ │ ├── hardware.js # GPU detection, PCIe links, VRAM monitoring
201
+ │ │ ├── presets.js # Preset persistence and invalidation logic
202
+ │ │ └── profiles.js # Speed, balanced, and quality profile rules
203
+ │ ├── cli/ # Interactive wizard and CLI argument parsing
204
+ │ ├── i18n/ # English and Spanish localization catalogs
205
+ │ └── web/ # Embedded HTTP/SSE server powering the desktop GUI
206
+ ├── electron/ # Desktop launcher and main process wrapper
207
+ ├── test/ # Node.js native test suite
208
+ └── docs/ # Technical specs, real benchmark measurements, and notes
209
+ ```
210
+
211
+ ---
99
212
 
100
- Load profiles are covered by unit tests and were checked with one real load per profile on LM Studio (Linux, 2× RTX 5070). Choosing between several downloaded variants of a model, and the profiles on Ollama, have not been exercised on real hardware yet.
213
+ ## Development & Testing
101
214
 
102
- ## Development
215
+ Clone and set up locally:
103
216
 
104
217
  ```bash
105
218
  git clone https://github.com/ronald32acunadev/llmtuner.git
106
219
  cd llmtuner
107
220
  npm install
108
- npm start # terminal wizard
109
- npm run desktop # desktop app
110
- ```
111
221
 
112
- ## Tests
222
+ # Start CLI wizard
223
+ npm start
113
224
 
114
- ```bash
225
+ # Start Desktop app
226
+ npm run desktop
227
+
228
+ # Run test suite
115
229
  npm test
116
230
  ```
117
231
 
118
- Includes as regression the real results of 2× RTX 5070 with Qwen2.5-Coder-32B: 16K and 20K with q8_0 fit entirely, 24K doesn't; 32K only fits with q4_0.
232
+ The test suite includes regression tests verifying real dual-RTX 5070 measurements with Qwen2.5-Coder-32B.
233
+
234
+ ---
235
+
236
+ ## Notes & Troubleshooting
237
+
238
+ - **Desktop Runtime Download**: The Electron runtime is downloaded on the first execution of `llm-tuner-desktop`. If downloading in a restricted offline environment, extract `electron-v*.zip` into the `dist/` directory of the installed `electron` package and create `path.txt` with the content `electron`.
239
+ - **Root / Sudo Installs**: Avoid running `npm install -g --unsafe-perm` under root without proper directory ownership, as Electron may fail to unpack its binary into user space.
240
+ - **LM Studio Compatibility**: Internal config paths are calibrated and tested against LM Studio 0.4.25+.
241
+
242
+ ---
119
243
 
120
- ## Notes
244
+ ## License
121
245
 
122
- - Electron is not downloaded when the package is installed: the first run of the desktop app downloads it. If that download fails, extract `~/.cache/electron/*/electron-*.zip` into the `dist` folder of the installed `electron` package and create `path.txt` next to it with the text `electron`. The desktop app disables the Chromium sandbox only when it can't work (no `chrome-sandbox` with root setuid).
123
- - LM Studio's internal files are not a public API. This version is verified with LM Studio 0.4.25.
246
+ [MIT](LICENSE) © Ronald Daniel Acuña Arias