1 puntos por GN⁺ 3 시간 전 | 1 comentarios | Compartir por WhatsApp
  • 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.gguf con --mmproj y 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/v1 y 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 repositorio unsloth-gemma-4-26B-A4B-it-GGUF de 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.cpp y aceleración Metal
  • El comando de ejecución consistió en indicar en llama-cli la ruta del modelo, -ngl 999, -fa on, -c 4096 y -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.cpp se carga para speculative decoding con --model-draft, --spec-type draft-mtp y --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 2 como 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-max del 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, 3 fue el más rápido y 2 tambié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 + MTP registró 72.2 tok/s con la combinación Unsloth GGUF Q4 y Q8 MTP
  • llama.cpp Metal por sí solo registró 58.2 tok/s con Unsloth GGUF Q4
  • MLX-LM registró 45.8 tok/s con Unsloth UD MLX 4-bit
  • MLX-LM registró 43.9 tok/s con mlx-community 4-bit y 38.1 tok/s con mlx-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.cpp también necesita el proyector multimodal de Gemma 4, mmproj-BF16.gguf, para habilitar funciones multimodales
  • Al cargar el proyector con --mmproj, llama.cpp anuncia soporte multimodal y Pi puede enviar imágenes
  • Una prueba ejecutando llama.cpp Metal + MTP sin el proyector dio 120.3 tok/s en prompt y 71.4 tok/s en generación
  • La ejecución final cargando mmproj-BF16.gguf dio 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, tmux y python@3.11 se instalaron con Homebrew
  • Se creó la ruta ~/Developer/ML-Models/Gemma4/repos y se clonó el repositorio ggml-org/llama.cpp en repos/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=ON y GGML_BLAS_VENDOR=Apple

Descarga de archivos del modelo

  • Se creó un entorno virtual de Python 3.11 y se instalaron huggingface_hub y hf_xet
  • Con huggingface-cli download se descargaron el modelo principal de Gemma 4, mmproj-BF16.gguf y el modelo draft MTP
  • Los archivos descargados fueron gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, mmproj-BF16.gguf y MTP/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 65536 y --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.sh ejecuta el servidor en una sesión tmux y deja logs en logs/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 baseUrl del proveedor local gemma4-local apunta a http://127.0.0.1:8080/v1
  • api es openai-completions y, al ser un servidor local, authHeader se deja en false
  • El ID del modelo es gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf y el nombre se define como Gemma 4 26B-A4B Q4 + MTP
  • input debe 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.json se puede establecer defaultProvider como gemma4-local y defaultModel como el nombre del archivo GGUF correspondiente
  • Al ejecutar pi --offline --list-models gemma, se espera que el soporte de imagen aparezca como yes
  • 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-server en 127.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-A3B en lugar de Gemma 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-GGUF y mmproj-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, obteniendo Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf y mmproj-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-local y su baseUrl es http://127.0.0.1:8081/v1
  • La configuración del modelo Qwen usa reasoning: true, input: ["text", "image"], contextWindow: 65536 y maxTokens: 8192

1 comentarios

 
GN⁺ 3 시간 전
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 -hf de llama.cpp descarga el modelo por ti. Gracias al autor por compartir su experiencia, pero puede que no sea la mejor guía para principiantes

    • No estaba escrito como una guía seria para desarrolladores. La grabación de pantalla recibió muchos favoritos y empezaron a llegar mensajes preguntando cómo configurarlo, así que solo hice un resumen rápido de cómo armé esta prueba
      Vi 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
    • En la práctica, habría que probarlo con prompts arbitrarios de usuarios más un system prompt suficientemente grande. Como mínimo más de 1000 tokens, y en realidad algo como 3000 tokens parece mejor
      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
    • Con 128 tokens, es como benchmarkear no la ópera sino solo la obertura
    • Es parecido a decir “funciona en mi computadora” sin mirar el problema real. 128 tokens de verdad no son nada, apenas un poco más que una respuesta breve de saludo
  • Hace tiempo escribí algo parecido usando ollama y opencode: https://blog.kulman.sk/running-local-llm-coding-server/

    • Ollama no es una buena opción: https://sleepingrobots.com/dreams/stop-using-ollama/
      ¿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
    • Sí es útil, y si usas la GUI de ollama probablemente hasta se pueda simplificar más
  • Si solo usas llama.cpp, no parece que huggingface-cli sea realmente necesario para descargar algo. Si le pasas -hf ..., descarga el modelo
    Para 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 \
    ...

    • Para el modelo draft puedes usar -hfd
  • Si 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 agent
    Claro, 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/...

    • ¿Lo usas en el día a día? El prompt de Claude Code es enorme, así que en modelos locales el procesamiento del prompt tarda muchísimo, y además no pasa mucho tiempo antes de que se agote todo el contexto
  • 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

    • En un M1 Max de 64GB, no he visto ninguna ventaja especial de oMLX o MLX frente a GGUF de llama.cpp
      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
    • Si buscas un sandbox para conectar a oMLX y Pi, aquí hay uno: https://github.com/Dotnaught/pi-sandbox
    • Me parece el estado del arte para inferencia local en Mac. Aunque aparezcan regresiones, los desarrolladores responden rapidísimo, y es de los proyectos open source más impresionantes que he visto recientemente
  • 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”

    • Ya casi no uso Google Search. 9 de cada 10 veces la calidad de la información es pésima y cuesta separar lo que necesitas de todo el spam alrededor
      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