Giới Thiệu

Không phải ai cũng có quyền truy cập vào cụm H100. Ở nhiều nơi trên thế giới — Đông Nam Á, Đông Âu, Mỹ Latinh, nhiều vùng ở châu Phi — sức mạnh tính toán khan hiếm và đắt đỏ. Thuê GPU instance trên cloud tốn kém gấp bội khi data center gần nhất cách bạn cả đại dương. Lựa chọn on-premise bị giới hạn bởi những gì nhà phân phối địa phương có trong kho, thường là phần cứng thế hệ trước nếu may mắn.

Nhưng nhu cầu chạy inference LLM thì ở khắp nơi. Lập trình viên cần trợ lý viết code. Startup cần chatbot. Nhà nghiên cứu cần thử nghiệm với các mô hình open-weight. Khoảng cách giữa “thứ người ta cần” và “thứ người ta có thể mua được” là rất lớn.

Chạy inference trên CPU thì khả thi về mặt kỹ thuật, nhưng chậm đến đau khổ — chỉ được vài token mỗi giây với mô hình 32B tham số. GPU tiêu dùng như RTX 4090 có thông số ấn tượng trên giấy, nhưng 24 GB VRAM đơn giản là không đủ chứa mô hình 32B ở mức lượng tử hóa hợp lý mà không cần offloading aggressively — thứ giết chết throughput. Và dù bạn có đủ tiền mua nhiều card RTX, NVLink không có trên phần cứng tiêu dùng, nên giao tiếp multi-GPU trở thành nút thắt cổ chai.

Bài viết này ghi lại trải nghiệm của mình khi chạy vLLM trên 8× Tesla V100 GPU (32 GB mỗi card, tổng 256 GB VRAM) để phục vụ Qwen3-Coder-32B-A3B-Instruct — mô hình tương đương Claude Sonnet 4.5 trong các tác vụ viết code. Quá trình không hề đơn giản, nhưng nó chạy được.

Giả Định

Hãy hình dung kịch bản này. Một kỹ sư mới tốt nghiệp đại học. Họ sống ở một quốc gia mà một node A100 có giá cao hơn cả lương năm. Họ lướt thị trường server cũ và tìm được một node với 8× Tesla V100 SXM2 32 GB GPU ở mức giá mà tài khoản ngân hàng chỉ vừa đủ chấp nhận. NVLink interconnect đi kèm. Tổng VRAM là 256 GB — dư sức chứa mô hình 32B với overhead thoải mái cho KV cache.

Lựa chọn mô hình là có chủ đích. Qwen3-Coder-32B-A3B-Instruct là kiến trúc Mixture-of-Experts (MoE) với tổng 32 tỷ tham số nhưng chỉ ~3 tỷ tham số active mỗi forward pass. Điều này khiến nó cực kỳ hiệu quả — bạn được chất lượng suy luận cấp 32B với chi phí inference gần bằng mô hình 3B. Trong các tác vụ viết code, nó cạnh tranh ngang ngửa với các mô hình thương mại hàng đầu và hoàn toàn open-weight.

Đây là cấu hình phần cứng:

Thành phầnThông số
GPU8× Tesla V100 SXM2 32 GB
Compute Capability7.0 (kiến trúc Volta)
InterconnectNVLink 2.0 (300 GB/s song hướng mỗi cặp GPU)
Tổng VRAM256 GB
PrecisionFP16, FP32 (không có BF16, không có FP8)

Ràng buộc then chốt: compute capability 7.0. V100 ra mắt năm 2017. Nó có trước BF16 (Ampere, cc 8.0), FP8 (Hopper, cc 9.0), và nhiều fused attention kernel mà các framework inference hiện đại mặc định có sẵn. Con số duy nhất này — 7.0 — là nguồn gốc của gần như mọi vấn đề phía sau.

Triển Khai

Bức Tường PyTorch

Điều đầu tiên bạn phát hiện là PyTorch 2.8.x trở đi đã bỏ hỗ trợ compute capability 7.0 trong các bản build sẵn. Nếu bạn cài PyTorch mới nhất từ pip, CUDA kernel âm thầm fail hoặc ném lỗi khó hiểu kiểu:

CUDA error: no kernel image is available for execution on the device

Lý do là PyTorch wheel chỉ đi kèm kernel biên dịch cho cc 7.5+ (hoặc thậm chí 8.0+ ở một số bản build). V100 của bạn đơn giản là không được mời vào bữa tiệc.

Hiệu ứng domino rất tàn khốc: vLLM, SGLang, và hầu hết framework inference dựa trên Python đều phụ thuộc vào phiên bản PyTorch mới. Khi PyTorch không hỗ trợ phần cứng của bạn, mọi thứ xây trên nó cũng không hỗ trợ.

Ghim Đúng Bộ Phần Mềm

Sau rất nhiều thử và sai, mình tìm được bộ phần mềm hoạt động được. Điểm mấu chốt là bạn cần khóa phiên bản cụ thể của ba thành phần đồng thời — NVIDIA driver, CUDA toolkit, và chính vLLM.

