Chi phí bộ nhớ LLM: Vì sao KV cache đắt và cách tối ưu
Trả lời nhanh: chi phí bộ nhớ LLM tăng vì GPU phải giữ weights, activation tạm thời và KV cache. Trong lúc sinh văn bản, KV cache lưu key và value của token trước để không tính lại. Cache tăng gần tuyến tính theo độ dài context và số phiên đồng thời, nên prompt dài có thể làm giảm batch size, throughput và tăng chi phí phục vụ.
Cập nhật lần cuối: 20/08/2026
Một mô hình có thể vừa khít trong GPU khi chạy một prompt ngắn nhưng hết bộ nhớ khi phục vụ nhiều cuộc trò chuyện dài. Trọng số không hề thay đổi. Thứ phình ra là trạng thái suy luận, đặc biệt là KV cache.
Đây là lý do câu hỏi “model cần bao nhiêu VRAM?” chưa đủ. Ta phải hỏi thêm:
- context dài bao nhiêu token;
- output tối đa bao nhiêu token;
- bao nhiêu request chạy đồng thời;
- attention dùng bao nhiêu KV head;
- cache lưu ở precision nào;
- engine phân bổ và tái sử dụng bộ nhớ ra sao.
Nếu không tính những yếu tố này, dự toán hạ tầng LLM dễ đúng trong demo nhưng sai khi lên production.
Chi phí bộ nhớ LLM gồm những phần nào?
Chi phí bộ nhớ LLM inference thường gồm bốn nhóm: model weights, KV cache, activation hoặc workspace tạm thời, và phần overhead của runtime.
| Thành phần | Tăng theo | Đặc điểm |
|---|---|---|
| Model weights | Số tham số và precision | Tương đối cố định sau khi load model |
| KV cache | Token, layer, KV head, concurrency | Tăng động trong mỗi phiên sinh |
| Activations/workspace | Batch, sequence, kernel | Tạm thời nhưng có thể tạo peak lớn |
| Runtime overhead | Engine, allocator, graph, buffer | Phụ thuộc implementation và cấu hình |
Với huấn luyện, còn có gradient, optimizer states và activation cho backpropagation. Bài này tập trung vào inference, nơi KV cache thường là biến số khó kiểm soát nhất khi context và lưu lượng tăng.
KV cache là gì?
Trong self-attention, mỗi token tạo ra query, key và value. Khi sinh token tiếp theo, query mới cần so với key của các token trước rồi dùng trọng số attention để tổng hợp value.
Nếu không cache, model phải tính lại key và value của toàn bộ prefix sau mỗi token mới. KV cache giữ các tensor này theo từng layer để lần decode tiếp theo chỉ tính K và V cho token mới.
Không cache:
token 1 -> tính K,V của 1
token 2 -> tính lại K,V của 1,2
token 3 -> tính lại K,V của 1,2,3
Có KV cache:
token 1 -> lưu K,V của 1
token 2 -> chỉ tính K,V của 2 rồi nối cache
token 3 -> chỉ tính K,V của 3 rồi nối cache
Tài liệu Hugging Face mô tả cache được duy trì theo từng layer. Nhờ cache, model tránh lặp phần tính toán của token cũ. Đổi lại, bộ nhớ tăng tuyến tính theo chiều dài chuỗi.
Vì sao KV cache tăng nhanh?
Một ước tính đơn giản cho cache của một sequence là:
KV bytes = 2 x số layer x số KV head x head dimension
x số token x byte mỗi phần tử
Hệ số 2 đại diện cho Key và Value.
Ví dụ giả định một model có:
- 32 layer;
- 8 KV head;
- head dimension 128;
- cache FP16, tức 2 byte mỗi phần tử;
- context 32.768 token.
Khi đó:
2 x 32 x 8 x 128 x 32.768 x 2
= 4.294.967.296 byte
≈ 4 GiB cho một sequence
Nếu có 8 sequence cùng kích thước chạy đồng thời, riêng KV cache lý thuyết đã khoảng 32 GiB, chưa tính weights, workspace và phân mảnh. Đây chỉ là ví dụ minh họa; kiến trúc thật có số layer, KV head và precision khác nhau.
ByteByteGo nêu một ví dụ 70B với context 128.000 token có KV cache khoảng 40 GB. Con số cụ thể phụ thuộc kiến trúc, nhưng thông điệp ổn định: context window tối đa trên model card không đồng nghĩa ta có thể phục vụ nhiều phiên ở độ dài đó với chi phí hợp lý.
Prefill và decode khác nhau thế nào?
LLM inference thường có hai pha.
Prefill
Model xử lý toàn bộ prompt đầu vào, tính attention cho các token và xây KV cache. Với prompt dài, prefill nặng về tính toán và có thể làm tăng time to first token.
Decode
Model sinh từng token tiếp theo. Mỗi bước đọc KV cache của prefix để tính attention. Decode thường bị giới hạn bởi memory bandwidth vì phải chuyển lượng lớn weights và cache để tạo một token cho mỗi sequence.
Hai chỉ số cần tách:
- TTFT, Time to First Token: chịu ảnh hưởng lớn từ prefill, queue và prompt length;
- TPOT, Time Per Output Token: phản ánh tốc độ decode sau token đầu.
Nếu chỉ đo tổng latency, khó biết nên tối ưu prompt, scheduler, attention kernel hay batch.
Context dài làm chi phí tăng theo cách nào?
Context dài tạo ít nhất bốn loại chi phí:
- Prefill compute: attention của prompt dài cần nhiều phép tính.
- KV capacity: cache phải giữ K và V cho nhiều token hơn.
- Decode bandwidth: mỗi token mới phải đọc vùng cache dài hơn.
- Scheduling: một request dài chiếm block lâu, làm giảm chỗ cho request khác.
Do đó, “đã hỗ trợ 128K context” chỉ là năng lực kỹ thuật. Sản phẩm vẫn cần ngân sách token theo use case. Đưa toàn bộ lịch sử chat, tài liệu và log vào mọi request thường là cách đắt nhất để tạo cảm giác có trí nhớ.
Multi-Head, Multi-Query và Grouped-Query Attention ảnh hưởng ra sao?
Trong Multi-Head Attention truyền thống, mỗi query head có key head và value head tương ứng. Multi-Query Attention dùng nhiều query head nhưng chia sẻ một key head và một value head, giảm mạnh cache và bandwidth. Grouped-Query Attention nằm giữa hai cách: nhiều query head được chia thành nhóm, mỗi nhóm dùng chung KV head.
Bài báo GQA mô tả đây là cách cân bằng chất lượng của multi-head với tốc độ gần multi-query trong thí nghiệm của nhóm tác giả. Với người vận hành, ý nghĩa là số KV head có thể nhỏ hơn số attention head, làm công thức KV cache giảm đáng kể.
Đây là thuộc tính kiến trúc của model. Không thể bật GQA bằng một flag serving nếu checkpoint không hỗ trợ, trừ khi có quy trình chuyển đổi và huấn luyện bổ sung phù hợp.
PagedAttention giải quyết vấn đề gì?
KV cache có kích thước động. Mỗi request dài ngắn khác nhau và kết thúc ở thời điểm khác nhau. Nếu engine dành một vùng liên tục theo độ dài tối đa cho mỗi request, nhiều bộ nhớ bị lãng phí. Nếu vùng trống phân tán, allocator khó tìm một khối liên tục đủ lớn dù tổng dung lượng vẫn còn.
PagedAttention lấy cảm hứng từ virtual memory của hệ điều hành. Nó chia KV cache thành block cố định và ánh xạ logical block của sequence tới physical block không cần liền kề.
Lợi ích chính:
- cấp phát theo nhu cầu thay vì độ dài tối đa;
- giảm phân mảnh;
- chia sẻ prefix block trong một số chiến lược decoding;
- cho phép scheduler giữ nhiều request hơn trong batch.
Bài báo vLLM công bố PagedAttention báo cáo throughput cao hơn 2 đến 4 lần so với các hệ thống baseline được thử nghiệm, ở cùng mức latency trong thiết lập của nghiên cứu. Không nên coi con số này là cam kết cho mọi model và phần cứng, nhưng nó cho thấy quản lý cache có thể quan trọng ngang kernel tính toán.
FlashAttention có giảm KV cache không?
FlashAttention là thuật toán attention chính xác, tối ưu theo I/O bằng cách chia phép tính thành tile để giảm đọc ghi giữa HBM và SRAM trên GPU. Bài báo gốc tập trung vào việc tránh vật chất hóa ma trận attention lớn và giảm memory traffic.
Nó không đồng nghĩa KV cache biến mất. Với autoregressive decoding, cache của token cũ vẫn cần được lưu nếu muốn tránh tính lại. FlashAttention chủ yếu tối ưu cách thực hiện attention, đặc biệt hữu ích cho prefill và huấn luyện; PagedAttention chủ yếu tối ưu cách tổ chức cache cho serving. Hai kỹ thuật giải các lớp vấn đề khác nhau và có thể cùng xuất hiện trong một stack.
Tám cách giảm chi phí bộ nhớ LLM
1. Giảm token không mang giá trị
Đo token theo từng phần: system prompt, lịch sử, tài liệu RAG, output tool và response. Loại boilerplate lặp lại, metadata không dùng và tài liệu truy xuất có độ liên quan thấp.
2. Tóm tắt lịch sử có kiểm soát
Thay vì giữ toàn bộ hội thoại, tạo state có cấu trúc gồm mục tiêu, quyết định, dữ kiện và việc còn mở. Giữ nguyên đoạn gần nhất; tóm tắt phần cũ; lưu nguồn để truy xuất lại khi cần.
3. Dùng RAG chọn lọc
Retrieval nên đưa vào top-k chunk thực sự cần thiết. Reranking và threshold giúp tránh đẩy nhiều văn bản tương tự vào context. Chunk quá lớn làm lãng phí token; chunk quá nhỏ làm mất ý nghĩa.
4. Chọn model có GQA hoặc MQA phù hợp
Nếu chất lượng đáp ứng, kiến trúc có ít KV head giúp giảm cache. Đánh giá cả task quality, latency và memory ở đúng context production.
5. Quantize KV cache
Giảm precision của key và value có thể giảm dung lượng. Tài liệu Hugging Face hỗ trợ chiến lược quantized cache trong một số cấu hình. Đổi lại, quantize và dequantize thêm compute, có thể giảm chất lượng hoặc không tăng tốc với context ngắn.
6. Offload cache sang CPU
Offloading chuyển cache của các layer không hoạt động sang CPU và prefetch khi cần. Cách này giải OOM trong một số trường hợp nhưng phụ thuộc băng thông PCIe/NVLink và có thể tăng latency. Nó là trao đổi giữa capacity với tốc độ.
7. Dùng paging, continuous batching và scheduler phù hợp
Engine serving nên phân bổ cache theo block, gom request động và có chính sách preemption. Tối ưu này tăng utilization mà không thay đổi model, nhưng cần benchmark dưới tải thật.
8. Giới hạn output và concurrency
Output token cũng kéo dài cache. Đặt max_new_tokens, stop condition, deadline và quota theo endpoint. Admission control ngăn một vài request cực dài làm toàn bộ dịch vụ hết bộ nhớ.
Prefix caching có giúp giảm chi phí không?
Nếu nhiều request dùng chung một prefix như system prompt dài hoặc tài liệu cố định, prefix caching có thể tái sử dụng kết quả prefill hoặc block KV đã tính. Điều này giảm compute và đôi khi giảm sao chép cache.
Tuy nhiên, hiệu quả phụ thuộc:
- prefix phải giống chính xác theo tokenizer và thứ tự;
- cache key phải tính cả model version và cấu hình;
- dữ liệu nhạy cảm không được chia sẻ sai tenant;
- cache invalidation phải theo phiên bản prompt;
- hit rate đủ cao để bù overhead.
Prefix caching không giúp nếu mỗi prompt có phần đầu khác nhau hoặc context thay đổi liên tục.
Khi nào nên dùng context dài, khi nào nên dùng memory ngoài?
| Nhu cầu | Context dài | Memory ngoài/RAG |
|---|---|---|
| Phân tích một tài liệu liền mạch | Hữu ích | Có thể làm mất liên kết xa |
| Lịch sử người dùng nhiều tháng | Đắt và khó kiểm soát | Phù hợp hơn nếu có schema và quyền |
| Dữ kiện thay đổi thường xuyên | Dễ cũ | Truy xuất tại thời điểm cần |
| Cần trích nguồn | Có thể giữ nguồn trong prompt | RAG thuận lợi cho provenance |
| Tác vụ thời gian thực | Cần kiểm soát TTFT | Chọn ít dữ liệu liên quan |
Một thiết kế tốt thường kết hợp: state có cấu trúc, retrieval, đoạn hội thoại gần và context window vừa đủ. Không nên xem context là database.
Quy trình 7 bước tối ưu production
Bước 1: Đo phân phối token
Theo dõi input token, output token, concurrency và độ dài theo endpoint ở p50, p95, p99. Không lập kế hoạch bằng max context danh nghĩa.
Bước 2: Lập ngân sách VRAM
Tách weights, KV cache, workspace và safety margin. Tính cho concurrency mục tiêu, không chỉ một request.
Bước 3: Benchmark prefill và decode riêng
Đo TTFT, TPOT, throughput và memory ở nhiều tổ hợp input/output. Giữ model, precision và phần cứng nhất quán khi so sánh.
Bước 4: Tối ưu context ở tầng ứng dụng
Rút system prompt, lọc lịch sử, rerank tài liệu và giới hạn output trước khi mua thêm GPU. Đây thường là đòn bẩy rẻ nhất.
Bước 5: Chọn engine và cache strategy
Thử paging, continuous batching, prefix caching, quantized cache và offload. Mỗi cấu hình cần kiểm tra chất lượng lẫn latency.
Bước 6: Đặt guardrail
Giới hạn token, concurrency, thời gian chờ và memory watermark. Khi áp lực tăng, ưu tiên request theo lớp dịch vụ thay vì để OOM ngẫu nhiên.
Bước 7: Theo dõi và cải tiến
Dashboard nên nối token với chi phí, latency và task success. Nếu giảm token nhưng chất lượng giảm mạnh, tối ưu chưa thành công.
Những hiểu lầm phổ biến
Model fit trong GPU nghĩa là phục vụ được
Sai. Weights vừa khít có thể không chừa chỗ cho KV cache và workspace. Production cần concurrency cùng safety margin.
Context window dài hơn luôn tốt hơn
Sai. Nhiều token không liên quan có thể tăng latency và làm model khó tập trung. Chất lượng phụ thuộc chọn đúng thông tin, không chỉ chứa nhiều.
Quantization luôn tăng tốc
Sai. Nó thường giảm memory, nhưng tốc độ phụ thuộc kernel, phần cứng, batch và chi phí dequantization.
Cache chỉ là vấn đề hạ tầng
Sai. Product design quyết định lịch sử nào được gửi, RAG lấy bao nhiêu chunk và output dài đến đâu. Phần lớn hóa đơn bắt đầu từ quyết định ứng dụng.
Tăng GPU là cách đơn giản nhất
Nhiều GPU tạo thêm chi phí giao tiếp, scheduling và vận hành. Nếu prompt chứa dữ liệu dư thừa, phần cứng chỉ che vấn đề.
FAQ - Câu hỏi thường gặp
Chi phí bộ nhớ LLM tăng tuyến tính hay bậc hai theo context?
Dung lượng KV cache tăng gần tuyến tính theo số token. Phép tính attention trong prefill truyền thống có thành phần bậc hai theo sequence length, dù các kernel như FlashAttention giảm I/O và bộ nhớ trung gian.
KV cache có nằm trong weights không?
Không. Weights là tham số đã học và dùng chung. KV cache là trạng thái động tạo cho từng sequence trong quá trình inference.
Xóa lịch sử chat có giải phóng KV cache không?
Nếu phiên inference kết thúc và engine thu hồi block, cache tương ứng có thể được giải phóng. Cách quản lý cụ thể phụ thuộc engine, scheduler và prefix cache.
RAG có luôn rẻ hơn context dài không?
Không. RAG thêm embedding, search, reranking và vận hành index. Nó có lợi khi giúp chỉ đưa thông tin liên quan vào prompt và duy trì nguồn dữ liệu cập nhật.
PagedAttention và FlashAttention có giống nhau không?
Không. PagedAttention quản lý KV cache theo block cho serving. FlashAttention tối ưu thuật toán attention theo chuyển động dữ liệu giữa các tầng bộ nhớ GPU.
Làm sao ước tính concurrency tối đa?
Lấy VRAM còn lại sau weights, workspace và safety margin, chia cho KV cache trung bình mỗi request, rồi xác nhận bằng load test. Scheduler và phân phối độ dài khiến con số thực tế khác phép chia lý thuyết.
Tóm lại
Chi phí bộ nhớ LLM là kết quả của cả kiến trúc model, engine serving và cách sản phẩm sử dụng context. KV cache đổi recomputation lấy memory: nhờ nó decode nhanh hơn, nhưng mỗi token và mỗi phiên đồng thời đều có chi phí.
Hướng tối ưu nên đi theo thứ tự:
- đo token và latency theo workload thật;
- giảm context không tạo giá trị;
- chọn model và attention architecture phù hợp;
- tối ưu paging, batching, prefix cache, precision và offload;
- dùng guardrail để bảo vệ hệ thống ở p99.
Nếu cần giảm chi phí bằng mô hình nhỏ hơn, xem Knowledge Distillation là gì?. Để hiểu phần cứng tăng tốc phép toán AI, đọc TPU của Google là gì?. Với mô hình hướng tùy chỉnh, bài Inkling là gì? cung cấp thêm một góc nhìn kiến trúc.
Nguồn tham khảo
- Why An LLM’s Memory Gets Expensive and How to Fix It, ByteByteGo.
- Efficient Memory Management for LLM Serving with PagedAttention, Kwon và cộng sự.
- FlashAttention, Dao và cộng sự.
- GQA, Ainslie và cộng sự.
- Cache strategies, Hugging Face.