一、请求api的代码使用stream流式传输
# 新增一个流式对话入口
def chat_completion_stream(self, user_input: str):
user_input = user_input.strip()
self.update_conversation(role="user", content=user_input)
# 返回生成器
full_content = ""
for chunk in self.call_deepseek_api_stream():
full_content += chunk
yield chunk
# 只有流式结束后,才将完整的回复存入历史记录
self.update_conversation(role="assistant", content=full_content)
二、必须使用gevent
原因:流式传输时间比较长,文字越多越长,Flask正在等待 DeepSeek 返回数据(流式传输中),但是 Gunicorn 的 Worker 进程 认为该请求处理时间过长(默认通常是 30秒),于是强制杀死了这个进程。
Gunicorn 默认的 Worker 类型是 sync(同步)。在这种模式下,一个 Worker 只能处理一个请求。如果这个请求是流式的长连接(比如 AI 生成故事需要 60秒),Worker 就会被“卡住”,直到超时被主进程干掉。
你需要将 Gunicorn 的 Worker 模式从默认的 sync 改为支持异步 IO 的 gevent,并适当延长超时时间。
具体如下:https://www.jianshu.com/p/f31fa861088c
首先检查cdn和nginx是否把超时拉到最大
一、nginx把stream的url设置timeout300s,关闭缓存proxy_buffering off
我的所有返回流式生成结果的url都是 xxx.com/xxxx/xxx/stream
# 单独处理流式接口,不超时 ======
location ^~ /stream {
proxy_pass http://127.0.0.1:8002;
# 长连接核心配置
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_buffering off;
# 透传 IP 头
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
二、腾讯云cdn
回源超时配置,默认是10秒,设置最高60秒和300秒

我之前就是所有东西都做好了,直接连接服务器sse没问题,挂上cdn 10秒就断开了。原来是回源连接超时限制太短了。
接下来配置环境gunicorn和gevent
Step A、用pip安装gevent库
source /var/virtualenvs/mysite_venv/bin/activate
pip install gevent
Step B、修改gunicorn配置文件
cd /mnt/www/mysite
vi gunicorn.conf
最后一行加上gevent模式,整个文件内容如下
# 进程为4
workers = 4
# 监听本地8000端口,之后这个端口来的就是看这个网站的。
bind = '127.0.0.1:8000'
#搭配gevent使用
worker_class="gevent" #sync, gevent,meinheld
timeout = 300 # 搭配异步,允许长连接保持 5分钟
保存后 重启gunicorn,我是用supervisor,所以直接
supervisorctl reload
这样就生效了,很简单吧。其他地方都不需要修改,就上面简单两步搞定。
gevent模式启用后瞬间秒开网站。
Step C,完成兼容性改造,释放性能
1.导入所有其他库前先执行:
from gevent import monkey
monkey.patch_all()
否则:
socket 没被正确打补丁
SQLAlchemy 连接池阻塞
Flask 的 werkzeug 可能表现异常

- scoped_session上下文由线程安全thread-local改为协程安全greenlet-local
Flask 的应用上下文(app_context)和请求上下文(request_context)默认是为多线程设计的。
SQLAlchemy 的 scoped_session 默认用 线程本地(thread-local) 存储。
但 Gevent 是协程模型(Greenlet),多个协程运行在同一个线程中。不同请求的 SQLAlchemy Session 可能在 Gevent 下相互污染。
#修改 scoped_session 的 local 普通 thread-local → greenlet-local(推荐)
from sqlalchemy.orm import scoped_session, sessionmaker
import greenlet
Session = scoped_session(sessionmaker(), scopefunc=greenlet.getcurrent)
3.SQLAlchemy 默认连接池数量是5,太小了,在 gevent 下容易被用光。
配置更大的连接池:
engine = create_engine(
DB_URL,
pool_size=20,
max_overflow=40,
pool_recycle=1800,
pool_pre_ping=True
)

三、通过 Header 告诉 Nginx 别缓存
Nginx 默认开启了 proxy_buffering,它会先把上游(Gunicorn)发来的数据存到缓冲区,等攒满了或者连接关闭了再发给客户端。这对普通网页加载有好处,但对 流式传输(Streaming/SSE) 是致命的。
在 Flask 返回 Response 时,带上一个特殊的 Header:X-Accel-Buffering: no。Nginx 看到这个 Header 就会自动关闭缓冲,直接放行数据。
@bp_story.route('/gen_stream', methods=['GET', 'POST'])
def story_gen_stream():
# ... (前面的代码不变) ...
def generate():
# ... (yield 逻辑不变) ...
# 确保这里 yield 的是字符串,且每次 yield 都会强制刷新
for chunk in ai_service.chat_completion_stream(user_input):
yield chunk
# 修改 Response,添加 headers
return Response(
stream_with_context(generate()),
mimetype='text/plain', # 或者 'text/event-stream'
headers={
'X-Accel-Buffering': 'no', # 【关键】告诉 Nginx 不要缓冲
'Cache-Control': 'no-cache', # 告诉浏览器/客户端不要缓存
'Connection': 'keep-alive', # 保持连接
}
)