1 điểm bởi GN⁺ 3 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Cấu hình coding agent cục bộ này cho phép chạy mô hình qua API tương thích OpenAI trên macOS ngay cả khi mất Internet, đồng thời để Pi xử lý đầu vào văn bản và hình ảnh
  • Thử nghiệm dùng Apple M1 Max 64GB, macOS 15.7.7, với llama.cpp Metal và mô hình Gemma 4 26B-A4B GGUF; tốc độ sinh mặc định đạt 58.2 tok/s
  • Sau khi thêm MTP draft model và chỉnh --spec-draft-n-max 3, tốc độ sinh tăng lên 72.2 tok/s, cải thiện khoảng 24%
  • Cần nạp mmproj-BF16.gguf bằng --mmproj và đặt đầu vào mô hình của Pi thành ["text", "image"] thì đầu vào hình ảnh như ảnh chụp màn hình mới được truyền đi
  • Cấu hình cuối cùng chạy máy chủ llama.cpp tại 127.0.0.1:8080/v1 và để Pi dùng nó làm nhà cung cấp cục bộ; Qwen3.6 35B-A3B cho benchmark coding agent tốt hơn nhưng trong thử nghiệm này chậm hơn ở mức 55 tok/s

Mục tiêu của cấu hình coding agent cục bộ

  • Một vài lần mất Internet khiến không thể dùng coding agent là động lực để thử cấu hình chạy cục bộ
  • Cấu hình mong muốn phải đủ nhanh để dùng thực tế trên Mac và phải dùng được từ các công cụ khác thông qua API tương thích OpenAI
  • Mục tiêu còn là có thể xử lý ảnh chụp màn hình hoặc hình ảnh khi cần để đưa lại kết quả do agent tạo ra làm đầu vào
  • Cấu hình cuối cùng gồm llama.cpp, Gemma 4 26B-A4B GGUF, Q8 MTP draft model, Gemma 4 multimodal projector và coding agent terminal Pi
  • Môi trường thử nghiệm là Apple M1 Max, 64GB bộ nhớ hợp nhất, macOS 15.7.7

Mô hình

  • Mô hình chính là gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, nằm trong kho unsloth-gemma-4-26B-A4B-it-GGUF trên Hugging Face
  • Tệp này có dung lượng khoảng 16GB; khi để cùng MTP draft head và multimodal projector thì thư mục mô hình vào khoảng 17GB
  • Prompt benchmark là Write a compact Python function that parses a unified diff and returns the changed file paths. Then explain two edge cases.
  • Mỗi benchmark sinh khoảng 128 token

Chạy cơ bản: llama.cpp + Metal

  • Mô hình chính được chạy trực tiếp bằng llama.cpp với tăng tốc Metal
  • Lệnh chạy dùng llama-cli với đường dẫn mô hình, -ngl 999, -fa on, -c 4096, -n 128
  • Ở cấu hình cơ bản, tốc độ xử lý prompt là 298.0 tok/s và tốc độ sinh là 58.2 tok/s
  • 58 tok/s không phải quá nhanh nhưng vẫn dùng được; với tác vụ coding agent thì càng cần tốc độ cao vì có nhiều lần gọi công cụ

Thêm MTP draft model

  • Gemma 4 cung cấp MTP draft model ở dạng MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • Trong llama.cpp, mô hình này được nạp cho speculative decoding bằng --model-draft, --spec-type draft-mtp, --spec-draft-n-max
  • Lần chạy MTP đầu tiên ghi nhận 69.2 tok/s với 4 draft token
  • Tài liệu Unsloth khuyến nghị bắt đầu với --spec-draft-n-max 2, nhưng nên thử từ 1 đến 6 tùy phần cứng để chọn giá trị nhanh nhất
  • Sau khi tinh chỉnh --spec-draft-n-max, mức nhanh nhất là 72.2 tok/s với 3 draft token
  • Mô hình chính chạy đơn lẻ đạt 58.2 tok/s, còn cấu hình thêm Q8 MTP draft model đạt 72.2 tok/s
  • Tốc độ xử lý prompt gần như giữ nguyên, còn tốc độ sinh cải thiện khoảng 24%

