SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor

Ollama context deadline exceeded怎么解决

Ollama出现“context deadline exceeded”表示请求在模型响应前超时。按客户端、模型加载、keep_alive、num_ctx和nginx逐层定位原因并修复。

“context deadline exceeded”的实际含义

Ollama 报错 context deadline exceeded 表示请求超时。某段 Go 代码为请求设置了截止时间,模型未能在截止时间前完成处理,随后截止时间到期。没有发生崩溃,也没有文件损坏。截止时间到达时,任务仍在运行。

该措辞来自 Go 的标准 context 包,本身就是一个有用的线索。基于 httpx 构建的 Python 客户端则会引发 httpx.ReadTimeout。浏览器会显示普通网络错误。如果您看到这些确切文字,说明某个 Go 程序放弃等待:可能是 Ollama 命令行工具、Ollama 服务器本身,或调用 API(应用程序编程接口)的 Go 应用。

这里涉及 5 层。其中 3 层会各自设置截止时间:您的客户端、服务器的模型加载超时,以及反向代理。另外 2 层,即 keep_alive 和 num_ctx,不会设置截止时间,但会决定在一个截止时间内需要完成多少工作。它们会在不同阶段失败,也需要不同的修复方法。因此,关键是确定究竟是哪一层导致了该错误。

  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 完全没有报告进度,通常意味着文件仍在读取,或机器正在使用交换空间。要在加载期间获取更多详细信息,请设置 OLLAMA_DEBUG=1 后重启服务,再重复上述操作。

判断延迟来自加载还是生成

Ollama 会报告自身的耗时,因此无需猜测这部分原因。

ollama run --verbose llama3.1:8b "Why is the sky blue?"

答案输出后,它会打印 total duration、load duration、prompt eval count、prompt eval rate、eval count 和 eval rate。运行两次。第二次运行时,load duration 应降至接近 0,因为模型已经驻留在内存中。如果没有下降,说明模型在两次运行之间被卸载,这就是下文所述的 keep_alive 情况。

API 返回的最终 JSON 对象中也会包含相同的数值,分别是 load_duration、prompt_eval_duration 和 eval_duration。文档说明所有时长均以纳秒返回,因此除以 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 占主导,说明成本来自提示词处理,请转到 num_ctx 章节。如果 eval_duration 占主导,说明模型在当前硬件上的生成速度本来就较慢,任何超时设置都无法改变这一点。使用 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] section 下添加变量。这是 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 保存到了编辑器标记之外,或保存到了错误的 section 名称下,因此设置的变量没有生效。需要明确这一设置的作用:延长加载超时可以避免服务器过早放弃,但不会让加载速度变快。如果模型无法装入内存,机器会使用 swap,加载过程会非常缓慢;增大超时值只会让失败发生得更晚。

暂停后第一个请求为什么会变慢

Ollama 会卸载空闲模型以释放内存。keep_alive 设置决定模型何时卸载。Ollama 文档在 October 2026 记录的默认值为 5 minutes。因此,每小时只使用一次的聊天应用会在每条消息到来时重新加载模型,每条消息都要承担完整的冷启动开销。发生超时的请求通常是安静一段时间后的第一个请求,这正是人们描述为随机问题的典型模式。

检查当前驻留在内存中的模型:

ollama ps
curl -s http://127.0.0.1:11434/api/ps

如果列表为空,或模型将在几分钟后过期,即可确认这一点。keep_alive 接受持续时间字符串,例如 "10m" 或 "24h";也接受表示秒数的普通数字、用于立即卸载的 0,以及用于无限期保留模型的负数。可以按请求设置,也可以在服务上设置 OLLAMA_KEEP_ALIVE,使其应用于所有请求。请求值优先:Ollama 文档说明,keep_alive API 参数会覆盖 OLLAMA_KEEP_ALIVE 设置。因此,即使客户端发送了自己的 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(键值缓存)大小。两者都会增加处理量。

