Ollama 提供 OpenAI 兼容接口时,请求体里的 stream 字段控制返回方式。遇到流式响应中断,先要区分是数据没到达、连接被切断,还是客户端解析出错。这个现象通常不是兼容接口缺失,而是流式数据的客户端处理方式和服务端连接管理不匹配。
建议先直接使用 curl 观察原始响应,确认服务端是否持续输出 data: 行。若 curl 正常而代码中断,问题多在客户端超时设置或 SSE 解析逻辑;若 curl 也中断,则需检查 Ollama 服务地址、网络链路以及反向代理缓冲设置。排查时应先关闭 stream 对比,再将问题范围缩小到传输层或解析层。
一、用 curl 确认服务端是否真的中断
在本地终端执行下面命令,注意 -N 参数会关闭 curl 缓冲,让数据到达后立即显示。如果本地设置了代理环境变量,建议临时加上 `--noproxy` "*" 排除干扰。
curl -N `--noproxy` "*" \
-X POST http://localhost:11434/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"llama3","messages":[{"role":"user","content":"hi"}],"stream":true}'
看响应是否持续输出多行 data: {...},最后以 data: [DONE] 结束。如果 curl 能完整跑完,说明服务端和网络链路正常,应继续查客户端;如果 curl 中途停止或报错,说明问题出在 Ollama 服务进程、端口监听或本地反向代理上。
二、客户端解析:SSE 格式必须按行处理
OpenAI 兼容流式接口返回的是 Server-Sent Events (SSE),不是一次性的 JSON。每个数据块以 data: 开头,块之间有空行,结束标志是 data: [DONE]。很多中断现象其实是把流式响应当普通 JSON 读,或者没有逐行处理,导致拿到不完整内容后报错。
以 Python requests 为例,不建议直接调 response.json(),而应遍历响应行。下面是一个稳妥的读取骨架:
import requests
resp = requests.post(
"http://localhost:11434/v1/chat/completions",
headers={"Content-Type": "application/json"},
json={
"model": "llama3",
"messages": [{"role": "user", "content": "hi"}],
"stream": True
},
stream=True,
timeout=(10, 300) # connect timeout / read timeout
)
for line in resp.iter_lines(decode_unicode=True):
if not line:
continue
if not line.startswith("data:"):
continue
data = line[5:].strip()
if data == "[DONE]":
break
print(data) # 这里再按你的逻辑解析 JSON
注意 iter_lines() 在部分环境中可能因编码判断而把行拆错,如果你遇到这种情况,可以改用 iter_content 然后手动按 \n 切分。但最常见的问题仍然是:读到了 [DONE] 之前就超时,或者根本没读到 [DONE]。
三、超时、缓冲区与反向代理的干扰
即使服务端正常,客户端读超时设置太短也会造成“中断”假象。生成回复需要时间,如果你的 timeout 只给了几秒,长回答很容易触发读超时。建议把读超时放宽到 300 秒或设为 None(不推荐生产环境无限制,但调试时可用)。
另一个常见干扰是反向代理。如果 Ollama 挂在 Nginx 后面,Nginx 默认会缓冲上游响应,导致流式数据被积攒到一定量才发给客户端。这时需要在 Nginx 配置里关闭缓冲并加长超时:
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
这条配置不是对所有版本都必需,而且需要结合你的 Nginx 版本和网络环境确认。如果 Ollama 直接监听本机端口,可以跳过这一步。
四、验证清单和保守建议
- 关闭系统代理环境变量后,用 curl 是否正常?
- 响应头
Content-Type是否包含text/event-stream? - 客户端是否按行解析、遇到
[DONE]时主动结束? - 读超时是否宽裕?是否在捕获异常时把 ConnectionResetError 和 ReadTimeout 区分开?
- 是否有反向代理开启缓冲?
建议按这个顺序排查:先改客户端超时和解析逻辑,再用 curl 对照。不要一开始就调 Ollama 的服务参数,因为多数中断源于客户端或中间层。如果 curl 本身也中断,可以尝试换一个更大的模型或更长的提示词,看是否与生成时间有关;如果短内容正常、长内容中断,优先检查代理缓冲和客户端超时。
Ollama 服务端自身的资源占用也可能导致连接提前关闭,但那是另一个层面的问题,需要结合具体环境和日志确认。调试时可以先在 Ollama 的日志输出里查有没有异常退出记录,但保守的做法是先排除传输层因素,再考虑服务端负载。