【FDE系列】阶段2:Day 28:FastAPI 入门 — 把你的函数变成 API 服务

📚前言

📒FDE系列内容总纲:

【大纲】FDE 前沿部署工程师学习系列教程-CSDN博客

🚄前置课程列表:

阶段一:

【FDE系列】阶段1Day 1:AI 层级关系 --- 四个嵌套的圈-CSDN博客

【FDE系列】阶段1Day 2:AI 三阶段发展史 --- 会认 → 会判断 → 会创造-CSDN博客

【FDE系列】阶段1Day 3:符号 AI vs 机器学习 --- 两条路线的本质区别-CSDN博客

【FDE系列】阶段1Day 4:Transformer 的历史意义 --- 2017 年的分水岭-CSDN博客

【FDE系列】阶段1Day 5:本周复习与自测 --- 检验你的 AI 认知地基-CSDN博客

【FDE系列】阶段1Day 6:Transformer 架构 --- 一张图纸盖出千千万万栋楼-CSDN博客

【FDE系列】阶段1Day 7:LLM 本质 --- 文字接龙机器-CSDN博客

【FDE系列】阶段1Day 8:Token --- 模型眼中的最小单位-CSDN博客

【FDE系列】阶段1Day 9:AI 幻觉 --- 为什么会一本正经地胡说八道-CSDN博客

【FDE系列】阶段1Day 10:上下文窗口 --- 模型的记忆力上限 + 本周复习-CSDN博客

【FDE系列】阶段1Day 11:Prompt --- 给模型立规矩-CSDN博客

【FDE系列】阶段1Day 12:Memory --- 让模型记住上下文

【FDE系列】阶段1Day 13:RAG --- 给模型配图书管理员-CSDN博客

【FDE系列】阶段1Day 14:Tool Use --- 让模型动手操作-CSDN博客

【FDE系列】阶段1Day 15:MCP --- 统一的工具接口标准 + 第三周复习-CSDN博客

【FDE系列】阶段1Day 16:什么是 FDE --- 把 AI 变成客户结果的人-CSDN博客

【FDE系列】阶段1Day 17:FDE vs 传统实施 --- 三大本质区别-CSDN博客

【FDE系列】阶段1Day 18:FDE 三重身份 + C6 胜任力模型-CSDN博客

【FDE系列】阶段1Day 19:七阶段行动路径 + 行业经验的价值-CSDN博客

【FDE系列】阶段1Day 20:阶段总结与产出物 --- 第一阶段收官-CSDN博客


阶段二:

【FDE系列】阶段2:Day 21:Python 环境搭建 --- 写出你的第一行代码-CSDN博客

【FDE系列】阶段2:Day 22:变量、数据类型、条件判断 --- Python 的"记忆"和"判断"-CSDN博客

【FDE系列】阶段2:Day 23:循环与函数 --- 让代码跑 100 遍、把逻辑打包复用-CSDN博客

【FDE系列】阶段2:Day 24:数据结构 --- 列表、字典、集合、元组-CSDN博客

【FDE系列】阶段2:Day 25:文件读写与 JSON --- 让程序连通外部数据(第一周收官)-CSDN博客

【FDE系列】阶段2:Day 26:模块化编程 --- 把代码拆成"抽屉柜"-CSDN博客

【FDE系列】阶段2:Day 27:异常处理与日志 --- 让程序"摔不烂、查得到"-CSDN博客


🚀阶段2·Day 28:FastAPI 入门 --- 把你的函数变成 API 服务

FDE 学习系列教程 · 第二阶段 · 第 2 周 · Day 3 预计时长:3 小时 | 难度:★★★☆☆ | 前置知识:Day 22-27(函数、模块、异常基础)
📌 一句话目标:理解 HTTP/API 的基本交互,用 FastAPI 写出可通过网址访问的接口,掌握路径参数、查询参数和自动文档------FDE 技术栈的主干正式登场。

