大模型应用开发教程12 | LLMOps 与部署实战(FastAPI 后端 + 前端应用)
·
理论部分
当我们把“调用模型”的代码写成脚本后,会很快遇到一个问题:脚本能跑,但离“应用”还差很远。原因是脚本天然是单机、单用户、一次性运行的形态,而应用需要:
- 可复用:前端、其他服务、甚至不同终端都能调用
- 可观测:能知道服务是否健康、耗时多少、报错是什么
- 可交付:一个 URL 或一个页面,让人可以直接用
因此,最常见的工程形态是“前后端分离”:
- 后端服务(API):统一封装模型调用,负责鉴权/限流/日志/错误处理等(本篇先做最小版本)
- 前端应用(UI):提供交互体验,负责展示与用户输入
这一篇我们用 FastAPI 写一个最小对话服务,然后用 Streamlit 写一个最小聊天界面,把端到端链路跑通。
实践部分
本案例做什么
我们会做两件事:
- 启动 FastAPI 后端服务:提供
/health与/chat接口 - 启动 Streamlit 前端:把用户输入发给后端
/chat,展示模型回复
主要代码 1:FastAPI 后端
脚本:src/5.2_backend_api.py
import uvicorn
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import time
import os
from dotenv import load_dotenv
from openai import OpenAI
# 加载环境变量
load_dotenv()
# 初始化 OpenAI 客户端 (智谱 AI)
client = OpenAI(
api_key=os.getenv("ZHIPUAI_API_KEY"),
base_url=os.getenv("ZHIPUAI_BASE_URL")
)
app = FastAPI(
title="LLM Chat API Service",
description="基于 FastAPI 的大模型对话服务 (Direct API)",
version="1.0.0"
)
# === 定义请求体模型 ===
class ChatRequest(BaseModel):
query: str
model_name: str = "glm-4-flash" # 默认模型
class ChatResponse(BaseModel):
answer: str
processing_time: float
# === API 路由 ===
@app.get("/")
def read_root():
return {"message": "Welcome to LLM Chat API Service! Visit /docs for Swagger UI."}
@app.get("/health")
def health_check():
return {"status": "healthy", "timestamp": time.time()}
@app.post("/chat", response_model=ChatResponse)
def chat_endpoint(request: ChatRequest):
start_time = time.time()
try:
print(f"收到请求: {request.query} (Model: {request.model_name})")
# 直接调用大模型 API
response = client.chat.completions.create(
model=request.model_name,
messages=[
{"role": "system", "content": "你是一个乐于助人的 AI 助手。"},
{"role": "user", "content": request.query}
],
temperature=0.7
)
answer = response.choices[0].message.content
process_time = time.time() - start_time
return ChatResponse(
answer=answer,
processing_time=process_time
)
except Exception as e:
print(f"Error: {e}")
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
print("🚀 正在启动 FastAPI 后端服务 (Direct LLM)...")
print("文档地址: http://127.0.0.1:8002/docs")
uvicorn.run(app, host="127.0.0.1", port=8002)
主要代码 2:Streamlit 前端
脚本:src/5.2_frontend_ui.py
import streamlit as st
import requests
import time
# === 配置 ===
BACKEND_URL = "http://127.0.0.1:8002/chat"
st.set_page_config(page_title="AI 聊天助手", page_icon="🤖")
# === 侧边栏 ===
with st.sidebar:
st.header("⚙️ 设置")
model_name = st.selectbox("选择模型", ["glm-4-flash", "glm-4-air", "glm-4-plus"])
st.info("这是一个基于 FastAPI + Streamlit 的前后端分离演示应用。")
st.markdown("---")
st.markdown("**状态**: 🟢 后端服务需先启动")
# === 主界面 ===
st.title("🤖 智能对话助手 (API 版)")
st.caption("🚀 由 Streamlit 和 FastAPI 驱动,直接调用大模型")
# === 初始化会话状态 (History) ===
if "messages" not in st.session_state:
st.session_state.messages = [
{"role": "assistant", "content": "你好!我是你的 AI 助手,有什么可以帮你的吗?"}
]
# === 显示历史消息 ===
for msg in st.session_state.messages:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])
# === 处理用户输入 ===
if prompt := st.chat_input("请输入你的问题..."):
# 1. 显示用户消息
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
# 2. 调用后端 API 获取回答
with st.chat_message("assistant"):
message_placeholder = st.empty()
full_response = ""
try:
with st.spinner("思考中..."):
# 发送请求到后端
payload = {"query": prompt, "model_name": model_name}
response = requests.post(BACKEND_URL, json=payload)
if response.status_code == 200:
data = response.json()
answer = data.get("answer", "")
# 模拟打字机效果
for chunk in answer:
full_response += chunk
message_placeholder.markdown(full_response + "▌")
message_placeholder.markdown(full_response)
else:
st.error(f"后端报错: {response.status_code} - {response.text}")
full_response = "抱歉,服务暂时不可用。"
except requests.exceptions.ConnectionError:
st.error("❌ 无法连接到后端服务。请确保 `src/5.2_backend_api.py` 正在运行。")
full_response = "连接失败"
# 3. 保存助手回复到历史
st.session_state.messages.append({"role": "assistant", "content": full_response})
运行方式
第一步,启动后端(保持运行):
python3 src/5.2_backend_api.py
第二步,验证后端健康(可选):
curl http://127.0.0.1:8002/health
第三步,启动前端(另开一个终端):
streamlit run src/5.2_frontend_ui.py
运行结果示例
后端启动后会看到类似输出,并提示文档地址:
🚀 正在启动 FastAPI 后端服务 (Direct LLM)...
文档地址: http://127.0.0.1:8002/docs
INFO: Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit)
访问健康检查接口会返回类似 JSON:
{"status":"healthy","timestamp":1730000000.0}
前端启动后会输出 Streamlit 的访问地址(本地一般为 8501 端口),在页面里输入问题即可得到模型回复。
总结
这一篇我们把脚本升级为可交互的应用形态:用 FastAPI 把模型调用封装为统一接口,用 Streamlit 做一个轻量前端界面,并跑通了端到端链路。
作为整个教程的收尾,我们也把 12 篇内容串起来回顾一遍。我们从最基础的环境与第一次调用开始,逐步搭起了一套完整的 LLM 应用能力栈:
- 第 2~4 篇:跑通调用与多轮对话,理解消息列表与会话状态
- 第 5~6 篇:掌握提示词工程与结构化输出,让结果更稳定、更可用
- 第 7~8 篇:理解并落地 RAG,从“能检索”升级到“能基于资料回答”
- 第 9~10 篇:跑通工具调用与 ReAct Agent,让模型具备“多步行动”能力
- 第 11 篇:理解微调的定位与流程,知道何时需要以及产物是什么
- 第 12 篇:完成服务化与前后端串联,把能力封装成一个可交付的应用形态
到这里,我们已经具备了从 0 到 1 开发大模型应用的完整路径:既能用 Prompt/RAG/Agent 解决效果问题,也能用 API + UI 的方式把能力交付出去。接下来如果要继续增强,就可以围绕“效果、性能、成本、安全、评测、观测”把这个应用逐步工程化。
更多推荐
所有评论(0)