Thành phầnPhiên bảnLý do
NVIDIA Driver575.57.xDòng driver cuối cùng hỗ trợ V100 tốt và tương thích CUDA 12.8+
CUDA Toolkit12.8.x – 12.9.xYêu cầu bởi CUDA kernel của vLLM; 12.8 vẫn bao gồm target cc 7.0
vLLMv0.9.2 hoặc v0.10.1V1 engine chạy được trên cc 7.0; phải biên dịch từ source
PyTorch2.6.x – 2.7.xPhiên bản cuối cùng hỗ trợ cc 7.0 trong source build

Phiên bản driver quan trọng hơn bạn nghĩ. Quá cũ thì không dùng được CUDA 12.8. Quá mới thì NVIDIA có thể đã deprecated codepath cho V100. Dòng 575.57.x nằm đúng vùng an toàn.

Biên Dịch vLLM Từ Mã Nguồn

Các wheel vLLM build sẵn trên PyPI không bao gồm kernel cc 7.0. Bạn phải biên dịch từ source với TORCH_CUDA_ARCH_LIST chính xác:

# Clone the specific vLLM version
git clone --branch v0.10.1 https://github.com/vllm-project/vllm.git
cd vllm

# Set the compute capability target
export TORCH_CUDA_ARCH_LIST="7.0"
export MAX_JOBS=8

# Install build dependencies
pip install -r requirements/build.txt

# Build and install — this takes 30-60 minutes on a decent CPU
pip install -e .

Một số thứ sẽ khiến bạn vấp:

  • TORCH_CUDA_ARCH_LIST="7.0" là then chốt. Thiếu nó, bản build sẽ target theo PyTorch đã cài, thứ không bao gồm 7.0
  • MAX_JOBS kiểm soát biên dịch song song. Đặt bằng số CPU core, nhưng cẩn thận RAM — mỗi job biên dịch có thể dùng 2-4 GB RAM
  • Bản build sẽ đưa ra hàng trăm warning về CUDA feature deprecated. Bỏ qua chúng — đó là warning, không phải error
  • Nếu build fail vì OOM, giảm MAX_JOBS

Mình đã biên dịch và kiểm thử thành công cả v0.9.2v0.10.1. Cả hai đều hoạt động với V1 engine trên phần cứng V100.

Chạy Mô Hình

Sau khi vLLM được biên dịch, phục vụ mô hình khá đơn giản:

vllm serve Qwen/Qwen3-Coder-32B-A3B-Instruct \
  --tensor-parallel-size 8 \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.90 \
  --dtype float16 \
  --trust-remote-code

Các flag quan trọng:

  • --tensor-parallel-size 8 — phân bố mô hình trên cả 8 V100 qua NVLink
  • --max-model-len 32768 — cửa sổ context (chi tiết thêm ở Bài Học Rút Ra)
  • --dtype float16 — V100 không hỗ trợ BF16; FP16 là lựa chọn duy nhất
  • --gpu-memory-utilization 0.90 — dành 10% headroom cho các đợt tăng đột biến KV cache

Mô hình load xong, health check pass, và bạn có thể gọi API tương thích OpenAI tại http://localhost:8000/v1/chat/completions. Nó chạy.

Bài Học Rút Ra

Đánh Đổi Cửa Sổ Context Là Thật

Đây là bài học quan trọng nhất: tốc độ inference giảm đáng kể khi cửa sổ context vượt quá 128K token trên phần cứng V100.

Băng thông bộ nhớ V100 (900 GB/s) và việc thiếu cơ chế attention tăng tốc phần cứng (không có FlashAttention-2 native, không có PagedAttention hardware optimization) khiến quản lý KV cache trở thành nút thắt cổ chai ở context size lớn. Dưới 128K token, throughput chấp nhận được — khoảng 15-25 token/giây cho một request đồng thời. Trên 128K, nó rơi xuống đơn vị và độ trễ trở nên không thực tế cho sử dụng tương tác.

Khuyến nghị của mình: giới hạn --max-model-len ở 32768 hoặc 65536 cho workload production. Nếu cần context đầy đủ 128K+, hãy batch request trong giờ thấp điểm và chấp nhận throughput chậm hơn như một sự đánh đổi.

Độ dài ContextThroughput xấp xỉ (tok/s)Thực tế?
≤ 32K20–25Có — sử dụng tương tác
32K – 64K15–20Có — độ trễ chấp nhận được
64K – 128K8–15Trên ranh giới — chỉ nên batch
> 128K< 8Không — không thực tế cho hầu hết trường hợp

FP16 Cần Chú Ý Cẩn Thận

Không có BF16, bạn bị kẹt với FP16 cho toàn bộ inference. FP16 có dải động hẹp hơn (±65.504 so với ±3,4×10³⁸ của BF16/FP32), nghĩa là vấn đề ổn định số học có thể xuất hiện trên một số kiến trúc mô hình. Với Qwen3-Coder, mình chưa thấy suy giảm độ chính xác trên tác vụ viết code, nhưng hãy theo dõi output — đặc biệt với prompt nặng toán.

V1 Engine Là Lựa Chọn Duy Nhất