🧑‍🤝‍🧑 老哥开场白

这周前两节课在给代码"精装修"。今天开始,干一件让你身价上涨的事:把 Python 函数变成网络服务

回想第一阶段你调 Dify API 的经历:你发一段请求,它返回一个结果。你有没有好奇过------"服务端"是怎么收到请求、又怎么返回的?

今天你就坐到服务端这一侧来。学完你会发现:所谓 API 服务,本质就是"一个一直在运行的 Python 程序,等着别人通过网址来调用它的函数"。

复制代码
之前:你写脚本 → 自己运行 → 看结果
今天:你写服务 → 启动后一直跑 → 浏览器/客户系统/AI Agent 通过 HTTP 来调用

👉 FastAPI 是目前 Python 世界最火的 API 框架(GitHub 80K+ Star),以"自带文档、写得少、自动校验"著称。今天新概念密集(HTTP、路由、参数),但每个都马上动手验证,别怕。

🌐 先搞懂 API 和 HTTP(3 分钟版)

用餐厅类比理解一切

复制代码
你(客户端)去餐厅:
  1. 招呼服务员,点菜(发起请求 Request)
  2. 后厨按菜单做菜(服务器处理逻辑)
  3. 服务员端菜上来(返回响应 Response)

HTTP 就是客户端和服务器之间"点菜---上菜"的规矩。

URL 就是"菜单位置"

复制代码
http://localhost:8000/devices/A1
└──────┬──────┘ └────┬────┘ └──┬──┘
     服务器地址      端口      路径(你要哪个功能)
  • localhost = 本机(你自己的电脑当服务器)

  • 8000 = 门牌号(端口号),FastAPI 默认住 8000

  • /devices/A1 = 路径,标识"我要查 A1 设备"

四种常用 HTTP 方法:动词

方法 中文意思 对应操作 典型场景
GET 查询 查设备、查工单
POST 新增 提交一条新工单
PUT 整体更新 修改工单全部信息
DELETE 删除 关闭工单

这四个词合称 CRUD(Create 增 / Read 查 / Update 改 / Delete 删),就是一切业务系统的基本面。今天先用 GET,明天补齐其余三个。

状态码:服务器的"回话语气"

状态码 含义 人话
200 OK 办妥了
201 Created 新建成功
400 Bad Request 你发的东西有问题
404 Not Found 你要的东西不存在
500 Internal Server Error 服务器自己炸了

懂的同学这段可以直接往下翻。不过 404 和 500 的区别(一个是你请求错了,一个是服务器内部错)后面调试天天用,不放心十秒扫一遍也行。

🛠️ 安装与第一个服务

第 1 步:建虚拟环境装库

复制代码
# 新建项目文件夹并进入
mkdir fastapi_demo
cd fastapi_demo

python -m venv venv
venv\Scripts\activate

# fastapi 是框架,uvicorn 是"服务器"(负责真正监听端口、收发网络请求)
pip install fastapi "uvicorn[standard]"

💡 两个东西分工不同:FastAPI 负责"请求来了调用哪个函数",uvicorn 负责"网络收发"。FastAPI 应用要靠 uvicorn 跑起来。

第 2 步:写第一个应用

新建 main.py

复制代码
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def root():
    return {"message": "FDE 设备服务已启动", "status": "ok"}

逐行拆解:

复制代码
app = FastAPI()
# 创建一个应用实例,相当于"开了一家餐厅"

@app.get("/")
# 装饰器:登记规则------"有人用 GET 访问首页 /,就调用下面这个函数"

def root():
    return {...}
# 返回字典 → FastAPI 自动把它转成 JSON 发回去(上周学的 json 它帮你干了)

那个 @app.get(...)装饰器 ,长着 @ 符号。现在不用研究它的原理,记住这个套路即可:函数上面贴一个 @app 路由标签,这个函数就变成了网络接口。

