Sửa lỗi Ollama context deadline exceeded
Lỗi `context deadline exceeded` nghĩa là request hết thời gian chờ trước khi model trả lời. Xác định timeout nằm ở client, load model hay nginx.
Ý nghĩa thực sự của “context deadline exceeded”
Lỗi context deadline exceeded của Ollama là một báo cáo timeout. Một đoạn mã Go đã đặt deadline cho request, model không hoàn tất trong thời gian đó và deadline đã hết. Không có tiến trình nào 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ách diễn đạt này xuất phát từ package chuẩn context của Go và bản thân đó đã là một manh mối hữu ích. Một client Python xây dựng trên httpx sẽ phát sinh httpx.ReadTimeout. Trình duyệt chỉ 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 layer liên quan. 3 layer tự đặt deadline: client của bạn, timeout load model của server và reverse proxy. 2 layer còn lại, keep_alive và num_ctx, không đặt deadline nhưng quyết định lượng công việc phải hoàn tất trong một deadline. Chúng fail ở các thời điểm khác nhau và cần cách xử lý khác nhau. Vì vậy, việc cần làm là xác định layer nào gây ra lỗi.
- HTTP client của bạn, đã cấp cho request một khoảng thời gian cố định.
- Timeout load model của Ollama server, hết hạn khi một model lớn được đọc từ disk lần đầu.
keep_alive, unload model giữa các request, khiến call tiếp theo phải trả lại chi phí load.num_ctxđủ lớn để riêng việc xử lý prompt đã chạy trong nhiều phút trên máy chỉ có CPU.- Một reverse proxy như nginx hoặc Traefik, ngắt connection trước khi Ollama kịp phản hồi.
Hãy kiểm tra danh sách trên theo đúng thứ tự. Mỗi bước bên dưới sẽ loại một layer khỏi phạm vi kiểm tra, để bạn không phải đ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 dừng lại chậm
Ollama unload model khi 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 10 năm 2026. Vì vậy, một chat app 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 xác 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 gian hết hạn chỉ còn vài phút sẽ xác nhận nguyên nhân. keep_alive 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à 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. Giá trị của request được ưu tiên: tài liệu Ollama nêu rằng API parameter keep_alive ghi đè thiết lập OLLAMA_KEEP_ALIVE, nên client gửi keep_alive riêng vẫn unload model theo lịch của client đó.
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 reboot. Bạn nên đặt request này trong một systemd unit nhỏ để không ai phải chờ cold start đầu tiên sau reboot. Chi phí là rõ ràng: model được pin sẽ giữ memory mãi mãi, nên trên máy nhỏ bạn chỉ nên pin một model, không phải 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à đó là phần được prompt eval đo. 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ả 2 đề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 ở giai đoạn prefill trong khi client hoàn toàn không thấy dữ liệu nào, vì streaming chưa bắt đầu. Client chạm deadline rồi báo context deadline exceeded, còn server vẫn xử lý trong suốt thời gian đó. Hãy xác nhận bằng các số liệu trong phần trước. Gửi prompt dài rồi đọc prompt_eval_count và prompt_eval_duration; Ollama định nghĩa đây là thời gian dùng để đánh giá các token trong prompt chưa có trong cache. Nếu thời gian này lên đến vài phút trong khi eval_duration nhỏ, đó là prefill. Vì chỉ các token chưa có trong cache mới được tính, lần gửi lại cùng prompt trên một model vẫn đang được load có thể cho kết quả thấp hơn nhiều. Vì vậy, hãy so sánh các lần chạy đầu tiên. Để xem cache lớn hơn tốn bao nhiêu, chạy prompt với "options": {"num_ctx": 2048} rồi chạy lại với 32768, đồng thời đọc load_duration, vì thời gian load model được báo ở đó chứ không phải trong prompt_eval_duration.
Giá trị mặc định của server lấy từ OLLAMA_CONTEXT_LENGTH. Giá trị num_ctx trong object options của từng request sẽ ghi đè giá trị này. Tăng giá trị lên mức tối đa mà model công bố chỉ vì model hỗ trợ mức đó là lỗi thường gặp. Việc cấp phát KV cache có thể đẩy model ra khỏi 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ế trình bày chi tiết về việc 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.
Quantisation nhỏ hơn sẽ load nhanh hơn vì có ít dữ liệu cần đọc
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, và việc load model chủ yếu là đọc file đó từ disk vào memory.
Dữ liệu đằng sau biểu đồ này
[
{
"label": "q4_K_M",
"download_size_gb": 4.9
},
{
"label": "q8_0",
"download_size_gb": 8.5
},
{
"label": "fp16",
"download_size_gb": 16
}
]Đó là 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. 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 thực hiện trước khi pull bất kỳ thứ gì có dung lượng lớn.
Cần thay đổi gì trên một máy thuê
Áp dụng các thay đổi theo thứ tự mà kết quả đo cho thấy, mỗi lần chỉ áp dụng một thay đổi. Chạy lại lệnh đo thời gian sau mỗi thay đổi.
- Cố định model bằng
OLLAMA_KEEP_ALIVE=-1và warm model khi boot, để request của người dùng không phải chịu chi phí load. Sau đó kiểm tra để bảo đảm không client nào tự gửikeep_alive, vì giá trị trong request sẽ ghi đè cấu hình của server. - 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 còn đủ chỗ cho cache.
- Tăng
proxy_read_timeouttrong nginx hoặcresponseHeaderTimeouttrong Traefik, đồng thời tắt buffering để token được stream đến client. - Tăng timeout trong client của bạn, vì một chương trình Go hoặc Python có timeout 30 giây sẽ fail với mọi model cần suy nghĩ lâu hơn thời gian đó.
Còn một nguyên nhân khác liên quan đến tất cả các trường hợp trên. Ollama chỉ xử lý đồng thời một số lượng request giới hạn 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 xử lý muộn thay vì bị fail. Điều gì xảy ra khi nhiều người dùng chung một máy Ollama trình bày các cấu hình parallelism, còn cài đặt cơ bản trên VPS trình bày cấu hình 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 phải dấu hiệu có thứ gì bị hỏng hoặc hỏng dữ liệu. Bước tiếp theo là xác định layer nào đặt deadline, vì client, quá trình load model và reverse proxy đều đặt timeout riêng, còn keep_alive và num_ctx quyết định lượng công việc phải hoàn tất trong các khoảng thời gian đó.
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, trực tiếp đế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 phản hồ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.
Vì 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 10 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à chịu toàn bộ thời gian cold start. Request gửi ngay sau đó thấy model đã nằm trong memory nên trả về nhanh. Chạy ollama ps để xem những gì đang được load và thời điểm chúng 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. Client tự gửi keep_alive sẽ ghi đè setting đó, nên cũng hãy kiểm tra các client của bạn.
Vì sao chỉ lỗi khi đi qua nginx?
nginx ghi rõ proxy_read_timeout với 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 lỗi. Tìm upstream timed out (110: Connection timed out) while reading response header from upstream trong error log của nginx, 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. Setting này chỉ thay đổi 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ẽ rất chậm; timeout lớn hơn chỉ khiến lỗi xảy ra muộn hơn chứ không khắc phục nguyên nhân. Kiểm tra giá trị mặc định của build bạn đang dùng bằng cách chạy ollama --version và đọc envconfig/config.go tại tag đó, sau đó xem quá trình load mất vài phút là dấu hiệu cần chọn quantisation nhỏ hơn.