👋 我是 Yulia,一线 AI 应用开发工程师:4 年工程经验,在职做大模型应用落地。
只写一件事------把最新 AI 技术讲成人话 + 给你能直接上手用的代码 (真实可验证,不搬运不注水)。
有用就点个 关注,持续更新大模型应用的前沿实战。
📚 本文是《后端开发从入门到靠谱》系列第 7 篇。第五课选定了主线语言 Python + FastAPI,第六课学完了 Python 语法------这一篇正式用 FastAPI 写出你的第一个 API 接口。整个系列共 20 篇,从 0 基础一路到能独立写生产级后端。关注我,不错过后续内容。
上一课学完了 Python 语法,但语法只是"会写字",离"写出一套能用的后端"还差一步------框架。框架就是一套现成的骨架,帮你处理掉那些又繁琐又容易出错的事(解析请求、校验参数、返回 JSON),让你专心写业务。
这一课,我们用 Python 生态里目前最火的 Web 框架 FastAPI,从 0 写出第一个 API 接口,最后拼成一个能接大模型的「AI 问答接口」------直接把路铺到 AI 应用后端。
读完你会拿到:
- 一个直觉模型:API 是什么、HTTP 请求/响应长什么样(餐厅点餐类比,0 基础秒懂)
- 为什么 FastAPI 又快又好用(底层 ASGI 异步 + 类型注解自动校验,讲到原理)
- 第一个能跑的 Hello World 接口(完整代码 + 逐行讲解)
- 路由、参数、请求体、自动文档四大核心(每项都下沉到"它内部怎么转")
- 异步并发的底层逻辑(为什么 FastAPI 能扛高并发)
- 一个完整的 AI 问答接口小项目(衔接大模型应用)
先看全景图,建立全局认知:
#mermaid-svg-enuVM5ULadxHWCH0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-enuVM5ULadxHWCH0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-enuVM5ULadxHWCH0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-enuVM5ULadxHWCH0 .error-icon{fill:#552222;}#mermaid-svg-enuVM5ULadxHWCH0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-enuVM5ULadxHWCH0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-enuVM5ULadxHWCH0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-enuVM5ULadxHWCH0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-enuVM5ULadxHWCH0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-enuVM5ULadxHWCH0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-enuVM5ULadxHWCH0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-enuVM5ULadxHWCH0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-enuVM5ULadxHWCH0 .marker.cross{stroke:#333333;}#mermaid-svg-enuVM5ULadxHWCH0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-enuVM5ULadxHWCH0 p{margin:0;}#mermaid-svg-enuVM5ULadxHWCH0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-enuVM5ULadxHWCH0 .cluster-label text{fill:#333;}#mermaid-svg-enuVM5ULadxHWCH0 .cluster-label span{color:#333;}#mermaid-svg-enuVM5ULadxHWCH0 .cluster-label span p{background-color:transparent;}#mermaid-svg-enuVM5ULadxHWCH0 .label text,#mermaid-svg-enuVM5ULadxHWCH0 span{fill:#333;color:#333;}#mermaid-svg-enuVM5ULadxHWCH0 .node rect,#mermaid-svg-enuVM5ULadxHWCH0 .node circle,#mermaid-svg-enuVM5ULadxHWCH0 .node ellipse,#mermaid-svg-enuVM5ULadxHWCH0 .node polygon,#mermaid-svg-enuVM5ULadxHWCH0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-enuVM5ULadxHWCH0 .rough-node .label text,#mermaid-svg-enuVM5ULadxHWCH0 .node .label text,#mermaid-svg-enuVM5ULadxHWCH0 .image-shape .label,#mermaid-svg-enuVM5ULadxHWCH0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-enuVM5ULadxHWCH0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-enuVM5ULadxHWCH0 .rough-node .label,#mermaid-svg-enuVM5ULadxHWCH0 .node .label,#mermaid-svg-enuVM5ULadxHWCH0 .image-shape .label,#mermaid-svg-enuVM5ULadxHWCH0 .icon-shape .label{text-align:center;}#mermaid-svg-enuVM5ULadxHWCH0 .node.clickable{cursor:pointer;}#mermaid-svg-enuVM5ULadxHWCH0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-enuVM5ULadxHWCH0 .arrowheadPath{fill:#333333;}#mermaid-svg-enuVM5ULadxHWCH0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-enuVM5ULadxHWCH0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-enuVM5ULadxHWCH0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-enuVM5ULadxHWCH0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-enuVM5ULadxHWCH0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-enuVM5ULadxHWCH0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-enuVM5ULadxHWCH0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-enuVM5ULadxHWCH0 .cluster text{fill:#333;}#mermaid-svg-enuVM5ULadxHWCH0 .cluster span{color:#333;}#mermaid-svg-enuVM5ULadxHWCH0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-enuVM5ULadxHWCH0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-enuVM5ULadxHWCH0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-enuVM5ULadxHWCH0 .icon-shape,#mermaid-svg-enuVM5ULadxHWCH0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-enuVM5ULadxHWCH0 .icon-shape p,#mermaid-svg-enuVM5ULadxHWCH0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-enuVM5ULadxHWCH0 .icon-shape .label rect,#mermaid-svg-enuVM5ULadxHWCH0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-enuVM5ULadxHWCH0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-enuVM5ULadxHWCH0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-enuVM5ULadxHWCH0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-enuVM5ULadxHWCH0 .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .blue tspan{fill:#fff!important;}#mermaid-svg-enuVM5ULadxHWCH0 .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .orange tspan{fill:#fff!important;}#mermaid-svg-enuVM5ULadxHWCH0 .green>*{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .green span{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .green tspan{fill:#fff!important;}#mermaid-svg-enuVM5ULadxHWCH0 .red>*{fill:#E15759!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .red span{fill:#E15759!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .red tspan{fill:#fff!important;}#mermaid-svg-enuVM5ULadxHWCH0 .cyan>*{fill:#76B7B2!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .cyan span{fill:#76B7B2!important;color:#fff!important;stroke:none!important;}#mermaid-svg-enuVM5ULadxHWCH0 .cyan tspan{fill:#fff!important;} HTTP 请求
HTTP 响应
自动生成
底层引擎
客户端
路由匹配
Pydantic 校验
业务函数
响应序列化
交互文档
ASGI 异步
一、先搞懂:API 到底是什么?
学框架前,先搞懂它服务的对象------API。这个词你在 AI 圈天天听("调用 OpenAI 的 API"),但很多人说不清它到底是什么。
一句话人话:API 是"菜单"。 想象你去餐厅吃饭:
- 你是客户端(浏览器、App、另一段代码)
- 服务员就是 API------它不负责做菜,只负责"接单"和"上菜"
- 厨房是服务器------真正干活的地方
你不需要知道厨房里怎么炒菜,只要照着菜单 点单,就能拿到菜。API 就是这个"菜单":它定义了你能点什么(接口) 、怎么点(请求格式) 、会得到什么(响应格式)。
#mermaid-svg-sAgOhIyNMqiIGkq2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sAgOhIyNMqiIGkq2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sAgOhIyNMqiIGkq2 .error-icon{fill:#552222;}#mermaid-svg-sAgOhIyNMqiIGkq2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sAgOhIyNMqiIGkq2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sAgOhIyNMqiIGkq2 .marker.cross{stroke:#333333;}#mermaid-svg-sAgOhIyNMqiIGkq2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sAgOhIyNMqiIGkq2 p{margin:0;}#mermaid-svg-sAgOhIyNMqiIGkq2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sAgOhIyNMqiIGkq2 .cluster-label text{fill:#333;}#mermaid-svg-sAgOhIyNMqiIGkq2 .cluster-label span{color:#333;}#mermaid-svg-sAgOhIyNMqiIGkq2 .cluster-label span p{background-color:transparent;}#mermaid-svg-sAgOhIyNMqiIGkq2 .label text,#mermaid-svg-sAgOhIyNMqiIGkq2 span{fill:#333;color:#333;}#mermaid-svg-sAgOhIyNMqiIGkq2 .node rect,#mermaid-svg-sAgOhIyNMqiIGkq2 .node circle,#mermaid-svg-sAgOhIyNMqiIGkq2 .node ellipse,#mermaid-svg-sAgOhIyNMqiIGkq2 .node polygon,#mermaid-svg-sAgOhIyNMqiIGkq2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sAgOhIyNMqiIGkq2 .rough-node .label text,#mermaid-svg-sAgOhIyNMqiIGkq2 .node .label text,#mermaid-svg-sAgOhIyNMqiIGkq2 .image-shape .label,#mermaid-svg-sAgOhIyNMqiIGkq2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-sAgOhIyNMqiIGkq2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sAgOhIyNMqiIGkq2 .rough-node .label,#mermaid-svg-sAgOhIyNMqiIGkq2 .node .label,#mermaid-svg-sAgOhIyNMqiIGkq2 .image-shape .label,#mermaid-svg-sAgOhIyNMqiIGkq2 .icon-shape .label{text-align:center;}#mermaid-svg-sAgOhIyNMqiIGkq2 .node.clickable{cursor:pointer;}#mermaid-svg-sAgOhIyNMqiIGkq2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sAgOhIyNMqiIGkq2 .arrowheadPath{fill:#333333;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sAgOhIyNMqiIGkq2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sAgOhIyNMqiIGkq2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sAgOhIyNMqiIGkq2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sAgOhIyNMqiIGkq2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sAgOhIyNMqiIGkq2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sAgOhIyNMqiIGkq2 .cluster text{fill:#333;}#mermaid-svg-sAgOhIyNMqiIGkq2 .cluster span{color:#333;}#mermaid-svg-sAgOhIyNMqiIGkq2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sAgOhIyNMqiIGkq2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sAgOhIyNMqiIGkq2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-sAgOhIyNMqiIGkq2 .icon-shape,#mermaid-svg-sAgOhIyNMqiIGkq2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sAgOhIyNMqiIGkq2 .icon-shape p,#mermaid-svg-sAgOhIyNMqiIGkq2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sAgOhIyNMqiIGkq2 .icon-shape .label rect,#mermaid-svg-sAgOhIyNMqiIGkq2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sAgOhIyNMqiIGkq2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sAgOhIyNMqiIGkq2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sAgOhIyNMqiIGkq2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-sAgOhIyNMqiIGkq2 .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-sAgOhIyNMqiIGkq2 .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-sAgOhIyNMqiIGkq2 .blue tspan{fill:#fff!important;}#mermaid-svg-sAgOhIyNMqiIGkq2 .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-sAgOhIyNMqiIGkq2 .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-sAgOhIyNMqiIGkq2 .orange tspan{fill:#fff!important;}#mermaid-svg-sAgOhIyNMqiIGkq2 .green>*{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-sAgOhIyNMqiIGkq2 .green span{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-sAgOhIyNMqiIGkq2 .green tspan{fill:#fff!important;} 点菜 请求
下单
做好的菜 响应
上菜
顾客 客户端
服务员 API
厨房 服务器
1.1 客户端和服务端怎么"对话"?------ HTTP
客户端和服务端之间说的话,有一套固定格式,叫 HTTP 协议。一段对话分两半:
#mermaid-svg-eXheeKlUyqpYGeZN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eXheeKlUyqpYGeZN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eXheeKlUyqpYGeZN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eXheeKlUyqpYGeZN .error-icon{fill:#552222;}#mermaid-svg-eXheeKlUyqpYGeZN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eXheeKlUyqpYGeZN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eXheeKlUyqpYGeZN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eXheeKlUyqpYGeZN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eXheeKlUyqpYGeZN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eXheeKlUyqpYGeZN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eXheeKlUyqpYGeZN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eXheeKlUyqpYGeZN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eXheeKlUyqpYGeZN .marker.cross{stroke:#333333;}#mermaid-svg-eXheeKlUyqpYGeZN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eXheeKlUyqpYGeZN p{margin:0;}#mermaid-svg-eXheeKlUyqpYGeZN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eXheeKlUyqpYGeZN .cluster-label text{fill:#333;}#mermaid-svg-eXheeKlUyqpYGeZN .cluster-label span{color:#333;}#mermaid-svg-eXheeKlUyqpYGeZN .cluster-label span p{background-color:transparent;}#mermaid-svg-eXheeKlUyqpYGeZN .label text,#mermaid-svg-eXheeKlUyqpYGeZN span{fill:#333;color:#333;}#mermaid-svg-eXheeKlUyqpYGeZN .node rect,#mermaid-svg-eXheeKlUyqpYGeZN .node circle,#mermaid-svg-eXheeKlUyqpYGeZN .node ellipse,#mermaid-svg-eXheeKlUyqpYGeZN .node polygon,#mermaid-svg-eXheeKlUyqpYGeZN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eXheeKlUyqpYGeZN .rough-node .label text,#mermaid-svg-eXheeKlUyqpYGeZN .node .label text,#mermaid-svg-eXheeKlUyqpYGeZN .image-shape .label,#mermaid-svg-eXheeKlUyqpYGeZN .icon-shape .label{text-anchor:middle;}#mermaid-svg-eXheeKlUyqpYGeZN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eXheeKlUyqpYGeZN .rough-node .label,#mermaid-svg-eXheeKlUyqpYGeZN .node .label,#mermaid-svg-eXheeKlUyqpYGeZN .image-shape .label,#mermaid-svg-eXheeKlUyqpYGeZN .icon-shape .label{text-align:center;}#mermaid-svg-eXheeKlUyqpYGeZN .node.clickable{cursor:pointer;}#mermaid-svg-eXheeKlUyqpYGeZN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eXheeKlUyqpYGeZN .arrowheadPath{fill:#333333;}#mermaid-svg-eXheeKlUyqpYGeZN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eXheeKlUyqpYGeZN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eXheeKlUyqpYGeZN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eXheeKlUyqpYGeZN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eXheeKlUyqpYGeZN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eXheeKlUyqpYGeZN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eXheeKlUyqpYGeZN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eXheeKlUyqpYGeZN .cluster text{fill:#333;}#mermaid-svg-eXheeKlUyqpYGeZN .cluster span{color:#333;}#mermaid-svg-eXheeKlUyqpYGeZN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eXheeKlUyqpYGeZN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eXheeKlUyqpYGeZN rect.text{fill:none;stroke-width:0;}#mermaid-svg-eXheeKlUyqpYGeZN .icon-shape,#mermaid-svg-eXheeKlUyqpYGeZN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eXheeKlUyqpYGeZN .icon-shape p,#mermaid-svg-eXheeKlUyqpYGeZN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eXheeKlUyqpYGeZN .icon-shape .label rect,#mermaid-svg-eXheeKlUyqpYGeZN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eXheeKlUyqpYGeZN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eXheeKlUyqpYGeZN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eXheeKlUyqpYGeZN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-eXheeKlUyqpYGeZN .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-eXheeKlUyqpYGeZN .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-eXheeKlUyqpYGeZN .blue tspan{fill:#fff!important;}#mermaid-svg-eXheeKlUyqpYGeZN .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-eXheeKlUyqpYGeZN .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-eXheeKlUyqpYGeZN .orange tspan{fill:#fff!important;} 请求 Request
方法 如 GET/POST
路径 如 /users
参数 如 query/body
响应 Response
状态码 如 200/404
数据 如 JSON
- 请求(Request) :你点单,包含三要素------方法 (干什么:
GET查、POST增、PUT改、DELETE删)、路径 (对哪个资源操作)、参数(具体细节)。 - 响应(Response) :厨房上菜,包含两要素------状态码 (
200成功、404没找到、422参数错)、数据(一般是 JSON 格式)。
JSON 是什么 :一种"键值对"的数据格式,人和机器都读得懂。Python 的字典几乎能无缝转成 JSON,这就是 Python 做后端特别顺的原因之一。
{"name": "Yulia", "age": 25}既是 Python 字典,也是合法的 JSON。
1.2 REST 风格:把"资源"组织成路径
FastAPI 默认按 REST 风格组织接口,核心就一条:用"名词"当路径,用"HTTP 方法"当动词。
| 想做的事 | 方法 | 路径 | 含义 |
|---|---|---|---|
| 查用户列表 | GET | /users |
获取用户集合 |
| 查某个用户 | GET | /users/123 |
获取 id=123 的用户 |
| 新建用户 | POST | /users |
创建一个用户 |
| 改用户 | PUT | /users/123 |
更新 id=123 |
| 删用户 | DELETE | /users/123 |
删除 id=123 |
路径里的 123 是路径参数,动态变化。这套"名词 + 动词"的约定,让接口一眼看懂,也是团队协作的基础。
二、为什么是 FastAPI?它到底快在哪
Python 能做 Web 的框架很多:老牌 Flask (轻量简单)、Django (大而全)、新兴 FastAPI(现代异步)。为什么我们选 FastAPI?
| 框架 | 风格 | 类型校验 | 自动文档 | 异步 | 适合 |
|---|---|---|---|---|---|
| Flask | 极简 | 无 | 无 | 需插件 | 小工具、快速原型 |
| Django | 全家桶 | 有 | 需配置 | 支持 | 大型网站(自带后台/ORM) |
| FastAPI | 现代 | 原生 | 原生 | 原生 | AI 应用后端、高并发 API |
FastAPI 的两个"灵魂级"卖点,都不是表面功能,而是底层设计:
- 类型注解驱动一切 ------你写一个
def f(x: int),FastAPI 就自动帮你做参数校验、自动生成文档。这在 Flask 里要手写一堆代码。 - 原生异步(ASGI) ------底层用
asyncio事件循环,一个进程能同时处理成千上万个请求,特别适合 AI 应用这种"大量 IO 等待"的场景(调大模型接口要等几秒,这段时间能服务别的请求)。
为什么 AI 应用尤其适合 FastAPI:AI 后端的特点是"计算不在本地"------你只是把请求转发给大模型 API,然后等它返回。这个"等"的过程里 CPU 是闲的。同步框架会让线程干等着,FastAPI 的异步能在这段时间去处理别人的请求,所以同样一台机器能扛更多并发。
三、第一个接口:Hello World
先装依赖(两条命令,装完就能用,不用懂内部):
bash
pip install fastapi uvicorn
fastapi:框架本体uvicorn:跑 FastAPI 的"引擎"(ASGI 服务器,负责接收网络请求、调度你的代码)
写一个 main.py:
python
from fastapi import FastAPI
app = FastAPI() # 创建一个应用实例,这就是整个服务的入口
@app.get("/") # 装饰器:把下面的函数绑定到 GET / 这个路径
def read_root():
return {"message": "Hello World"} # 返回一个字典,FastAPI 自动转成 JSON
逐行讲清三件事:
app = FastAPI()------app就是你的整个 Web 应用,后面所有接口都挂在它身上。@app.get("/")------这是 Python 的装饰器 (第六课讲过:装饰器就是"给函数加一层包装")。这里的意思是:当有人用 GET 方法访问根路径/时,就调用下面的read_root函数。return {"message": "Hello World"}------你只管返回 Python 字典,FastAPI 自动帮你序列化成 JSON 字符串发出去。
启动它(在 main.py 同目录下运行):
bash
uvicorn main:app --reload
main:app 的意思是"找 main.py 里的 app 对象",--reload 是"代码改了自动重启"。启动后访问 http://127.0.0.1:8000,浏览器会显示:
json
{"message": "Hello World"}
再访问 http://127.0.0.1:8000/docs,你会看到一张自动生成的可交互 API 文档------这就是 FastAPI 的杀手锏,下一节展开。
四、路由与参数:让接口"能办事"
Hello World 只返回死数据,真正的接口要接收输入。FastAPI 支持三类参数,覆盖 90% 的场景:
#mermaid-svg-BNQuYHFCZAtK7iie{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BNQuYHFCZAtK7iie .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BNQuYHFCZAtK7iie .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BNQuYHFCZAtK7iie .error-icon{fill:#552222;}#mermaid-svg-BNQuYHFCZAtK7iie .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BNQuYHFCZAtK7iie .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BNQuYHFCZAtK7iie .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BNQuYHFCZAtK7iie .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BNQuYHFCZAtK7iie .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BNQuYHFCZAtK7iie .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BNQuYHFCZAtK7iie .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BNQuYHFCZAtK7iie .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BNQuYHFCZAtK7iie .marker.cross{stroke:#333333;}#mermaid-svg-BNQuYHFCZAtK7iie svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BNQuYHFCZAtK7iie p{margin:0;}#mermaid-svg-BNQuYHFCZAtK7iie .edge{stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .section--1 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section--1 path,#mermaid-svg-BNQuYHFCZAtK7iie .section--1 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section--1 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section--1 text{fill:#ffffff;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth--1{stroke-width:17;}#mermaid-svg-BNQuYHFCZAtK7iie .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-0 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-0 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-0 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-0 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-0 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-0{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-0{stroke-width:14;}#mermaid-svg-BNQuYHFCZAtK7iie .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-1 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-1 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-1 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-1 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-1 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-1{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-1{stroke-width:11;}#mermaid-svg-BNQuYHFCZAtK7iie .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-2 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-2 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-2 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-2 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-2 text{fill:#ffffff;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-2{stroke-width:8;}#mermaid-svg-BNQuYHFCZAtK7iie .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-3 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-3 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-3 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-3 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-3 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-3{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-3{stroke-width:5;}#mermaid-svg-BNQuYHFCZAtK7iie .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-4 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-4 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-4 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-4 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-4 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-4{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-4{stroke-width:2;}#mermaid-svg-BNQuYHFCZAtK7iie .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-5 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-5 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-5 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-5 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-5 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-5{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-5{stroke-width:-1;}#mermaid-svg-BNQuYHFCZAtK7iie .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-6 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-6 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-6 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-6 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-6 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-6{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-6{stroke-width:-4;}#mermaid-svg-BNQuYHFCZAtK7iie .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-7 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-7 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-7 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-7 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-7 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-7{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-7{stroke-width:-7;}#mermaid-svg-BNQuYHFCZAtK7iie .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-8 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-8 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-8 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-8 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-8 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-8{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-8{stroke-width:-10;}#mermaid-svg-BNQuYHFCZAtK7iie .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-9 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-9 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-9 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-9 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-9 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-9{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-9{stroke-width:-13;}#mermaid-svg-BNQuYHFCZAtK7iie .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-10 rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-10 path,#mermaid-svg-BNQuYHFCZAtK7iie .section-10 circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-10 polygon,#mermaid-svg-BNQuYHFCZAtK7iie .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-10 text{fill:black;}#mermaid-svg-BNQuYHFCZAtK7iie .node-icon-10{font-size:40px;color:black;}#mermaid-svg-BNQuYHFCZAtK7iie .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .edge-depth-10{stroke-width:-16;}#mermaid-svg-BNQuYHFCZAtK7iie .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled,#mermaid-svg-BNQuYHFCZAtK7iie .disabled circle,#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:lightgray;}#mermaid-svg-BNQuYHFCZAtK7iie .disabled text{fill:#efefef;}#mermaid-svg-BNQuYHFCZAtK7iie .section-root rect,#mermaid-svg-BNQuYHFCZAtK7iie .section-root path,#mermaid-svg-BNQuYHFCZAtK7iie .section-root circle,#mermaid-svg-BNQuYHFCZAtK7iie .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-BNQuYHFCZAtK7iie .section-root text{fill:#ffffff;}#mermaid-svg-BNQuYHFCZAtK7iie .section-root span{color:#ffffff;}#mermaid-svg-BNQuYHFCZAtK7iie .section-2 span{color:#ffffff;}#mermaid-svg-BNQuYHFCZAtK7iie .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-BNQuYHFCZAtK7iie .edge{fill:none;}#mermaid-svg-BNQuYHFCZAtK7iie .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-BNQuYHFCZAtK7iie :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} FastAPI 参数
路径参数
写在 URL 路径里
查询参数
写在问号后面
请求体
POST 提交 JSON
请求头
放鉴权信息
4.1 路径参数(放在 URL 里)
python
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
访问 /items/42,item_id 就是 42。注意 item_id: int 这个类型注解------如果你访问 /items/abc,FastAPI 会直接返回 422 错误 ,而不是把 "abc" 当字符串传给你。这就是"类型注解驱动"的第一次体现:声明即校验。
4.2 查询参数(URL 问号后面)
python
@app.get("/users")
def list_users(name: str = None, page: int = 1):
return {"name": name, "page": page}
访问 /users?name=Yulia&page=2,函数就拿到 name="Yulia", page=2。name: str = None 里的 None 是默认值 ------不给 name 也不报错;page: int = 1 表示不给就默认第 1 页。
区别记法:路径参数 是"资源的一部分"(
/users/42,42 是哪个用户);查询参数 是"筛选条件"(/users?age=20,20 岁是条件)。一个在路径里,一个在问号后。
4.3 请求体(POST 提交的 JSON,重点)
查询参数只适合"少量简单数据",提交一整个对象(比如一个用户的信息)要用请求体 。这里 FastAPI 引入了 Pydantic:
python
from pydantic import BaseModel
class Item(BaseModel): # 定义一个数据模型
name: str
price: float
is_offer: bool = None # 有默认值 = 可选字段
@app.post("/items/")
def create_item(item: Item): # 声明参数类型为 Item,FastAPI 自动解析+校验
return {"name": item.name, "price": item.price}
这段代码的精髓在于 item: Item 这一句------你什么都没写校验逻辑,但 FastAPI 已经帮你做了三件事:
- 把请求体里的 JSON 自动转成
Item对象; - 校验字段类型(
price传了字符串?直接 422 拒绝); - 缺了
name这个必填字段?也 422 拒绝。
#mermaid-svg-a285lIhLmznZwmno{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a285lIhLmznZwmno .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a285lIhLmznZwmno .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a285lIhLmznZwmno .error-icon{fill:#552222;}#mermaid-svg-a285lIhLmznZwmno .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-a285lIhLmznZwmno .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a285lIhLmznZwmno .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a285lIhLmznZwmno .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a285lIhLmznZwmno .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a285lIhLmznZwmno .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a285lIhLmznZwmno .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a285lIhLmznZwmno .marker{fill:#333333;stroke:#333333;}#mermaid-svg-a285lIhLmznZwmno .marker.cross{stroke:#333333;}#mermaid-svg-a285lIhLmznZwmno svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a285lIhLmznZwmno p{margin:0;}#mermaid-svg-a285lIhLmznZwmno .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-a285lIhLmznZwmno .cluster-label text{fill:#333;}#mermaid-svg-a285lIhLmznZwmno .cluster-label span{color:#333;}#mermaid-svg-a285lIhLmznZwmno .cluster-label span p{background-color:transparent;}#mermaid-svg-a285lIhLmznZwmno .label text,#mermaid-svg-a285lIhLmznZwmno span{fill:#333;color:#333;}#mermaid-svg-a285lIhLmznZwmno .node rect,#mermaid-svg-a285lIhLmznZwmno .node circle,#mermaid-svg-a285lIhLmznZwmno .node ellipse,#mermaid-svg-a285lIhLmznZwmno .node polygon,#mermaid-svg-a285lIhLmznZwmno .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-a285lIhLmznZwmno .rough-node .label text,#mermaid-svg-a285lIhLmznZwmno .node .label text,#mermaid-svg-a285lIhLmznZwmno .image-shape .label,#mermaid-svg-a285lIhLmznZwmno .icon-shape .label{text-anchor:middle;}#mermaid-svg-a285lIhLmznZwmno .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-a285lIhLmznZwmno .rough-node .label,#mermaid-svg-a285lIhLmznZwmno .node .label,#mermaid-svg-a285lIhLmznZwmno .image-shape .label,#mermaid-svg-a285lIhLmznZwmno .icon-shape .label{text-align:center;}#mermaid-svg-a285lIhLmznZwmno .node.clickable{cursor:pointer;}#mermaid-svg-a285lIhLmznZwmno .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-a285lIhLmznZwmno .arrowheadPath{fill:#333333;}#mermaid-svg-a285lIhLmznZwmno .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-a285lIhLmznZwmno .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-a285lIhLmznZwmno .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a285lIhLmznZwmno .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-a285lIhLmznZwmno .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a285lIhLmznZwmno .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-a285lIhLmznZwmno .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-a285lIhLmznZwmno .cluster text{fill:#333;}#mermaid-svg-a285lIhLmznZwmno .cluster span{color:#333;}#mermaid-svg-a285lIhLmznZwmno div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-a285lIhLmznZwmno .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-a285lIhLmznZwmno rect.text{fill:none;stroke-width:0;}#mermaid-svg-a285lIhLmznZwmno .icon-shape,#mermaid-svg-a285lIhLmznZwmno .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a285lIhLmznZwmno .icon-shape p,#mermaid-svg-a285lIhLmznZwmno .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-a285lIhLmznZwmno .icon-shape .label rect,#mermaid-svg-a285lIhLmznZwmno .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a285lIhLmznZwmno .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-a285lIhLmznZwmno .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-a285lIhLmznZwmno :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-a285lIhLmznZwmno .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-a285lIhLmznZwmno .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-a285lIhLmznZwmno .blue tspan{fill:#fff!important;}#mermaid-svg-a285lIhLmznZwmno .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-a285lIhLmznZwmno .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-a285lIhLmznZwmno .orange tspan{fill:#fff!important;}#mermaid-svg-a285lIhLmznZwmno .green>*{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-a285lIhLmznZwmno .green span{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-a285lIhLmznZwmno .green tspan{fill:#fff!important;}#mermaid-svg-a285lIhLmznZwmno .red>*{fill:#E15759!important;color:#fff!important;stroke:none!important;}#mermaid-svg-a285lIhLmznZwmno .red span{fill:#E15759!important;color:#fff!important;stroke:none!important;}#mermaid-svg-a285lIhLmznZwmno .red tspan{fill:#fff!important;} 通过
失败
客户端发 JSON
FastAPI 接收
Pydantic 校验
转成 Python 对象
返回 422 错误
进入业务函数
五、Pydantic 到底做了什么?------ 类型注解的"魔法"拆解
上一节的 Item 能自动校验,底层原理值得搞懂,因为它贯穿 FastAPI 的一切。
5.1 类型注解本来只是"注释"
Python 3.5 引入了类型注解(type hints),但它本身不强制任何事:
python
def add(a: int, b: int) -> int:
return a + b
add("你", "好") # 不会报错!类型注解只是"提示",运行时照样执行
你写了 a: int,但传字符串进来,Python 根本不拦------因为 Python 是动态类型语言(第六课的核心结论)。
5.2 Pydantic 把注解"用起来"了
Pydantic 做的事,就是"读取你的类型注解,并在运行时真正执行校验"。
python
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
Item(name="苹果", price="3.5") # price 传了字符串 "3.5"
# Pydantic 会自动把它转成 float 3.5(能转就转,这叫"类型强制转换")
Item(name="苹果") # 缺了 price → 抛 ValidationError
它内部流程是:读字段的类型注解 → 对传入数据逐字段校验 → 能转就转("3.5" → 3.5)、不能转就报错 → 返回干净的 Python 对象 。所以你在业务函数里拿到的 item.price,永远是货真价实的 float,而不是"可能是字符串"。
5.3 为什么这很关键
传统 Web 框架里,请求数据进来都是"未经验证的原始数据",你得自己写一堆 if isinstance(...) 判断。Pydantic 把这块脏活全包了,你的业务代码只处理"已经被验证过、类型正确的数据"------代码更干净,也更不容易出 bug。这就是 FastAPI 敢说"少写代码"的底气。
六、自动交互文档:FastAPI 的杀手锏
启动服务后访问 /docs,你会看到一个可以在线点按钮测试接口 的页面(Swagger UI);访问 /redoc,是另一套更阅读友好的文档。
它不是 FastAPI"额外做"的功能,而是顺带生成的:
#mermaid-svg-gYHPCviXlx9kafxl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gYHPCviXlx9kafxl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gYHPCviXlx9kafxl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gYHPCviXlx9kafxl .error-icon{fill:#552222;}#mermaid-svg-gYHPCviXlx9kafxl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gYHPCviXlx9kafxl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gYHPCviXlx9kafxl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gYHPCviXlx9kafxl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gYHPCviXlx9kafxl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gYHPCviXlx9kafxl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gYHPCviXlx9kafxl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gYHPCviXlx9kafxl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gYHPCviXlx9kafxl .marker.cross{stroke:#333333;}#mermaid-svg-gYHPCviXlx9kafxl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gYHPCviXlx9kafxl p{margin:0;}#mermaid-svg-gYHPCviXlx9kafxl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gYHPCviXlx9kafxl .cluster-label text{fill:#333;}#mermaid-svg-gYHPCviXlx9kafxl .cluster-label span{color:#333;}#mermaid-svg-gYHPCviXlx9kafxl .cluster-label span p{background-color:transparent;}#mermaid-svg-gYHPCviXlx9kafxl .label text,#mermaid-svg-gYHPCviXlx9kafxl span{fill:#333;color:#333;}#mermaid-svg-gYHPCviXlx9kafxl .node rect,#mermaid-svg-gYHPCviXlx9kafxl .node circle,#mermaid-svg-gYHPCviXlx9kafxl .node ellipse,#mermaid-svg-gYHPCviXlx9kafxl .node polygon,#mermaid-svg-gYHPCviXlx9kafxl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gYHPCviXlx9kafxl .rough-node .label text,#mermaid-svg-gYHPCviXlx9kafxl .node .label text,#mermaid-svg-gYHPCviXlx9kafxl .image-shape .label,#mermaid-svg-gYHPCviXlx9kafxl .icon-shape .label{text-anchor:middle;}#mermaid-svg-gYHPCviXlx9kafxl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gYHPCviXlx9kafxl .rough-node .label,#mermaid-svg-gYHPCviXlx9kafxl .node .label,#mermaid-svg-gYHPCviXlx9kafxl .image-shape .label,#mermaid-svg-gYHPCviXlx9kafxl .icon-shape .label{text-align:center;}#mermaid-svg-gYHPCviXlx9kafxl .node.clickable{cursor:pointer;}#mermaid-svg-gYHPCviXlx9kafxl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gYHPCviXlx9kafxl .arrowheadPath{fill:#333333;}#mermaid-svg-gYHPCviXlx9kafxl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gYHPCviXlx9kafxl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gYHPCviXlx9kafxl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gYHPCviXlx9kafxl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gYHPCviXlx9kafxl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gYHPCviXlx9kafxl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gYHPCviXlx9kafxl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gYHPCviXlx9kafxl .cluster text{fill:#333;}#mermaid-svg-gYHPCviXlx9kafxl .cluster span{color:#333;}#mermaid-svg-gYHPCviXlx9kafxl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gYHPCviXlx9kafxl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gYHPCviXlx9kafxl rect.text{fill:none;stroke-width:0;}#mermaid-svg-gYHPCviXlx9kafxl .icon-shape,#mermaid-svg-gYHPCviXlx9kafxl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gYHPCviXlx9kafxl .icon-shape p,#mermaid-svg-gYHPCviXlx9kafxl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gYHPCviXlx9kafxl .icon-shape .label rect,#mermaid-svg-gYHPCviXlx9kafxl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gYHPCviXlx9kafxl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gYHPCviXlx9kafxl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gYHPCviXlx9kafxl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-gYHPCviXlx9kafxl .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-gYHPCviXlx9kafxl .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-gYHPCviXlx9kafxl .blue tspan{fill:#fff!important;}#mermaid-svg-gYHPCviXlx9kafxl .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-gYHPCviXlx9kafxl .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-gYHPCviXlx9kafxl .orange tspan{fill:#fff!important;}#mermaid-svg-gYHPCviXlx9kafxl .green>*{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-gYHPCviXlx9kafxl .green span{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-gYHPCviXlx9kafxl .green tspan{fill:#fff!important;} 代码里的类型注解
FastAPI 扫描
生成 OpenAPI 规范
Swagger UI /docs
ReDoc /redoc
因为你在每个接口都声明了参数类型,FastAPI 就能自动推断 出这个接口"要什么、返回什么",然后用 OpenAPI 规范(一种描述 API 的标准格式)记录下来,再渲染成网页。
这个文档的价值 :AI 应用后端里,前端同学、产品同学、甚至你自己过几天回来看,都能直接在 /docs 页面里看懂每个接口、直接测试,不用翻代码。它是"类型注解驱动"设计带来的最直观的回报。
七、异步与并发:FastAPI 快的底层逻辑
这是 FastAPI 最"硬核"、也最能体现深度的一节。我们由浅入深讲。
7.1 先说人话:一个人怎么同时做很多事
想象你在厨房煮面:水烧开要 5 分钟,这 5 分钟里你干等着 ,还是趁这时间切菜?
- 同步 = 干等:盯着锅,什么都不做,5 分钟后才开始切菜。
- 异步 = 切菜:开火烧水的同时,切菜、洗锅,水开了再回来下面。
事件循环(event loop) 就是那个"会管理碎片时间的人":它手上有几十个任务(请求),哪个任务在等 IO(等网络、等数据库、等大模型返回),它就把这个任务挂起、去处理别的任务,等 IO 完成了再回来继续。一个线程,就能并发处理海量请求。
7.2 传统同步框架为什么慢
Flask/Django 默认是同步 的:每个请求占一个线程,线程在处理请求时如果去等数据库/等大模型返回(IO 等待),这个线程就卡在那里干等,什么都干不了。请求一多,线程池被占满,新请求只能排队------这就是高并发下的性能瓶颈。
#mermaid-svg-oHuCsQfKXst0cs8x{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-oHuCsQfKXst0cs8x .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oHuCsQfKXst0cs8x .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oHuCsQfKXst0cs8x .error-icon{fill:#552222;}#mermaid-svg-oHuCsQfKXst0cs8x .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oHuCsQfKXst0cs8x .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oHuCsQfKXst0cs8x .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oHuCsQfKXst0cs8x .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oHuCsQfKXst0cs8x .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oHuCsQfKXst0cs8x .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oHuCsQfKXst0cs8x .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oHuCsQfKXst0cs8x .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oHuCsQfKXst0cs8x .marker.cross{stroke:#333333;}#mermaid-svg-oHuCsQfKXst0cs8x svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oHuCsQfKXst0cs8x p{margin:0;}#mermaid-svg-oHuCsQfKXst0cs8x .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-oHuCsQfKXst0cs8x .cluster-label text{fill:#333;}#mermaid-svg-oHuCsQfKXst0cs8x .cluster-label span{color:#333;}#mermaid-svg-oHuCsQfKXst0cs8x .cluster-label span p{background-color:transparent;}#mermaid-svg-oHuCsQfKXst0cs8x .label text,#mermaid-svg-oHuCsQfKXst0cs8x span{fill:#333;color:#333;}#mermaid-svg-oHuCsQfKXst0cs8x .node rect,#mermaid-svg-oHuCsQfKXst0cs8x .node circle,#mermaid-svg-oHuCsQfKXst0cs8x .node ellipse,#mermaid-svg-oHuCsQfKXst0cs8x .node polygon,#mermaid-svg-oHuCsQfKXst0cs8x .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oHuCsQfKXst0cs8x .rough-node .label text,#mermaid-svg-oHuCsQfKXst0cs8x .node .label text,#mermaid-svg-oHuCsQfKXst0cs8x .image-shape .label,#mermaid-svg-oHuCsQfKXst0cs8x .icon-shape .label{text-anchor:middle;}#mermaid-svg-oHuCsQfKXst0cs8x .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-oHuCsQfKXst0cs8x .rough-node .label,#mermaid-svg-oHuCsQfKXst0cs8x .node .label,#mermaid-svg-oHuCsQfKXst0cs8x .image-shape .label,#mermaid-svg-oHuCsQfKXst0cs8x .icon-shape .label{text-align:center;}#mermaid-svg-oHuCsQfKXst0cs8x .node.clickable{cursor:pointer;}#mermaid-svg-oHuCsQfKXst0cs8x .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-oHuCsQfKXst0cs8x .arrowheadPath{fill:#333333;}#mermaid-svg-oHuCsQfKXst0cs8x .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-oHuCsQfKXst0cs8x .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-oHuCsQfKXst0cs8x .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oHuCsQfKXst0cs8x .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oHuCsQfKXst0cs8x .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oHuCsQfKXst0cs8x .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-oHuCsQfKXst0cs8x .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-oHuCsQfKXst0cs8x .cluster text{fill:#333;}#mermaid-svg-oHuCsQfKXst0cs8x .cluster span{color:#333;}#mermaid-svg-oHuCsQfKXst0cs8x div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-oHuCsQfKXst0cs8x .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oHuCsQfKXst0cs8x rect.text{fill:none;stroke-width:0;}#mermaid-svg-oHuCsQfKXst0cs8x .icon-shape,#mermaid-svg-oHuCsQfKXst0cs8x .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oHuCsQfKXst0cs8x .icon-shape p,#mermaid-svg-oHuCsQfKXst0cs8x .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-oHuCsQfKXst0cs8x .icon-shape .label rect,#mermaid-svg-oHuCsQfKXst0cs8x .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oHuCsQfKXst0cs8x .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-oHuCsQfKXst0cs8x .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-oHuCsQfKXst0cs8x :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-oHuCsQfKXst0cs8x .blue>*{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-oHuCsQfKXst0cs8x .blue span{fill:#4E79A7!important;color:#fff!important;stroke:none!important;}#mermaid-svg-oHuCsQfKXst0cs8x .blue tspan{fill:#fff!important;}#mermaid-svg-oHuCsQfKXst0cs8x .orange>*{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-oHuCsQfKXst0cs8x .orange span{fill:#F28E2B!important;color:#fff!important;stroke:none!important;}#mermaid-svg-oHuCsQfKXst0cs8x .orange tspan{fill:#fff!important;}#mermaid-svg-oHuCsQfKXst0cs8x .green>*{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-oHuCsQfKXst0cs8x .green span{fill:#59A14F!important;color:#fff!important;stroke:none!important;}#mermaid-svg-oHuCsQfKXst0cs8x .green tspan{fill:#fff!important;} FastAPI 异步
事件循环
等待时切走 处理别的
同步框架
线程1 等数据库...
线程2 等大模型...
线程3 空转等待
7.3 在 FastAPI 里怎么写异步
FastAPI 里只要把函数定义成 async def,它就跑在事件循环里:
python
import asyncio
@app.get("/slow")
async def slow_endpoint():
await asyncio.sleep(2) # 模拟等 2 秒(比如等大模型返回)
return {"done": True}
关键点:
async def声明这是一个协程函数;await asyncio.sleep(2)里的await意思是"这里要等 2 秒,等的时候把我挂起,你先去处理别人"。
如果是普通 def,FastAPI 会把函数扔进线程池 跑(也能并发,但线程有开销、有上限);如果是 async def,就用轻量的协程跑,并发能力更强。规则:IO 密集(调接口、查数据库)用 async def,CPU 密集(算矩阵)用 def。
⚠️ 新手最常见的坑 :写了
async def,却在里面用了time.sleep()(同步阻塞)而不是await asyncio.sleep()。这会把整个事件循环卡死------一个人煮面时盯着锅发呆,后面所有人排队。异步函数里,凡是"等"的操作,都要用await的异步版本。
八、完整小项目:一个 AI 问答接口
把前面所有知识串起来,写一个能接大模型的「AI 问答接口」。这是 AI 应用后端的最小骨架:
python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Question(BaseModel): # 请求体:用户的问题
text: str # 必填:问题内容
model: str = "gpt-4o-mini" # 可选:用哪个模型,默认这个
class Answer(BaseModel): # 响应体:返回的答案
question: str
answer: str
@app.post("/ask", response_model=Answer)
async def ask(q: Question):
# 真实项目里,这里用 httpx/openai 的异步客户端调大模型 API:
# async with httpx.AsyncClient() as client:
# resp = await client.post("https://api.openai.com/...", json={...})
# answer = resp.json()["choices"][0]["message"]["content"]
answer = f"你问的是:{q.text}(真实项目里,这里会替换成大模型的回答)"
return {"question": q.text, "answer": answer}
逐行讲清设计思路:
Question/Answer两个 Pydantic 模型:用类型声明"接口的输入输出长什么样"------这正是 AI 应用后端的关键,让调用方一眼知道"我该传什么、会得到什么"。@app.post("/ask", response_model=Answer):response_model=Answer告诉 FastAPI,返回的数据要用Answer模型来校验和序列化------返回也受约束,不会把多余字段漏出去。async def ask(q: Question):异步函数 + 类型声明,q已经被 Pydantic 校验成干净的Question对象。- 注释里那三行是真实项目里调大模型的写法------用异步 的
httpx客户端发请求并await,这样等待大模型返回的几秒钟,事件循环能去服务其他用户。这就是 FastAPI 适合做 AI 后端的根本原因。
启动后,用 /docs 页面测试这个接口,或者在命令行:
bash
curl -X POST http://127.0.0.1:8000/ask \
-H "Content-Type: application/json" \
-d '{"text": "什么是 FastAPI?"}'
返回:
json
{"question": "什么是 FastAPI?", "answer": "你问的是:什么是 FastAPI?(真实项目里,这里会替换成大模型的回答)"}
这个最小骨架再往下走,就是接上真实的大模型 API、加数据库存对话历史、加鉴权------那些是后续文章的内容。
九、常见坑与避坑指南
| 坑 | 原因 | 解决方案 |
|---|---|---|
async def 里用 time.sleep() |
同步阻塞,卡死整个事件循环 | 换成 await asyncio.sleep();调外部用 httpx.AsyncClient |
路径参数声明 int 却传了字符串 |
类型注解驱动校验,/items/abc 匹配不了 int |
传数字,或参数类型改成 str |
忘写 response_model |
返回的数据不受约束,可能泄露内部字段 | 关键接口都声明 response_model |
| 动态路由和固定路由顺序错 | /users/me 可能被 /users/{id} 抢先匹配 |
固定路由写在前,动态路由写在后 |
| 前端调用报跨域 CORS 错误 | 浏览器同源策略,默认拒绝跨域请求 | 加 CORSMiddleware 中间件放行 |
| 启动报"找不到 app" | uvicorn main:app 的模块名/变量名写错 |
确认 main.py 文件名和 app = FastAPI() 的变量名一致 |
总结:一张图带走
这课的核心,一句话串起来:
- API 是菜单:客户端照着菜单(路径 + 方法)点单,服务端上菜(状态码 + JSON)。
- FastAPI 的灵魂是"类型注解驱动" :你声明
x: int、item: Item,它就自动帮你做校验、转类型、生成文档------少写大量脏活。 - Pydantic 是把注解"用起来"的那双手:运行时真正执行校验,业务代码只碰"已经干净的数据"。
- 异步 = 用等待的碎片时间干活 :
async def+await让一个进程扛住海量并发,特别适合"转发给大模型然后等结果"的 AI 后端。 - 最小 AI 后端 = FastAPI 路由 + Pydantic 模型 + 异步调大模型 :今天写的
/ask接口就是它的骨架。

三个立即可用的行动:
- 装
fastapi uvicorn,把第三到八节的代码全部亲手敲一遍(尤其第八节的 AI 问答接口); - 打开
/docs页面,把每个接口都点一遍,感受"自动文档 + 在线测试"; - 给第八节的
ask接口接上真实的大模型 API(用httpx.AsyncClient替换注释里的占位代码),你就有了自己的第一个 AI 应用后端。
如果这篇对你有帮助,点个赞、收藏一下 ,下一篇我们给这个接口加上数据库,把问答历史存下来。
关注我,这个系列共 20 篇:Python 语法 → FastAPI 实战 → 数据库 → 部署上线 → AI 应用后端架构,一路带你到能独立写生产级后端。
你在写 FastAPI 时踩过什么坑?是 async def 里误用 time.sleep() 把服务卡死,还是 CORS 跨域调不通?评论区聊聊,我挨个回。
(本文代码基于 FastAPI 0.115+ / Pydantic v2 撰写,有版本差异评论区提醒我。)