在命令行里跑通大模型只是开始,真正落地要把它变成一个用户能访问的 Web 服务。这篇教程用 FastAPI 搭后端、原生前端调用,完整实现一个带流式输出的对话网页,涵盖从接口封装到部署上线的每一步。

系统架构

一个典型的大模型 Web 应用分三层:

API Key 只放在后端,绝不能暴露给前端,这是安全底线。

前置准备

pip install fastapi uvicorn openai

并在后端环境设置好 OPENAI_API_KEY

步骤一:搭建后端骨架

新建 main.py,创建 FastAPI 应用:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel

app = FastAPI()

# 允许前端跨域访问
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 生产环境应改成具体域名
allow_methods=["*"],
allow_headers=["*"],
)

class ChatRequest(BaseModel):
message: str

步骤二:封装普通对话接口

import os
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

@app.post("/chat")
def chat(req: ChatRequest):
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": req.message}],
)
return {"reply": resp.choices[0].message.content}

步骤三:加上流式接口

流式输出让回答像打字一样逐字出现,体验更好。这里用 SSE(Server-Sent Events):

from fastapi.responses import StreamingResponse

@app.post("/chat-stream")
def chat_stream(req: ChatRequest):
def generate():
stream = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": req.message}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content or ""
yield f"data: {delta}\n\n" # SSE 数据格式
yield "data: [DONE]\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")

步骤四:启动后端

uvicorn main:app --reload --port 8000

看到 Uvicorn running on http://127.0.0.1:8000 即启动成功。

步骤五:前端调用

新建 index.html,用 fetch 读取流式响应:

<input id="input" placeholder="输入问题" />
<button onclick="send()">发送</button>
<div id="output"></div>

<script>
async function send() {
const message = document.getElementById("input").value;
const output = document.getElementById("output");
output.textContent = "";
const resp = await fetch("http://127.0.0.1:8000/chat-stream", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({message}),
});
const reader = resp.body.getReader();
const decoder = new TextDecoder();
while (true) {
const {done, value} = await reader.read();
if (done) break;
const text = decoder.decode(value);
for (const line of text.split("\n")) { // 解析 SSE 行
if (line.startsWith("data: ")) {
const content = line.slice(6);
if (content !== "[DONE]") output.textContent += content;
}
}
}
}
</script>

一次完整请求的时序

步骤六:部署上线

  • 后端:用 uvicorn main:app --host 0.0.0.0 --port 8000 生产启动,配合 Nginx 反向代理
  • 前端:静态文件可托管到 Vercel、Netlify 或对象存储
  • 全站用 HTTPS,避免流式请求被中间层缓冲
  • API Key 用环境变量或密钥管理服务注入,绝不写进代码库

常见问题

  • 前端报跨域错误:检查后端 CORS 配置和 allow_origins
  • 流式不逐字、一次性返回:确认没被 Nginx 缓冲,关闭 proxy_buffering
  • 请求超时:大模型响应慢,调大网关和客户端的超时时间
  • Key 泄漏:立即在控制台吊销,并排查是否误提交到 Git

小结

把大模型接入 Web 应用的主线是:后端用 FastAPI 封装模型调用(Key 藏在服务端)、用 SSE 实现流式输出、前端用 fetch 逐块渲染。掌握这套结构后,再加上会话管理、鉴权和限流,就能扩展成一个生产可用的 AI 应用。