第 3 步:启动服务

复制代码
uvicorn main:app --reload

main:app 的意思:main.py 文件里那个叫 app 的对象。--reload 是开发神器------你改完代码保存,服务自动重启,不用手动管。

看到这样的输出就是成功了:

复制代码
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Application startup complete.

第 4 步:访问它

打开浏览器,地址栏输入 http://localhost:8000/,你会看到:

复制代码
{"message": "FDE 设备服务已启动", "status": "ok"}

🎉 你的第一个 API 服务跑起来了! 此刻你的电脑既是客户端又是服务器。按 Ctrl + C 可以停掉服务。

📖 自动文档:FastAPI 白送的杀手锏

访问 http://localhost:8000/docs

一个完整的接口测试页面(Swagger UI)自动出现了------你没写一个字的文档!

复制代码
/docs    → Swagger UI(可交互文档,能直接在页面上点"Try it out"测接口)
/redoc   → ReDoc(另一种阅读型文档样式)

/docs 页面你可以:

  1. 点开 GET / 接口

  2. Try it outExecute

  3. 直接看到真实响应、状态码、响应头

📌 FDE 交付时,客户的开发同事问"你这接口怎么调?"------你把 /docs 链接发过去就完事了。自动生成的实时文档是 FastAPI 淘汰老一代框架的重要理由,明天你会更深地体会到。

🔧 路径参数:把信息放在网址里

新建一个接口,查指定设备的分级结果(复用上周的业务函数):

复制代码
from fastapi import FastAPI

app = FastAPI()


def grade_temperature(t):
    if t >= 90:
        return "紧急"
    elif t >= 80:
        return "严重"
    elif t >= 70:
        return "注意"
    return "正常"


@app.get("/grade/{temperature}")
def get_grade(temperature: int):
    level = grade_temperature(temperature)
    return {"temperature": temperature, "level": level}

注意花括号 {temperature}:它是网址里的占位符,用户填什么,函数就收到什么。

访问试一下:

复制代码
http://localhost:8000/grade/85   →  {"temperature": 85, "level": "严重"}
http://localhost:8000/grade/60   →  {"temperature": 60, "level": "正常"}

类型注解自动校验(第一次尝到甜头)

注意参数写的是 temperature: int。这个 : int类型注解。FastAPI 会拿它做自动校验:

复制代码
访问 /grade/85    → 85 能转成 int → 正常
访问 /grade/abc   → abc 转不成 int → FastAPI 自动返回 422 错误:

{
  "detail": [{
    "type": "int_parsing",
    "loc": ["path", "temperature"],
    "msg": "Input should be a valid integer"
  }]
}

你一行校验代码都没写,非法输入被干净利落地挡在门外,错误信息还特别规范。这就是 FastAPI 的核心爽点之一。

多个路径参数

复制代码
@app.get("/devices/{device_id}/sensors/{sensor_type}")
def read_sensor(device_id: str, sensor_type: str):
    return {"device": device_id, "sensor": sensor_type}

访问 /devices/A1/sensors/temperature → 两个值都能收到。

🔍 查询参数:问号后面的筛选条件

路径参数适合"定位资源",查询参数适合"筛选/分页/可选条件"。长这样:

复制代码
/devices?status=running&limit=10
         └──────┬───────┘ └────┬────┘
            第一个条件      再追加条件用 & 连接

在 FastAPI 里,函数里那些没在路径中出现的参数,自动变成查询参数

复制代码
DEVICES = [
    {"id": "A1", "temperature": 65, "running": True},
    {"id": "A2", "temperature": 82, "running": True},
    {"id": "A3", "temperature": 91, "running": True},
    {"id": "B1", "temperature": 75, "running": False},
]


@app.get("/devices")
def list_devices(running: bool | None = None, limit: int = 100):
    result = DEVICES

    # 传了 running 就筛选,没传就返回全部
    if running is not None:
        result = [d for d in result if d["running"] == running]

    return {"count": len(result[:limit]), "data": result[:limit]}

