1 pontos por GN⁺ 3 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • A configuração de um agente de programação local permite rodar modelos no macOS com uma API compatível com OpenAI mesmo durante falhas de internet, além de processar entradas de texto e imagem no Pi
  • Em um Apple M1 Max 64GB com macOS 15.7.7, foram usados llama.cpp Metal e o modelo Gemma 4 26B-A4B GGUF, com velocidade base de geração de 58.2 tok/s
  • Após adicionar um modelo draft MTP e ajustar --spec-draft-n-max 3, a velocidade de geração subiu para 72.2 tok/s, uma melhora de cerca de 24%
  • É preciso carregar mmproj-BF16.gguf com --mmproj e configurar a entrada do modelo no Pi como ["text", "image"] para que entradas de imagem como capturas de tela sejam enviadas
  • A configuração final executa o servidor llama.cpp em 127.0.0.1:8080/v1, com o Pi usando isso como provedor local; o Qwen3.6 35B-A3B mostrou benchmarks melhores como agente de programação, mas foi mais lento neste teste, com 55 tok/s

Objetivo da configuração do agente de programação local

  • Algumas quedas de internet que impediram o uso de agentes de programação motivaram a tentativa de uma configuração de execução local
  • A configuração desejada precisava ser rápida o bastante para uso real no Mac e também utilizável por outras ferramentas por meio de uma API compatível com OpenAI
  • O objetivo também era permitir processar capturas de tela ou imagens quando necessário, para reenviar ao agente os resultados que ele produzisse
  • A configuração final é composta por llama.cpp, Gemma 4 26B-A4B GGUF, modelo draft Q8 MTP, projetor multimodal Gemma 4 e o agente de programação de terminal Pi
  • O ambiente de teste era um Apple M1 Max, 64GB de memória unificada e macOS 15.7.7

Modelo

  • O modelo principal era gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, disponível no repositório unsloth-gemma-4-26B-A4B-it-GGUF no Hugging Face
  • Esse arquivo tem cerca de 16GB e, junto com o cabeçalho draft MTP e o projetor multimodal, a pasta do modelo fica com cerca de 17GB
  • O prompt de benchmark foi Write a compact Python function that parses a unified diff and returns the changed file paths. Then explain two edge cases.
  • Cada benchmark gerou cerca de 128 tokens

Execução base: llama.cpp + Metal

  • O modelo principal foi executado diretamente com llama.cpp e aceleração Metal
  • O comando de execução usava llama-cli com o caminho do modelo, -ngl 999, -fa on, -c 4096 e -n 128
  • Na configuração base, a velocidade de processamento do prompt foi 298.0 tok/s e a velocidade de geração foi 58.2 tok/s
  • 58 tok/s não é exatamente rápido, mas é utilizável; em tarefas com agentes de programação, a velocidade importa porque há muitas chamadas de ferramentas

Adicionando o modelo draft MTP

  • O Gemma 4 oferece um modelo draft MTP no formato MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • No llama.cpp, ele é carregado para decodificação especulativa com --model-draft, --spec-type draft-mtp e --spec-draft-n-max
  • A primeira execução com MTP registrou 69.2 tok/s com 4 tokens draft
  • A documentação da Unsloth recomenda --spec-draft-n-max 2 como ponto de partida, mas sugere testar de 1 a 6 em cada hardware para usar o valor mais rápido
  • Após ajustar --spec-draft-n-max, o melhor resultado foi 72.2 tok/s com 3 tokens draft
  • O modelo principal sozinho marcou 58.2 tok/s, enquanto a configuração com o modelo draft Q8 MTP chegou a 72.2 tok/s
  • A velocidade de processamento do prompt praticamente se manteve, e a velocidade de geração melhorou cerca de 24%

Resultados do ajuste de MTP

  • Foram testados valores de --spec-draft-n-max de 1 a 6
  • O valor 1 teve 295.5 tok/s no prompt e 68.4 tok/s na geração
  • O valor 2 teve 299.1 tok/s no prompt e 72.0 tok/s na geração
  • O valor 3 foi o mais rápido, com 295.6 tok/s no prompt e 72.2 tok/s na geração
  • O valor 4 caiu para 70.7 tok/s na geração, o valor 5 para 63.7 tok/s e o valor 6 para 61.2 tok/s
  • No M1 Max, 3 foi o melhor valor, e 2 também ficou bem próximo

