Ollama context deadline exceeded 修正方法
遇到 Ollama 的 `context deadline exceeded`?依序檢查 HTTP 用戶端、模型載入、keep_alive、提示長度與 nginx,找出實際逾時層級。
「context deadline exceeded」實際代表的意義
Ollama 的錯誤 context deadline exceeded 表示請求逾時。某段 Go 程式碼為請求設定了期限,但模型未能在期限內完成,期限因此到期。這不代表程式崩潰,也不代表檔案損毀。期限到期時,工作仍在執行。
這段訊息來自 Go 的標準 context 套件,本身就是有用的線索。以 httpx 建立的 Python 用戶端則會引發 httpx.ReadTimeout。瀏覽器會顯示一般網路錯誤。如果你看到的正是這段文字,表示某個 Go 程式放棄等待,可能是 Ollama 命令列工具、Ollama 伺服器本身,或呼叫 API(應用程式介面)的 Go 應用程式。
有 5 個層級可能設定該期限。它們會在不同階段失敗,也各自需要不同的修正方式。因此,完整的排查工作是確認究竟是哪一層觸發了期限。
- HTTP 用戶端為請求設定了固定的時間額度。
- Ollama 伺服器的模型載入逾時設定。大型模型第一次從磁碟讀取時,可能觸發此逾時。
keep_alive在請求之間卸載模型,導致下一次呼叫必須再次支付載入成本。num_ctx的值過大,導致僅處理提示就讓僅使用 CPU 的主機執行數分鐘。- 反向代理,例如 nginx 或 Traefik,在 Ollama 回應前中斷連線。
請依序排查上述清單。以下每個步驟都會排除一個層級,讓你不必再靠猜測。
直接呼叫 API,排除代理
在伺服器本機直接向 Ollama 發送要求,中間不經過代理。
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 本身不設定整體時間上限,只設定連線逾時,因此此命令會持續等待 Ollama 完成。這樣可以將問題分成兩部分。如果收到 JSON 回應,表示 Ollama 已回應,逾時期限來自前方的某個元件。如果這個呼叫本身卡住數分鐘,延遲就在 Ollama 內部,代理並非原因。
接著透過公開 URL 發送相同要求,並測量所需時間。
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}'如果在可疑的整數秒數後輸出 504,例如 60.0 或 30.0,這就是代理逾時。代理通常使用整數秒的預設值。模型不會連續兩次都剛好在 60.000 秒完成。如果直接呼叫立即遭拒,而不是緩慢完成,問題是監聽器設定,而不是逾時期限;Ollama 在連接埠 11434 綁定的位址涵蓋這種情況。
監看請求執行期間的伺服器日誌
開啟第二個工作階段並持續追蹤服務日誌,然後再次傳送請求。
journalctl -u ollama --no-pager --follow --pager-end正常的冷啟動會先記錄模型載入,接著記錄 runner 啟動,最後記錄請求已獲處理。載入失敗時則會出現以下內容;其中的字串可用來識別伺服器本身的載入逾時:
Error: timed out waiting for llama runner to start - progress 0.00 -這則訊息表示模型程序未能在伺服器配置的時間內完成啟動。進度數值表示載入進行到哪個階段。0.00 表示 runner 在期限前完全沒有回報,通常代表系統仍在讀取檔案,或機器正在使用 swap。如需取得載入期間的詳細資訊,請設定 OLLAMA_DEBUG=1 後重新啟動服務,再次執行。
判斷延遲來自載入或生成
Ollama 會回報自身的計時資訊,因此不必猜測延遲來源。
ollama run --verbose llama3.1:8b "Why is the sky blue?"回答結束後,Ollama 會列出 total duration、load duration、prompt eval count、prompt eval rate、eval count 和 eval rate。請執行兩次。第二次執行時,load duration 應降至幾乎為零,因為模型已常駐記憶體。如果沒有下降,表示模型在兩次執行之間被卸載,這就是後文的 keep_alive 情況。
API 也會在最後的 JSON 物件中回傳相同數值,分別是 load_duration、prompt_eval_duration 和 eval_duration。文件說明所有 duration 都以 nanoseconds 回傳,因此請除以 10^9 以換算為秒。
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")})'查看數值最大的項目。如果 load_duration 占主要部分,表示模型載入有問題,請前往接下來的兩個章節。如果 prompt_eval_duration 占主要部分,表示成本來自 prompt processing,請前往 num_ctx 章節。如果 eval_duration 占主要部分,表示模型只是在這台硬體上生成速度較慢,調整 timeout 設定也無法改善。請使用 num_predict 縮短輸出,或改用較小的模型。
確認版本後提高 OLLAMA_LOAD_TIMEOUT
控制伺服器等待模型啟動時間的伺服器變數是 OLLAMA_LOAD_TIMEOUT。不同版本的預設值可能不同,因此請依照目前建置版本讀取設定,不要直接採用任何文章中的值,包括本文。先列印版本。
ollama --version接著開啟該精確標籤的原始碼 https://github.com/ollama/ollama/blob/<your version>/envconfig/config.go,並搜尋 OLLAMA_LOAD_TIMEOUT。該檔案中的值就是二進位檔編譯時內建的預設值。請透過 systemd drop-in 設定自己的值。
sudo systemctl edit ollama.service在 [Service] 區段下加入變數。這是 Ollama 官方文件針對 Linux 提供的方法:
[Service]
Environment="OLLAMA_LOAD_TIMEOUT=15m"
Environment="OLLAMA_KEEP_ALIVE=-1"sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environment最後一個命令會列印服務實際收到的環境。若結果為空,表示 drop-in 儲存在編輯器標記之外,或使用了錯誤的區段名稱,因此設定沒有生效。請明確了解這項設定的作用:較長的載入逾時時間只能避免伺服器過早放棄,不會讓任何工作變快。若模型無法放入記憶體,系統就會使用 swap,載入速度會大幅變慢;提高數值只會讓失敗延後發生。
暫停後的第一個請求速度較慢
Ollama 會卸載閒置模型以釋放記憶體。keep_alive 設定決定等待時間。Ollama 文件在 2026 年 9 月查到的預設值為 5 分鐘。因此,每小時只使用一次的聊天應用程式,會在每則訊息送出時重新載入模型,而每則訊息都必須承擔完整的冷啟動時間。發生逾時的請求,是安靜一段時間後送出的第一個請求。這正是使用者描述為隨機問題的典型模式。
查看目前常駐的模型:
ollama ps
curl -s http://127.0.0.1:11434/api/ps如果清單為空,或模型將在幾分鐘後到期,就能確認這個原因。keep_alive 接受例如 "10m" 或 "24h" 的持續時間字串,也接受以秒為單位的純數字、可立即卸載的 0,以及讓模型永久保留在記憶體中的負數。可以逐一針對請求設定,也可以在服務上設定 OLLAMA_KEEP_ALIVE,套用至所有請求。
curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"keep_alive": -1
}'指定模型但不提供提示的請求會載入模型,然後直接返回。這是文件記載的開機後預熱主機方式,應放入小型 systemd 單元,避免任何人等待冷啟動。其代價很明確:固定常駐的模型會永久占用記憶體,因此在小型主機上只能固定一個模型,不能固定四個模型。讓模型在請求之間保持常駐 會說明記憶體計算方式與預熱單元。
為何較大的 num_ctx 會在產生第一個 token 前逾時
模型開始輸出前,必須先讀取完整的提示。這個階段稱為 prefill,也是 prompt eval 所測量的內容。num_ctx 設定內容長度,同時執行兩項功能:限制模型可處理的 token 數量,以及設定伺服器預先配置的 KV cache(key value cache)大小。兩者都會增加工作量。
在僅使用 CPU 的伺服器上,prefill 速度很慢,而且處理時間會隨提示中的 token 數量線性增加。將長文件貼入聊天時,prefill 可能持續數分鐘,而用戶端完全看不到內容,因為串流尚未開始。用戶端會到達期限並回報 context deadline exceeded,但伺服器在這段期間一直處理中。請使用上一節的數據加以驗證:先以 "options": {"num_ctx": 2048} 執行相同提示,再以 32768 執行,然後比較 prompt_eval_duration。
伺服器預設值來自 OLLAMA_CONTEXT_LENGTH,而 options 物件中的每個要求所設定的 num_ctx 會覆寫該值。常見錯誤是因為模型有宣告最大值,就將其提高到該最大值;這可能使 KV cache 配置耗盡 RAM,讓原本可正常運作的設定開始使用 swap。依實際記憶體選擇 num_ctx 說明了容量估算細節。
nginx 為何回傳 504 Gateway Time-out
nginx 將 proxy_read_timeout 的預設值設為 60s,而且錯誤日誌會明確指出失敗原因:
upstream timed out (110: Connection timed out) while reading response header from upstreamnginx 文件中的重要細節是:這項逾時「只套用於兩次連續讀取操作之間,不套用於整個回應的傳輸時間」。串流回應會在每個區塊傳送時重設計時器,因此串流聊天可以持續運作。使用 "stream": false 的請求會在答案完成前完全不傳送內容,因此整個生成流程都必須在這個單一時間範圍內完成。這就是同一個模型能在聊天視窗中運作,卻從指令碼執行時逾時的原因。
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 會影響串流功能。啟用緩衝時,nginx 可能會先收集回應,最後才一次傳送,因此 token 不會逐一出現,原本正常的串流也會看起來像是卡住。
Traefik 將相同的控制項放在路由器使用的 ServersTransport 上。
http:
serversTransports:
ollama:
forwardingTimeouts:
dialTimeout: "30s"
responseHeaderTimeout: "0s"
idleConnTimeout: "60s"responseHeaderTimeout 涵蓋寫入請求後等待回應標頭的時間,設為 0 表示不逾時。服務必須使用 serversTransport: ollama 依名稱參照該傳輸設定,否則你修改的區塊不會被任何服務使用。
較小的量化版本載入速度較快,因為需要讀取的資料較少
量化是權重儲存時所使用的精度。精度越低,檔案越小;而載入模型主要就是將檔案從磁碟讀入記憶體。
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
}
]這些是模型頁面公布的大小,不是從測試伺服器測得的數值。預設的 8B 版本大小為 4.9 GB。同一模型的完整精度版本為 16 GB,需要讀取的位元組數超過 3 倍,容納所需的記憶體也超過 3 倍。在採用共用儲存空間的租用伺服器上,這項差異可能決定載入是否能完成,或是否因逾時而失敗。載入大型模型前,應先執行確認哪個模型符合您的 RAM。
租用伺服器上的調整方式
依照測量結果指出的方向,按以下順序逐項套用。每完成一項,就重新執行計時命令。
- 使用
OLLAMA_KEEP_ALIVE=-1固定模型,或在開機時預先載入,讓任何使用者請求都不必等待載入。 - 將
num_ctx降低至提示詞實際需要的值,以縮短 prefill,並釋放 KV cache 佔用的記憶體。 - 改用較小的 quantisation,讓載入時讀取較少位元組,並為 cache 保留更多空間。
- 調高 nginx 的
proxy_read_timeout或 Traefik 的responseHeaderTimeout,並關閉 buffering,讓串流 token 能傳送至用戶端。 - 調高自有用戶端的 timeout,因為設定 30 秒預算的 Go 或 Python 程式,遇到思考時間更長的模型時就會失敗。
上述原因之外,還有一項常被忽略的因素。Ollama 同時處理的請求數量有限,其餘請求會排入佇列。因此,第二個呼叫端可能在佇列中等待,直到自身的 deadline 到期;此時不一定存在執行緩慢的模型。伺服器日誌會顯示請求延遲處理,而不是失敗。多個使用者共用一台 Ollama 伺服器時的情況說明平行處理設定;VPS 上的基本安裝說明這些覆寫設定所依賴的服務設定。
FAQ
Ollama 中的「context deadline exceeded」代表什麼?
這表示請求的截止時間已到,但模型尚未回應。這個詞來自 Go 的 context 套件,因此是某個 Go 程式輸出的訊息:可能是 Ollama 命令列工具、Ollama 伺服器,或呼叫 API 的 Go 應用程式。這是逾時,不表示任何元件損壞或資料毀損。下一步是找出由哪一層設定截止時間,因為用戶端、模型載入程序、keep_alive、num_ctx 及反向代理都會各自設定逾時。
我應該提高用戶端逾時,還是 Ollama 的逾時?
先進行測量。在伺服器本機使用 curl 傳送請求,直接連到 http://127.0.0.1:11434,因為 curl 不會施加整體時間限制。如果該呼叫傳回 JSON 內容,表示 Ollama 正在回應,截止時間問題出在用戶端或代理,因此應在對應位置提高逾時。如果該呼叫也會卡住,延遲就在 Ollama 內部;回應中的 load_duration 和 prompt_eval_duration 欄位會告訴你模型正在載入,還是正在讀取提示。
為什麼第一個請求會逾時,但下一個請求可以運作?
Ollama 會依照 keep_alive 設定的排程,卸載閒置模型以釋放記憶體。文件記載的預設值是 5 分鐘,並於 2026 年 9 月確認。閒置一段時間後的第一個請求必須從磁碟重新載入模型,因此需要完整的冷啟動時間;緊接著送出的請求則會發現模型仍在記憶體中,能快速傳回結果。執行 ollama ps 查看目前已載入的模型及其到期時間。設定 OLLAMA_KEEP_ALIVE=-1 可讓模型留在記憶體中,但記憶體也會持續被占用。
為什麼只有透過 nginx 時才會失敗?
nginx 文件指出,proxy_read_timeout 的預設值為 60s。此逾時適用於兩次連續讀取之間的間隔,不適用於整個回應。串流回應每收到一個區塊就會重設逾時;使用 "stream": false 傳送的請求則必須在單一時間窗口內完成。因此聊天視窗可以運作,但指令碼會失敗。請在 nginx error log 中尋找 upstream timed out (110: Connection timed out) while reading response header from upstream,然後提高 proxy_read_timeout 並設定 proxy_buffering off。
提高 OLLAMA_LOAD_TIMEOUT 會讓載入速度變快嗎?
不會。它只會改變伺服器在放棄並記錄 timed out waiting for llama runner to start 前等待的時間。如果模型無法放入記憶體,系統就會使用 swap,載入速度會大幅變慢;提高逾時只會讓失敗延後,無法解決問題。執行 ollama --version 並讀取該 tag 中的 envconfig/config.go,確認你所用 build 的預設值。若載入需要數分鐘,應將此視為改用較小 quantisation 的訊號。