
Ollama cắt prompt âm thầm: cách phát hiện và sửa num_ctx
Ollama mặc định num_ctx 2048 và cắt đầu prompt mà không báo lỗi. Cách phát hiện bằng prompt_eval_count, sửa bằng Modelfile, và cái giá VRAM phải trả.
Bot RAG chạy local của bạn trả lời sai một cách rất tự tin, dù bạn đã kiểm tra tay và biết chắc đoạn văn đúng nằm trong prompt. Bạn sửa system prompt cả buổi tối, viết hoa chữ IMPORTANT, nhân đôi câu lệnh JSON — không gì thay đổi. Bài này chỉ cách kiểm tra trong năm phút xem Ollama có đang cắt prompt của bạn không, và sửa dứt điểm.
Triệu chứng: model không "ngu", nó chỉ không nhìn thấy prompt
Một developer vừa công bố bản mổ xẻ chi tiết hệ RAG local của chính mình. Setup rất quen thuộc với dev Việt Nam: Llama 3.1 8B trên Ollama, GPU 12 GB, khoảng 3.000 file markdown chunk ở mức ~400 token, retrieve top 10 chunk mỗi câu hỏi.
Kết quả ban đầu: 46% câu trả lời đúng trên bộ test 400 câu. Tác giả viết: "The right paragraph was in the prompt every single time. The model just never saw it."
Nguyên nhân: num_ctx của Ollama đang để 2048 token, trong khi model card ghi 128K. Theo bài viết, "Ollama's num_ctx was set to 2048 tokens, and Ollama quietly chopped the front off every prompt longer than that. No error, no field in the response, no warning in my Python logs. 287 of my 400 prompts got cut."
Điểm chí mạng nằm ở hướng cắt. Ollama giữ phần đuôi và bỏ phần đầu: "Overflowing prompts are truncated silently from the front. The tail survives, so the question stays and the instructions and top-ranked chunks vanish." Bạn xếp prompt theo layout sách giáo khoa — instructions, rồi chunk tốt nhất, rồi câu hỏi — thì đúng hai thứ quan trọng nhất bị cắt đầu tiên.
Đó là lý do mọi nỗ lực sửa system prompt đều vô nghĩa. Bạn đang sửa đúng cái vùng mà model không bao giờ đọc tới.
Kiểm tra trong năm phút: đọc prompt_eval_count
Response của Ollama có field prompt_eval_count — số token prompt mà model thực sự xử lý. Bài viết nêu dấu hiệu nhận biết: "Spot it with prompt_eval_count in the response. If it sits at or just under your num_ctx no matter how long your prompt is, you're being truncated."
Tác giả log nó cạnh ước lượng token của mình, và output lặp lại một con số duy nhất:
5120 2047
3890 2047
1410 1402
6230 2047
Mọi prompt dài đều bị kẹt ở 2047. Prompt ngắn đi qua nguyên vẹn. Server log có ghi dòng truncating input prompt, nhưng API vẫn trả HTTP 200 với body trông hoàn toàn bình thường — nên không ai đi đọc log.
Tách kết quả eval theo độ dài prompt cho thấy bức tranh thật (số liệu từ bài viết): nhóm dưới 2048 token có 113 câu, đúng 96 câu (85%); nhóm trên 2048 token có 287 câu, chỉ đúng 88 câu (31%).
Sửa: hai cách chạy được, một cách không
Cách 1 — truyền theo từng request trên native API: options: {"num_ctx": 8192}.
Cách 2 — nướng vào model bằng Modelfile:
FROM llama3.1:8b
PARAMETER num_ctx 8192
Rồi ollama create notes-llama -f Modelfile và gọi notes-llama thay cho llama3.1:8b. Tác giả giữ cách này vì nó khiến bạn không thể quên setting ở một script khác.
Cách không chạy là cách trực giác nhất: endpoint OpenAI-compatible. Bài viết ghi rõ "The OpenAI-compatible endpoint ignored my per-request setting" — gửi num_ctx qua extra_body tới /v1/chat/completions thì usage.prompt_tokens vẫn đứng yên ở 2047. Nếu bạn đang đi qua client kiểu OpenAI, hãy set context ở Modelfile hoặc ở mức server.
Lưu ý quan trọng về version: tác giả nhắc "Newer Ollama releases added an OLLAMA_CONTEXT_LENGTH environment variable for the server-wide default, and raised the default itself, so check what your version does instead of trusting either my number or the model card." Đừng copy con số 2048 — hãy đo bằng prompt_eval_count trên chính máy bạn.
Giá phải trả: VRAM và latency
Sau khi sửa, kết quả lên 81% (324/400 câu) trên cùng bộ câu hỏi, cùng retrieval, cùng prompt. Tỷ lệ response đúng format JSON đi từ khoảng hai phần ba lên "every response but 3".
Chi phí được tác giả tính rõ. KV cache scale tuyến tính theo num_ctx, nên cửa sổ gấp 4 thì cache gấp 4. Với Llama 3.1 8B ở fp16: 32 layer × 8 KV head × 128 dims × 2 (K và V) × 2 byte = 128 KB mỗi token. Tức 2048 token tốn 256 MB KV cache, 8192 token tốn 1 GB. Trên máy tác giả, ollama ps đi từ ~5,9 GB lên 6,8 GB — vẫn vừa card 12 GB và còn chỗ cho embedding model. Median end-to-end mỗi câu hỏi tăng từ 1,9 s lên 3,4 s.
Đổi 1 GB VRAM và 1,5 giây lấy 140 câu trả lời đúng thêm là một trade-off dễ quyết. Nhưng nó chỉ dễ khi bạn biết card mình còn bao nhiêu chỗ trống.
Tính VRAM trước khi tăng num_ctx
Đây là chỗ nhiều người ước lượng sai. Một tác giả khác vừa ra mắt công cụ tính VRAM và lập luận rằng công thức "tham số × byte mỗi trọng số, cộng KV cache tính như thể mọi layer đều nhìn toàn bộ context" chỉ đúng với kiến trúc Llama cổ điển; với phần lớn model ra trong năm qua, theo lời tác giả, nó "is wrong, sometimes by an order of magnitude".
Ví dụ tác giả đưa ra: Gemma 4 31B giữ cửa sổ 1.024 token trên 50 trong 60 layer, chỉ 10 layer nhớ toàn bộ context — ở 128K token, tác giả tính cache thật là 10,8 GiB, trong khi coi mọi layer là global sẽ ra 120 GiB. Đây là con số do tác giả công cụ công bố, không phải đo độc lập.
Bản thân tác giả cũng cảnh báo: "These are estimates. Engine versions and settings change real usage, so keep some headroom and confirm with nvidia-smi." Dùng nó để chọn điểm khởi đầu, rồi xác nhận bằng ollama ps và nvidia-smi.
Ba việc nên làm ngay hôm nay
Theo khuyến nghị trong bài mổ xẻ, có ba thói quen rẻ tiền:
- Assert trên
prompt_eval_count. Nếu nó nằm trong vài token so vớinum_ctx, raise lỗi hoặc ít nhất log thật to. Một câuifđủ để tiết kiệm cả buổi tối. - Đặt câu hỏi và instruction quan trọng ở cuối prompt một-chuỗi. Nếu có gì bị cắt, nó nên là chunk xếp hạng thấp nhất, không phải output format của bạn.
- Set
num_ctxtường minh ở mọi nơi. Context length trên model card là trần, không phải mặc định.
Đoạn assert tối thiểu, viết lại theo ý tưởng trong bài (ví dụ minh hoạ, chỉnh theo code của bạn):
def ask_checked(prompt: str, num_ctx: int = 8192) -> dict:
resp = ask(prompt, num_ctx=num_ctx)
if resp["prompt_eval_count"] >= num_ctx - 8:
raise RuntimeError(f"prompt truncated at {resp['prompt_eval_count']} tokens")
return resp
Việc cần theo dõi tiếp: nếu bạn đang chạy Ollama sau một client OpenAI-style trong production, hãy kiểm tra ngay hôm nay xem usage.prompt_tokens có bị đóng băng ở một con số cố định không. Đó là dấu hiệu rõ nhất rằng retrieval của bạn đang tốt, còn pipeline thì đang vứt nó đi.
Không spam, hủy đăng ký bất kỳ lúc nào.
Bài viết liên quan

Benchmark LLM cho 1.00 nhờ bỏ qua 3 câu fail: 4 bug cần biết
09 thg 10, 2026