Comparação com MLX

  • Para verificar uma forma mais rápida de rodar o modelo no Mac, também foram testados modelos MLX baseados em mlx-lm
  • llama.cpp Metal + MTP registrou 72.2 tok/s com a combinação Unsloth GGUF Q4 e Q8 MTP
  • llama.cpp Metal sozinho registrou 58.2 tok/s com Unsloth GGUF Q4
  • MLX-LM registrou 45.8 tok/s com Unsloth UD MLX 4-bit
  • MLX-LM registrou 43.9 tok/s em mlx-community 4-bit e 38.1 tok/s em mlx-community OptiQ 4-bit
  • Nesta configuração específica, o llama.cpp foi mais rápido que o MLX, e o llama.cpp com MTP foi a melhor escolha
  • Também foi testado o Gemma 4 MTP com gemma-4-swift-mlx, mas o checkpoint MLX 26B 4-bit testado não correspondia às weight keys esperadas pelo loader, então o teste foi interrompido sem baixar e ajustar um novo modelo

Adicionando suporte a imagem

  • Para anexar capturas de tela no Pi, a entrada do modelo não pode ser apenas texto
  • Originalmente, o item do modelo local estava configurado como "input": ["text"], e nesse caso o Pi não conseguia enviar corretamente ao modelo a saída da ferramenta de imagem
  • O servidor llama.cpp também precisa do projetor multimodal Gemma 4, mmproj-BF16.gguf, para recursos multimodais
  • Ao carregar o projetor com --mmproj, o llama.cpp anuncia suporte multimodal e o Pi pode enviar imagens
  • Um teste executando llama.cpp Metal + MTP sem o projetor registrou 120.3 tok/s no prompt e 71.4 tok/s na geração
  • A execução final com mmproj-BF16.gguf carregado registrou 297.4 tok/s no prompt e 72.2 tok/s na geração
  • Na execução final com o projetor carregado, não houve perda de velocidade na geração de texto

Instalação do llama.cpp

  • As dependências cmake, git, tmux e python@3.11 foram instaladas com Homebrew
  • Foi criado o caminho ~/Developer/ML-Models/Gemma4/repos, e o repositório ggml-org/llama.cpp foi clonado em repos/llama.cpp
  • A build foi configurada com cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_METAL=ON -DGGML_ACCELERATE=ON
  • Depois disso, a build de release foi executada com cmake --build build --config Release -j
  • A build testada tinha as opções GGML_METAL=ON, GGML_ACCELERATE=ON, GGML_BLAS=ON e GGML_BLAS_VENDOR=Apple

Download dos arquivos de modelo

  • Foi criado um ambiente virtual com Python 3.11 e instalados huggingface_hub e hf_xet
  • O huggingface-cli download foi usado para baixar o modelo principal Gemma 4, mmproj-BF16.gguf e o modelo draft MTP
  • Os arquivos baixados foram gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, mmproj-BF16.gguf e MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • A pasta final do modelo, em models/unsloth-gemma-4-26B-A4B-it-GGUF/, contém esses três arquivos

Iniciando o servidor local

  • O servidor final é executado com llama-server, especificando o modelo principal, o modelo draft MTP e o projetor multimodal
  • As opções principais são --spec-type draft-mtp, --spec-draft-n-max 3, -ngl 999, -fa on, -c 65536 e --parallel 1
  • O servidor é executado com --host 127.0.0.1 --port 8080
  • O endpoint compatível com OpenAI é http://127.0.0.1:8080/v1
  • O wrapper start_server.sh executa o servidor em uma sessão tmux e grava os logs em logs/llama-server-mtp.log
  • Após chmod +x start_server.sh, o servidor é iniciado com ./start_server.sh
  • O funcionamento do servidor pode ser verificado com curl http://127.0.0.1:8080/v1/models

Configuração do Pi

  • O Pi lê a configuração do provedor de modelo em ~/.pi/agent/models.json
  • O baseUrl do provedor local gemma4-local aponta para http://127.0.0.1:8080/v1
  • api é openai-completions e, como é um servidor local, authHeader fica como false
  • O ID do modelo é gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, e o nome é configurado como Gemma 4 26B-A4B Q4 + MTP
  • input deve ser ["text", "image"]; caso contrário, o Pi trata o modelo como somente texto
  • A janela de contexto é 65536 e o máximo de tokens é 8192
  • Se necessário, em ~/.pi/agent/settings.json, defaultProvider pode ser definido como gemma4-local e defaultModel como o nome desse arquivo GGUF
  • Ao executar pi --offline --list-models gemma, o esperado é que o suporte a imagens apareça como yes
  • O modelo local é executado com pi --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf
  • A execução não interativa é feita com pi -p --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf "Explain what this repository does"
  • A entrada com captura de tela é feita com pi -p @"/path/to/screenshot.png" "Describe this image and point out anything relevant to the UI"

