Nginx 代理 Ollama 流式接口:从踩坑到解决的完整指南

作者头像

谢藏锋

2025-07-28
后端开发
AI摘要Ollama 的流式生成功能遇到问题时,Nginx 代理导致响应一次性返回,影响了实时交互体验。问题根源在于 Nginx 的缓冲与超时机制与流式传输的分块特性冲突。通过修改 Nginx 配置,关闭缓冲和超时设置,使响应传递为分块形式。同时需确保请求头正确传递,并延长超时时间至合理范围(如 300-600 秒),以支持更复杂的实时交互需求。
文章封面

最近在集成 Ollama 的流式生成功能时遇到了一个棘手的问题:通过 Nginx 代理后,原本应该逐字输出的回答变成了一次性完整返回。这个问题不仅影响用户体验,更让整个实时交互的设计失去了意义。经过一番调试和研究,我终于找到了症结所在,今天就来分享一下这个过程中的收获。​

流式传输的本质与 Nginx 的冲突​

首先我们需要理解,Ollama 的 stream 接口之所以能实现逐字输出,核心在于采用了分块传输编码(Chunked Transfer Encoding)。这种传输方式允许服务器边生成内容边向客户端发送,每个数据块独立传输,不需要预先知道整个响应的大小。​

而 Nginx 作为反向代理的默认行为,却与此特性背道而驰。Nginx 会自动缓冲服务器响应,直到缓冲区填满或请求完成才会一次性发送给客户端 —— 这就是为什么代理后流式输出会变成完整输出的根本原因。这种机制在普通 Web 请求中能提高效率,但在需要实时交互的场景下就成了障碍。​

关键配置项解析​

解决问题的关键在于修改 Nginx 配置,让其放弃缓冲行为,忠实传递每一个数据块。经过测试,以下几个配置项必不可少:

location /ollama/ {
    proxy_pass http://127.0.0.1:11434/;
    
    # 核心配置:关闭缓冲机制
    proxy_buffering off;          # 禁止响应缓冲
    proxy_cache off;              # 关闭缓存功能
    chunked_transfer_encoding on; # 保持分块传输编码
    
    # 连接处理
    proxy_set_header Connection ''; # 清除连接头,避免被修改
    proxy_http_version 1.1;        # 使用HTTP/1.1支持长连接
    
    # 超时设置
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
}

其中proxy_buffering off是最关键的配置,它直接禁用了 Nginx 的响应缓冲。而chunked_transfer_encoding on则确保分块传输编码能正确传递到客户端。

长连接与超时设置的重要性​

在调试过程中,我发现即使关闭了缓冲,有时流式传输仍会中途中断。这是因为 Nginx 默认的超时时间过短(通常是 60 秒),而大型模型的生成过程很容易超过这个时限。​

将超时时间延长到合理范围(如 300 秒)能有效解决这个问题:​

  • proxy_connect_timeout:与后端服务建立连接的超时时间​
  • proxy_send_timeout:发送请求到后端的超时时间​
  • proxy_read_timeout:等待后端响应的超时时间​

这些值的设置需要根据实际使用的模型和网络环境调整,对于生成类任务,建议设置为 300-600 秒。​

请求头与响应头的正确传递​

另一个容易被忽略的细节是请求头的处理。Ollama 的 stream 接口依赖特定的请求头来启用流式模式,因此需要确保 Nginx 正确传递这些头部信息:

# 传递关键请求头
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

特别需要注意的是Content-Type响应头,流式接口通常使用application/x-ndjsontext/event-stream类型,Nginx 不应修改这些头部信息。

完整配置示例

整合以上所有要点,这里提供一个完整的 Nginx 配置示例:

server {
    listen 80;
    server_name ai.example.com;

    location /ollama/ {
        proxy_pass http://127.0.0.1:11434/;
        
        # 流式传输核心配置
        proxy_buffering off;
        proxy_cache off;
        proxy_pass_request_headers on;
        proxy_set_header Connection '';
        proxy_http_version 1.1;
        chunked_transfer_encoding on;
        
        # 超时设置
        proxy_connect_timeout 300s;
        proxy_send_timeout 300s;
        proxy_read_timeout 300s;
        
        # 头部设置
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}


0