Kết quả tinh chỉnh MTP

  • Đã thử các giá trị --spec-draft-n-max từ 1 đến 6
  • Giá trị 1 cho 295.5 tok/s ở prompt và 68.4 tok/s ở sinh
  • Giá trị 2 cho 299.1 tok/s ở prompt và 72.0 tok/s ở sinh
  • Giá trị 3 cho 295.6 tok/s ở prompt và 72.2 tok/s ở sinh, là nhanh nhất
  • Giá trị 4 cho 70.7 tok/s ở sinh, giá trị 5 là 63.7 tok/s, giá trị 6 là 61.2 tok/s nên chậm hơn
  • Trên M1 Max, 3 là nhanh nhất, còn 2 cũng cho kết quả rất gần

So sánh với MLX

  • Để kiểm tra cách chạy mô hình nhanh hơn trên Mac, tác giả cũng thử các mô hình MLX dựa trên mlx-lm
  • llama.cpp Metal + MTP đạt 72.2 tok/s với tổ hợp Unsloth GGUF Q4 và Q8 MTP
  • llama.cpp Metal đơn lẻ đạt 58.2 tok/s với Unsloth GGUF Q4
  • MLX-LM đạt 45.8 tok/s với Unsloth UD MLX 4-bit
  • MLX-LM đạt 43.9 tok/s với mlx-community 4-bit, và 38.1 tok/s với mlx-community OptiQ 4-bit
  • Trong cấu hình cụ thể này, llama.cpp nhanh hơn MLX, và llama.cpp có MTP là lựa chọn tốt nhất
  • Tác giả cũng thử Gemma 4 MTP với gemma-4-swift-mlx, nhưng checkpoint MLX 26B 4-bit đã thử không khớp với weight key mà loader mong đợi, nên dừng lại thay vì tải lại và tinh chỉnh mô hình mới

Thêm hỗ trợ hình ảnh

  • Nếu muốn đính kèm ảnh chụp màn hình trong Pi thì đầu vào mô hình không thể chỉ là văn bản
  • Ban đầu mục mô hình cục bộ được đặt là "input": ["text"], và trong trường hợp đó Pi không thể gửi đúng đầu ra từ công cụ hình ảnh vào mô hình
  • Máy chủ llama.cpp cũng cần Gemma 4 multimodal projectormmproj-BF16.gguf để có khả năng đa phương thức
  • Khi nạp projector bằng --mmproj, llama.cpp sẽ công bố hỗ trợ đa phương thức và Pi có thể gửi hình ảnh
  • Bài test chạy llama.cpp Metal + MTP mà không có projector cho 120.3 tok/s ở prompt và 71.4 tok/s ở sinh
  • Lần chạy cuối cùng có nạp mmproj-BF16.gguf cho 297.4 tok/s ở prompt và 72.2 tok/s ở sinh
  • Ở lần chạy cuối có projector, không thấy suy giảm tốc độ sinh văn bản

Cài đặt llama.cpp

  • Các phụ thuộc được cài bằng Homebrew gồm cmake, git, tmux, python@3.11
  • Tạo đường dẫn ~/Developer/ML-Models/Gemma4/repos rồi clone kho ggml-org/llama.cpp vào repos/llama.cpp
  • Bản build được cấu hình bằng cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_METAL=ON -DGGML_ACCELERATE=ON
  • Sau đó chạy cmake --build build --config Release -j để build bản phát hành
  • Bản build được thử có các thiết lập GGML_METAL=ON, GGML_ACCELERATE=ON, GGML_BLAS=ON, GGML_BLAS_VENDOR=Apple

Tải tệp mô hình

  • Tạo môi trường ảo Python 3.11 và cài huggingface_hub cùng hf_xet
  • Dùng huggingface-cli download để tải mô hình chính Gemma 4, mmproj-BF16.gguf và MTP draft model
  • Các tệp cần tải là gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, mmproj-BF16.gguf, MTP/gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • Thư mục mô hình cuối cùng chứa ba tệp này dưới models/unsloth-gemma-4-26B-A4B-it-GGUF/

Khởi động máy chủ cục bộ

  • Máy chủ cuối cùng chạy bằng llama-server, với mô hình chính, MTP draft model và multimodal projector đều được chỉ định
  • Các tùy chọn chính là --spec-type draft-mtp, --spec-draft-n-max 3, -ngl 999, -fa on, -c 65536, --parallel 1
  • Máy chủ chạy với --host 127.0.0.1 --port 8080
  • Endpoint tương thích OpenAI là http://127.0.0.1:8080/v1
  • Wrapper start_server.sh chạy máy chủ trong phiên tmux và ghi log vào logs/llama-server-mtp.log
  • Sau chmod +x start_server.sh, khởi động máy chủ bằng ./start_server.sh
  • Có thể kiểm tra máy chủ hoạt động bằng curl http://127.0.0.1:8080/v1/models

