60天企业 AI 实战训练营 · 阶段 1 · 第 2 周

HTTP、REST API
与 FastAPI

理解企业系统集成的基础通信机制,把 AI 能力封装成服务

Day 06 讲师 · 包学斌 2026 · 09 含实操 · 请自带电脑
Client curl · App FastAPI uvicorn POST /summarize 200 OK · JSON

按 → 或 空格键 翻页 · F 全屏

今天这堂课解决什么问题

课程目标

01
读懂一次网络调用
Method / URL / Header / Body / 状态码 —— 看一眼报文就知道问题在哪一环。
02
设计资源化接口
URL 是名词、方法有语义、错误可治理 —— 团队与企业系统都能放心接。
03
把 AI 变成服务
FastAPI + Pydantic:类型即校验即文档,装进昨天的容器跑起来。
它在 60 天课程中的位置
Day 2-3 · Python 企业开发基础已完成
Day 4 · Git 与企业软件开发规范已完成
Day 5 · Docker 与 AI 运行环境已完成
Day 6 · HTTP、REST API 与 FastAPI今天
Day 7 · 大语言模型工程基础下一课
阶段 1 交付底线:Git ✓ · Docker ✓ · 结构化日志 · 健康检查 —— 今天起你的模型有了"门牌号"
互动 · 举手投票 + 点击选择

调别人接口时,你最怕什么?

凭直觉点一个 —— 每个选项都是真实事故

点一个选项,看看它意味着什么 →
01
Part 01

一次 HTTP 调用的解剖

看不懂报文,就永远在猜

curl 无状态 方法与状态码 Header 与 Body
Part 01 · 一次 HTTP 调用的解剖

请求飞过去,响应飞回来

每点一次,看一个环节 —— HTTP 是无状态的请求-响应协议

REQUEST · 客户端 → 服务端
Method+URLPOST /api/v1/summarize
HeaderContent-Type: application/json
HeaderAuthorization: Bearer eyJhbGci...
HeaderX-Correlation-Id: f3a9-c2e1
Body{"text": "Q3对账差异说明……", "max_len": 120}
RESPONSE · 服务端 → 客户端
Status LineHTTP/1.1 200 OK
HeaderContent-Type: application/json
HeaderX-Correlation-Id: f3a9-c2e1(原样带回)
Body{"summary": "……", "tokens": 421}
无状态:每个请求自带全部信息,服务端不"记得"上一个请求 —— 这就是水平扩容的前提,也是要靠 token / CorrelationId 补上下文的原因。
Part 01 · 一次 HTTP 调用的解剖

Header 全家福:五个最该认识的

Content-Type我发的是 JSON:application/json
Authorization我是谁:Bearer Token / API Key
X-Correlation-Id全链路日志用同一把钥匙串起来
Accept-Encoding能接受 gzip —— 大响应省一半流量
Connectionkeep-alive 长连接:复用不重建
企业 AI 微服务的三件套
gzip 压缩 · keep-alive 长连接 · CorrelationId 头贯穿全链路日志 —— 网关到模型服务一查到底。
两个易错点
Header 键大小写不敏感,但请规范化书写;Body 过大要正确设置 Content-Length,否则可能被代理截断。
版本演进
HTTP/1.1 文本协议 → HTTP/2 二进制多路复用 → HTTP/3 基于 QUIC。对业务代码几乎透明,对延迟影响很大。
Part 01 · 一次 HTTP 调用的解剖

HTTP 方法:动词要有纪律

GET读取资源 —— 只读,可缓存幂等 ✓
POST创建 / 触发动作不幂等
PUT整体替换幂等 ✓
PATCH部分修改
DELETE删除资源幂等 ✓
OPTIONSCORS 预检 —— 浏览器先来问一句
幂等为什么重要
网络抖动重试是常态:幂等的方法重试才安全。AI Agent 的写操作 Tool 应对应 POST / PUT / PATCH,明确语义。
两个常见坑
用 GET 传大参数 —— 超 URL 长度上限;用 GET 改状态 —— 重试、预取、爬虫都会误触发。
纯查询也别滥用 POST
POST 做查询丢失可缓存性、无法收藏、日志难排查 —— 查询条件多时用 POST /search 专用端点。
Part 01 · 一次 HTTP 调用的解剖

状态码:把结论说在明面上

