Cách thiết lập num_ctx trong Ollama để tránh cắt prompt
Ollama tự động cắt prompt nếu vượt quá giới hạn token mặc định. Bạn cần cấu hình num_ctx trong Modelfile hoặc API request và tính toán kỹ dung lượng KV cache RAM trước khi tăng.
num_ctx làm gì và tại sao prompt dài của bạn bị cắt
Context length của Ollama là số lượng token mà một model đã load có thể giữ trong bộ nhớ cùng lúc, và num_ctx là tùy chọn thiết lập giá trị này. Ollama chọn một giá trị mặc định thấp hơn nhiều so với mức tối đa mà model công bố, vì vậy một prompt dài sẽ bị cắt trước khi model kịp đọc nó. Không có thông báo nào trong phản hồi cho bạn biết điều này đã xảy ra.
Llama 3.1 8B được liệt kê với cửa sổ context 128k trên thư viện model của Ollama. Một máy chủ mặc định sẽ không cung cấp cho bạn con số đó. Tài liệu của chính Ollama đưa ra các giá trị mặc định khác nhau trên các trang khác nhau: FAQ nói là 4096 token, tài liệu tham khảo Modelfile nói num_ctx mặc định là 2048, và trang về context length nói giá trị mặc định được chọn dựa trên VRAM (video RAM) khả dụng: 4k nếu dưới 24 GiB, 32k từ 24 đến 48 GiB, và 256k nếu trên mức đó. Mỗi thông tin đều đúng với một bản build nào đó. Sự không thống nhất này là bài học hữu ích ở đây: hãy đọc giá trị từ chính máy chủ đang chạy của bạn thay vì tin vào bất kỳ trang nào, kể cả trang này.
Việc cắt bớt diễn ra âm thầm vì model vẫn trả lời, và câu trả lời vẫn đọc được bình thường. Nó được viết dựa trên phần cuối của dữ liệu đầu vào. Một bản tóm tắt bỏ lỡ nửa đầu của tài liệu trông giống như một model yếu. Nguyên nhân thường là do cửa sổ context quá nhỏ.
Kiểm tra độ dài context mà server Ollama thực sự áp dụng
Cách kiểm tra hiệu quả trên mọi bản build là prompt_eval_count, số lượng token trong prompt mà server báo cáo đã xử lý. Hãy gửi nhiều hơn mức context cho phép, con số đó sẽ dừng lại ở giới hạn.
sudo apt update && sudo apt install -y jq
LONG=$(python3 -c "print('the quick brown fox jumps over the lazy dog. ' * 2000)")
jq -n --arg p "$LONG" '{model:"llama3.1:8b", prompt:$p, stream:false, options:{num_ctx:4096}}' |
curl -s http://localhost:11434/api/generate -d @- |
jq '{prompt_eval_count, prompt_eval_duration}'Prompt đó dài khoảng 18,000 từ, lớn hơn nhiều so với 4096 token. prompt_eval_count trả về gần mức 4096 thay vì gần với số lượng token thực tế, vì server đã cắt bỏ phần còn lại. Chạy lại với "num_ctx":16384 và con số sẽ tăng lên. Nếu bản build của bạn trả về lỗi thay vì cắt bớt, đó cũng là kết quả tương tự với tín hiệu cảnh báo rõ ràng hơn.
ollama psCột CONTEXT, trên các bản build có hiển thị, chứa độ dài context mà model đang chạy tại thời điểm hiện tại. Cột PROCESSOR ngay bên cạnh cho biết vị trí của model. 100% CPU là trạng thái bình thường trên VPS không có GPU. Việc phân tách như 30%/70% CPU/GPU trên máy có GPU nghĩa là trọng số (weights) cộng với cache không còn nằm vừa trong VRAM, và nguyên nhân thường do num_ctx bị tăng lên.
journalctl -u ollama --no-pager | grep -i n_ctx | tail -n 5Trình chạy inference in ra kích thước context trong một dòng chứa n_ctx. Cách diễn đạt chính xác có thể thay đổi giữa các bản release, vì vậy nếu không thấy dòng này, hãy coi đó là do đổi tên chứ không phải bằng chứng cho bất kỳ vấn đề nào.
Bốn vị trí để thiết lập num_ctx
Trong request. Gửi "options": {"num_ctx": 16384} đến /api/generate hoặc /api/chat. Thiết lập này ghi đè mọi cài đặt khác và chỉ áp dụng cho một lần gọi đó. Nếu giá trị khác với giá trị mà model đang chạy, server sẽ reload lại model trước, bạn có thể thấy điều này trong load_duration ở phần response: thời gian sẽ nhảy từ gần bằng 0 lên đến vài giây. Độ trễ tương tự cũng xuất hiện khi model đã ở trạng thái idle đủ lâu để bị unload, vì vậy khi đã chốt được kích thước context, bạn nên giữ model thường trú với keep_alive.
Trong phiên tương tác. Bên trong ollama run, gõ /set parameter num_ctx 16384. Thiết lập này chỉ có hiệu lực trong phiên đó.
Trong Modelfile. Cách này "đóng băng" giá trị vào một model đã đặt tên, nhờ đó mọi client đều nhận được giá trị này mà không cần thay đổi gì ở phía client.
FROM llama3.1:8b
PARAMETER num_ctx 16384ollama create llama3.1-16k -f ./Modelfile
ollama run llama3.1-16kTrên server. OLLAMA_CONTEXT_LENGTH thiết lập giá trị mặc định cho mọi request không mang theo num_ctx riêng. Với systemd, hãy thêm một file drop-in thay vì sửa trực tiếp file unit.
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_CONTEXT_LENGTH=16384"sudo systemctl daemon-reload
sudo systemctl restart ollama
ollama psThứ tự ưu tiên rất quan trọng khi bạn debug client của người khác. Một request mang theo num_ctx sẽ ghi đè giá trị mặc định của server, vì vậy một chat front end hoặc một agent tự gửi giá trị nhỏ của riêng nó sẽ âm thầm vô hiệu hóa thay đổi của bạn trong systemd. Khi bạn trỏ một coding agent vào server Ollama của mình, hãy kiểm tra xem client gửi gì trước khi đổ lỗi cho server.
Tại sao bạn không thể chỉ đặt num_ctx bằng mức tối đa của model
Cơ chế attention yêu cầu mỗi token phải xem xét mọi token trước đó. Các key và value được tính toán cho những token trước sẽ được lưu giữ để không phải tính lại cho mỗi token mới, và kho lưu trữ đó chính là KV cache (key/value cache). Nó được cấp phát cho toàn bộ num_ctx khi model load, chứ không phải tăng dần theo cuộc hội thoại, vì vậy context lớn sẽ tiêu tốn bộ nhớ ngay cả với một prompt chỉ có một dòng.
Hướng dẫn về chi phí inference của DigitalOcean nêu công thức tính toán trong một dòng:
kv_bytes_per_token = 2 * layers * kv_heads * head_dim * bytes_per_valueSố 2 đại diện cho việc đếm riêng biệt key và value. Hãy lấy các con số khác từ chính model của bạn.
curl -s http://localhost:11434/api/show -d '{"model":"llama3.1:8b"}' |
jq '.model_info | {ctx: ."llama.context_length", layers: ."llama.block_count", heads: ."llama.attention.head_count", kv_heads: ."llama.attention.head_count_kv", embed: ."llama.embedding_length"}'Llama 3.1 8B có 32 layer và 8 key/value head. Kích thước head là embed chia cho heads, nên ở đây là 4096 / 32 = 128, và một số model công bố trực tiếp thông số này là llama.attention.key_length. Cache mặc định lưu trữ các giá trị f16, nên bytes_per_value là 2, và 2 32 8 128 2 cho kết quả là 131.072 byte. Đó là 128 KiB cache cho mỗi token của context. Nhân với độ dài context và chi phí sẽ không còn là con số trừu tượng nữa.
The data behind this chart
[
{
"label": "4k",
"kv_cache_gib": 0.5,
"total_ram_gib": 5.1
},
{
"label": "8k",
"kv_cache_gib": 1,
"total_ram_gib": 5.6
},
{
"label": "16k",
"kv_cache_gib": 2,
"total_ram_gib": 6.6
},
{
"label": "32k",
"kv_cache_gib": 4,
"total_ram_gib": 8.6
},
{
"label": "64k",
"kv_cache_gib": 8,
"total_ram_gib": 12.6
},
{
"label": "128k",
"kv_cache_gib": 16,
"total_ram_gib": 20.6
}
]Các hàng 6 đó là kết quả tính toán từ công thức trên, không phải số đo thực tế. Cột tổng cộng cộng thêm 4,9 GB dung lượng tải xuống mà thư viện Ollama liệt kê cho llama3.1:8b vào tháng 8 năm 2026, tương đương 4,6 GiB, và nó chưa bao gồm các compute buffer cũng như chính tiến trình server. Hãy coi đây là mức tối thiểu.
Hình thái của vấn đề nằm ở đây. Ở mức 8k, cache tốn 1 GiB, chỉ là con số nhỏ so với trọng số (weights). Ở mức tối đa 128k của model, nó tốn 16 GiB, gấp hơn ba lần trọng số, với tổng dung lượng gần 20.6 GiB. Vì vậy, một VPS 4 GB không thể load model này với bất kỳ context hữu dụng nào. Một VPS 8 GB chạy thoải mái ở 8k. Một VPS 16 GB đạt tới 32k mà vẫn còn dư tài nguyên cho các tác vụ khác trên máy. Mỗi ngưỡng đó đều tăng lên theo trọng số, vì vậy nếu bạn đang cân nhắc một model lớn hơn so với bản 8B này, các phép tính tương tự được thực hiện cho tag Qwen 27B trên VPS chỉ dùng CPU sẽ cho thấy trọng số để lại rất ít không gian cho context khi dung lượng RAM nằm trong khoảng từ 8 đến 64 GB.
Điều gì xảy ra khi KV cache không đủ chỗ
Trên VPS chỉ dùng CPU, tiến trình sẽ đơn giản là phình to ra. Hãy theo dõi nó trong khi model đang load và khi một request dài đang chạy.
free -m
ps -eo rss,comm --sort=-rss | head -n 5RSS (resident set size) được in ra theo đơn vị kilobyte. Nếu swap được sử dụng trong free -m bắt đầu tăng, hãy giảm context xuống. Một KV cache nằm trong swap sẽ làm quá trình tạo token bị khựng lại hàng giây cho mỗi token, vì mỗi token mới đều phải đọc lại toàn bộ cache.
Nếu máy chủ hết sạch bộ nhớ, kernel sẽ chọn tiến trình lớn nhất và kill nó.
sudo dmesg | grep -i "killed process"Một dòng thông báo Out of memory: Killed process 1234 (ollama) nghĩa là context bạn yêu cầu không đủ chỗ. Ollama thường từ chối trước khi đạt đến mức đó, và request sẽ thất bại kèm theo thông báo nêu rõ dung lượng bộ nhớ cần thiết so với dung lượng bộ nhớ còn trống.
Trên máy chủ có GPU, lỗi xảy ra êm hơn. Các layer sẽ tràn sang RAM hệ thống, ollama ps hiển thị sự phân chia giữa CPU và GPU, và throughput giảm mạnh. Mức độ giảm phụ thuộc vào phần cứng của bạn, vì vậy hãy đo số token mỗi giây trên máy của bạn tại mỗi thiết lập context thay vì tin vào con số từ máy của người khác.
Thời gian prefill tăng nhanh hơn độ dài prompt
Prefill là công việc được thực hiện trên input của bạn trước khi token output đầu tiên xuất hiện. Mỗi token trong prompt đều phải xử lý mọi token đứng trước nó, vì vậy tổng khối lượng công việc tăng theo bình phương độ dài input. Việc tăng gấp đôi độ dài prompt sẽ khiến thời gian chờ token đầu tiên tăng hơn gấp đôi.
Phản hồi của hệ thống sẽ hiển thị các thông số đo lường, vì vậy bạn không cần phải tin tưởng một cách mù quáng.
jq -n --arg p "$LONG" '{model:"llama3.1:8b", prompt:$p, stream:false, options:{num_ctx:16384}}' |
curl -s http://localhost:11434/api/generate -d @- |
jq '{tokens: .prompt_eval_count, prefill_seconds: (.prompt_eval_duration/1000000000)}'Chạy phép đo đó với một prompt ngắn rồi chạy lại với một prompt dài. Sau đó lấy số token chia cho số giây trong từng trường hợp. Trên VPS chỉ dùng CPU, prefill thường là phần chậm nhất của request có context dài. Chỉ số token mỗi giây đo từ prompt ngắn sẽ không dự đoán được thời gian này. Khi prefill kéo dài quá timeout của bất kỳ lớp nào phía trước, prompt dài thường trả về lỗi context deadline exceeded thay vì câu trả lời. Vì vậy, hãy xác định lớp nào đã timeout trước khi giảm context.
Concurrency (tính đồng thời) là nơi vấn đề này gây ảnh hưởng lớn nhất. Mỗi yêu cầu đang được phục vụ đều cần cache riêng, vì vậy bộ nhớ trong biểu đồ trên là tính theo từng yêu cầu thay vì tính theo server, và một yêu cầu dài có thể chiếm dụng toàn bộ tài nguyên trong khi các yêu cầu ngắn phải xếp hàng chờ đợi. Hãy thiết lập OLLAMA_NUM_PARALLEL một cách thận trọng, và đọc bài số lượng người dùng đồng thời mà một LLM tự host có thể phục vụ trước khi bạn tăng cả hai thông số này cùng lúc.
Lấy lại ngữ cảnh với cache nhỏ hơn
bytes_per_value trong công thức là một thiết lập bạn có thể kiểm soát. FAQ của Ollama ghi lại OLLAMA_KV_CACHE_TYPE, với f16 là mặc định ở mức 2 byte, cộng với q8_0 ở mức 1 byte và q4_0 cho các mức thấp hơn. Chuyển sang q8_0 sẽ giảm một nửa cache, vì vậy hàng 32k sẽ tốn 2 GiB thay vì 4 GiB. Việc lượng tử hóa (quantising) các trọng số sẽ giải phóng bộ nhớ từ phía còn lại của cùng một ngân sách, và thẻ GLM thực sự phù hợp với VPS được xử lý qua từng bước lượng tử hóa nếu đó là sự đánh đổi bạn muốn thực hiện. FAQ tương tự cũng ghi lại OLLAMA_FLASH_ATTENTION=1, thứ mà một số bản build yêu cầu trước khi cache đã lượng tử hóa có hiệu lực.
[Service]
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"Hãy xác nhận thay vì giả định: khởi động lại service, load model ở cùng num_ctx như trước và so sánh RSS. Hỗ trợ phụ thuộc vào model và backend, vì vậy nếu một thiết lập không thay đổi gì nghĩa là tổ hợp của bạn không được hỗ trợ. Tài liệu liệt kê các tùy chọn này mà không đảm bảo kết quả chất lượng, vì vậy hãy kiểm tra q4_0 với các prompt của riêng bạn trước khi tin dùng nó. Nếu các nút điều chỉnh này là lý do bạn ở đây, Ollama và llama.cpp hiển thị chúng theo cách khác nhau.
Công thức chọn num_ctx
- Đọc context tối đa, số lượng layer và số lượng key/value head của model từ
/api/show. - Tính số byte trên mỗi token bằng công thức, sau đó nhân với dung lượng context bạn muốn.
- Cộng thêm kích thước trọng số (weight), so sánh với RAM trống và giữ lại ít nhất 1 GiB cho các tiến trình khác trên máy chủ.
- Thiết lập giá trị, load model, sau đó xác nhận cấu hình đã áp dụng bằng
ollama psvàprompt_eval_count. - Chạy workload thực tế trong khi theo dõi
free -m, và giảm một nửa context nếu swap bắt đầu hoạt động.
Hầu hết các tác vụ cần ít context hơn mức người dùng thường cấp. Việc tóm tắt một báo cáo dài chỉ cần 16k. Một giao diện truy xuất dữ liệu dán năm đoạn tài liệu hiếm khi vượt quá 8k. Một coding agent đọc toàn bộ file là trường hợp thực sự cần 64k hoặc hơn, và đây cũng là trường hợp bạn nên chọn cấu hình máy chủ dựa trên context thay vì làm ngược lại. Nếu server vẫn còn mới, hãy bắt đầu từ cài đặt Ollama trên VPS và tinh chỉnh context sau khi các model đã load thành công.
FAQ
Độ dài context mặc định trong Ollama là bao nhiêu?
Điều này phụ thuộc vào bản build và phần cứng, vì vậy hãy kiểm tra thay vì mặc định. FAQ của Ollama ghi là 4096 tokens, tài liệu tham khảo Modelfile ghi num_ctx mặc định là 2048, và trang về độ dài context ghi rằng giá trị mặc định được chọn dựa trên VRAM khả dụng: 4k nếu dưới 24 GiB, 32k từ 24 đến 48 GiB, và 256k nếu trên mức đó. Một VPS chỉ dùng CPU sẽ rơi vào mức thấp. ollama ps sẽ in ra context đang áp dụng trên các bản build có hỗ trợ cột này, và prompt_eval_count trong phản hồi API sẽ xác nhận điều đó trên mọi bản build.
Tại sao Ollama bỏ qua phần đầu của prompt dài của tôi?
Vì prompt dài hơn cửa sổ context, nên server đã cắt bớt trước khi model kịp xử lý, và không có lỗi nào được trả về. Hãy gửi lại cùng prompt đó với num_ctx lớn hơn và theo dõi prompt_eval_count trong phản hồi tăng lên. Nếu con số đó không đổi, có thể có thành phần nào đó giữa bạn và server đang tự thiết lập num_ctx, đây là tình trạng phổ biến với các giao diện chat và framework agent.
Cần thêm bao nhiêu RAM nếu tăng num_ctx?
Hãy nhân độ dài context với chi phí cache trên mỗi token, đó là 2 * layers * kv_heads * head_dim * bytes_per_value. Với Llama 3.1 8B ở định dạng f16, con số này là 128 KiB mỗi token, vậy 32k tokens sẽ tốn 4 GiB và toàn bộ 128k sẽ tốn 16 GiB cộng thêm vào trọng số model. Cache được cấp phát khi model load, vì vậy một num_ctx lớn sẽ chiếm dung lượng bộ nhớ đó ngay cả khi prompt của bạn vẫn ngắn.
Cửa sổ context lớn hơn có làm Ollama chậm đi không?
Có, theo hai cách. Thời gian prefill tăng theo bình phương độ dài prompt, nên input dài sẽ làm chậm token đầu tiên nhiều hơn so với độ dài của nó. Cache lớn hơn cũng cạnh tranh tài nguyên bộ nhớ: trên máy có GPU, nó đẩy các layer vào RAM hệ thống, còn trên máy chỉ dùng CPU, nó đẩy máy vào tình trạng swap. Một num_ctx lớn mà bạn không bao giờ dùng hết vẫn tốn bộ nhớ, mặc dù nó không làm tốn thời gian prefill.
Tôi có thể đặt num_ctx vĩnh viễn cho một model không?
Có. Hãy viết một Modelfile chứa FROM llama3.1:8b và PARAMETER num_ctx 16384, sau đó chạy ollama create llama3.1-16k -f ./Modelfile. Mọi client yêu cầu llama3.1-16k sẽ nhận được context đó mà không cần gửi thêm tùy chọn nào. Một request tự mang theo num_ctx của riêng nó vẫn sẽ được ưu tiên, vì vậy đây chỉ là cách đặt giá trị mặc định chứ không phải giới hạn tối đa.