第十三节:FastApi入门以及AI智能体案例落地实操
一. FastApi入门
前言
FastAPI 是一个现代、高性能的 Web 框架,用于构建 API,基于 Python 3.7+ 的标准类型提示。本文将从三个核心模块带你逐步了解 FastAPI 生态:
-
Pydantic - 数据验证与序列化的基石
-
同步与异步 - 理解异步编程的核心概念
-
FastAPI 入门 - 路由、参数、请求体、文件上传等实战
一、Pydantic 初识
Pydantic 是 FastAPI 的核心依赖之一,用于数据验证、设置管理和序列化。FastAPI 深度集成了 Pydantic,让数据处理变得简单而强大。
1.1 安装 Pydantic 插件
在 PyCharm 中安装 Pydantic 插件,可以获得更好的代码提示和错误检查体验。
1.2 基础数据模型
Pydantic 通过继承 BaseModel 来定义数据模型,利用 Python 的类型提示实现自动验证:
from pydantic import BaseModel
class User(BaseModel):
name: str = "Ypf"
age: int
# 使用
myUser = User(age='18')
print(myUser)
关键点:
-
自动类型转换:
age='18'会被自动转换为整数18 -
默认值:
name设置了默认值"Ypf",实例化时可以不传 -
类型安全:如果传入不符合类型的数据,会抛出
ValidationError
1.3 Annotated 类型注解
Python 3.9+ 引入的 Annotated 允许在类型提示中放置额外的元数据:
from typing import Annotated
def sayHello(name: Annotated[str, "姓名"]) -> str:
return f"hello {name}"
print(sayHello("Ypf"))
Annotated 的第一个参数是类型,后续参数是元数据。在 FastAPI 中,这被广泛用于:
-
参数描述
-
验证规则
-
OpenAPI 文档生成
二、同步与异步编程
理解异步编程是掌握 FastAPI 的关键。让我们通过咖啡店的例子来对比同步和异步。
2.1 基本概念
-
并发:本质是时间片切换,指一个时间段内(通常 1 秒)处理多个请求
-
同步:发布一个任务,需要等待结束后才能执行其他任务(串行执行)
-
异步:发布一个任务,不等待结束,继续执行其他任务(并发执行)
2.2 C# 中的异步原理(参考)
await 时释放当前线程 → 线程回到线程池 → 进入状态机等待异步操作完成 → 退出状态机 → 从线程池返回一个新的线程执行 await 下面的代码
2.3 同步版本 - 咖啡店接单
import time
def make_coffee(name, timecost: int):
print(f"店员开始做{name},需要{timecost}秒")
time.sleep(timecost) # 同步等待,阻塞
print(f"店员已经做好{name}")
def coffee_shop_sync():
start_time = time.time()
# 接一个单,等做好,再接下一个(串行)
make_coffee("美式咖啡", 3)
make_coffee("拿铁咖啡", 2)
make_coffee("卡布奇诺", 1)
total_time = time.time() - start_time
print(f"\n同步模式总耗时:{total_time:.1f}秒")
输出结果:
店员开始做美式咖啡,需要3秒
店员已经做好美式咖啡
店员开始做拿铁咖啡,需要2秒
店员已经做好拿铁咖啡
店员开始做卡布奇诺,需要1秒
店员已经做好卡布奇诺
同步模式总耗时:6.0秒
同步模式是串行执行,总耗时 = 3 + 2 + 1 = 6 秒。
2.4 异步版本 - 咖啡店接单
import asyncio
import time
async def make_coffee_async(name, timecost: int):
print(f"店员开始做{name},需要{timecost}秒")
await asyncio.sleep(timecost) # 异步不等待,不阻塞
print(f"店员已经做好{name}")
async def coffee_shop_async():
start_time = time.time()
# 多个任务并发执行
await asyncio.gather(
make_coffee_async("美式咖啡", 3),
make_coffee_async("拿铁咖啡", 2),
make_coffee_async("卡布奇诺", 1),
)
total_time = time.time() - start_time
print(f"\n异步模式总耗时:{total_time:.1f}秒")
if __name__ == '__main__':
print("-----异步接单模式------")
asyncio.run(coffee_shop_async())
输出结果:
店员开始做美式咖啡,需要3秒
店员开始做拿铁咖啡,需要2秒
店员开始做卡布奇诺,需要1秒
店员已经做好卡布奇诺
店员已经做好拿铁咖啡
店员已经做好美式咖啡
异步模式总耗时:3.0秒
异步模式是并发执行,总耗时 = max(3, 2, 1) = 3 秒。
2.5 对比总结
|
模式 |
执行方式 |
总耗时 |
适用场景 |
|---|---|---|---|
|
同步 |
串行 |
6秒 |
CPU 密集型任务 |
|
异步 |
并发 |
3秒 |
I/O 密集型任务(网络请求、数据库查询) |
关键语法:
-
async def:定义异步函数(协程) -
await:等待异步操作完成,释放当前线程 -
asyncio.gather():并发运行多个协程 -
asyncio.run():运行异步主函数
三、FastAPI 入门实战
3.1 安装依赖
pip install fastapi uvicorn
3.2 启动方式
方式 A:通过代码启动
import uvicorn
from fastapi import FastAPI
app = FastAPI()
if __name__ == '__main__':
uvicorn.run(app, host="127.0.0.1", port=8000)
方式 B:命令行启动(推荐开发时使用)
fastapi dev 文件名.py
3.3 访问地址
-
API 地址:
http://127.0.0.1:8000 -
Swagger 文档:
http://127.0.0.1:8000/docs
3.4 基础路由
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def index():
print('这是第一个接口')
return "Hello FastApi"
@app.get("/root/index")
async def root():
print('这是第一个接口')
return {"这是第一个接口"}
装饰器说明:
-
@app.get():GET 请求 -
@app.post():POST 请求 -
@app.put():PUT 请求 -
@app.delete():DELETE 请求 -
还有
@app.patch()、@app.options()等
3.5 路径参数(Path Parameters)
3.5.1 基础路径参数
@app.get("/root/getModel/{model_name}")
async def get_model(model_name: ModelName):
# ...
3.5.2 枚举类型路径参数
使用枚举可以限制参数的可选值,Swagger 文档中会自动显示下拉列表:
from enum import Enum
class ModelName(str, Enum):
Chinese = "中文"
English = "英文"
French = "法语"
@app.get("/root/getModel/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.English:
return {"modelName": model_name, "msg": "这是英文"}
if model_name.value == "中文":
return {"modelName": model_name, "msg": "这是中文"}
if model_name.value == "法语":
return {"modelName": model_name, "msg": "这是法语"}
return {"modelName": model_name, "msg": "其它语言"}
请求示例: http://127.0.0.1:8000/root/getModel/中文
枚举使用技巧:
-
ModelName.English:获取枚举成员 -
ModelName.English.value:获取枚举值"英文"
3.6 查询参数(Query Parameters)
3.6.1 基础查询参数
URL 中 ? 后面的参数:
fake_items_db = [
{"item_name": "苹果"},
{"item_name": "香蕉"},
{"item_name": "橙子"},
{"item_name": "笔记本电脑"},
{"item_name": "无线鼠标"},
{"item_name": "蓝牙耳机"},
{"item_name": "纯棉T恤"},
{"item_name": "休闲裤"},
{"item_name": "保温杯"},
{"item_name": "充电宝"},
]
@app.get("/root/getItems")
async def read_item(skip: int = 0, limit: int = 5):
return fake_items_db[skip : skip + limit]
请求示例:
-
http://127.0.0.1:8000/root/getItems→ 使用默认值 skip=0, limit=5 -
http://127.0.0.1:8000/root/getItems?skip=2&limit=3→ 自定义参数
3.6.2 带元数据的查询参数
使用 Query 添加描述、验证规则等:
from fastapi import Query
from typing import Annotated
@app.get("/root/getItems")
async def read_item(skip: int = 0, limit: Annotated[int, Query(description='条数')] = 5):
return fake_items_db[skip : skip + limit]
3.7 请求体与数据校验(Request Body)
3.7.1 定义请求体模型
使用 Pydantic 的 BaseModel + Field 来定义请求体和验证规则:
from pydantic import BaseModel, Field
class param(BaseModel):
name: str = Field(description="商品名称")
price: float = Field(description="商品价格在0-5000之间", ge=0, le=5000)
tax: float | None = None
description: str | None = Field(description="商品描述", max_length=100)
Field 验证规则:
|
规则 |
说明 |
示例 |
|---|---|---|
|
|
大于等于 |
|
|
|
小于等于 |
|
|
|
大于 |
|
|
|
小于 |
|
|
|
字符串最大长度 |
|
|
|
字符串最小长度 |
|
|
|
正则表达式 |
|
|
|
字段描述 |
|
注意: 字符串类型约束长度要用
max_length/min_length,int 类型要用le/ge。
3.7.2 使用请求体
from fastapi import Body
from typing import Annotated
@app.post("/testBodyCheck/")
async def bodyCheck(item: param):
print(item)
item_dict = item.model_dump() # 将对象字段转变成字典
if item.tax is not None:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
请求示例(JSON):
{
"name": "iPhone 15",
"price": 5999,
"tax": 599.9,
"description": "最新款苹果手机"
}
注意: 上述示例中 price=5999 超过了 le=5000 的限制,FastAPI 会自动返回 422 错误。
3.7.3 Body(embed=True) - 嵌入请求体
@app.post("/testBodyCheck/")
async def bodyCheck(item: Annotated[list[param], Body(embed=True)]):
# ...
embed=True 的作用:请求体需要多一层包裹。
不带 embed:
{
"name": "iPhone",
"price": 4999
}
带 embed=True:
{
"item": {
"name": "iPhone",
"price": 4999
}
}
3.7.4 Pydantic 常用方法
item.model_dump() # 将模型转换为字典
item.model_dump_json() # 将模型转换为 JSON 字符串
3.8 文件上传
FastAPI 提供两种文件上传方式:
3.8.1 方式一:以字节形式读取(File)
from fastapi import File
@app.post("/upload1/")
def upload1(file: bytes = File(description="以字节形式读取文件")):
return {"filesize": len(file)}
特点:
-
文件内容直接读入内存
-
适合小文件
-
返回字节数组
bytes
3.8.2 方式二:UploadFile(推荐)
from fastapi import UploadFile, File
@app.post("/upload2/")
def upload2(file: UploadFile = File(description="待上传的文件")):
return {"filename": file.filename, "content_type": file.content_type}
UploadFile 的属性:
|
属性 |
说明 |
|---|---|
|
|
文件名 |
|
|
MIME 类型(如 |
|
|
文件对象(类文件对象) |
UploadFile 的方法:
|
方法 |
说明 |
|---|---|
|
|
读取文件内容 |
|
|
写入数据 |
|
|
移动文件指针 |
|
|
关闭文件 |
保存文件示例:
@app.post("/upload/")
async def upload(file: UploadFile = File(...)):
with open(f"uploads/{file.filename}", "wb") as buffer:
content = await file.read()
buffer.write(content)
return {"filename": file.filename}
四、完整示例代码汇总
4.1 完整的 FastAPI 应用
import uvicorn
from fastapi import FastAPI, Path, Query, File, UploadFile, Body
from typing import Annotated
from enum import Enum
from pydantic import BaseModel, Field
# ===================== 1. 初始化 =====================
app = FastAPI()
# ===================== 2. 实体声明 =====================
class ModelName(str, Enum):
Chinese = "中文"
English = "英文"
French = "法语"
fake_items_db = [
{"item_name": "苹果"},
{"item_name": "香蕉"},
{"item_name": "橙子"},
{"item_name": "笔记本电脑"},
{"item_name": "无线鼠标"},
{"item_name": "蓝牙耳机"},
{"item_name": "纯棉T恤"},
{"item_name": "休闲裤"},
{"item_name": "保温杯"},
{"item_name": "充电宝"},
]
class param(BaseModel):
name: str = Field(description="商品名称")
price: float = Field(description="商品价格在0-5000之间", ge=0, le=5000)
tax: float | None = None
description: str | None = Field(description="商品描述", max_length=100)
# ===================== 3. 方法声明 =====================
@app.get("/")
async def index():
return "Hello FastApi"
@app.get("/root/index")
async def root():
return {"这是第一个接口"}
@app.get("/root/getModel/{model_name}")
async def get_model(model_name: ModelName):
if model_name is ModelName.English:
return {"modelName": model_name, "msg": "这是英文"}
if model_name.value == "中文":
return {"modelName": model_name, "msg": "这是中文"}
if model_name.value == "法语":
return {"modelName": model_name, "msg": "这是法语"}
return {"modelName": model_name, "msg": "其它语言"}
@app.get("/root/getItems")
async def read_item(skip: int = 0, limit: Annotated[int, Query(description='条数')] = 5):
return fake_items_db[skip : skip + limit]
# ===================== 4. 请求体配置校验 =====================
@app.post("/testBodyCheck/")
async def bodyCheck(item: param):
item_dict = item.model_dump()
if item.tax is not None:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
# ===================== 5. 文件上传 =====================
@app.post("/upload1/")
def upload1(file: bytes = File(description="以字节形式读取文件")):
return {"filesize": len(file)}
@app.post("/upload2/")
def upload2(file: UploadFile = File(description="待上传的文件")):
return {"filename": file.filename, "content_type": file.content_type}
if __name__ == '__main__':
uvicorn.run(app, host="127.0.0.1", port=8000)
五、FastAPI 的核心优势
5.1 自动生成文档
启动服务后访问 http://127.0.0.1:8000/docs,你会看到:
-
交互式 Swagger UI 文档
-
所有 API 端点列表
-
可以直接在浏览器中测试接口
-
请求/响应 schema 自动展示
另外还有 ReDoc 文档:http://127.0.0.1:8000/redoc
5.2 类型安全与自动验证
-
基于 Python 类型提示
-
自动进行数据验证
-
验证失败返回清晰的错误信息
-
自动转换类型(如字符串转数字)
5.3 高性能
-
基于 Starlette(ASGI 框架)
-
支持异步编程
-
性能可与 Node.js 和 Go 媲美
-
自动处理异步 I/O
5.4 开发体验
-
优秀的编辑器支持(代码提示、自动补全)
-
热重载(
fastapi dev) -
调试友好
-
代码简洁易读
六、总结
本文涵盖了 FastAPI 开发的核心基础知识:
-
Pydantic:数据模型定义、自动验证、类型安全
-
异步编程:async/await 语法、并发 vs 串行、I/O 密集型场景
-
FastAPI 路由:路径参数、查询参数、请求体、文件上传
-
数据校验:Field 验证规则、枚举类型限制
-
自动文档:Swagger UI 开箱即用
掌握这些基础后,你可以进一步探索:
-
依赖注入(Depends)
-
数据库集成(SQLAlchemy)
-
认证授权(OAuth2、JWT)
-
中间件
-
后台任务
-
WebSocket
FastAPI 的设计理念是"让正确的事情变得容易",希望这篇笔记能帮助你快速上手!
参考资料:
-
FastAPI 官方文档:https://fastapi.tiangolo.com/
-
Pydantic 官方文档:https://docs.pydantic.dev/
二. AI智能体落地实操
一、项目概述
基于 FastAPI 框架构建的 AI 聊天机器人后端服务,提供用户认证和 AI 对话功能。
-
AI 服务:阿里云 DashScope(通义千问模型)
-
认证方式:JWT Token(HS256 算法)
-
密码加密:Argon2 算法
-
开发语言:Python 3.9+
二、创建虚拟环境
在项目根目录下操作:
# 1. 进入项目目录
cd e:\06-架构之路\19-前沿技术\04-AI\Code\AI大模型专题\11-FastApi案例
# 2. 创建虚拟环境(在项目目录下生成 .venv 文件夹)
python -m venv .venv
# 3. 激活虚拟环境
source .venv/Scripts/activate
激活成功后,终端前面会出现 (.venv) 标识。
三、安装依赖包
3.1 一键安装(推荐)
pip install -r requirements.txt
3.2 手动逐个安装
pip install fastapi uvicorn PyJWT pwdlib[argon2] openai python-dotenv pydantic python-multipart bcrypt==4.3.0
或
pip install fastapi # Web框架
pip install uvicorn # ASGI服务器
pip install openai # OpenAI/DashScope API客户端
pip install python-jose # JWT令牌生成与验证
pip install pwdlib # 密码哈希(Argon2)
pip install python-dotenv # 环境变量加载
pip install pydantic # 数据模型验证
pip install "python-jose[cryptography]" # JWT加密扩展
3.3 验证安装
pip list
确认以下包已安装:
|
包名 |
用途 |
|---|---|
|
|
Web 框架 |
|
|
服务器 |
|
|
AI API 客户端 |
|
|
JWT 认证 |
|
|
密码哈希 |
|
|
环境变量 |
四、配置环境变量
编辑项目根目录的 .env 文件:
DASHSCOPE_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
DASHSCOPE_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
MODEL_NAME="qwen3.7-plus"
配置项说明
|
配置项 |
示例值 |
说明 |
|---|---|---|
|
|
|
阿里云 DashScope API 密钥(必填) |
|
|
|
API 服务地址(默认即可) |
|
|
|
AI 模型名称(可选的模型:qwen-turbo、qwen-plus、qwen-max 等) |
注意:
.env文件包含敏感信息,请勿提交到 Git 仓库。
五、测试账号
|
用户名 |
密码 |
说明 |
|---|---|---|
|
|
|
管理员账号(默认) |
六、启动服务
6.1 确保虚拟环境已激活
.venv\Scripts\activate
6.2 启动服务
python main.py
6.3 访问地址
|
地址 |
说明 |
|---|---|
|
|
Web 服务地址 |
|
|
Swagger API 文档(推荐) |
|
|
ReDoc 备用文档 |
6.4 停止服务
在终端按 Ctrl + C。
七、项目结构
FastApi案例/
│
├── main.py # 应用入口,启动服务
├── .env # 环境变量配置(API密钥等)
├── requirements.txt # 项目依赖清单
├── launch.json # 调试配置文件
│
└── app/
├── __init__.py
│
├── config/
│ ├── __init__.py
│ └── configEntity.py # 配置管理类,加载.env配置
│
├── models/
│ ├── __init__.py
│ ├── userEntity.py # 用户相关数据模型 + 模拟数据库
│ └── chatEntity.py # 聊天相关数据模型
│
└── routers/
├── __init__.py
├── users.py # 用户管理路由(登录、注册、JWT认证)
└── chat.py # 聊天服务路由(对话、模型列表、历史记录)
八、API 接口列表
8.1 用户管理接口
|
方法 |
路径 |
需要认证 |
功能 |
|---|---|---|---|
|
POST |
|
否 |
用户登录,获取 JWT Token |
8.2 聊天服务接口
|
方法 |
路径 |
需要认证 |
功能 |
|---|---|---|---|
|
POST |
|
是 |
AI 聊天(支持流式/非流式) |
|
GET |
|
否 |
获取可用 AI 模型列表 |
|
GET |
|
是 |
获取用户聊天历史记录 |
|
GET |
|
否 |
健康检查接口 |
九、调用示例
9.1 登录获取 Token
curl -X POST "http://localhost:8000/users/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=root&password=123456"
成功返回示例:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"username": "root"
}
9.2 发送聊天消息
curl -X POST "http://localhost:8000/chat/chat" \
-H "Authorization: Bearer <你的Token>" \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "你好"}],
"stream": false
}'
十、常见问题
10.1 虚拟环境激活失败
# 如果提示"禁止执行脚本",以管理员身份运行 PowerShell:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
# 然后重新激活
.venv\Scripts\activate
10.2 端口被占用
# 查看端口占用
netstat -ano | findstr :8000
# 或修改 main.py 中的 port 参数
10.3 依赖安装慢
# 使用国内镜像源
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
10.4 Swagger 认证失败
在 Swagger UI 页面点击 Authorize 按钮,填写:
|
字段 |
值 |
|---|---|
|
username |
|
|
password |
|
|
client_id |
留空 |
|
client_secret |
留空 |
十一、开发说明
11.1 密码生成
如果要添加新用户,使用以下方式生成密码哈希:
from pwdlib import PasswordHash
password_hash = PasswordHash.recommended()
hashed = password_hash.hash("你的密码")
print(hashed)
11.2 JWT Token 配置
|
配置项 |
默认值 |
说明 |
|---|---|---|
|
签名算法 |
HS256 |
JWT 签名算法 |
|
Token 有效期 |
30 分钟 |
过期后需要重新登录 |
|
密钥 |
64位随机字符串 |
用于签名和验证 Token |
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。

浙公网安备 33010602011771号