2xx 成功
200 OK · 201 已创建
204 成功无返回体
202 已受理(异步任务)
4xx 客户端的锅
400 参数错 · 401 未认证
403 无权限 · 404 不存在
409 冲突 · 422 语义错
429 限流(附 Retry-After)
5xx 服务端的锅
500 未预期异常
502/504 网关 / 上游超时
503 不可用(维护中)
422 是 FastAPI 校验失败的默认响应 —— 参数类型/范围不对,框架自动返。企业规则:严格按状态码语义响应,方便上游熔断、监控、重试。
实操 ① · 8 分钟 · 需要联网(或用 F12 替代)

亲手拆一次 HTTP

1curl -i https://httpbin.org/get —— 看状态行、响应头与回显的请求头
2主动要一个错误:curl -i https://httpbin.org/status/404(再试试 418)
3发一个 JSON:curl -i -X POST https://httpbin.org/post -H "Content-Type: application/json" -d "{\"msg\":\"hi\"}"
4浏览器 F12 → Network:刷新任意页面,找出 Method / Status / Content-Type / Correlation 头
08:00
验收标准
能指出一次真实请求的 Method 与 Status
能说出 401403 的区别
POST 报文里找到了 Content-Type 头

内网不通就用 F12 观察任意网站 —— 同样算过

互动 · 快问快答

对错判断:三道送命题

先举手投票,再点击揭晓答案

1. Header 的名字是大小写敏感的?
错 —— HTTP/1.1 里 Header 名不区分大小写;HTTP/2 统一小写。规范书写是纪律,不是语法。
✗ 错
2. HTTP/2 更快,是因为文本报文压得更短?
错 —— HTTP/2 是二进制分帧 + 多路复用:一条连接并行跑多个请求,队头阻塞大幅缓解。
✗ 错
3. 删除资源用 GET /api/delete?id=7 也能实现,无所谓?
GET 不得有副作用 —— 重试、预取、爬虫、浏览器预热都会"误删"。删除就用 DELETE。
✗ 别这么干
02
Part 02

REST:资源思维

URL 是名词,方法是动词,状态码是结论

URL = 资源 方法 = 操作 状态码 = 结果
Part 02 · REST 资源思维

从"动词接口"到"资源接口"

每点一次,看一次重构

动词式 · 不推荐
GET /api/getUser?id=1
POST /api/deleteUser
GET /api/getOrderList?type=a
每个动作造一个 URL —— 缓存、权限、监控都没法统一治理。
资源式 · REST
GET /users/1
DELETE /users/1
GET /orders?type=a
资源靠 URL 标识、操作靠方法表达、结果靠状态码表达 —— 三件事各归其位。
进阶
REST 还有更高阶约束(HATEOAS 等),企业落地先做到前两条:资源化 URL + 方法语义,就已经领先大多数团队。
Part 02 · REST 资源思维

AI 能力的资源化设计

POST /documents/{id}/summarize
文档摘要 —— 动作型子资源:资源是 documents,摘要是它的一个动作,POST 合理。
GET /orders/{id}/risk
订单风险评分 —— 只读计算:幂等、可缓存,网关还能给它单独配限流。
POST /embeddings
向量化 —— OpenAI 风格已成事实标准:批量文本进,向量数组出。
GET /healthz
健康检查 —— Compose / K8s 探针就打这里,昨天 HEALTHCHECK 已经在用。
把 AI 能力当资源来设计,而不是当函数来暴露 —— 资源可以被缓存、限流、授权、审计。
互动 · 找茬游戏

这些 API 设计合格吗?

先心里给个判断,再点击揭晓

GET /api/getUser?id=1 URL 动词化 —— 资源是名词:GET /users/1
POST /documents/42/summarize 动作型子资源 + POST,语义清楚
200 + body 里写 code: 500 内部错误 状态码失真 —— 监控、熔断、网关全部失灵
DELETE /orders/7 幂等删除,重试安全
GET /search?keyword=invoices&limit=50 查询用 GET,可缓存可收藏;大参数才考虑 POST /search
POST /deleteUser body 传 id: 1 删除用 DELETE;POST /deleteX 无法统一治理
03
Part 03

FastAPI:类型即文档

类型声明 = 参数校验 = 自动文档

FastAPI 类型注解 Pydantic 校验 OpenAPI / Swagger
Part 03 · FastAPI

十五行起一个 AI 服务

