AI技术栈 —— 流式输出
一、Python实现代码
Server-Sent Events(SSE)技术是实现流式输出功能的核心
import json
import time
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel, Field
from sse_starlette import EventSourceResponse, ServerSentEvent
from fastapi.middleware.cors import CORSMiddleware
class DialogStateResponse:
def __init__(self, message_type, content):
self.message_type = message_type
self.content = content
def to_json(self, text_test=""):
tp = time.time()
time_str = time.strftime("%H:%M:%S", time.localtime(tp))
return {"text": text_test, "create_time": time_str, "message_type": self.message_type, "content": self.content}
app = FastAPI()
# 添加以下配置
app.add_middleware(
CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], expose_headers=["*"] # 生产环境应指定具体域名 # 新增:暴露所有响应头
)
import asyncio
class AgentDtoModel(BaseModel):
query: str
async def content_generator():
for i in range(10):
str_i = str(i) + "_"
sse = ServerSentEvent(
event="Chat",
data=f"{json.dumps({'choices': [{'delta': {'content': DialogStateResponse(message_type='content', content=str_i).to_json()}}]}, ensure_ascii=False)}\n\n",
)
yield sse
await asyncio.sleep(1) # 使用异步sleep
@app.post("/stream_output")
async def stream_output(agent_dto_model: AgentDtoModel):
return EventSourceResponse(content=content_generator())
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=11100)
<!DOCTYPE html>
<html>
<head>
<title>POST流式测试</title>
</head>
<body>
<button onclick="startPostStream()">开始POST流式请求</button>
<div id="output" style="white-space: pre-wrap"></div>
<script>
async function startPostStream() {
const output = document.getElementById("output");
output.innerHTML = "";
const response = await fetch(
"http://192.168.10.101:11100/stream_output",
{
method: "POST",
mode: "cors", // 显式声明CORS模式
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: "None",
}),
}
);
const reader = response.body
.pipeThrough(new TextDecoderStream())
.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
// 修复事件解析逻辑
value.split("\n\n").forEach((eventData) => {
if (!eventData.trim()) return;
let jsonStr = "";
eventData.split("\n").forEach((line) => {
if (line.startsWith("data: ")) {
jsonStr += line.slice(6); // 提取data字段内容
}
});
try {
const data = JSON.parse(jsonStr);
console.log(data);
output.innerHTML += `${data.choices[0].delta.content.content}`;
} catch (e) {
console.error("解析错误:", jsonStr, e);
}
});
}
}
</script>
</body>
</html>
参考文章或视频链接 |
---|
[1] 《实用技巧:大模型的流式输出在 OpenAI 和 LangChain 中的使用》—— 阿里云 |
[2] 《ChatGPT流式输出实现原理》—— 优快云 |
[3] 《ChatGPT流式输出原理揭秘》—— 掘金 |