Cấu hình Pi

  • Pi đọc cấu hình nhà cung cấp mô hình từ ~/.pi/agent/models.json
  • baseUrl của nhà cung cấp cục bộ gemma4-local trỏ tới http://127.0.0.1:8080/v1
  • apiopenai-completions, và vì là máy chủ cục bộ nên authHeader được để là false
  • ID mô hình là gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf, còn tên được đặt là Gemma 4 26B-A4B Q4 + MTP
  • input phải là ["text", "image"], nếu không Pi sẽ coi mô hình là chỉ hỗ trợ văn bản
  • Cửa sổ ngữ cảnh được đặt là 65536, số token tối đa là 8192
  • Nếu cần, trong ~/.pi/agent/settings.json có thể đặt defaultProvidergemma4-localdefaultModel là tên tệp GGUF tương ứng
  • Khi chạy pi --offline --list-models gemma, kết quả mong đợi là hỗ trợ hình ảnh hiển thị yes
  • Chạy mô hình cục bộ bằng pi --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf
  • Chạy không tương tác dùng dạng pi -p --provider gemma4-local --model gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf "Explain what this repository does"
  • Đầu vào ảnh chụp màn hình dùng dạng pi -p @"/path/to/screenshot.png" "Describe this image and point out anything relevant to the UI"

Cấu hình cuối cùng

  • Runtime suy luận cuối cùng là llama.cpp
  • Tăng tốc trên macOS là tổ hợp Metal + Accelerate
  • Mô hình chính là gemma-4-26B-A4B-it-UD-Q4_K_XL.gguf
  • Draft model là gemma-4-26B-A4B-it-Q8_0-MTP.gguf
  • Thiết lập MTP là --spec-draft-n-max 3
  • Multimodal projector là mmproj-BF16.gguf
  • Máy chủ là llama-server tại 127.0.0.1:8080
  • API là /v1 tương thích OpenAI
  • Coding agent là Pi, và đầu vào mô hình của Pi là ["text", "image"]
  • Trong môi trường này, MTP draft model đã nâng tốc độ sinh của Gemma 4 từ 58.2 tok/s lên 72.2 tok/s, đồng thời cấu hình vẫn đủ đơn giản để chạy như một máy chủ cục bộ tương thích OpenAI

Phương án thay thế Qwen3.6 35B-A3B

  • Một số người đề xuất dùng Qwen3.6 35B-A3B thay cho Gemma 4 26B-A4B
  • Theo các benchmark có thể kiểm chứng, Qwen được đánh giá là coding agent tốt hơn đáng kể so với Gemma 4
  • Tuy nhiên cấu hình Qwen chậm hơn; với tổ hợp Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf, unsloth-Qwen3.6-35B-A3B-MTP-GGUF, mmproj-BF16.gguf thì đạt 55 tok/s
  • 55 tok/s thay vì 72 tok/s tạo ra khác biệt đáng kể khi người dùng phải chờ
  • Cách tải mô hình Qwen là lấy Qwen3.6-35B-A3B-UD-Q4_K_XL.ggufmmproj-BF16.gguf từ unsloth/Qwen3.6-35B-A3B-MTP-GGUF
  • Máy chủ Qwen dùng cùng llama-server nhưng chạy với --port 8081
  • Tên nhà cung cấp Qwen trong cấu hình Pi là qwen36-local, baseUrlhttp://127.0.0.1:8081/v1
  • Cấu hình mô hình Qwen dùng reasoning: true, input: ["text", "image"], contextWindow: 65536, maxTokens: 8192