在仅使用 CPU 的服务器上,prefill 速度较慢,并且与提示词中的 token 数量成线性关系。将长文档粘贴到聊天中时,prefill 可能持续数分钟,而客户端完全看不到输出,因为流式传输尚未开始。客户端达到截止时间后会报告 context deadline exceeded,但服务器一直在处理。使用上一节中的数据即可验证这一点。发送长提示词并读取 prompt_eval_count 和 prompt_eval_duration;Ollama 将它们定义为评估未缓存提示词 token 所用的时间。这里耗时数分钟,而 eval_duration 较小,就说明是在执行 prefill。由于只计算未缓存的 token,如果模型仍处于加载状态,相同提示词的再次请求可能报告更短的耗时,因此应比较首次运行结果。要查看更大缓存的成本,分别使用 "options": {"num_ctx": 2048} 和 32768 运行提示词,并同时读取 load_duration;模型加载耗时会报告在该字段中,而不是 prompt_eval_duration 中。

服务器默认值来自 OLLAMA_CONTEXT_LENGTH,而 options 对象中的单请求 num_ctx 会覆盖该默认值。常见错误是因为模型存在标称最大值,就将其提高到该最大值。这样可能导致 KV cache 分配耗尽 RAM,使原本正常工作的配置开始使用交换空间。根据实际内存选择 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 可能会先收集响应,最后一次性转发,因此令牌不会逐个出现,正常工作的流式响应会看起来像卡住了一样。

Traefik 在路由器使用的 ServersTransport 上提供相同的控制项。

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

responseHeaderTimeout 控制请求写入后等待响应头的时间,设置为 0 表示不超时。服务必须通过 serversTransport: ollama 按名称引用该传输配置,否则你修改的配置块不会被实际使用。

较小的量化版本加载更快,因为需要读取的数据更少

量化表示权重的存储精度。精度越低,文件越小;而加载模型主要是将该文件从磁盘读入内存。

图表Published download sizes for llama3.1 8B on the ollama.com library, October 2026
此图表背后的数据
[
  {
    "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倍。在使用共享存储的租用服务器上,这一差异可能决定加载是能够完成,还是因超时而失败。开始下载任何大型模型前,应先确认哪个模型适合您的 RAM。

租用服务器上需要修改的内容

按测量结果指示的顺序逐项修改。每次只改一项,然后重新运行计时命令。

  1. 使用 OLLAMA_KEEP_ALIVE=-1 固定模型,并在启动时预热模型,使用户请求不再承担加载开销。随后确认客户端没有自行发送 keep_alive,因为请求中的值会覆盖服务器设置。
  2. 将 num_ctx 降低到提示词实际需要的值。这样可以缩短预填充时间,并释放 KV 缓存占用的内存。
  3. 使用更小的量化版本,使加载时读取更少的数据,并为缓存留出更多空间。
  4. 提高 nginx 中的 proxy_read_timeout 或 Traefik 中的 responseHeaderTimeout,并关闭缓冲,以便流式 token 及时发送到客户端。
  5. 提高自有客户端中的超时时间。Go 或 Python 程序如果只允许 30 秒,而模型思考时间更长,就会失败。

上述问题背后还可能有一个共同原因。Ollama 同时处理的请求数量有限,其余请求会进入队列。因此,第二个调用方可能在队列中等待,直到自身的截止时间到期,即使模型本身并不慢。服务器日志会显示请求延迟处理,而不是处理失败。多个人共享同一台 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 年 10 月检查。空闲一段时间后的第一个请求需要从磁盘重新加载模型,因此要经历完整的冷启动;紧接着发送的请求则可直接使用内存中的模型,所以返回较快。运行 ollama ps 查看当前已加载的模型及其到期时间。设置 OLLAMA_KEEP_ALIVE=-1 可让模型保留在内存中,但内存会持续被占用。客户端自行发送的 keep_alive 会覆盖该设置,因此也请检查客户端配置。

为什么只有通过 nginx 访问时才失败?

nginx 文档将 proxy_read_timeout 的默认值记录为 60s。该超时时间适用于两次连续读取之间的间隔,而不是整个响应的持续时间。流式响应每收到一个数据块都会重置计时器,而使用 "stream": false 发送的请求必须在单个时间窗口内完成。因此,聊天窗口可以正常工作,而脚本会失败。在 nginx 错误日志中查找 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 的时长。如果模型无法装入内存,机器会使用交换空间,加载速度会大幅下降;增大超时时间只会让失败更晚发生,不能解决问题。运行 ollama --version 并在对应标签中读取 envconfig/config.go,以确认您所用构建的默认值。需要几分钟才能完成加载,通常说明应改用更小的量化模型。