Chạy model local: đừng bắt đầu bằng model

Chạy model local: đừng bắt đầu bằng model

Một playbook triển khai inference local cho builder: thử nhỏ, đo đúng, đặt guardrail, rồi mới quyết định scale hay dừng.

9 giờ tối, một tech lead nhắn mình: “Team đang tính kéo một con 27B 1-bit về chạy local, có nên không?” Câu hỏi nghe như hỏi mua GPU, nhưng thật ra là hỏi về quyền vận hành: ai chịu latency, ai debug kernel, ai giữ endpoint sống lúc demo thành production.

Điểm mình muốn chốt ngay: đừng xem local inference là lựa chọn model. Hãy xem nó là lựa chọn triển khai. Model chỉ là một loài trong khu rừng; nếu tầng tán CUDA, server API, cache, logging và tiêu chí dừng không sống nổi, loài đẹp mấy cũng thành cây cảnh để chụp màn hình.

Bài này là playbook cho builder muốn thử triển khai local LLM kiểu Bonsai-27B 1-bit qua PrismML fork của llama.cpp, có server OpenAI-compatible để app hiện có gọi vào gần như không đổi code.

Sơ đồ minh họa cho bài Chạy model local: đừng bắt đầu bằng model

Sơ đồ tóm tắt ý chính của bài viết.

Mục tiêu của buổi thử: trả lời 4 câu, không phải khoe prompt

Trong một buổi chiều hoặc tối, team bạn chỉ cần trả lời bốn câu:

  1. Máy có chạy được binary đúng không? Ở đây là CUDA-enabled build, vì định dạng Q1_0_g128 GGUF cần kernel phù hợp.
  2. Model có trả lời ổn qua CLI không? CLI smoke test giúp tách lỗi model khỏi lỗi server.
  3. Endpoint local có tương thích workflow hiện tại không? OpenAI-compatible nghĩa là client có thể gọi kiểu /v1/completions hoặc chat API quen thuộc, không phải viết lại cả app.
  4. Có dấu hiệu đáng scale không? Latency, token throughput, memory, lỗi timeout, và độ ổn định qua nhiều lượt gọi.

Nếu buổi thử không trả lời được bốn câu này, đừng nâng cấp prompt, đừng đổi model vội. Bạn đang thiếu đường quan sát hệ thống.

Checklist trước khi kéo model về

Trước khi download vài GB weights, mình sẽ bắt team tick checklist này:

Quantization là kỹ thuật nén trọng số model xuống ít bit hơn để giảm bộ nhớ và chi phí chạy. Với 1-bit, cái giá không chỉ nằm ở “model nhỏ hơn”, mà nằm ở việc bạn cần runtime biết cách giải mã định dạng đó. Trong case Bonsai-27B Q1_0_g128 GGUF, PrismML fork cung cấp CUDA kernels chuyên biệt. Bỏ qua chi tiết này giống như đem một loài bản địa sang vùng đất khác rồi quên kiểm tra đất và khí hậu.

Bước 1: khóa môi trường chạy

Đừng bắt đầu bằng pip install dài ngoằng. Bắt đầu bằng runtime.

nvidia-smi
nvcc --version || true
python --version

Nếu nvidia-smi không thấy GPU, dừng. Nếu bạn đang chạy Colab, máy dev, hoặc server nội bộ, ghi lại loại GPU và memory. Không cần benchmark hoành tráng ở bước này; chỉ cần biết tầng phần cứng có tồn tại.

Cài dependency tối thiểu:

python -m pip install -U huggingface_hub requests

Ở team thật, mình khuyên tạo file runbook.md ngay từ đầu:

## Local LLM Trial
- GPU:
- CUDA:
- Model file:
- llama.cpp fork commit:
- Build flags:
- Smoke prompt:
- Stop criteria:

Nghe hơi thủ công, nhưng tới lúc binary build được trên máy A mà chết trên máy B, bạn sẽ cảm ơn dòng commit đó.

Bước 2: build đúng binary, đừng cầu may với wheel có sẵn

Với model cần kernel đặc thù, dùng đúng fork là quyết định vận hành, không phải sở thích open-source.

git clone https://github.com/PrismML/llama.cpp prismml-llama
cd prismml-llama
cmake -B build -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j

Sau build, kiểm tra ít nhất ba executable:

ls build/bin/llama-cli build/bin/llama-server build/bin/llama-bench

Nếu thiếu llama-server, bạn chưa có đường phục vụ app. Nếu thiếu llama-bench, bạn thiếu dụng cụ đo. Nếu chỉ có CLI và một câu trả lời đẹp, đó mới là demo tầng thấp, chưa phải workflow.

Nguồn về TileLang nhắc mình một điều đáng giữ: performance không tự nhiên xuất hiện vì bạn có GPU. Kernel, memory layout, shared memory, register, autotuning — toàn bộ lớp này quyết định phần lớn cảm giác “nhanh hay ì”. Bạn không nhất thiết phải viết kernel bằng TileLang, nhưng phải biết khi nào mình đang phụ thuộc vào kernel do người khác viết.

Bước 3: smoke test bằng CLI trước khi mở server

Tải model GGUF từ Hugging Face theo repo bạn dùng, rồi chạy CLI với prompt cố định. Ví dụ cấu trúc lệnh:

