一、Flask的使用
安装flask
pip install Flask
启动服务:
python app.py
服务将在 http://localhost:5000
运行
案例
from flask import Flask, request, jsonify import time # 创建 Flask 应用 app = Flask(__name__) # 示例数据(模拟数据库) users = [ {"id": 1, "name": "Alice", "email": "alice@example.com"}, {"id": 2, "name": "Bob", "email": "bob@example.com"} ] @app.route('/cook_sync') def cook_sync(): print("开始做菜 A...") time.sleep(5) # 模拟做一个很慢的菜 (比如等大模型响应) print("菜 A 做好了!") return "菜 A 完成" # 根路由 - 欢迎信息 @app.route('/') def home(): return "欢迎使用用户管理 API!请访问 /users 查看用户列表" # GET 请求示例 - 获取所有用户 @app.route('/users', methods=['GET']) def get_users(): return jsonify({"users": users}) # GET 请求示例 - 获取单个用户 @app.route('/users/<int:user_id>', methods=['GET']) def get_user(user_id): user = next((u for u in users if u["id"] == user_id), None) if user: return jsonify(user) return jsonify({"error": "用户不存在"}), 404 # POST 请求示例 - 创建新用户 @app.route('/users', methods=['POST']) def create_user(): # 从请求体中获取 JSON 数据 data = request.get_json() if not data or 'name' not in data or 'email' not in data: return jsonify({"error": "缺少必要参数(name 和 email)"}), 400 # 创建新用户 new_user = { "id": len(users) + 1, "name": data['name'], "email": data['email'] } users.append(new_user) return jsonify(new_user), 201 # 运行应用 if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)
二、FastAPI的使用
安装FastAPI和uvicorn:
pip install fastapi uvicorn
主要特点:
-
自动文档:内置 Swagger UI 和 ReDoc 文档
-
数据验证:使用 Pydantic 模型验证输入数据
-
类型提示:Python 类型提示提供更好的开发体验
-
异步支持:原生支持 async/await
-
标准兼容:基于 OpenAPI 和 JSON Schema 标准
案例
from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import List, Optional # 创建 FastAPI 应用 app = FastAPI( title="用户管理API", description="简单的用户管理接口示例", version="1.0.0" ) # 用户模型(使用Pydantic进行数据验证) class User(BaseModel): id: int name: str email: str age: Optional[int] = None # 可选字段 # 创建用户请求模型 class UserCreate(BaseModel): name: str email: str age: Optional[int] = None # 模拟数据库 fake_db = { 1: {"id": 1, "name": "Alice", "email": "alice@example.com", "age": 30}, 2: {"id": 2, "name": "Bob", "email": "bob@example.com"} } # 根路由 - 欢迎信息 @app.get("/", tags=["Root"]) def read_root(): return {"message": "欢迎使用用户管理API!请访问 /docs 查看接口文档"} # GET 请求示例 - 获取所有用户 @app.get("/users", response_model=List[User], tags=["Users"]) def get_all_users(): return list(fake_db.values()) # GET 请求示例 - 获取单个用户 @app.get("/users/{user_id}", response_model=User, tags=["Users"]) def get_user(user_id: int): if user_id not in fake_db: raise HTTPException(status_code=404, detail="用户不存在") return fake_db[user_id] # POST 请求示例 - 创建新用户 @app.post("/users", response_model=User, tags=["Users"], status_code=201) def create_user(user: UserCreate): # 生成新ID new_id = max(fake_db.keys()) + 1 if fake_db else 1 # 创建用户对象 new_user = { "id": new_id, "name": user.name, "email": user.email } # 添加可选字段 if user.age is not None: new_user["age"] = user.age # 保存到"数据库" fake_db[new_id] = new_user return new_user # 运行应用(通过命令行执行) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=9999)
服务将在 http://localhost:9999
运行
FastAPI 自动生成交互式文档:
-
Swagger UI:
http://localhost:9999/docs
-
ReDoc:
http://localhost:9999/redoc
Swagger的界面如下:
三、FastAPI和Flask的区别和联系
想象一下你在经营一家餐厅:
Flask 的同步路由 (Synchronous): 就像只有一个厨师,而且他一次只能做一个菜。
-
工作方式:
- 第一个客人点单(一个请求来了)。
- 厨师开始做这道菜(处理这个请求)。
- 关键点: 在这道菜完全做好、端给客人之前,即使第二个客人已经点好单,厨师也不会开始做第二道菜。他必须等第一道菜完成。如果第一道菜是“佛跳墙”(一个很慢的操作,比如等待数据库、等待外部 API、或者等待大模型生成结果),那么后面所有的客人都要排队等着。
-
代码示例 (简化示意):
# Flask (同步) from flask import Flask import time app = Flask(__name__) @app.route('/cook_sync') def cook_sync(): print("开始做菜 A...") time.sleep(5) # 模拟做一个很慢的菜 (比如等大模型响应) print("菜 A 做好了!") return "菜 A 完成" # 当一个请求访问 /cook_sync 时,服务器会卡住 5 秒, # 这期间无法处理其他请求(除非你开了多个服务员/进程)。
- 特点: 简单直接,符合我们通常的编程思路(一步接一步)。但是,如果某个步骤很慢(等待 I/O 操作),整个流程就会被阻塞,效率不高,无法同时处理很多“等待中”的任务。
FastAPI 的异步路由 (Asynchronous): 就像一个很厉害的厨师,他可以同时处理多个任务。
-
工作方式:
- 第一个客人点单(请求 1)。厨师开始做菜 A,比如先把米饭放进电饭煲(开始一个需要等待的操作,比如请求大模型)。
- 关键点: 在等待米饭煮熟(等待大模型响应)的时候,厨师**不会闲着**。他会立刻去看有没有其他客人的订单(处理请求 2)。
- 第二个客人点单(请求 2)。厨师开始处理菜 B,比如开始洗菜(执行一些快代码)。
- 如果菜 B 也需要等待(比如等水烧开),厨师又会去看有没有其他事做(处理请求 3 或查看米饭是否熟了)。
- 一旦米饭煮熟了(大模型的响应回来了),厨师就会回来继续完成菜 A 的后续步骤。
代码示例 (简化示意):
# FastAPI (异步) from fastapi import FastAPI import asyncio # Python 的异步库 app = FastAPI() @app.get('/cook_async') async def cook_async(): # 注意这里的 async print("开始做菜 A (异步)...") await asyncio.sleep(5) # 模拟做一个很慢的菜,但这里用 await # 表示“在这里等待,但允许服务器去做别的事” print("菜 A (异步) 做好了!") return "菜 A (异步) 完成" # 当一个请求访问 /cook_async 时,服务器在 `await asyncio.sleep(5)` 这里 # 会“暂停”这个任务,转而去处理其他进来的请求。5秒后,当等待结束, # 服务器会回来继续执行这个任务。这使得服务器能同时处理很多“等待中”的请求。
- 特点: 需要使用
async
和await
关键字。特别擅长处理那些包含等待时间(I/O 密集型,如网络请求、读写文件、数据库查询、等待大模型响应)的任务。同一个厨师(服务器进程)可以同时“照看”很多道菜,大大提高了效率(并发能力)。
联系和区别总结:
特性 | Flask (同步) | FastAPI (异步) |
---|---|---|
核心机制 | 同步阻塞 (一步接一步) | 异步非阻塞 (利用等待时间处理其他事) |
比喻 | 单任务厨师 | 多任务厨师 |
代码风格 | 标准 Python 函数 (def ) |
使用 async def 和 await |
擅长场景 | CPU 密集型任务 (需要持续计算) | I/O 密集型任务 (大量等待时间,如网络、磁盘、LLM) |
并发能力 | 较低 (依赖多进程/多线程) | 非常高 (单个进程能处理大量并发连接) |
性能 | 对于 I/O 密集场景,性能较低 | 对于 I/O 密集场景,性能非常高 |
学习曲线 | 相对平缓 (同步逻辑易理解) | 稍陡峭 (需要理解 async/await 和事件循环) |
数据校验 | 需额外库 (如 Flask-WTF, Marshmallow) | 内置 Pydantic,自动数据校验和文档生成 |
联系:
- 它们都是 Python Web 框架,用来创建 API 或 Web 应用。
- 它们都能接收 HTTP 请求,根据 URL 路由到相应的处理函数,然后返回 HTTP 响应。
- Flask 也可以通过一些方式(比如使用
gevent
或asyncio
扩展)实现类似异步的功能,但不是其天生设计。FastAPI 也可以运行同步代码(它会自动在线程池里运行,避免阻塞主循环)。
在利用大模型(LLM)部署时怎么选择?
强烈推荐使用 FastAPI (异步)。
原因:
- LLM 调用是典型的 I/O 密集型操作: 当你的 API 调用一个大模型(无论是本地部署的还是云上的 API),你的程序需要等待模型进行计算并返回结果。这个等待时间可能从几百毫秒到几秒甚至更长。
- 异步能极大提高并发处理能力:
- 使用 Flask (同步),当一个请求在等待 LLM 响应时,处理这个请求的那个服务器进程/线程就完全卡住了,不能为其他用户服务。如果你想同时服务 100 个用户,你可能需要启动 100 个(甚至更多)Flask 工作进程,这会消耗大量内存和 CPU 资源。
- 使用 FastAPI (异步),当一个请求
await
LLM 的响应时,服务器会把这个任务暂时挂起,然后立即去处理其他用户的请求。当 LLM 的响应回来后,服务器再继续处理之前挂起的任务。这样,一个 FastAPI 进程就能同时处理成百上千个“等待 LLM 响应”的并发请求,资源利用率极高。
- FastAPI 的内置特性很方便: FastAPI 基于 Pydantic 进行自动的数据校验和文档生成(Swagger UI / ReDoc)。这对于定义清晰的 LLM 输入(如 prompt、参数)和输出结构非常有帮助,能减少很多模板代码,提高开发效率和接口质量。
简单来说:
- 如果你希望你的 LLM 应用能够同时服务很多用户,并且高效地利用服务器资源,FastAPI 的异步特性是巨大的优势。
- 如果你只是做一个内部小工具,用户量极少,或者你的团队完全不熟悉异步编程且不愿意学习,用 Flask 也能实现功能,但性能和并发能力会差很多,需要更多服务器资源来弥补。
结论: 对于需要调用大模型的场景,FastAPI 的异步模型几乎是必然的选择,因为它能更好地应对 LLM 调用带来的等待时间,实现高并发、高性能的服务。