注:bool | None 表示"布尔值或者 None",是 Python 3.10+ 的写法;老版本写作 Optional[bool](Day 30 细讲类型注解)。

测试:

复制代码
http://localhost:8000/devices                  → 全部 4 台
http://localhost:8000/devices?running=true     → 只看运行中的 3 台
http://localhost:8000/devices?running=true&limit=2  → 运行中的前 2 台
http://localhost:8000/devices?limit=2          → 全部数据的前 2 台

路径参数 vs 查询参数怎么选

场景 用法 例子
定位"哪个资源"(必填) 路径参数 /devices/A1
筛选/分页/排序(可选) 查询参数 /devices?running=true&limit=10
层级从属关系 路径参数 /devices/A1/orders/3

实在弄不懂也没关系,用多了自然有感觉。记个经验法则:"是谁"进路径,"怎么过滤"进问号。

🛠️ FDE 实战:设备查询服务(GET 全家桶)

main.py 补完整:

复制代码
from fastapi import FastAPI, HTTPException

app = FastAPI(title="FDE 设备管理 API", version="0.1.0")

DEVICES = [
    {"id": "A1", "name": "注塑机A1", "temperature": 65, "vibration": 8,
     "running": True, "owner": "李工"},
    {"id": "A2", "name": "注塑机A2", "temperature": 82, "vibration": 12,
     "running": True, "owner": "王工"},
    {"id": "A3", "name": "注塑机A3", "temperature": 91, "vibration": 16,
     "running": True, "owner": "赵工"},
    {"id": "B1", "name": "冲压机B1", "temperature": 75, "vibration": 9,
     "running": False, "owner": "李工"},
]


def grade(t):
    if t >= 90:
        return "紧急"
    if t >= 80:
        return "严重"
    if t >= 70:
        return "注意"
    return "正常"


@app.get("/", tags=["基础"])
def root():
    return {"service": "FDE 设备管理 API", "docs": "/docs"}


# 1. 查询单台设备(路径参数 + 404 处理)
@app.get("/devices/{device_id}", tags=["设备"])
def get_device(device_id: str):
    for d in DEVICES:
        if d["id"] == device_id:
            return {**d, "level": grade(d["temperature"])}
    raise HTTPException(status_code=404, detail=f"设备 {device_id} 不存在")


# 2. 设备列表 + 多条件筛选(查询参数)
@app.get("/devices", tags=["设备"])
def list_devices(running: bool | None = None,
                 level: str | None = None,
                 owner: str | None = None):
    result = []
    for d in DEVICES:
        if running is not None and d["running"] != running:
            continue
        if level and grade(d["temperature"]) != level:
            continue
        if owner and d["owner"] != owner:
            continue
        result.append({**d, "level": grade(d["temperature"])})

    return {"count": len(result), "items": result}


# 3. 实时分级计算(路径参数直接传温度)
@app.get("/grade/{temperature}", tags=["工具"])
def calc_grade(temperature: float):
    return {"temperature": temperature, "level": grade(temperature)}

验收步骤

  1. uvicorn main:app --reload 启动

  2. 打开 /docs,观察三个接口都已自动列好、还按 tags 分了组

  3. 逐个 Try it out:

    • GET /devices/A3 → 返回带 level 的完整档案

    • GET /devices/A9 → 返回规范的 404

    • GET /devices?level=严重 → 返回 A2

    • GET /devices?running=true&owner=李工 → 只返回 A1

    • GET /grade/87.5 → 注意 float 类型,小数也能收

关于 404:HTTPException

复制代码
raise HTTPException(status_code=404, detail="设备不存在")

业务上查不到东西时,不能返回 200 再塞个错误信息------那叫"骗客户端"。正确姿势是抛出 HTTPException,FastAPI 会把它变成标准 HTTP 错误响应。状态码本身就是接口契约的一部分。

