基于flask做大模型SSE输出

默认情况下,Fask以多线程模式运行,每个请求都落在一个新线程上。

SSE:基于HTTP的协议,用于实现服务器向客户端推送实时数据。使用长轮询机制,客户端通过HTTP连接向服务器发送请求,并保持该连接打开,服务器可以随时向客户端推送新的数据。

SSE协议使用简单的文本格式,数据通过纯文本的消息流进行传输,每个消息以"data:"开头,以两个换行符"\n\n"结尾,如果传递的数据中有字典要使用变量传递。

对比webSocket

连接:

SSE 可使用普通的HTTP连接通信,不需要特殊协议或握手过程。

WebSocket使用自定义协议,需要通过握手过程建立连接。

数据传输:

SSE只支持服务器向客户端的单向数据传输,即服务器可以主动向客户端推送数据。

WebSocket支持全双工通信,服务器和客户端可以同时发送和接收数据。

兼容性:

SSE在大多数现代浏览器中得到支持,某些旧版本的浏览器中可能不被完全支持。

WebSocket在大多数现代浏览器中得到广泛支持,包括旧版本的浏览器。

在使用flask框架做大模型问答,实现SSE模型的输出,可尝试flask-sse包。

flask-sse

基于 Python 的 Flask 微框架扩展,GitCode - 全球开发者的开源社区,开源代码托管平台

  • flask_sse.py 包含了扩展的核心逻辑,用于处理SSE。
  • tests 目录提供了单元测试案例,确保功能正确性。
  • examples 包含可直接运行的例子,帮助理解如何集成到Flask应用中。

使用该包是需要选配置redis,用于存储待发送的消息,

通过自定义CallBackHandler实现流式输出

自定义异步输出Handler

class AsyncChainStreamHandler(StreamingStdOutCallbackHandler):

    def __init__(self):
        self.tokens = []
        self.finish = False  # 结束后要改为True

    async def on_llm_new_token(self, token: str, **kwargs):
        print(token, end="| ")
        self.tokens.append(token)

    def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
        self.finish = 1

    def on_llm_error(self, error: Exception, **kwargs: Any) -> None:
        print(str(error))
        self.tokens.append(str(error))

    async def generate_tokens(self):
        while not self.finish or self.tokens:
            if self.tokens:
                data = self.tokens.pop(0)
                print(f"data: {data}, tokens length: {len(self.tokens)}")
                yield data
            else:
                pass
class ChainStreamHandler(StreamingStdOutCallbackHandler):
    def __init__(self):
        self.tokens = []
        self.finish = False  # 结束后要改为True

    def on_llm_new_token(self, token: str, **kwargs):
        print(token, end="| ")
        self.tokens.append(token)

    def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
        self.finish = 1

    def on_llm_error(self, error: Exception, **kwargs: Any) -> None:
        print(str(error))
        self.tokens.append(str(error))

    def generate_tokens(self):
        while not self.finish or self.tokens:
            if self.tokens:
                data = self.tokens.pop(0)
                print(f"data: {data}, tokens length: {len(self.tokens)}")
                yield data
            else:
                pass

使用原有的Handler:

from langchain.callbacks import StreamingStdOutCallbackHandler, AsyncIteratorCallbackHandler

使用langchain声明大模型时调用

handler = StreamingStdOutCallbackHandler()  # on_llm_new_token 默认控制台输出
# handler = AsyncChainStreamHandler()
model = ChatOpenAI(
    streaming=stream,
    verbose=True,
    callbacks=[handler],
    openai_api_key="EMPTY",
    openai_api_base="http://ip:8090/v1",  # 不同于requests请求的地址
    model_name="Qwen1.5-32B-Chat",
    temperature=0.7,
    max_tokens=4096
)
返回:return Response(handler.generate_tokens(), mimetype='text/event-stream')

参考:

https://flask-sse.readthedocs.io/en/latest/api.html#flask_sse.ServerSentEventsBlueprint

如何支持Flask-SSE访问控制-腾讯云开发者社区-腾讯云

大模型平台都在用的SSE协议是怎么样的?-51CTO.COM

Flask-SSE 教程:实时事件流的简易实现-CSDN博客

Flask框架进阶-Flask流式输出和受访配置--纯净详解版-CSDN博客

https://zhuanlan.zhihu.com/p/645053138

### 大模型流式输出的实现原理 大模型的流式输出是一种高效的数据传输机制,能够实现实时数据推送和动态更新的功能。其核心依赖于 **Server-Sent Events (SSE)** 技术[^1]。 SSE 是一种基于 HTTP 协议的标准技术,允许服务器向客户端发送事件驱动的消息流。 #### Server-Sent Events 的工作流程 SSE 的基本工作机制如下:当客户端发起请求后,服务器保持连接打开状态,并持续向客户端发送消息直到连接关闭或超时。这种方式非常适合需要单向通信的应用场景,例如实时日志推送、通知提醒等[^3]。 以下是 Python 中实现 SSE 流式输出的一个简单代码示例: ```python from flask import Flask, Response, stream_with_context app = Flask(__name__) @app.route('/stream') def stream(): def generate(): yield 'data: Starting the event stream...\n\n' for i in range(5): yield f'data: Event {i}\n\n' import time time.sleep(1) yield 'data: Stream completed.\n\n' return Response(stream_with_context(generate()), content_type='text/event-stream') if __name__ == '__main__': app.run(debug=True) ``` 上述代码展示了如何利用 Flask 创建一个支持 SSE 的服务端接口。每次调用 `/stream` 路径时,都会返回一系列按时间间隔生成的事件。 #### ChatGPT 的流式输出方案 对于像 ChatGPT 这样的复杂大模型而言,其实现过程不仅涉及基础的技术框架,还需要考虑性能优化与用户体验设计。具体来说,ChatGPT 使用 SSE 来逐步传递生成的结果给用户界面,从而让用户感受到更流畅的交互体验。 除了 SSE 之外,WebSocket 和 gRPC-Web 等协议也可以用来完成类似的流式输出需求。然而,在许多情况下,由于兼容性和开发成本的原因,SSE 成为了首选解决方案之一。 #### 前端对接实践 从前端角度来看,接收并展示来自后端的服务端事件同样重要。现代浏览器提供了内置 API `EventSource` 对象来简化这一操作[^2]。下面是一段简单的 HTML+JavaScript 示例演示如何消费由上面定义好的 RESTful 接口发出的内容: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>SSE Demo</title> </head> <body> <pre id="output"></pre> <script type="application/javascript"> const source = new EventSource("/stream"); let outputElement = document.getElementById('output'); source.onmessage = function(event){ let data = JSON.parse(event.data); console.log(data); // 可选的日志记录行为 outputElement.textContent += `${event.data}\n`; }; // 错误处理逻辑 source.onerror = () => { alert("An error occurred while connecting to server."); }; </script> </body> </html> ``` 此脚本创建了一个持久化的链接到指定 URL (`/stream`) 并监听所有的传入消息。每当接收到新消息时,它会被追加显示在页面上的 `<pre>` 元素里。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值