Configuração final

  • O runtime final de inferência é llama.cpp
  • A aceleração no macOS usa a combinação Metal + Accelerate
  • O modelo principal é gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf
  • O modelo draft é gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • A configuração de MTP é --spec-draft-n-max 3
  • O projetor multimodal é mmproj-BF16.gguf
  • O servidor é o llama-server em 127.0.0.1:8080
  • A API é a /v1 compatível com OpenAI
  • O agente de programação é o Pi, e a entrada do modelo no Pi é ["text", "image"]
  • O modelo draft MTP elevou a velocidade de geração do Gemma 4 neste ambiente de 58.2 tok/s para 72.2 tok/s, e a configuração é simples o bastante para rodar como um servidor local compatível com OpenAI

Alternativa: Qwen3.6 35B-A3B

  • Algumas pessoas sugerem usar Qwen3.6 35B-A3B em vez de Gemma 4 26B-A4B
  • Em benchmarks verificáveis, o Qwen é avaliado como um agente de programação muito melhor que o Gemma 4
  • Porém, essa configuração foi mais lenta, registrando 55 tok/s com a combinação Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf, unsloth-Qwen3.6-35B-A3B-MTP-GGUF e mmproj-BF16.gguf
  • 55 tok/s em vez de 72 tok/s faz uma diferença considerável para quem está esperando respostas
  • O download do modelo Qwen é feito a partir de unsloth/Qwen3.6-35B-A3B-MTP-GGUF, baixando Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf e mmproj-BF16.gguf
  • O servidor Qwen usa o mesmo llama-server, mas com --port 8081
  • Na configuração do Pi, o nome do provedor Qwen é qwen36-local, e o baseUrl é http://127.0.0.1:8081/v1
  • A configuração do modelo Qwen usa reasoning: true, input: ["text", "image"], contextWindow: 65536 e maxTokens: 8192