💡 现在数据还存在内存列表里(服务重启数据就没了)。别着急,这是为了专注学接口本身。下周 SQL 模块接上 MySQL,数据就能持久化;接口代码几乎不用动------分层的好处提前感受一下。

📝 本课小结

知识点 一句话记住
API 服务 一直运行、等别人通过 HTTP 调用函数的程序
HTTP 四方法 GET 查 / POST 增 / PUT 改 / DELETE 删
状态码 200 成功 / 404 没有 / 422 参数错 / 500 服务器炸
FastAPI 定义函数 + 贴 @app.get 标签 = 接口
uvicorn 真正监听端口的服务器:uvicorn main:app --reload
自动文档 /docs 白送可交互接口文档
路径参数 /devices/{id},定位"是谁",必填
查询参数 ?running=true&limit=10,筛选条件,可选
类型注解校验 id: int 非法输入自动返回 422
HTTPException 业务错误用标准状态码回应,如 404

💡 今天最核心的认知 :API 是 FDE 把 AI 能力嵌入客户系统的标准插座。你写的分级函数一旦挂上 HTTP 接口,客户的工单系统、MES、甚至一个 AI Agent 都能通过标准方式调用它------编程语言无关、系统无关。这就是"服务化"的价值。


📋 课后练习

  1. 健康检查接口 :新增 GET /health,返回当前时间(用 datetime)和服务状态 {"status": "healthy", "time": "..."}。这是运维监控最爱调的接口。

  2. 搜索接口 :新增 GET /search?q=关键字,在设备名称里模糊匹配(提示:q in d["name"]),支持可选的 min_temp 参数,只返回温度高于该值的设备。在 /docs 里测试三组组合。

  3. 故意触发错误 :不写代码,只用浏览器访问,分别制造一次 404(查不存在的设备)和一次 422(给 /grade/温度 传文字),把两种返回的 JSON 抄下来对比,理解它们各自在告诉调用方什么。


💭 今日反思

  1. 从"自己跑脚本"到"把能力挂上网等别人调",这个转变让你想到实施工作里的哪种升级?(现场工具 → 标准化服务?)

  2. 为什么说"自动文档"对 FDE 特别值钱?想想你交付项目时和客户 IT 人员对接的痛苦经历。


明天预告 :今天只做了"查"。明天上 POST/PUT/DELETE 完整增删改查,并学习 Pydantic 模型------用一个类定义请求体长什么样,FastAPI 自动完成校验、序列化和文档。学完明天,你将拥有一个完整的工单管理 API,这是第 6 周对接企业系统的预演。


FDE 学习系列教程 · 第二阶段 · 第 2 周 Day 3 · 完

相关推荐
天远Date Lab1 小时前
零信任架构实战:基于天远名下企业A构建自动化商户合规网关
人工智能·ai·工具分享
李航19831 小时前
用 DeepDraw 几何引擎开发建筑设计软件(十):推挤工具
python·3d
xingyuzhisuan1 小时前
无限画布AI视频:瓦片重叠率对拼接接缝瑕疵率影响实测
人工智能
广州山泉婚姻1 小时前
DeepSeek Harness本地部署指南:Windows环境下解决API、权限、远程访问各类问题
人工智能·深度学习
Thomas.Sir1 小时前
第16课:PyTorch|循环神经网络RNN与序列数据处理【让模型拥有“记忆”】
人工智能·pytorch·rnn
Luhui Dev2 小时前
大模型 Token 与成本优化工程指南
人工智能·ai·agent·luhuidev
木子算法2 小时前
测出来的值会抖:约束和目标带噪声时,「可行」和「更好」该怎么判
人工智能·算法·目标跟踪
IT·陈寒2 小时前
JavaScript实战技巧总结
人工智能·大模型·api·创业·变现·简历优化