from fastapi import FastAPI app = FastAPI(title="Day06 Demo") @app.get("/healthz") def healthz(): return {"status": "ok"} @app.get("/sum/{a}/{b}") def sum_two(a: int, b: int): return {"a": a, "b": b, "sum": a + b}
跑起来
uvicorn app:app --reload --port 8000 —— 热重载开发,生产换多 worker。
免费得到两份文档
/docs(Swagger UI,能直接试调)与 /redoc —— 由 OpenAPI Schema 自动生成。
核心思想
基于 Starlette + Pydantic:类型注解同时驱动参数校验、序列化、文档 —— 写一处,三处生效。
Part 03 · FastAPI

Pydantic:把校验写进类型里

from pydantic import BaseModel, Field class SummarizeIn(BaseModel): text: str = Field(min_length=1, max_length=8000) max_len: int = Field(default=100, ge=20, le=500) lang: str = "zh" @app.post("/summarize") def summarize(req: SummarizeIn): return { "summary": req.text[: req.max_len], "lang": req.lang, }
自动 422
传错类型、超长、缺字段 → FastAPI 返回 422 + 哪个字段、什么原因 —— 不用自己写 if。
文档同步升级
模型一改,/docs 的请求示例与校验说明自动更新 —— 文档永远不会过期。
别裸奔
裸 dict 收参 + 手工 if 校验 = 漏洞温床;复杂业务失败与参数校验失败要用不同状态码区分。
Part 03 · FastAPI

async 的坑:别阻塞事件循环

@app.get("/bad") async def bad(): # ✗ 同步 requests 卡住 # 整个事件循环 r = requests.get(url, timeout=5) return r.json()
@app.get("/good") async def good(): # ✓ 异步等待,不占线程 async with httpx.AsyncClient() as c: r = await c.get(url, timeout=5) return r.json()
规则
async def 里不许调同步阻塞库(requests、time.sleep、CPU 密集推理)—— 要么改用异步库,要么把端点写成普通 def(自动进线程池)。
部署
生产用 gunicorn -k uvicorn.workers.UvicornWorker -w 4 多进程;再大的并发靠副本数与网关限流。
实操 ② · 12 分钟 · 两人一组

写一个 mock AI 服务

1进入 day04-lab,新建 api.py/healthz + /summarize(Pydantic:text 1-8000 字,max_len 20-500)
2pip install fastapi uvicornuvicorn api:app --reload
3浏览器打开 http://127.0.0.1:8000/docs —— 在 Swagger 里直接试调
4故意传错:max_len 传 99999、text 传空 —— 观察 422 明细
5curl 复查:curl -i -X POST .../summarize -H "Content-Type: application/json" -d "{\"text\":\"...\"}"
12:00
验收标准
/healthz 返回 200
非法参数得到 422 + 字段明细
/docs 里能看到请求示例

卡住就举手 —— 实操环节助教会巡场

04
Part 04

企业集成实践

从"能跑"到"能接进企业系统"

Docker 统一错误 超时与重试 全链路日志
Part 04 · 企业集成实践

一次 AI 调用的完整链路

每点一次,多一跳 —— 企业里没有"直连"

Client
浏览器 / 上游系统
Nginx / Ingress
TLS 终结 · 限流 · gzip
FastAPI
校验 · 业务 · 422
Model / DB
Volume 挂载 · 超时保护
每一跳都带 X-Correlation-Id:出了问题,拿着这把钥匙从网关日志一路查到模型日志 —— 五分钟定位,而不是五小时。
Part 04 · 企业集成实践

契约三件套:错误 · 分页 · 版本

统一错误体
{ "error": { "code": "DOC_NOT_FOUND", "message": "…", "details": [] } }
配对的状态码说真话:404 就是 404。
分页约定
GET /documents?limit=50&offset=100 → { "items": [...], "total": 321 }
列表必有上限 —— 防一次拉全表拖垮服务。
版本化
/v1/summarize · /v2/summarize
破坏性改动升版本,旧版给下线窗口 —— 接口一旦发布就是契约。
为什么较真
企业系统间的集成靠契约运转:错误体统一,上游才能统一告警;分页有上限,网关才能限流;版本清晰,迁移才有路线图。
Part 04 · 企业集成实践

超时、重试与限流:稳字三件套

