调用ai的api流式传输

一、请求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秒


image.png

我之前就是所有东西都做好了,直接连接服务器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 可能表现异常


image.png
  1. 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
)
image.png

三、通过 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',  # 保持连接
        }
    )
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容