第十三节:FastApi入门以及AI智能体案例落地实操

一.  FastApi入门

前言

FastAPI 是一个现代、高性能的 Web 框架,用于构建 API,基于 Python 3.7+ 的标准类型提示。本文将从三个核心模块带你逐步了解 FastAPI 生态:

  1. Pydantic - 数据验证与序列化的基石

  2. 同步与异步 - 理解异步编程的核心概念

  3. 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 验证规则:

规则

说明

示例

ge

大于等于

ge=0

le

小于等于

le=5000

gt

大于

gt=0

lt

小于

lt=100

max_length

字符串最大长度

max_length=100

min_length

字符串最小长度

min_length=2

regex

正则表达式

regex="^[a-zA-Z]+$"

description

字段描述

description="商品名称"

注意: 字符串类型约束长度要用 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 的属性:

属性

说明

filename

文件名

content_type

MIME 类型(如 image/png

file

文件对象(类文件对象)

UploadFile 的方法:

方法

说明

read(size)

读取文件内容

write(data)

写入数据

seek(offset)

移动文件指针

close()

关闭文件

保存文件示例:

@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 开发的核心基础知识:

  1. Pydantic:数据模型定义、自动验证、类型安全

  2. 异步编程:async/await 语法、并发 vs 串行、I/O 密集型场景

  3. FastAPI 路由:路径参数、查询参数、请求体、文件上传

  4. 数据校验:Field 验证规则、枚举类型限制

  5. 自动文档:Swagger UI 开箱即用

掌握这些基础后,你可以进一步探索:

  • 依赖注入(Depends)

  • 数据库集成(SQLAlchemy)

  • 认证授权(OAuth2、JWT)

  • 中间件

  • 后台任务

  • WebSocket

FastAPI 的设计理念是"让正确的事情变得容易",希望这篇笔记能帮助你快速上手!


参考资料:

 

 

二.  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

确认以下包已安装:

包名

用途

fastapi

Web 框架

uvicorn

服务器

openai

AI API 客户端

python-jose

JWT 认证

pwdlib

密码哈希

python-dotenv

环境变量


四、配置环境变量

编辑项目根目录的 .env 文件:

DASHSCOPE_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
DASHSCOPE_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
MODEL_NAME="qwen3.7-plus"

配置项说明

配置项

示例值

说明

DASHSCOPE_API_KEY

sk-xxxxxxxx

阿里云 DashScope API 密钥(必填

DASHSCOPE_BASE_URL

https://dashscope.aliyuncs.com/compatible-mode/v1

API 服务地址(默认即可)

MODEL_NAME

qwen3.7-plus

AI 模型名称(可选的模型:qwen-turbo、qwen-plus、qwen-max 等)

注意.env 文件包含敏感信息,请勿提交到 Git 仓库。


五、测试账号

用户名

密码

说明

root

123456

管理员账号(默认)


六、启动服务

6.1 确保虚拟环境已激活

.venv\Scripts\activate

6.2 启动服务

python main.py

6.3 访问地址

地址

说明

http://localhost:8000

Web 服务地址

http://localhost:8000/docs

Swagger API 文档(推荐)

http://localhost:8000/redoc

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

/users/token

用户登录,获取 JWT Token

8.2 聊天服务接口

方法

路径

需要认证

功能

POST

/chat/chat

AI 聊天(支持流式/非流式)

GET

/chat/models

获取可用 AI 模型列表

GET

/chat/history

获取用户聊天历史记录

GET

/chat/health

健康检查接口


九、调用示例

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

root

password

123456

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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2026-05-29 07:26  Yaopengfei  阅读(16)  评论(0)    收藏  举报