客户端:永远设 timeout
连接 + 读取超时必设。没有超时的调用 = 没有下限的等待,下游一卡全线拖死。
重试:只重试幂等请求
指数退避 + 随机抖动,带上限;POST 下单类操作用幂等键,否则重试 = 重复扣款。
服务端:限流与背压
超限返回 429 + Retry-After;AI 推理类大任务改异步:202 受理 + 任务状态查询。
连锁失效
没超时 → 线程挂满 → 重试风暴 → 雪崩。稳字三件套是系统自保的免疫系统,不是可选项。
Part 04 · 企业集成实践

CorrelationId + 结构化日志

一把钥匙串全程
入口取/生成 X-Correlation-Id,写进每条日志、透传给每个下游调用。
日志是 JSON,不是散文
ts / level / msg / corr_id / latency_ms —— 机器可检索,阶段 1 底线之一。
别打印密钥
呼应 Day 5:日志里打印完整环境变量 = 密钥泄漏,脱敏是底线。
{ "ts": "2026-09-08T10:21:03Z", "level": "INFO", "msg": "summarize done", "corr_id": "f3a9-c2e1", "latency_ms": 412, "tokens": 421 }
自查一下
corr_id 去日志平台一搜,这条请求经过的每一跳全部出场 —— 这才是"可观测"。
实操 ③ · 15 分钟 · 综合演练

给容器装上门牌号

1在 day04-lab 新建 api.py/healthz + /summarize(复用实操②的代码与 Pydantic 模型)
2Dockerfile 改启动命令:CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"],加 EXPOSE 8000
3requirements.txt 补 fastapiuvicorn(锁版本)
4compose.yaml 给服务加 ports: ["8080:8000"]docker compose up -d --build
5验收:curl http://localhost:8080/healthz → 浏览器开 /docs → 传错参数看 422
15:00
验收清单
/healthz 从宿主机 8080 可达
/docs 可打开并试调成功
非法参数返回 422 明细
docker logs 能看到 JSON 日志

卡住就举手 —— 实操环节助教会巡场

Part 04 · 企业集成实践 · 互动讨论

三大血泪坑

1
调用 AI 服务不设超时
下游一卡,线程挂满,整条链路雪崩 —— timeout 是必选项。
2
接口不分版本,v1/v2 混在一个路径里改
客户端升级即爆炸 —— 契约变更必须走版本。
3
async def 里调同步 requests
事件循环被阻塞,QPS 掉一个数量级 —— 用 httpx 或普通 def。
课堂讨论 · 2 分钟
为了"兼容",新接口所有情况都返 200,body 里用 code 区分成功失败 —— 这样最稳吗?
答案:最不稳
监控全绿、熔断失灵、网关重试失误 —— 全链路都在"猜"。状态码说真话,错误体说细节,两者各司其职。
总结

今天你带走了什么

原理
HTTP 无状态:请求-响应各带全部信息
原理
报文 = Method+URL+Header+Body / Status
原理
GET 幂等可缓存,POST 承担副作用
原理
状态码 = 结论:2xx/4xx/5xx 严格分家
规范
REST:URL 名词 · 方法动词 · 拒绝动词化
规范
统一错误体 + 分页上限 + /v1 版本化
规范
Pydantic 前置校验,非法参数止步 422
规范
timeout 必设,重试只给幂等请求
集成
FastAPI 装进容器,healthz 对接探针
集成
/docs 即契约:联调先看 OpenAPI
集成
CorrelationId + JSON 日志贯穿全链路
心法
先看 /docs 再写代码,先说状态码再说业务
"API 不是把函数挂到网上,而是对同行的一份承诺。"
课后作业 · 明日预告

今天到此,服务起步

作业 1 · 契约加固
给 /summarize 补齐统一错误体(404 / 422 场景)与分页参数 limit 上限。
作业 2 · 文档
README 增加"curl 三步调用"与 /docs 链接 —— 呼应"新人一天跑通"。
作业 3 · 阅读
FastAPI 官方教程前四章:fastapi.tiangolo.com/zh/tutorial/;MDN HTTP Overview。
明日预告 · Day 07
大语言模型工程基础
服务有了门牌号,明天让"大脑"上车 —— LLM 工程里最重要的输入、输出、随机性、上下文与幻觉。

谢谢 · Q&A —— 实操问题随时在群里 @ 包学斌

Day 06 · HTTP、REST API 与 FastAPI · 包学斌
1 / 28