Cách sửa lỗi Ollama context deadline exceeded
Lỗi `context deadline exceeded` của Ollama là timeout trước khi model trả lời. Tìm đúng lớp gây lỗi: client, model load, keep_alive, tải prompt hoặc nginx.
Ý nghĩa thực sự của “context deadline exceeded”
Lỗi context deadline exceeded của Ollama là thông báo timeout. Một đoạn mã Go đã đặt deadline cho request, model không hoàn tất trong khoảng thời gian đó và deadline đã hết hạn. Không có gì bị crash và không có file nào bị hỏng. Tác vụ vẫn đang chạy khi hết thời gian.
Cụm từ này xuất phát từ package chuẩn context của Go. Đây là một manh mối hữu ích. Client Python xây dựng trên httpx sẽ phát sinh httpx.ReadTimeout. Trình duyệt sẽ hiển thị một lỗi mạng thông thường. Nếu bạn đang đọc đúng những từ này, một chương trình Go đã ngừng chờ: công cụ dòng lệnh Ollama, chính Ollama server hoặc một ứng dụng Go gọi API (application programming interface).
Có 5 lớp có thể đặt deadline đó. Chúng gây lỗi tại các thời điểm khác nhau và mỗi lớp cần một cách xử lý khác nhau. Vì vậy, việc cần làm là xác định lớp nào đã kích hoạt.
- HTTP client của bạn đặt một khoảng thời gian cố định cho request.
- Model load timeout của Ollama server kích hoạt khi lần đầu đọc một model lớn từ disk.
keep_alivegỡ model khỏi memory giữa các request, khiến request tiếp theo phải trả lại chi phí load.num_ctxđủ lớn khiến riêng việc xử lý prompt đã chạy trong nhiều phút trên máy chỉ dùng CPU.- Reverse proxy như nginx hoặc Traefik ngắt connection trước khi Ollama phản hồi.
Hãy kiểm tra danh sách trên theo thứ tự. Mỗi bước bên dưới sẽ loại bỏ một lớp khỏi quá trình kiểm tra, để bạn không phải phỏng đoán.
Gọi trực tiếp API để loại proxy khỏi quá trình kiểm tra
Chạy request ngay trên server, gọi thẳng đến Ollama và không đi qua proxy.
time curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"prompt": "Why is the sky blue?",
"stream": false
}' | head -c 400curl không tự đặt giới hạn thời gian tổng thể, mà chỉ đặt connect timeout. Vì vậy, command này sẽ chờ cho đến khi Ollama xử lý xong. Cách này giúp khoanh vùng nguyên nhân. Nếu nhận được JSON body, Ollama đã phản hồi và timeout nằm ở thành phần phía trước nó. Nếu chính call này treo trong nhiều phút, độ trễ nằm bên trong Ollama và proxy không phải nguyên nhân.
Bây giờ gửi cùng request qua public URL và đo thời gian.
curl -s -o /dev/null -w '%{http_code} %{time_total}\n' \
-X POST https://llm.example.com/api/generate \
-d '{"model": "llama3.1:8b", "prompt": "hi", "stream": false}'Nếu status 504 xuất hiện sau một khoảng thời gian tròn bất thường, như 60.0 hoặc 30.0 giây, đó là proxy timeout. Proxy thường dùng các giá trị mặc định tròn. Model không thể liên tiếp hoàn tất chính xác sau 60.000 giây. Nếu direct call bị từ chối ngay lập tức thay vì phản hồi chậm, bạn đang gặp vấn đề với listener chứ không phải vấn đề về timeout. Ollama bind vào địa chỉ nào trên port 11434 sẽ trình bày trường hợp này.
Theo dõi log của server trong khi request chạy
Mở một session thứ hai và theo dõi log của service, sau đó gửi lại request.
journalctl -u ollama --no-pager --follow --pager-endMột lần khởi động lạnh bình thường sẽ ghi log model đang được load, sau đó runner khởi động, rồi request được xử lý. Lỗi load sẽ có dạng như sau. Đây là chuỗi xác định timeout load của chính server:
Error: timed out waiting for llama runner to start - progress 0.00 -Thông báo này có nghĩa là process của model chưa khởi động xong trong khoảng thời gian server cho phép. Con số tiến độ cho biết process đã chạy đến đâu. Giá trị 0.00 có nghĩa là runner chưa báo cáo gì trước deadline. Nguyên nhân thường là file vẫn đang được đọc hoặc máy đang sử dụng swap. Để xem chi tiết hơn trong lúc load, hãy restart service với OLLAMA_DEBUG=1 được thiết lập rồi thực hiện lại.
Đo xem độ trễ đến từ việc nạp model hay sinh nội dung
Ollama tự báo cáo thời gian xử lý, nên bạn không cần phỏng đoán phần này.
ollama run --verbose llama3.1:8b "Why is the sky blue?"Sau khi trả lời, nó in ra total duration, load duration, prompt eval count, prompt eval rate, eval count và eval rate. Chạy lệnh 2 lần. Ở lần chạy thứ hai, load duration phải giảm xuống gần như bằng 0 vì model đã nằm sẵn trong bộ nhớ. Nếu giá trị này không giảm, model đang bị unload giữa 2 lần chạy. Đây là trường hợp keep_alive được đề cập ở phần bên dưới.
API cũng trả về các giá trị này trong object JSON cuối cùng, lần lượt là load_duration, prompt_eval_duration và eval_duration. Tài liệu cho biết mọi khoảng thời gian đều được trả về theo nanosecond, vì vậy hãy chia cho 10^9 để đọc theo giây.
curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"prompt": "Why is the sky blue?",
"stream": false
}' | python3 -c 'import json,sys; d=json.load(sys.stdin); print({k: round(v/1e9, 2) for k, v in d.items() if k.endswith("_duration")})'Xem giá trị lớn nhất. Nếu load_duration chiếm phần lớn, bạn đang gặp vấn đề khi load model, hãy chuyển đến 2 phần tiếp theo. Nếu prompt_eval_duration chiếm phần lớn, việc xử lý prompt là nguyên nhân gây chậm, hãy chuyển đến phần num_ctx. Nếu eval_duration chiếm phần lớn, model chỉ đơn giản là sinh nội dung chậm trên phần cứng này; không setting timeout nào có thể thay đổi điều đó. Rút ngắn output bằng num_predict hoặc chuyển sang model nhỏ hơn.
Tăng OLLAMA_LOAD_TIMEOUT sau khi kiểm tra phiên bản
Biến của server quy định thời gian chờ để model khởi động là OLLAMA_LOAD_TIMEOUT. Giá trị mặc định đã thay đổi giữa các bản release, vì vậy hãy đọc giá trị dành cho bản build của bạn thay vì lấy từ bất kỳ bài viết nào, kể cả bài này. Trước tiên, hãy in phiên bản.
ollama --versionSau đó mở source của tag chính xác đó, https://github.com/ollama/ollama/blob/<your version>/envconfig/config.go, rồi tìm OLLAMA_LOAD_TIMEOUT. Giá trị trong file đó là giá trị mặc định đã được biên dịch vào binary của bạn. Hãy đặt giá trị riêng thông qua systemd drop-in.
sudo systemctl edit ollama.serviceThêm các biến bên dưới section [Service]. Đây là phương thức được tài liệu chính thức của Ollama hướng dẫn cho Linux:
[Service]
Environment="OLLAMA_LOAD_TIMEOUT=15m"
Environment="OLLAMA_KEEP_ALIVE=-1"sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=EnvironmentLệnh cuối cùng in ra môi trường mà service thực tế đã nhận. Kết quả trống có nghĩa là drop-in được lưu bên ngoài các marker của editor hoặc bên dưới tên section sai, nên không có giá trị nào bạn đặt được áp dụng. Cần hiểu rõ tác dụng của việc này: timeout load dài hơn chỉ ngăn server bỏ cuộc, không làm quá trình nhanh hơn. Nếu model không vừa trong memory, máy sẽ dùng swap, quá trình load sẽ rất chậm, và giá trị lớn hơn chỉ khiến lỗi xuất hiện muộn hơn.
Vì sao request đầu tiên sau một khoảng tạm dừng lại chậm
Ollama unload model không hoạt động để giải phóng memory. Thiết lập keep_alive quyết định thời điểm thực hiện việc này. Tài liệu Ollama ghi giá trị mặc định là 5 phút, được kiểm tra vào tháng 9 năm 2026. Vì vậy, một ứng dụng chat chỉ được dùng mỗi giờ một lần sẽ reload model trong từng message, và mỗi message đều phải chịu toàn bộ thời gian cold start. Request bị timeout là request đầu tiên sau một khoảng không có hoạt động. Đây chính là mẫu lỗi thường bị mô tả là xảy ra ngẫu nhiên.
Kiểm tra model hiện đang resident:
ollama ps
curl -s http://127.0.0.1:11434/api/psDanh sách trống hoặc thời điểm hết hạn chỉ còn vài phút sẽ xác nhận điều này. keep_alive chấp nhận chuỗi duration như "10m" hoặc "24h", một số nguyên biểu thị số giây, 0 để unload ngay lập tức và một số âm để giữ model trong memory vô thời hạn. Bạn có thể đặt giá trị này cho từng request hoặc đặt OLLAMA_KEEP_ALIVE trên service để áp dụng cho mọi request.
curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"keep_alive": -1
}'Request có model nhưng không có prompt sẽ load model rồi trả về. Đây là cách được tài liệu hướng dẫn để warm một máy sau khi reboot. Bạn nên đặt request này trong một unit systemd nhỏ để không ai phải chờ cold start. Chi phí là rõ ràng: model được pin sẽ giữ memory vĩnh viễn. Vì vậy, trên một máy nhỏ, bạn chỉ nên pin một model thay vì bốn model. Giữ model resident giữa các request giải thích cách tính memory và unit warm-up.
Vì sao num_ctx lớn gây timeout trước token đầu tiên
Trước khi model tạo ra bất kỳ nội dung nào, nó phải đọc toàn bộ prompt. Giai đoạn này gọi là prefill, và prompt eval dùng để đo thời gian đó. num_ctx đặt độ dài context và thực hiện đồng thời 2 việc. Nó giới hạn số token mà model được phép xem xét, đồng thời xác định kích thước KV cache (key value cache) mà server cấp phát ngay từ đầu. Cả hai đều làm tăng khối lượng xử lý.
Trên server chỉ dùng CPU, prefill chậm và thời gian xử lý tăng tuyến tính theo số token trong prompt. Một tài liệu dài được dán vào chat có thể mất vài phút trong giai đoạn prefill trong khi client hoàn toàn không nhận được dữ liệu nào, vì quá trình streaming chưa bắt đầu. Client hết thời gian chờ và báo lỗi context deadline exceeded, còn server vẫn xử lý liên tục trong suốt thời gian đó. Hãy kiểm chứng bằng các số liệu ở phần trước: chạy cùng một prompt với "options": {"num_ctx": 2048}, sau đó chạy với 32768, rồi so sánh prompt_eval_duration.
Giá trị mặc định của server lấy từ OLLAMA_CONTEXT_LENGTH. Giá trị num_ctx trong mỗi request, nằm trong object options, sẽ ghi đè giá trị mặc định này. Tăng giá trị lên mức tối đa mà model công bố chỉ vì mức tối đa đó tồn tại là lỗi thường gặp. Nguyên nhân là việc cấp phát KV cache có thể khiến model không còn đủ RAM và biến một cấu hình đang hoạt động thành cấu hình phải dùng swap. Chọn num_ctx dựa trên dung lượng bộ nhớ thực tế có phần giải thích chi tiết về sizing.
Vì sao nginx trả về 504 Gateway Time-out
nginx ghi rõ proxy_read_timeout với giá trị mặc định là 60s, và error log nêu thẳng nguyên nhân:
upstream timed out (110: Connection timed out) while reading response header from upstreamChi tiết quan trọng nằm trong tài liệu nginx: timeout “chỉ được tính giữa hai lần đọc liên tiếp, không tính cho toàn bộ thời gian truyền response”. Response dạng streaming sẽ đặt lại bộ đếm sau mỗi chunk, nên các phiên chat streaming vẫn hoạt động. Request có "stream": false không gửi dữ liệu nào cho đến khi câu trả lời hoàn tất, nên toàn bộ quá trình generation phải kết thúc trong một khoảng thời gian đó. Vì vậy, cùng một model có thể hoạt động trong cửa sổ chat nhưng lại timeout khi chạy từ script.
location / {
proxy_pass http://127.0.0.1:11434;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
proxy_buffering off;
}sudo nginx -t && sudo systemctl reload nginxproxy_buffering off ảnh hưởng đến streaming. Khi bật buffering, nginx có thể gom response rồi chuyển tiếp toàn bộ ở cuối, khiến token không còn xuất hiện từng cái một và một stream đang hoạt động trông giống như bị treo.
Traefik đặt cùng tùy chọn này trong ServersTransport mà router sử dụng.
http:
serversTransports:
ollama:
forwardingTimeouts:
dialTimeout: "30s"
responseHeaderTimeout: "0s"
idleConnTimeout: "60s"responseHeaderTimeout bao phủ thời gian chờ response headers sau khi request đã được ghi xong, và giá trị 0 nghĩa là không timeout. Service phải tham chiếu transport bằng tên thông qua serversTransport: ollama, nếu không bạn chỉ sửa một block không được sử dụng.
Bản quantisation nhỏ hơn tải nhanh hơn vì có ít dữ liệu cần đọc hơn
Quantisation là độ chính xác dùng để lưu weights. Độ chính xác thấp hơn tạo ra file nhỏ hơn, còn việc tải model chủ yếu là đọc file đó từ disk vào memory.
The data behind this chart
[
{
"label": "q4_K_M",
"download_size_gb": 4.9
},
{
"label": "q8_0",
"download_size_gb": 8.5
},
{
"label": "fp16",
"download_size_gb": 16
}
]Đây là các kích thước được công bố trên trang model, không phải số đo từ một máy test. Bản build 8B mặc định có dung lượng 4.9 GB. Bản build full precision của cùng model có dung lượng 16 GB, tức có số byte cần đọc nhiều hơn 3 lần và cần nhiều hơn 3 lần memory để lưu model. Trên server thuê dùng shared storage, chênh lệch này quyết định việc load có hoàn tất hay bị timeout. Tính xem model nào phù hợp với RAM của bạn là bước cần kiểm tra trước khi pull bất kỳ model lớn nào.
Cần thay đổi gì trên máy chủ thuê
Áp dụng các thay đổi này theo thứ tự mà kết quả đo cho thấy, mỗi lần chỉ áp dụng một thay đổi, rồi chạy lại lệnh đo thời gian sau từng thay đổi.
- Ghim model bằng
OLLAMA_KEEP_ALIVE=-1hoặc warm model khi boot, để không request nào của người dùng phải trả chi phí load. - Giảm
num_ctxxuống mức mà prompt thực tế cần. Việc này rút ngắn prefill và giải phóng phần memory mà KV cache đang giữ. - Dùng quantisation nhỏ hơn để quá trình load đọc ít byte hơn và model chừa thêm chỗ cho cache.
- Tăng
proxy_read_timeouttrong nginx hoặcresponseHeaderTimeouttrong Traefik, đồng thời tắt buffering để các token được stream đến client. - Tăng timeout trong client của bạn, vì chương trình Go hoặc Python có budget 30 giây sẽ fail với bất kỳ model nào cần suy nghĩ lâu hơn.
Còn một nguyên nhân có thể nằm sau tất cả các vấn đề này. Ollama chỉ phục vụ một số lượng request giới hạn cùng lúc và đưa các request còn lại vào queue. Vì vậy, caller thứ hai có thể phải chờ trong queue đến khi deadline của chính nó hết hạn, dù không có model nào xử lý chậm. Server log sẽ cho thấy request được phục vụ trễ thay vì bị fail. Điều gì xảy ra khi nhiều người dùng chung một máy Ollama giải thích các thiết lập về parallelism, còn cài đặt cơ bản trên VPS giải thích cách thiết lập service mà các override này giả định.
FAQ
“context deadline exceeded” trong Ollama có nghĩa là gì?
Nghĩa là deadline của request đã hết trước khi model trả lời. Cụm từ này xuất phát từ package context của Go, nên một chương trình Go đã in ra nó: công cụ dòng lệnh Ollama, Ollama server hoặc một ứng dụng Go gọi API. Đây là lỗi timeout, không có nghĩa là dữ liệu bị hỏng hoặc bị corrupt. Bước tiếp theo là xác định layer nào đã đặt deadline, vì client, quá trình load model, keep_alive, num_ctx và reverse proxy đều có timeout riêng.
Tôi nên tăng timeout của client hay timeout của Ollama?
Hãy đo trước. Gửi request bằng curl ngay trên server, gọi thẳng đến http://127.0.0.1:11434, vì curl không áp đặt giới hạn thời gian tổng thể. Nếu lệnh đó trả về JSON body, Ollama đang trả lời và deadline thuộc về client hoặc proxy của bạn, nên hãy tăng timeout ở đó. Nếu lệnh đó cũng bị treo, độ trễ nằm bên trong Ollama; các field load_duration và prompt_eval_duration trong response cho biết model đang được load hay đang đọc prompt của bạn.
Tại sao request đầu tiên bị timeout nhưng request tiếp theo lại chạy được?
Ollama unload model không hoạt động để giải phóng memory, theo lịch do keep_alive đặt. Giá trị mặc định được tài liệu ghi nhận là 5 phút, được kiểm tra vào tháng 9 năm 2026. Request đầu tiên sau một khoảng thời gian idle phải load lại model từ disk và mất toàn bộ thời gian cold start. Request gửi ngay sau đó thấy model vẫn resident nên trả về nhanh. Chạy ollama ps để xem những gì đã được load và thời điểm hết hạn. Đặt OLLAMA_KEEP_ALIVE=-1 để giữ model trong memory, đồng thời chấp nhận rằng memory sẽ tiếp tục bị chiếm dụng.
Tại sao lỗi chỉ xảy ra khi tôi đi qua nginx?
nginx ghi rõ proxy_read_timeout có giá trị mặc định là 60s. Timeout này áp dụng giữa hai lần đọc liên tiếp, không áp dụng cho toàn bộ response. Streaming reply sẽ reset timeout sau mỗi chunk, còn request gửi bằng "stream": false phải hoàn tất trong một khoảng timeout duy nhất. Vì vậy cửa sổ chat hoạt động nhưng script lại thất bại. Tìm upstream timed out (110: Connection timed out) while reading response header from upstream trong nginx error log, sau đó tăng proxy_read_timeout và đặt proxy_buffering off.
Tăng OLLAMA_LOAD_TIMEOUT có làm quá trình load nhanh hơn không?
Không. Nó chỉ thay đổi khoảng thời gian server chờ trước khi bỏ cuộc và ghi log timed out waiting for llama runner to start. Nếu model không vừa trong memory, máy sẽ dùng swap, quá trình load sẽ chậm nghiêm trọng. Timeout lớn hơn chỉ khiến lỗi xuất hiện muộn hơn, không giải quyết nguyên nhân. Kiểm tra giá trị mặc định của build bằng cách chạy ollama --version và đọc envconfig/config.go tại tag đó, sau đó xem việc load mất vài phút là dấu hiệu cần chọn một quantisation nhỏ hơn.