SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-09-07

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 個層級可能設定該期限。它們會在不同階段失敗,也各自需要不同的修正方式。因此,完整的排查工作是確認究竟是哪一層觸發了期限。

  1. HTTP 用戶端為請求設定了固定的時間額度。
  2. Ollama 伺服器的模型載入逾時設定。大型模型第一次從磁碟讀取時,可能觸發此逾時。
  3. keep_alive 在請求之間卸載模型,導致下一次呼叫必須再次支付載入成本。
  4. num_ctx 的值過大,導致僅處理提示就讓僅使用 CPU 的主機執行數分鐘。
  5. 反向代理,例如 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 400

curl 本身不設定整體時間上限,只設定連線逾時,因此此命令會持續等待 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 durationload durationprompt eval countprompt eval rateeval counteval rate。請執行兩次。第二次執行時,load duration 應降至幾乎為零,因為模型已常駐記憶體。如果沒有下降,表示模型在兩次執行之間被卸載,這就是後文的 keep_alive 情況。

API 也會在最後的 JSON 物件中回傳相同數值,分別是 load_durationprompt_eval_durationeval_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 upstream

nginx 文件中的重要細節是:這項逾時「只套用於兩次連續讀取操作之間,不套用於整個回應的傳輸時間」。串流回應會在每個區塊傳送時重設計時器,因此串流聊天可以持續運作。使用 "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 nginx

proxy_buffering off 會影響串流功能。啟用緩衝時,nginx 可能會先收集回應,最後才一次傳送,因此 token 不會逐一出現,原本正常的串流也會看起來像是卡住。

Traefik 將相同的控制項放在路由器使用的 ServersTransport 上。

http:
  serversTransports:
    ollama:
      forwardingTimeouts:
        dialTimeout: "30s"
        responseHeaderTimeout: "0s"
        idleConnTimeout: "60s"

responseHeaderTimeout 涵蓋寫入請求後等待回應標頭的時間,設為 0 表示不逾時。服務必須使用 serversTransport: ollama 依名稱參照該傳輸設定,否則你修改的區塊不會被任何服務使用。

較小的量化版本載入速度較快,因為需要讀取的資料較少

量化是權重儲存時所使用的精度。精度越低,檔案越小;而載入模型主要就是將檔案從磁碟讀入記憶體。

ChartPublished download sizes for llama3.1 8B on the ollama.com library, September 2026
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。

租用伺服器上的調整方式

依照測量結果指出的方向,按以下順序逐項套用。每完成一項,就重新執行計時命令。

  1. 使用 OLLAMA_KEEP_ALIVE=-1 固定模型,或在開機時預先載入,讓任何使用者請求都不必等待載入。
  2. num_ctx 降低至提示詞實際需要的值,以縮短 prefill,並釋放 KV cache 佔用的記憶體。
  3. 改用較小的 quantisation,讓載入時讀取較少位元組,並為 cache 保留更多空間。
  4. 調高 nginx 的 proxy_read_timeout 或 Traefik 的 responseHeaderTimeout,並關閉 buffering,讓串流 token 能傳送至用戶端。
  5. 調高自有用戶端的 timeout,因為設定 30 秒預算的 Go 或 Python 程式,遇到思考時間更長的模型時就會失敗。

上述原因之外,還有一項常被忽略的因素。Ollama 同時處理的請求數量有限,其餘請求會排入佇列。因此,第二個呼叫端可能在佇列中等待,直到自身的 deadline 到期;此時不一定存在執行緩慢的模型。伺服器日誌會顯示請求延遲處理,而不是失敗。多個使用者共用一台 Ollama 伺服器時的情況說明平行處理設定;VPS 上的基本安裝說明這些覆寫設定所依賴的服務設定。

FAQ

Ollama 中的「context deadline exceeded」代表什麼?

這表示請求的截止時間已到,但模型尚未回應。這個詞來自 Go 的 context 套件,因此是某個 Go 程式輸出的訊息:可能是 Ollama 命令列工具、Ollama 伺服器,或呼叫 API 的 Go 應用程式。這是逾時,不表示任何元件損壞或資料毀損。下一步是找出由哪一層設定截止時間,因為用戶端、模型載入程序、keep_alivenum_ctx 及反向代理都會各自設定逾時。

我應該提高用戶端逾時,還是 Ollama 的逾時?

先進行測量。在伺服器本機使用 curl 傳送請求,直接連到 http://127.0.0.1:11434,因為 curl 不會施加整體時間限制。如果該呼叫傳回 JSON 內容,表示 Ollama 正在回應,截止時間問題出在用戶端或代理,因此應在對應位置提高逾時。如果該呼叫也會卡住,延遲就在 Ollama 內部;回應中的 load_durationprompt_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 的訊號。