1 bình luận

 
Ý kiến trên Hacker News
  • Prompt benchmark là “viết một hàm Python ngắn gọn để phân tích unified diff và trả về đường dẫn tệp đã thay đổi, đồng thời giải thích hai edge case”, và nếu mỗi benchmark chỉ sinh khoảng 128 token thì có vẻ 128 token là quá ít để cho ra kết quả tốt
    Tăng tốc MTP phụ thuộc vào việc các token dự đoán được chấp nhận thường xuyên đến đâu; theo kinh nghiệm thì ở phần đầu của đầu ra tỷ lệ chấp nhận cao hơn, nên các bài test ngắn có thể tạo ra tăng tốc dương tính giả
    llama.cpp có một công cụ benchmark chuyên dụng quét qua các đối số mà không cần khởi động lại server và gửi prompt: https://github.com/ggml-org/llama.cpp/blob/master/tools/llam...
    Phần tải mô hình cũng lẽ ra nên nhắc rằng tham số -hf của llama.cpp có thể tự tải mô hình thay. Cảm ơn tác giả đã chia sẻ trải nghiệm, nhưng với người mới thì đây có thể không phải hướng dẫn tốt nhất

    • Đây vốn không phải bài viết như một hướng dẫn chuẩn cho lập trình viên. Bản ghi màn hình nhận được nhiều lượt lưu và tôi bắt đầu nhận tin nhắn hỏi cách thiết lập, nên tôi chỉ nhanh chóng tổng hợp lại cách mình cấu hình bài test này
      Sau khi thấy công bố “nhanh gấp 2 lần” của Unclothe, tôi tự hỏi “liệu mức này đã đủ nhanh để dùng thực tế chưa?” nên đã tự thiết lập thử
      Năm ngoái tôi cũng từng test với kiểu như Devstral, nhưng nó quá chậm và ngớ ngẩn nên tôi không muốn tiếp tục dùng; còn lần này thì cuối cùng tôi đã cảm thấy nó đủ dùng cả về tốc độ lẫn độ thông minh
    • Một cách thực tế hơn là phải thử nghiệm với đủ cả system prompt ngoài prompt người dùng ngẫu nhiên. Tối thiểu nên là hơn 1000 token, thực tế khoảng 3000 token có vẻ hợp lý
      llama.cpp có công cụ cho việc này, và để đo đúng thì cần thêm prefill trước khi sinh token. Việc đo tốc độ sinh token ở ngữ cảnh dài như 32k hay 64k cũng đang ngày càng quan trọng hơn
    • 128 token thì giống như benchmark mỗi khúc dạo đầu, chứ không phải cả vở opera
    • Nó hơi giống kiểu nói “máy tôi chạy được” mà không xem xét vấn đề thực tế. 128 token thật sự chẳng là gì, chỉ nhỉnh hơn một câu chào ngắn một chút
  • Trước đây tôi cũng từng viết một bài tương tự dùng ollama và opencode: https://blog.kulman.sk/running-local-llm-coding-server/

    • Ollama không phải lựa chọn tốt: https://sleepingrobots.com/dreams/stop-using-ollama/
      opencode có phải đang ngốn quá nhiều ngữ cảnh cho system prompt không? Mô hình cục bộ vốn bị giới hạn ngữ cảnh, và nếu nhớ không nhầm thì opencode dùng khoảng 10k hoặc gần mức đó
    • Nó thực sự hữu ích, và nếu dùng ollama GUI thì có lẽ còn có thể đơn giản hóa hơn nữa
  • Nếu chỉ dùng llama.cpp thì có vẻ không nhất thiết phải cần huggingface-cli để tải thứ gì đó. Chỉ cần truyền -hf ... là nó sẽ tải mô hình
    Nếu muốn đổi vị trí tải xuống thì đặt LLAMA_CACHE:
    LLAMA_CACHE="models" ./llama-server \
    -hf unsloth/gemma-4-31B-it-GGUF:UD-Q4_K_XL \
    ...

    • Với draft model thì dùng -hfd
  • Nếu RAM bộ nhớ hợp nhất lớn nhưng teraflops và băng thông GB/s chỉ ở mức trung bình trở xuống, thì thường MoE là lựa chọn có hy vọng nhất. Trên môi trường của tôi là M2 Max 96GB, hạng nhất hiện tại theo tiêu chí (trí tuệ, tok/s, độ sâu ngữ cảnh) là DeepSeek-V4-Flash REAP25 <65gb gguf + ds4-server + pi agent
    Dĩ nhiên nó không tốt hơn API đám mây, nhưng nếu cần thì vẫn đủ để chấp nhận dùng. Ngay cả trên chuyến bay 4 tiếng không có Internet, LLM cục bộ ngốn 60W mà pin vẫn trụ đủ
    Nhánh ds4 hỗ trợ REAP ở đây: https://github.com/ljubomirj/ds4/tree/reap-compact-support
    Việc DS4F chỉ rơi xuống mức không dùng được dưới 10 tok/s ở ngữ cảnh 784K tạo ra khác biệt rất lớn

  • Tôi tự hỏi liệu những mô hình cục bộ kiểu này có thật sự giải quyết được vấn đề cho cả những người không phải chuyên gia ở một ngôn ngữ lập trình cụ thể hay không
    Ngoài tự động hoàn thành nội dòng hay triển khai từng đơn vị, tôi chưa chắc nó có thể thiết kế và ghép nối các đặc tả kỹ thuật thực sự hoạt động được

  • Dùng llama.cpp/server để chạy LLM cục bộ rồi kết hợp với Claude Code hay Codex-CLI là tương đối đơn giản
    Cài đặt llama server cần thiết thường bị rải rác khắp nơi, nên tôi đang duy trì hướng dẫn cho một vài open LLM phổ biến ở đây: https://pchalasani.github.io/claude-code-tools/integrations/...

    • Bạn có dùng nó như driver hằng ngày không? Prompt của Claude Code cực lớn, nên trên mô hình cục bộ việc xử lý prompt mất rất nhiều thời gian, và chẳng bao lâu là dùng hết cả ngữ cảnh
  • Tôi đã khá thành công khi dùng omlx.ai để tải nhiều mô hình MLX phù hợp với phần cứng của mình, rồi tự động chạy open-source và harness đóng (Claude Code, Codex) bằng các mô hình đó
    Làm được cả trên UI web lẫn desktop, nên cá nhân tôi thấy dùng omlx thì không cần phải làm theo bài blog đó

    • Trên M1 Max 64GB, tôi không thấy oMLX hay MLX có lợi thế gì đặc biệt hơn GGUF của llama.cpp
      Các bản dựng Gemma 4 MLX mà tôi tìm được cho đến nay chậm hơn ở cùng mức lượng tử hóa, và với MTP thì chậm hơn rất nhiều
      Sau khi chọn mô hình xong, web UI tích hợp của llama.cpp khá ổn, còn nếu muốn nghịch thử nhiều thứ thì LM Studio cũng tốt
      Gemma-4 và Qwen 3.6 hoàn toàn không cần cả một khối lớn system prompt kiểu opencode thông thường, và bỏ đi còn tốt hơn
    • Nếu bạn đang tìm một sandbox để gắn với oMLX và Pi thì có cái này: https://github.com/Dotnaught/pi-sandbox
    • Tôi xem đây là trạng thái tối tân nhất cho suy luận cục bộ trên Mac. Ngay cả khi có hồi quy thì các nhà phát triển phản ứng cực nhanh, và đây là một trong những dự án open-source ấn tượng nhất tôi từng thấy gần đây
  • DeepSeek v4 Flash chạy bằng ds4 của antirez khá ấn tượng
    Xét về “kiến thức được lưu sẵn” thì nó cho cảm giác như mô hình cỡ GPT-4, nhưng ở các luồng gọi công cụ dài thì còn làm tốt hơn các mô hình cỡ GPT-4
    Trên MBP M4 Max 128GB, tốc độ sinh khoảng 24 t/s và prefill khoảng 200 t/s. Tôi tưởng nó sẽ chậm, và với các việc như sinh mã thì đúng là chậm, nhưng như một bộ điều phối máy móc cho các tác vụ đơn giản thì lại hữu ích đến ngạc nhiên
    Với các mục đích không mang tính agent, đây là mô hình đủ ổn để trò chuyện, và còn có lợi thế là hoàn toàn tự chạy và riêng tư
    [0]https://github.com/antirez/ds4

  • Nếu muốn làm theo kiểu cực lười thì chỉ cần mở Claude Code trong terminal, trỏ nó vào bài này rồi bảo “làm đi”

    • Giờ tôi gần như không còn dùng Google Search nữa. 9 trên 10 lần chất lượng thông tin quá tệ, và rất khó lọc ra thứ mình cần giữa đống spam xung quanh
      Còn Claude thì xử lý xong trong một lần hoặc chỉ cần chỉnh rất ít là được
      Cánh cổng dẫn đến tri thức và thực thi giờ là LLM, còn Google Search thì có cảm giác như khủng long
      Nó thậm chí còn ấn tượng hơn cả smartphone, như thể đang sống trước thời đại cả một thế kỷ vậy