大模型上游返回超长输出导致Nginx
大模型 API 一次返回几千甚至上万字的文本时,Nginx 默认的响应缓冲区很容易被塞满,进而抛出 upstream sent too big header 或直接返回 500。
这个问题不是程序逻辑写错,而是 Nginx 的 proxy_buffer 相关参数跟不上上游响应体的大小。
本文会从定位错误开始,逐步给出修改配置、重载验证和后续避坑的完整流程。
先确认 500 错误来自 Nginx 还是后端
看到 500 后不要急着改代码,先查 Nginx 错误日志。
默认路径通常是 /var/log/nginx/error.log,如果你用宝塔面板,可以在“日志”菜单里直接查看。
执行:
tail -n 100 /var/log/nginx/error.log
如果看到类似下面的内容,就能判断是 buffer 溢出:
upstream sent too big header while reading response header from upstream
或者:
upstream sent too big header while reading response header from upstream, client: ...
这里的“too big header”指的是 Nginx 接收上游响应头时,缓冲区装不下。
大模型接口经常会在响应头里塞很长的自定义信息,比如耗时、token 数、业务标记,所以即使正文不大也可能触发。
也有一种情况是响应体过大导致的 buffer 溢出,日志里会出现 upstream sent more data than specified in "Content-Length" 或 recv() failed。
下面统一按 buffer 参数调整来处理。
修改 Nginx 代理缓冲区配置
找到对应站点或 API 反向代理的配置文件。
如果用宝塔面板,路径通常是 /www/server/panel/vhost/nginx/你的域名.conf;
手动安装的 Nginx 一般在 /etc/nginx/conf.d/ 或 /etc/nginx/sites-available/。
在 location / 或具体的 location /api/ 块里加入以下配置:
proxy_buffering off;
proxy_buffer_size 16k;
proxy_buffers 8 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 128k;
如果不想完全关闭缓冲,也可以保留缓冲但调大容量:
proxy_buffer_size 32k;
proxy_buffers 16 64k;
proxy_busy_buffers_size 128k;
proxy_buffer_size 负责单个响应头的大小,proxy_buffers 控制响应体缓冲区的数量和单个大小,proxy_busy_buffers_size 决定 Nginx 在未读取完上游数据时能发送给客户端的缓冲区上限。
对大模型接口,建议先把 proxy_buffer_size 调到 16k 以上,proxy_buffers 改成 8 32k,基本能覆盖绝大多数超长输出场景。
修改后先检查配置语法:
nginx -t
看到 syntax is ok 后重载 Nginx:
nginx -s reload
宝塔用户可以直接在面板右上角点击“重载配置”,效果一样。
进阶:按上游接口单独调整
如果这台服务器上还运行着普通网站,全局调大 buffer 会占用更多内存。
更稳妥的做法是只为大模型 API 的 location 单独设置。
比如你通过 /api/llm/ 转发到大模型服务:
location /api/llm/ {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffer_size 32k;
proxy_buffers 16 64k;
proxy_busy_buffers_size 128k;
}
这样普通页面请求仍然使用默认小缓冲区,只有大模型接口走加大后的配置,内存占用更可控。
如果你使用的是宝塔反向代理功能,可以在站点设置 -> 反向代理 -> 配置文件里直接修改,不需要手动编辑整个 server 块。
避坑指南
配置调大后,有几个容易忽略的坑:
proxy_buffering off不要随意全局开启。 关闭缓冲会大幅降低静态文件和普通接口的传输效率,只建议在 AI 流式输出场景使用。- 调整后必须重载 Nginx。 只保存文件不重载,配置不会生效。
- 如果上游是 HTTPS,还要确认 SSL 缓冲区。 某些场景下需要同步调整
large_client_header_buffers和http2_max_field_size,但大模型 API 场景较少遇到。 - 注意内存开销。 每增加一个
proxy_buffers的块,Nginx 会为每个连接预分配对应内存。并发高时,过大的 buffer 可能拖垮服务器,所以按需调整即可,不要盲目配到 1MB。 - 如果 500 仍然存在,检查后端服务日志。 有些时候是后端接口自身抛错,Nginx 只是把错误透传成 500。
验证修复效果
重载配置后,重新请求原来报错的大模型接口。
可以用 curl 直接观察响应:
curl -i https://your-domain.com/api/llm/chat -X POST -H "Content-Type: application/json" -d '{"prompt":"写一篇长文"}' -o /dev/null -s -w "HTTP状态码: %{http_code}\n响应耗时: %{time_total}s\n"
返回 200 且不再出现 500,说明 buffer 配置已经生效。
再去 Nginx 错误日志确认没有新增的 too big header 记录:
tail -n 20 /var/log/nginx/error.log
如果日志干净,问题就解决了。
常见疑问
只调大 proxy_buffer_size 够吗?
不一定。
若错误是响应头过大,只调这一个参数就够;
若响应体也很大,proxy_buffers 和 proxy_busy_buffers_size 也要同步加大。
最好两个都调整,再按实际内存情况回退。
流式输出必须关闭缓冲吗?
如果是 SSE 或流式输出,建议在对应 location 里设置 proxy_buffering off;。
否则 Nginx 可能会缓冲整个响应,导致前端迟迟收不到第一条数据,体验明显变卡。
大模型接口返回超大 JSON 时还有哪些优化点?
除了调整 Nginx buffer,还可以检查后端是否压缩响应内容。gzip on; 配合 gzip_types application/json; 能显著减小传输体积,降低 buffer 压力。
注意开启 gzip 后客户端请求头要带 Accept-Encoding: gzip,现代浏览器默认都支持。
如果你正在处理大模型上游返回超长输出导致 Nginx buffer 溢出 500 错误,先按本文步骤完成配置调整,再根据自己服务器的并发情况微调参数。
遇到仍然报错时,优先回看避坑部分,并检查后端真实日志,通常很快就能定位。