← Back to 文字

FastAPI 最小服务

本文来自《AI 应用开发课程》月份 1 课程文档,已整理为网站文章版本。

学习目标

学完本节后,你应当能够:

  • 理解为什么月份 1 必须学 FastAPI。
  • 启动一个最小 FastAPI 服务。
  • 理解路由、请求处理和自动文档的基本关系。

前置知识

  • 已完成 Python 工程化模块
  • 已完成普通 LLM API 调用

1. 为什么月份 1 就学 FastAPI

因为 AI 应用最终很少只是脚本。你迟早会面对这些需求:

  • 对外提供接口
  • 与前端或其他服务对接
  • 做健康检查
  • 做流式响应
  • 上传文件或接收结构化请求

FastAPI 是这条路线中的默认后端框架,原因不是“它最流行”,而是它在月份 1 阶段刚好覆盖:

  • 类型友好
  • Pydantic 集成强
  • 文档自动生成
  • 异步支持自然

2. 安装依赖

在项目中执行:

uv add fastapi uvicorn

3. 最小服务

创建 app/main.py

from fastapi import FastAPI

app = FastAPI(title="Month1 AI Service")


@app.get("/health")
async def health() -> dict[str, str]:
    return {"status": "ok"}

启动:

uv run uvicorn app.main:app --reload

访问:

  • http://127.0.0.1:8000/health
  • http://127.0.0.1:8000/docs

4. 代码讲解

app = FastAPI(...)

创建应用实例。

@app.get("/health")

声明一个 GET 路由。

async def health()

使用异步函数定义接口,便于后续接入异步模型调用。

5. FastAPI 请求处理图

flowchart LR
    A["客户端请求"] --> B["FastAPI 路由匹配"]
    B --> C["请求参数解析"]
    C --> D["调用 service 层"]
    D --> E["返回响应模型"]

月份 1 最关键的是理解:

  • 路由层不是业务层
  • FastAPI 只是协议入口,不应该承载所有逻辑

6. 推荐目录结构

app/
├── api/
│   └── routes.py
├── services/
│   └── chat_service.py
├── models.py
└── main.py

为什么要拆 api/services/

因为后面 CLI 和 API 都要复用 services/ 中的核心逻辑。

7. 实操任务

  1. 起一个最小 FastAPI 服务
  2. 添加 /health
  3. 打开 /docs
  4. 将服务目录拆成 apiservices

8. 自测题

  1. 为什么月份 1 不推荐把所有逻辑都写在 main.py
  2. 为什么 FastAPI 特别适合和 Pydantic 配合?
  3. /docs 为什么对学习阶段很有价值?

9. 作业与验收

验收标准:

  • 服务可以启动
  • /health 可访问
  • /docs 可访问
  • 目录中已有服务层位置

10. 常见错误

  • 路由文件和业务逻辑混在一起
  • 启动命令模块路径写错
  • 只关注接口能返回,不关注结构是否清晰

11. 本章与前文关系

前面的 LLM API 和 Tool Calling 模块,仍然主要停留在“脚本能力”层面。现在要解决的,是月份 1 的一个关键跨越:

如何把模型能力变成服务能力?

FastAPI 的作用不是让你多学一个 Web 框架,而是让你开始从“我自己能跑通”升级到“其他系统也能调用”。

12. 本章在研发助手项目中的位置

研发助手项目到第 4 周时必须同时支持:

  • CLI 使用
  • API 使用

CLI 更适合本地研发工作流,API 更适合:

  • 调试
  • 对外展示
  • 后续前端接入
  • 服务化思维训练

所以 FastAPI 在月份 1 的地位不是可选项,而是服务化底盘。

13. 为什么月份 1 选 FastAPI,而不是泛讲所有后端框架

这里的取舍非常明确:

  • 月份 1 不做“后端框架横向对比课”
  • 月份 1 只学习对 AI 应用最直接有用的一套服务化能力

FastAPI 适合当前阶段,主要因为它天然贴合:

  • Pydantic 模型
  • 异步调用
  • 自动文档
  • 轻量服务化

14. 错误示例 vs 正确示例

错误示例:把路由、模型调用和业务逻辑全塞进 main.py

这样做短期能跑,长期会让项目快速失控:

  • 路由层和业务层混在一起
  • 逻辑无法复用给 CLI
  • 测试边界不清晰

正确示例:入口层极薄,服务层承载核心逻辑

月份 1 后续所有 FastAPI 代码都应围绕这个原则组织。

15. 完整文件级示例:main.py + routes.py

app/main.py

"""FastAPI 应用入口。"""

from fastapi import FastAPI

from app.api.routes import router


app = FastAPI(
    title="Month1 AI Service",
    description="月份 1 的最小 AI 服务示例",
)

app.include_router(router)

app/api/routes.py

"""定义月份 1 的最小 API 路由。"""

from fastapi import APIRouter


router = APIRouter()


@router.get("/health")
async def health() -> dict[str, str]:
    """健康检查接口。

    它的存在并不是为了技术炫耀,而是为了让你和调用方都能快速判断服务是否启动成功。
    """

    return {"status": "ok"}

16. 逐段解释这组完整示例

为什么 app = FastAPI(...) 不直接写全部逻辑

因为 FastAPI 实例应该更像应用的装配点,而不是逻辑仓库。

为什么先单独引入 router

这是在提前建立一种非常重要的工程习惯:

  • main.py 负责组装
  • routes.py 负责路由定义
  • service 层负责业务

为什么第一个接口一定是 /health

因为这是最基础的可观测性入口。它能快速回答:

  • 服务起没起来
  • 路由有没有挂上
  • 基础运行环境是否正常

17. 从最小服务到月份 1 服务化项目的递进

第一步:只有 /health

验证:

  • 服务能启动
  • 路由能工作
  • 自动文档可访问

第二步:增加 /chat

把已有模型调用能力接成服务。

第三步:增加 /tools/run

把工具执行能力接成服务。

第四步:增加流式响应

提升体验并理解更真实的数据流。

18. 自动文档为什么在学习阶段特别有价值

FastAPI 自动生成的 /docs,对月份 1 有两个特别重要的价值:

  • 它让你可以快速验证请求和响应结构
  • 它让你看到 Pydantic 模型如何自动转成接口文档

这会帮助你建立一个很重要的直觉:

模型结构、服务结构和文档结构,其实是联动的。

19. 调试与排错:本章最常见问题

问题一:启动命令模块路径写错

例如 uvicorn app.main:app --reload 里的 app.main:app 对不上实际目录。

问题二:服务启动了,但 /docs 打不开

说明你要检查:

  • 端口是否正确
  • 路由是否注册
  • 应用是否真的启动成功

问题三:把 FastAPI 学成“接口函数大杂烩”

月份 1 必须时刻记住:FastAPI 只是入口,不是业务堆放处。

20. 本章完成后你应该具备的能力

完成本章后,你应当做到:

  1. 能启动最小 FastAPI 服务。
  2. 能解释 /health/docs 的意义。
  3. 能理解入口层与路由层的最小拆分。
  4. 能为后续 /chat/tools/run 做准备。

21. 如果你卡在这里,先回看哪几章

22. 从本章过渡到下一章的桥接说明

接下来进入 02-请求响应模型设计.md

本章解决的是“服务壳子怎么起”,下一章将解决“这个壳子里装什么结构”。也就是:你的 API 到底接收什么、返回什么、错误如何表达。这一步会把 FastAPI 和前面学过的 Pydantic 真正连接起来。

Fin