跳转到内容

2.3.3 项目:Web API 开发

Web API 请求响应架构图

这个项目把 Python 从脚本带到服务端。你会用 FastAPI 把功能包装成可被其他程序调用的接口,理解 API 如何连接模型、应用和用户,为后面的 AI 应用开发打基础。

  • 理解什么是 API,为什么 AI 工程师需要会写 API
  • 学会使用 FastAPI 框架构建 Web API
  • 掌握 RESTful API 的基本设计原则
  • 构建一个可以被其他程序调用的 AI 服务接口

你训练了一个很棒的 AI 模型——然后呢?

模型训练好只是第一步。要让别人使用你的模型,你需要把它包装成一个 API 服务

你的 AI 模型 → 包装成 API → 手机 App / 网站 / 其他程序 调用
具体例子:
- ChatGPT 模型 → 通过 API 提供服务 → 各种 App 调用
- 图像识别模型 → 通过 API → 用户上传图片获得识别结果
- 推荐算法 → 通过 API → 电商网站展示推荐商品

所以 API 是连接 AI 模型和真实世界的桥梁


API(Application Programming Interface) = 应用程序编程接口。

简单理解:API 就是一个程序和程序之间的”对话窗口”

你去餐厅吃饭的过程就是一个 API 调用:

你(客户端) → 向服务员(API)说"一碗牛肉面"(请求)
服务员 → 传给后厨(服务器)
后厨 → 做好面
服务员 → 把面端给你(响应)

你不需要知道后厨怎么做的面,你只需要知道怎么点餐(发请求)和怎么接面(收响应)

概念说明类比
URL(端点)API 的地址餐厅地址
HTTP 方法操作类型点餐 / 退菜 / 加菜
请求体发送的数据你要的菜名
响应返回的结果端上来的菜
状态码操作是否成功200=成功, 404=没这道菜
方法用途示例
GET获取数据获取任务列表
POST创建数据添加新任务
PUT更新数据(整体)修改任务全部信息
DELETE删除数据删除一个任务

Terminal window
pip install fastapi uvicorn
作用
fastapiWeb 框架,用来编写 API
uvicornASGI 服务器,用来运行 FastAPI 应用

创建文件 main.py

from fastapi import FastAPI
# 创建应用实例
app = FastAPI(title="我的第一个 API", version="1.0")
# 定义一个端点
@app.get("/")
def root():
return {"message": "Hello, World!", "status": "running"}
@app.get("/hello/{name}")
def hello(name: str):
return {"message": f"你好,{name}!", "name": name}

启动服务器:

Terminal window
uvicorn main:app --reload
  • main = 文件名(main.py
  • app = FastAPI 实例名
  • --reload = 代码修改后自动重启(开发时用)

打开浏览器访问:

  • http://127.0.0.1:8000 → 看到 Hello World
  • http://127.0.0.1:8000/hello/小明 → 看到个性化问候
  • http://127.0.0.1:8000/docs自动生成的交互式 API 文档!

让我们把之前的命令行任务管理器改造成 Web API:

"""
任务管理 API
运行: uvicorn main:app --reload
文档: http://127.0.0.1:8000/docs
"""
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from datetime import datetime
# 创建应用
app = FastAPI(
title="任务管理 API",
description="一个简单的 RESTful 任务管理接口",
version="1.0"
)
# ---------- 数据模型 ----------
class TaskCreate(BaseModel):
"""创建任务时的请求体"""
title: str
priority: str = ""
class TaskUpdate(BaseModel):
"""更新任务时的请求体"""
title: str | None = None
priority: str | None = None
done: bool | None = None
class Task(BaseModel):
"""任务的完整数据"""
id: int
title: str
priority: str
done: bool
created_at: str
# ---------- 模拟数据库(内存存储) ----------
tasks_db: list[dict] = []
next_id: int = 1
# ---------- API 端点 ----------
@app.get("/")
def root():
"""API 首页"""
return {
"name": "任务管理 API",
"version": "1.0",
"endpoints": {
"查看所有任务": "GET /tasks",
"创建任务": "POST /tasks",
"查看单个任务": "GET /tasks/{task_id}",
"更新任务": "PUT /tasks/{task_id}",
"删除任务": "DELETE /tasks/{task_id}",
"API 文档": "GET /docs"
}
}
@app.get("/tasks")
def get_tasks(done: bool | None = None):
"""
获取所有任务。
可选参数:
- done: 过滤已完成(true)或未完成(false)的任务
"""
if done is not None:
filtered = [t for t in tasks_db if t["done"] == done]
return {"count": len(filtered), "tasks": filtered}
return {"count": len(tasks_db), "tasks": tasks_db}
@app.post("/tasks", status_code=201)
def create_task(task: TaskCreate):
"""创建新任务"""
global next_id
new_task = {
"id": next_id,
"title": task.title,
"priority": task.priority,
"done": False,
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
tasks_db.append(new_task)
next_id += 1
return {"message": "任务创建成功", "task": new_task}
@app.get("/tasks/{task_id}")
def get_task(task_id: int):
"""获取指定 ID 的任务"""
for task in tasks_db:
if task["id"] == task_id:
return task
# 找不到任务,返回 404
raise HTTPException(status_code=404, detail=f"任务 {task_id} 不存在")
@app.put("/tasks/{task_id}")
def update_task(task_id: int, task_update: TaskUpdate):
"""更新任务"""
for task in tasks_db:
if task["id"] == task_id:
if task_update.title is not None:
task["title"] = task_update.title
if task_update.priority is not None:
task["priority"] = task_update.priority
if task_update.done is not None:
task["done"] = task_update.done
return {"message": "更新成功", "task": task}
raise HTTPException(status_code=404, detail=f"任务 {task_id} 不存在")
@app.delete("/tasks/{task_id}")
def delete_task(task_id: int):
"""删除任务"""
for i, task in enumerate(tasks_db):
if task["id"] == task_id:
removed = tasks_db.pop(i)
return {"message": "删除成功", "task": removed}
raise HTTPException(status_code=404, detail=f"任务 {task_id} 不存在")
@app.get("/stats")
def get_stats():
"""获取任务统计信息"""
total = len(tasks_db)
done = sum(1 for t in tasks_db if t["done"])
return {
"total": total,
"done": done,
"pending": total - done,
"completion_rate": f"{done/total:.1%}" if total > 0 else "0%"
}
Terminal window
# 启动服务器
uvicorn main:app --reload

然后打开 http://127.0.0.1:8000/docs,你可以在浏览器中直接测试所有 API。

也可以用命令行测试:

Terminal window
# 创建任务
curl -X POST http://127.0.0.1:8000/tasks \
-H "Content-Type: application/json" \
-d '{"title": "学习 FastAPI", "priority": "高"}'
# 查看所有任务
curl http://127.0.0.1:8000/tasks
# 完成任务
curl -X PUT http://127.0.0.1:8000/tasks/1 \
-H "Content-Type: application/json" \
-d '{"done": true}'
# 删除任务
curl -X DELETE http://127.0.0.1:8000/tasks/1

或者用 Python 的 requests 库:

import requests
BASE_URL = "http://127.0.0.1:8000"
# 创建任务
resp = requests.post(f"{BASE_URL}/tasks", json={"title": "学习 Python", "priority": ""})
print(resp.json())
# 获取所有任务
resp = requests.get(f"{BASE_URL}/tasks")
print(resp.json())

FastAPI 使用 Pydantic 来验证请求数据——你定义好数据模型,FastAPI 自动帮你检查:

from pydantic import BaseModel, Field
class TaskCreate(BaseModel):
title: str = Field(..., min_length=1, max_length=100, description="任务标题")
priority: str = Field(default="", description="优先级: 高/中/低")
# 如果用户发送了不合法的数据
# POST /tasks {"title": ""} → 自动返回 422 错误(标题太短)
# POST /tasks {} → 自动返回 422 错误(缺少 title)
# POST /tasks {"title": "OK"} → 成功,priority 使用默认值 "中"

你不需要手动写验证代码——Pydantic 和 FastAPI 帮你搞定了。


现在数据存在内存里,服务器重启就没了。改成用 JSON 文件保存。

@app.get("/tasks/search")
def search_tasks(keyword: str):
"""按关键词搜索任务"""
keyword_lower = keyword.lower()
return [task for task in tasks if keyword_lower in task.title.lower()]

当任务很多时,支持分页返回:

GET /tasks?page=1&size=10

提前预习:创建一个 /predict 端点,接收文本输入,返回情感分析结果。

项目交付参考与讲解
  1. 启动时加载任务,增删改后保存,这样持久化更稳定。让存储的 JSON 结构尽量接近响应结构,便于调试。
  2. 增加 /tasks/search,对标题做不区分大小写的子串匹配。
  3. 通过 pagesize 实现分页,在返回前切片任务列表。
  4. 把 AI 端点先当作扩展功能,前提是 CRUD API 已经稳定。复用同一套校验和错误处理风格,这样新路由行为更可预测。
  5. 自查:打开 /docs,用 curl 测每个端点,并确认无效请求体会触发 FastAPI 自动生成的 422 校验错误。

  • API 能正常启动和访问
  • 实现了完整的 CRUD(增删改查)操作
  • 使用了 Pydantic 做数据验证
  • 有适当的错误处理(HTTPException)
  • 自动生成的 API 文档(/docs)可以正常使用
  • 能用 curl 或 requests 测试所有端点
版本目标交付重点
基础版跑通最小闭环能输入、能处理、能输出,并保留一组示例
标准版形成可展示项目增加配置、日志、错误处理、README 和截图
挑战版接近作品集质量增加评估、对比实验、失败样本分析和下一步路线

建议先完成基础版,不要一开始就追求大而全。每提升一个版本,都要把“新增了什么能力、怎么验证、还有什么问题”写进 README。

学完这一页,至少保留这张证据卡:

项目目标
CLI、爬虫、API、AI API 调用,或集成式 Python 工作坊目标
运行命令
启动项目时使用的准确命令
工件
输出文件、API 响应、JSON 记录、截图或 README 说明
失败检查
依赖、网络、解析、路由、输入验证或 API key 问题
期望产出
可复现的迷你项目文件夹,包含运行结果和一个失败案例