vLLM đang chuyển từ V0 engine sang V1. Trên phần cứng V100, V0 engine có nhiều vấn đề tương thích với compute capability CUDA cũ. V1 engine, dù vẫn đang hoàn thiện, xử lý cc 7.0 trơn tru hơn. Nếu gặp lỗi về missing kernel hoặc unsupported operation, hãy đảm bảo bạn đang dùng V1.

Tính Tái Tạo Bản Build Rất Quan Trọng

Ghi lại chính xác phiên bản phần mềm. Một bản CUDA point release nhỏ hoặc patch PyTorch có thể phá hỏng bản build. Mình khuyến nghị tạo Docker image ngay khi có bản build chạy được để không bao giờ phải chiến đấu với quá trình biên dịch lần nữa:

# Save your working environment
pip freeze > requirements-v100-vllm.txt

# Tag your CUDA/driver versions in a Dockerfile or README
echo "NVIDIA Driver: $(nvidia-smi --query-gpu=driver_version --format=csv,noheader | head -1)"
echo "CUDA: $(nvcc --version | grep release)"
echo "PyTorch: $(python -c 'import torch; print(torch.__version__)')"
echo "vLLM: $(python -c 'import vllm; print(vllm.__version__)')"

Thảo Luận Tương Lai

Thị Trường GPU Cũ Đang Trở Nên Chiến Lược

Khi các hyperscaler nâng cấp lên cụm H100/B200, một làn sóng phần cứng V100 và A100 thanh lý đang đổ ra thị trường thứ cấp. Với tổ chức ở những vùng khan hiếm compute, đây là cửa sổ cơ hội — khả năng inference nghiêm túc với chi phí chỉ bằng phần nhỏ giá gốc. Câu hỏi không phải GPU cũ có chạy được LLM không. Câu hỏi là hệ sinh thái phần mềm sẽ tiếp tục hỗ trợ chúng bao lâu.

Vách Đá Hỗ Trợ Phần Mềm

Xu hướng rất rõ: NVIDIA và PyTorch đang dần bỏ hỗ trợ compute capability cũ. Hôm nay là cc 7.0 (V100). Ngày mai có thể là cc 7.5 (T4, RTX 2080), và cuối cùng là cc 8.0 (A100). Mỗi chu kỳ deprecation bỏ rơi phần cứng — không phải vì silicon không tính toán được, mà vì không ai biên dịch kernel cho nó nữa. Các bản build do cộng đồng duy trì sẽ ngày càng quan trọng để kéo dài tuổi thọ hữu ích của phần cứng cũ.

Mô Hình Mixture-of-Experts Thay Đổi Cuộc Chơi

Sự trỗi dậy của kiến trúc MoE như Qwen3-Coder-32B-A3B (32B tổng, 3B active) là bước ngoặt cho phần cứng cũ. Bạn được chất lượng mô hình lớn với chi phí inference mô hình nhỏ. Khi càng nhiều mô hình MoE ra mắt, ngưỡng phần cứng tối thiểu cho inference LLM hữu ích giảm đáng kể. Một node V100 vật lộn với mô hình dense 70B có thể thoải mái phục vụ mô hình MoE 32B — số tham số active, không phải tổng, mới quyết định hiệu năng inference.

Distillation và Quantization Đang Thu Hẹp Khoảng Cách

Các kỹ thuật như GPTQ, AWQ, và knowledge distillation tiếp tục cải thiện. Một mô hình 32B được lượng tử hóa tốt trên V100 ngày nay cho chất lượng output mà năm ngoái cần mô hình 70B trên A100. Xu hướng này có lợi cho phần cứng cũ — mỗi thế hệ nghiên cứu quantization và distillation thực chất kéo dài tuổi thọ hữu ích của GPU hiện có.

Rào Cản Thực Sự Là Kiến Thức, Không Phải Phần Cứng

Trở ngại lớn nhất để chạy LLM trên GPU cũ không phải phần cứng — mà là biết chính xác tổ hợp driver, CUDA, PyTorch, và framework nào sẽ hoạt động cùng nhau. Bài viết này tồn tại vì mình đã mất nhiều ngày tìm ra qua thử và sai. Cộng đồng AI cần tài liệu tốt hơn về các ma trận tương thích này, đặc biệt cho phần cứng không còn nằm trong vùng “hỗ trợ chính thức.”

Những Điều Cần Nhớ

  1. Tesla V100 có thể phục vụ LLM lớp 32B hiện đại — nhưng chỉ khi ghim phiên bản cẩn thận và biên dịch từ source
  2. Khóa bộ phần mềm: NVIDIA driver 575.57.x + CUDA 12.8.x–12.9.x + vLLM biên dịch từ source với TORCH_CUDA_ARCH_LIST="7.0"
  3. Giới hạn cửa sổ context ở 32K–64K cho sử dụng tương tác; trên 128K, throughput giảm đến mức không thực tế
  4. Mô hình MoE là lý tưởng cho phần cứng cũ — Qwen3-Coder-32B-A3B cho chất lượng 32B với chi phí inference 3B
  5. Ghi lại và container hóa bản build hoạt động ngay lập tức — tính tái tạo rất mong manh trên phần cứng deprecated