MODEL=/path/to/bonsai-27b-q1_0_g128.gguf

./build/bin/llama-cli \
  -m "$MODEL" \
  -p "Viết 5 gạch đầu dòng kiểm tra trước khi deploy API local." \
  -n 200 \
  -ngl 99

-ngl là số lớp offload lên GPU; trong công việc, nó ảnh hưởng trực tiếp tới memory và tốc độ. Đừng copy giá trị của người khác rồi coi là chuẩn. Thử vài mức khác nhau nếu máy bạn giới hạn VRAM.

Tiêu chí qua bước này: model load được, sinh text không lỗi, thời gian phản hồi không bất thường, không crash vì memory.

Tiêu chí dừng: lỗi kernel, lỗi format GGUF, GPU memory không đủ dù đã giảm offload, hoặc output rác liên tục với prompt cơ bản. Dừng ở đây rẻ hơn debug qua HTTP.

Bước 4: mở endpoint local tương thích OpenAI

Khi CLI ổn, mới bật server:

./build/bin/llama-server \
  -m "$MODEL" \
  --host 0.0.0.0 \
  --port 8000 \
  -c 4096 \
  -ngl 99

Context size là vùng ngữ cảnh model xử lý trong một lượt. Tăng context giúp nhét nhiều lịch sử hơn, nhưng thường kéo theo memory và latency. Đừng set thật lớn chỉ vì thấy tham số đó tồn tại.

Client Python tối giản:

import requests

BASE_URL = "http://localhost:8000/v1/chat/completions"

payload = {
    "model": "local-bonsai-27b",
    "messages": [
        {"role": "system", "content": "Bạn là trợ lý kỹ thuật trả lời ngắn gọn."},
        {"role": "user", "content": "Nêu 3 rủi ro khi chạy LLM local."}
    ],
    "temperature": 0.2,
    "stream": False
}

r = requests.post(BASE_URL, json=payload, timeout=120)
print(r.json())

Ví dụ cụ thể: giả sử app nội bộ của bạn đang gọi OpenAI API để tạo mô tả ticket. Nếu endpoint local giữ shape tương thích, bạn chỉ cần đổi base_url, thêm config model, rồi chạy lại test suite. Đây là lợi ích thật: giảm chi phí tích hợp, không phải hứa hẹn model sẽ thông minh hơn.

Guardrail: đo như operator, không đo như người xem demo

Trong lần thử đầu, mình sẽ log tối thiểu:

| Hạng mục | Vì sao cần đo | Dấu hiệu nên dừng |
|---|---|---|
| Time to first token | Người dùng cảm nhận độ chờ | Chậm thất thường qua các request giống nhau |
| Tokens/second | Ước lượng capacity | Không đủ cho concurrency mục tiêu |
| GPU memory | Biết còn chỗ cho context/cache | Sát trần ngay ở prompt ngắn |
| Error rate | Nhìn độ ổn định | Timeout/crash sau vài lượt |
| Output sanity | Kiểm tra chất lượng tối thiểu | Trả lời lệch vai trò hoặc lặp vô nghĩa |

KV cache là bộ nhớ lưu key-value attention của các token trước đó để sinh tiếp nhanh hơn. Quantized KV cache có thể giảm memory, nhưng phải test chất lượng và lỗi dài ngữ cảnh. Speculative decoding là cách dùng một model nhỏ đoán trước token để model lớn xác nhận, có thể tăng tốc nhưng thêm độ phức tạp vận hành.

Nói gọn cho người phải trực pager: chỉ bật tối ưu khi bạn có metric trước và sau. Không có baseline thì mọi tối ưu đều là kể chuyện.

Khi nào scale, khi nào dừng?

Scale nếu:

Dừng nếu:

Bài về Reachy Mini chạy speech-to-speech local cho thấy một hướng rất thực tế: local không chỉ là LLM, mà là cả cascade VAD → STT → LLM → TTS. VAD là phát hiện đoạn có giọng nói, STT là speech-to-text, TTS là text-to-speech. Khi pipeline nhiều mắt xích, LLM local chỉ là một tầng trong chuỗi thức ăn; nghẽn ở STT hay TTS thì người dùng vẫn thấy chậm.

Với RAG cũng vậy. Nguồn Qdrant về filtered vector search nhắc một failure mode hay bị quên: filter metadata có thể làm graph tìm kiếm bị đứt đoạn. Nếu local LLM của bạn trả lời sai vì retrieval kém, đổi sang model 1-bit hay 4-bit không sửa được gốc rễ.

Thứ bạn nên nghĩ khác sau bài này

Trước đây, câu hỏi thường là: “Model local này có chạy được không?”

Sau bài này, câu hỏi nên đổi thành: “Workflow local này có vận hành được không, và tiêu chí dừng của mình là gì?”

Một buổi thử tốt không cần kết thúc bằng quyết định scale. Nó chỉ cần giúp team bớt mù: biết binary nào chạy, endpoint nào sống, metric nào đáng tin, và rủi ro nào không nên mang vào production.

Chạy model local giống chăm một khoảnh rừng nhỏ: đừng chỉ ngắm cây cao nhất, hãy xem đất, nước, ánh sáng và mấy con sâu trong log.

---
Bụi Wire — nghiện đọc release notes lúc 2 giờ sáng

Nguồn tham khảo