1 comentários

 
GN⁺ 3 시간 전
Comentários do Hacker News
  • Se o prompt do benchmark era “escreva uma função Python concisa que faça o parsing de um unified diff e retorne os caminhos dos arquivos alterados, e explique dois casos de borda”, e cada benchmark gerou cerca de 128 tokens, então 128 tokens parecem poucos demais para obter um bom resultado
    A aceleração via MTP depende da frequência com que os tokens previstos são aceitos; pela minha experiência, a taxa de aceitação é maior no começo da saída, então testes curtos podem criar uma aceleração com falso positivo
    O llama.cpp tem uma ferramenta dedicada de benchmark que percorre argumentos sem precisar reiniciar o servidor e reenviar o prompt: https://github.com/ggml-org/llama.cpp/blob/master/tools/llam...
    A seção de download de modelos também deveria ter mencionado que o argumento -hf do llama.cpp baixa o modelo para você. Agradeço ao autor por compartilhar a experiência, mas talvez não seja o melhor guia para iniciantes

    • Não foi escrito como um guia de desenvolvedor propriamente dito. A gravação de tela recebeu muitos favoritos e começaram a chegar mensagens perguntando como configurar, então organizei rapidamente como montei esse teste
      Vi o anúncio de “2x mais rápido” da Unclothe e pensei: “será que agora ficou rápido o suficiente para usar de verdade?”, então fui lá configurar por conta própria
      No ano passado também testei coisas como Devstral, mas eram lentas e burras demais, então eu não tinha vontade de continuar usando; desta vez finalmente cheguei à sensação de que dá para usar de verdade tanto em velocidade quanto em inteligência
    • Na prática, o ideal seria testar com prompts reais de usuários mais um prompt de sistema suficientemente grande. No mínimo 1000 tokens, e na prática algo como 3000 parece melhor
      O llama.cpp tem ferramenta para isso, e para medir direito é preciso incluir o prefill antes da geração de tokens. Também está ficando cada vez mais importante medir a velocidade de geração em contextos longos, como 32k ou 64k
    • Com 128 tokens, você está benchmarkando não a ópera, mas só a abertura
    • É parecido com dizer “funciona no meu computador” sem olhar o problema real. 128 tokens realmente não são nada, só um pouco mais do que uma resposta curta de saudação
  • Já escrevi um post parecido no passado usando ollama e opencode: https://blog.kulman.sk/running-local-llm-coding-server/

    • Ollama não é uma boa escolha: https://sleepingrobots.com/dreams/stop-using-ollama/
      O opencode não consome contexto demais com o prompt de sistema? Modelos locais têm limitações grandes de contexto e, se bem me lembro, o opencode usa algo em torno de 10k disso, ou perto disso
    • É realmente útil e, se você usar a GUI do ollama, talvez dê até para simplificar mais
  • Se você usar só llama.cpp, não parece que huggingface-cli seja realmente necessário para baixar algo. Basta passar -hf ... e ele baixa o modelo
    Para mudar o local do download, é só definir LLAMA_CACHE:
    LLAMA_CACHE="models" ./llama-server \
    -hf unsloth/gemma-4-31B-it-GGUF:UD-Q4_K_XL \
    ...

    • Para o modelo draft, basta usar -hfd
  • Se a RAM de memória unificada é grande, mas os teraflops e a largura de banda em GB/s são medianos ou piores, normalmente MoE é a opção mais promissora. No meu ambiente, um M2 Max 96GB, o atual número 1 em (inteligência, tok/s, profundidade de contexto) é DeepSeek-V4-Flash REAP25 <65gb gguf + ds4-server + pi agent
    Claro, não é melhor que uma API em nuvem, mas é utilizável o bastante para valer a pena se for necessário. Mesmo em um voo de 4 horas sem internet, o LLM local consumindo 60W ainda deixou a bateria aguentar bem
    O branch ds4 com suporte a REAP está aqui: https://github.com/ljubomirj/ds4/tree/reap-compact-support
    O grande diferencial é que o DS4F só cai para um nível impraticável de menos de 10 tok/s quando chega a 784K de contexto

  • Fico curioso se esses modelos locais realmente conseguem resolver problemas até para usuários que não são especialistas em uma linguagem de programação específica
    Além de autocompletar inline ou implementar unidades isoladas, não tenho certeza se conseguem de fato projetar e compor uma especificação técnica funcional

  • Subir um LLM local com llama.cpp/server e usar junto com Claude Code ou Codex-CLI é relativamente simples
    Como as configurações necessárias do llama server costumam estar espalhadas por vários lugares, mantenho aqui instruções para alguns LLMs abertos populares: https://pchalasani.github.io/claude-code-tools/integrations/...

    • Você usa isso no dia a dia? O prompt do Claude Code é enorme, então em modelos locais o processamento do prompt demora muito e logo o contexto também se esgota
  • Tenho usado omlx.ai com bastante sucesso para baixar vários modelos MLX adequados ao meu hardware e automatizar a execução de harnesses open source e fechados (Claude Code, Codex) com esses modelos
    Dá para fazer tanto pela UI web quanto pela de desktop, então, pessoalmente, com o omlx eu nem preciso seguir post de blog

    • Em um M1 Max de 64GB, não vi nenhuma vantagem especial de oMLX ou MLX sobre GGUF do llama.cpp
      Os builds de Gemma 4 em MLX que encontrei até agora eram mais lentos na mesma quantização e, com MTP, muito mais lentos
      Depois de escolher o modelo, a UI web embutida do llama.cpp é bem boa, e para experimentar várias coisas o LM Studio também serve bem
      Gemma-4 e Qwen 3.6 não precisam daquele grande bloco típico de prompt de sistema do opencode; na verdade, é melhor remover
    • Se você estiver procurando um sandbox para conectar ao oMLX e ao Pi, tem este aqui: https://github.com/Dotnaught/pi-sandbox
    • Eu diria que é o estado da arte para inferência local no Mac. Mesmo quando surge regressão, os desenvolvedores reagem muito rápido, e é um dos projetos open source mais impressionantes que vi recentemente
  • O DeepSeek v4 Flash rodando no ds4 do antirez foi bem impressionante
    Em termos de “conhecimento armazenado”, parece um modelo nível GPT-4, mas em chamadas de ferramenta de fluxo longo ele se sai melhor que modelos nível GPT-4
    Em um MBP M4 Max de 128GB, a geração fica em cerca de 24 t/s e o prefill em cerca de 200 t/s. Eu esperava que fosse lento, e em tarefas como geração de código realmente é, mas como orquestrador de máquinas para tarefas simples é surpreendentemente útil
    Para usos não agentivos, é um modelo perfeitamente bom para conversar, com a vantagem de ser totalmente self-hosted e privado
    [0]https://github.com/antirez/ds4

  • Se quiser fazer isso da forma mais preguiçosa possível, basta abrir o Claude Code no terminal, apontar para este post e mandar ele simplesmente “fazer isso”

    • Quase não uso mais a busca do Google. Em 9 de cada 10 vezes, a qualidade da informação é péssima e é difícil filtrar o que preciso no meio do spam ao redor
      Já o Claude resolve de uma vez ou com pouquíssimo ajuste
      O portal de entrada para conhecimento e execução agora é o LLM, e o Google Search parece um dinossauro
      É algo tão incrível que parece até mais impactante do que smartphones, como se estivéssemos um século no futuro