- La configuración de un agente local de programación permite ejecutar modelos en macOS mediante una API compatible con OpenAI incluso durante fallas de internet, y hacer que Pi procese entradas de texto e imagen
- Se usó llama.cpp Metal con el modelo Gemma 4 26B-A4B GGUF en un Apple M1 Max de 64 GB con macOS 15.7.7, con una velocidad base de generación de 58.2 tok/s
- Después de añadir un modelo draft MTP y ajustar
--spec-draft-n-max 3, la velocidad de generación subió a 72.2 tok/s, una mejora de aproximadamente 24% - Para que se envíen entradas de imagen como capturas de pantalla, hay que cargar
mmproj-BF16.ggufcon--mmprojy configurar la entrada del modelo de Pi como["text", "image"] - La configuración final ejecuta el servidor de llama.cpp en
127.0.0.1:8080/v1y Pi lo usa como proveedor local; Qwen3.6 35B-A3B mostró mejores benchmarks como agente de programación, pero en esta prueba fue más lento con 55 tok/s
Objetivo de la configuración del agente local de programación
- Varias caídas de internet que impidieron usar agentes de programación motivaron el intento de una configuración de ejecución local
- La configuración deseada tenía que ser lo bastante rápida para usarse de verdad en una Mac, y además debía poder usarse desde otras herramientas mediante una API compatible con OpenAI
- También se buscaba una configuración capaz de procesar capturas de pantalla o imágenes cuando fuera necesario, para volver a dar como entrada los resultados generados por el agente
- La configuración final quedó compuesta por
llama.cpp, Gemma 4 26B-A4B GGUF, un modelo draft Q8 MTP, el proyector multimodal de Gemma 4 y el agente de programación en terminal Pi - El entorno de pruebas fue un Apple M1 Max con 64 GB de memoria unificada y macOS 15.7.7
Modelo
- El modelo principal fue
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, disponible en el repositoriounsloth-gemma-4-26B-A4B-it-GGUFde Hugging Face - Ese archivo pesa alrededor de 16 GB, y con la cabecera draft MTP y el proyector multimodal la carpeta del modelo queda en unos 17 GB
- El prompt de benchmark fue
Write a compact Python function that parses a unified diff and returns the changed file paths. Then explain two edge cases. - Cada benchmark genera alrededor de 128 tokens
Ejecución base: llama.cpp + Metal
- El modelo principal se ejecutó directamente con
llama.cppy aceleración Metal - El comando de ejecución consistió en indicar en
llama-clila ruta del modelo,-ngl 999,-fa on,-c 4096y-n 128 - En la configuración base, la velocidad de procesamiento del prompt fue de 298.0 tok/s y la velocidad de generación fue de 58.2 tok/s
- 58 tok/s no es particularmente rápido, pero sí usable; en tareas de agentes de programación, donde hay muchas llamadas a herramientas, se necesita la mayor velocidad posible
Añadir un modelo draft MTP
- Gemma 4 ofrece un modelo draft MTP en la forma
MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf - En
llama.cppse carga para speculative decoding con--model-draft,--spec-type draft-mtpy--spec-draft-n-max - La primera ejecución de MTP registró 69.2 tok/s con 4 draft tokens
- La documentación de Unsloth recomienda
--spec-draft-n-max 2como punto de partida, pero indica probar entre 1 y 6 según el hardware y usar el valor más rápido - Tras ajustar
--spec-draft-n-max, el valor más rápido fue 72.2 tok/s con 3 draft tokens - El modelo principal por sí solo alcanzó 58.2 tok/s, y la configuración con modelo draft Q8 MTP llegó a 72.2 tok/s
- La velocidad de procesamiento del prompt casi se mantuvo, mientras que la velocidad de generación mejoró alrededor de 24%
Resultados del ajuste de MTP
- Se probaron valores de
--spec-draft-n-maxdel 1 al 6 - El valor 1 dio 295.5 tok/s en prompt y 68.4 tok/s en generación
- El valor 2 dio 299.1 tok/s en prompt y 72.0 tok/s en generación
- El valor 3 fue el más rápido con 295.6 tok/s en prompt y 72.2 tok/s en generación
- El valor 4 bajó a 70.7 tok/s en generación, el 5 a 63.7 tok/s y el 6 a 61.2 tok/s
- En el entorno M1 Max,
3fue el más rápido y2también dio un resultado bastante cercano
Comparación con MLX
- Para revisar una forma más rápida de ejecutar el modelo en Mac, también se probaron modelos MLX basados en
mlx-lm llama.cpp Metal + MTPregistró 72.2 tok/s con la combinación Unsloth GGUF Q4 y Q8 MTPllama.cpp Metalpor sí solo registró 58.2 tok/s con Unsloth GGUF Q4MLX-LMregistró 45.8 tok/s con Unsloth UD MLX 4-bitMLX-LMregistró 43.9 tok/s conmlx-community 4-bity 38.1 tok/s conmlx-community OptiQ 4-bit- En esta configuración específica, llama.cpp fue más rápido que MLX, y llama.cpp con MTP fue la mejor opción
- También se intentó usar Gemma 4 MTP con
gemma-4-swift-mlx, pero el checkpoint MLX de 26B 4-bit probado no coincidía con la weight key esperada por el loader, así que se dejó ahí en vez de volver a descargar y ajustar un modelo nuevo
Añadir soporte de imagen
- Para adjuntar capturas de pantalla en Pi, la entrada del modelo no puede ser solo de texto
- Originalmente, la entrada del modelo local estaba configurada como
"input": ["text"], y en ese caso Pi no podía enviar correctamente al modelo la salida de herramientas de imagen - El servidor
llama.cpptambién necesita el proyector multimodal de Gemma 4,mmproj-BF16.gguf, para habilitar funciones multimodales - Al cargar el proyector con
--mmproj,llama.cppanuncia soporte multimodal y Pi puede enviar imágenes - Una prueba ejecutando
llama.cpp Metal + MTPsin el proyector dio 120.3 tok/s en prompt y 71.4 tok/s en generación - La ejecución final cargando
mmproj-BF16.ggufdio 297.4 tok/s en prompt y 72.2 tok/s en generación - En la ejecución final con el proyector cargado no apareció ninguna caída en la velocidad de generación de texto
Instalación de llama.cpp
- Las dependencias
cmake,git,tmuxypython@3.11se instalaron con Homebrew - Se creó la ruta
~/Developer/ML-Models/Gemma4/reposy se clonó el repositorioggml-org/llama.cppenrepos/llama.cpp - La compilación se configuró con
cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_METAL=ON -DGGML_ACCELERATE=ON - Después se hizo la compilación release con
cmake --build build --config Release -j - La build probada tenía las opciones
GGML_METAL=ON,GGML_ACCELERATE=ON,GGML_BLAS=ONyGGML_BLAS_VENDOR=Apple
Descarga de archivos del modelo
- Se creó un entorno virtual de Python 3.11 y se instalaron
huggingface_hubyhf_xet - Con
huggingface-cli downloadse descargaron el modelo principal de Gemma 4,mmproj-BF16.ggufy el modelo draft MTP - Los archivos descargados fueron
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf,mmproj-BF16.ggufyMTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf - La carpeta final del modelo, bajo
models/unsloth-gemma-4-26B-A4B-it-GGUF/, contiene esos tres archivos
Iniciar el servidor local
- El servidor final se ejecuta con
llama-server, indicando el modelo principal, el modelo draft MTP y el proyector multimodal - Las opciones clave son
--spec-type draft-mtp,--spec-draft-n-max 3,-ngl 999,-fa on,-c 65536y--parallel 1 - El servidor se ejecuta con
--host 127.0.0.1 --port 8080 - El endpoint compatible con OpenAI es
http://127.0.0.1:8080/v1 - El wrapper
start_server.shejecuta el servidor en una sesióntmuxy deja logs enlogs/llama-server-mtp.log - Tras
chmod +x start_server.sh, el servidor se inicia con./start_server.sh - El funcionamiento del servidor se verifica con
curl http://127.0.0.1:8080/v1/models
Configuración de Pi
- Pi lee la configuración de proveedores de modelos desde
~/.pi/agent/models.json - El
baseUrldel proveedor localgemma4-localapunta ahttp://127.0.0.1:8080/v1 apiesopenai-completionsy, al ser un servidor local,authHeaderse deja enfalse- El ID del modelo es
gemma-4-26B-A4B-it-UD-Q4_K_XL.ggufy el nombre se define comoGemma 4 26B-A4B Q4 + MTP inputdebe ser["text", "image"]; de lo contrario, Pi tratará el modelo como si fuera solo de texto- La ventana de contexto se configura en 65536 y el máximo de tokens en 8192
- Si hace falta, en
~/.pi/agent/settings.jsonse puede establecerdefaultProvidercomogemma4-localydefaultModelcomo el nombre del archivo GGUF correspondiente - Al ejecutar
pi --offline --list-models gemma, se espera que el soporte de imagen aparezca comoyes - El modelo local se ejecuta con
pi --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf - La ejecución no interactiva se hace con
pi -p --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf "Explain what this repository does" - La entrada con captura de pantalla se hace con
pi -p @"/path/to/screenshot.png" "Describe this image and point out anything relevant to the UI"
Configuración final
- El runtime final de inferencia es
llama.cpp - La aceleración en macOS usa la combinación Metal + Accelerate
- El modelo principal es
gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf - El modelo draft es
gemma-4-26B-A4B-it-Q8_0-MTP.gguf - La configuración de MTP es
--spec-draft-n-max 3 - El proyector multimodal es
mmproj-BF16.gguf - El servidor es
llama-serveren127.0.0.1:8080 - La API es compatible con OpenAI en
/v1 - El agente de programación es Pi, y la entrada del modelo en Pi es
["text", "image"] - El modelo draft MTP elevó la velocidad de generación de Gemma 4 en este entorno de 58.2 tok/s a 72.2 tok/s, y la configuración es lo bastante simple como para ejecutarse como un servidor local compatible con OpenAI
Alternativa Qwen3.6 35B-A3B
- Algunas personas sugieren usar
Qwen3.6 35B-A3Ben lugar deGemma 4 26B-A4B - Según benchmarks verificables, Qwen está considerado un agente de programación mucho mejor que Gemma 4
- Sin embargo, la configuración con Qwen fue más lenta, registrando 55 tok/s con la combinación
Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf,unsloth-Qwen3.6-35B-A3B-MTP-GGUFymmproj-BF16.gguf - 55 tok/s en lugar de 72 tok/s representa una diferencia importante cuando la persona usuaria tiene que esperar
- La descarga del modelo Qwen se hace desde
unsloth/Qwen3.6-35B-A3B-MTP-GGUF, obteniendoQwen3.6-35B-A3B-UD-Q4_K_XL.ggufymmproj-BF16.gguf - El servidor de Qwen usa el mismo
llama-server, pero ejecutado con--port 8081 - En la configuración de Pi, el nombre del proveedor de Qwen es
qwen36-localy subaseUrleshttp://127.0.0.1:8081/v1 - La configuración del modelo Qwen usa
reasoning: true,input: ["text", "image"],contextWindow: 65536ymaxTokens: 8192
1 comentarios
Comentarios de Hacker News
Si el prompt del benchmark era “escribe una función concisa en Python que analice un unified diff y devuelva las rutas de los archivos modificados, y explica dos casos límite”, y cada benchmark generó unos 128 tokens, entonces 128 tokens parece demasiado poco para obtener un buen resultado
La aceleración por MTP depende de qué tan seguido se adopten los tokens predichos; por experiencia, al inicio de la salida la tasa de adopción suele ser más alta, así que una prueba corta puede producir una aceleración con falso positivo
llama.cpp tiene una herramienta dedicada de benchmark que recorre los argumentos sin necesidad de reiniciar el servidor ni enviar prompts: https://github.com/ggml-org/llama.cpp/blob/master/tools/llam...
La sección de descarga de modelos también debería haber mencionado que el argumento
-hfde llama.cpp descarga el modelo por ti. Gracias al autor por compartir su experiencia, pero puede que no sea la mejor guía para principiantesVi el anuncio de Unclothe de “2x más rápido” y pensé: “¿esto ya será lo bastante rápido como para usarse de verdad?”, así que lo configuré por mi cuenta
El año pasado también probé cosas como Devstral, pero eran demasiado lentas y tontas como para querer seguir usándolas; esta vez por fin sentí que tanto la velocidad como la inteligencia ya eran lo bastante útiles
llama.cpp tiene herramientas para eso, y para medir bien hay que incluir un prefill antes de la generación de tokens. También cada vez importa más medir la velocidad de generación en contextos largos como 32k o 64k
Hace tiempo escribí algo parecido usando ollama y opencode: https://blog.kulman.sk/running-local-llm-coding-server/
¿opencode no consume demasiado contexto con su system prompt? Los modelos locales tienen límites fuertes de contexto y, si no recuerdo mal, opencode usa unos 10k o algo cercano a eso
Si solo usas llama.cpp, no parece que
huggingface-clisea realmente necesario para descargar algo. Si le pasas-hf ..., descarga el modeloPara cambiar la ubicación de descarga, basta con configurar
LLAMA_CACHE:LLAMA_CACHE="models" ./llama-server \-hf unsloth/gemma-4-31B-it-GGUF:UD-Q4_K_XL \...-hfdSi tienes bastante RAM de memoria unificada pero teraflops y ancho de banda GB/s entre medios y bajos, normalmente MoE es lo más prometedor. En mi entorno, un M2 Max de 96GB, el número 1 actual en
(inteligencia, tok/s, profundidad de contexto)es DeepSeek-V4-Flash REAP25<65gb gguf+ ds4-server + pi agentClaro, no supera a una API en la nube, pero sí alcanza un nivel que uno toleraría si hace falta. Incluso en un vuelo de 4 horas sin internet, el LLM local consumiendo 60W dejó batería suficiente
La rama de ds4 con soporte para REAP está aquí: https://github.com/ljubomirj/ds4/tree/reap-compact-support
Hace una gran diferencia que DS4F recién en 784K de contexto caiga a un nivel inutilizable de menos de 10 tok/s
Me pregunto si estos modelos locales realmente pueden resolver problemas incluso para usuarios que no son expertos en cierto lenguaje de programación
Más allá del autocompletado en línea o la implementación de una unidad, no estoy seguro de que puedan diseñar y ensamblar una especificación técnica que de verdad funcione
Levantar un LLM local con llama.cpp/server y usarlo junto con Claude Code o Codex-CLI es relativamente sencillo
Como la configuración necesaria de llama server suele estar dispersa por todas partes, aquí mantengo instrucciones para varios open LLM populares: https://pchalasani.github.io/claude-code-tools/integrations/...
He usado omlx.ai con bastante éxito para descargar varios modelos MLX adecuados para mi hardware y ejecutar automáticamente harnesses abiertos y cerrados (Claude Code, Codex) con esos modelos
Se puede hacer tanto desde la UI web como desde la de escritorio, así que personalmente con omlx no hace falta seguir una entrada de blog
Las compilaciones MLX de Gemma 4 que he encontrado hasta ahora eran más lentas con la misma cuantización, y con MTP eran mucho más lentas
Una vez elegido el modelo, la UI web integrada de llama.cpp está bastante bien, y para andar probando cosas LM Studio también sirve
Gemma-4 y Qwen 3.6 no necesitan para nada ese gran bloque típico del system prompt de opencode; de hecho, es mejor quitarlo
DeepSeek v4 Flash ejecutado con ds4 de antirez me pareció bastante impresionante
En términos de “conocimiento almacenado”, se siente como un modelo nivel GPT-4, pero en llamadas de herramientas de flujo largo lo hace mejor que modelos de nivel GPT-4
En una MBP M4 Max de 128GB, la generación da unos 24 t/s y el prefill unos 200 t/s. Esperaba que fuera lento, y en tareas como generación de código realmente lo es, pero como orquestador de máquinas para tareas simples resulta sorprendentemente útil
Para usos no agentivos, es un modelo bastante decente para conversar, y además tiene la ventaja de ser completamente autónomo y privado
[0]https://github.com/antirez/ds4
Si quieres hacerlo de la forma más floja posible, solo abre Claude Code en la terminal, apunta a esta publicación y dile “hazlo”
En cambio, Claude lo resuelve de una vez o con muy pocos ajustes
La puerta de entrada al conocimiento y a la ejecución ahora es el LLM, y Google Search se siente como un dinosaurio
Se siente como estar un siglo en el futuro, incluso más impresionante que el smartphone mismo