你是一个具有充分实战经验,有着丰富教学与面试别人&准备面试的企业计算机老师,请你向我教学FastAPI,要求: |
**大模型应用开发基础 **+ 手撕 Naive RAG
学习内容:
- 后端基础: FastAPI 路由、异步 I/O、Pydantic 数据校验
- LangChain 核心: LLM, Prompt Templates, Output Parsers, LCEL
- Naive RAG 流程: Document Loaders, Text Splitters, Embeddings, Vector Stores
- 向量数据库: FAISS/ChromaDB 本地化使用
手撕系列:
- FastAPI 搭建 “Hello, World” API 服务
- LangChain LCEL 编写第一个 LLM Chain
- 30分钟手撕一个完整的 Naive RAG 应用
解锁技能:
- 熟练使用 FastAPI 搭建 API
- 掌握 LangChain 核心组件与 LCEL 表达式语言
- 能够从零开始,快速构建一个基于文档问答的 RAG Demo
FastAPI
1. FastAPI 介绍
FastAPI 是基于 Python 3.7+ 的现代异步 Web 框架,核心优势三点:
- 性能:底层基于 Starlette(ASGI),性能接近 NodeJS 和 Go,远超 Flask/Django REST
- 开发效率:利用 Python类型检测自动完成参数校验、序列化、文档生成
- 自动文档:内置 Swagger UI (
/docs) 和 ReDoc (/redoc),零额外配置
1.2 核心概念与路由创建
1.2.1 最小可运行应用
from fastapi import FastAPI |
启动:uvicorn main:app --reload ; uvicorn 是 ASGI server,--reload 用于开发热重载
1.2.2 路径参数 vs 查询参数
# 路径参数:URL 的一部分,必填 |
FastAPI 根据函数参数是否出现在路径模板中,自动判断它是路径参数还是查询参数,无需任何额外注解
1.2.3 请求体
from pydantic import BaseModel |
Pydantic 作用:数据验证、类型转换、JSON Schema 生成。这是 FastAPI 的核心设计哲学。
1.2.4 五种 HTTP 方法
# 读取 |
1.2.5 响应模型
class ItemOut(BaseModel): |
response_model 的作用不只是文档,它强制过滤输出字段,是生产环境中防止数据泄露的重要手段
1.3 依赖注入
from fastapi import Depends |
依赖可以嵌套、共享、自动处理生命周期。相当于把横切关注点(auth、db session、rate limit)从业务逻辑中彻底解耦
1.4 异步支持
import asyncio |
什么时候用 async def,什么时候用普通 def
| 场景 | 建议 |
|---|---|
| 数据库查询(async driver)、HTTP 请求 | async def |
调用同步阻塞库(如 requests) |
普通 def(FastAPI 会放到线程池) |
| CPU 密集型(图像处理、ML 推理) | 普通 def + BackgroundTasks 或独立进程 |
1.5 错误处理
from fastapi import HTTPException |
自定义全局异常处理器:
from fastapi.requests import Request |
1.6 中间件
from fastapi.middleware.cors import CORSMiddleware |
1.7 Router 模块化
# routers/items.py |
生产项目推荐结构:
project/ |
2. FastAPI 和 Flask 的核心差异是什么?选型依据?
WSGI / ASGI 两个都是协议/接口规范,定义的是 Web 服务器(如 Nginx)和 Python 应用之间怎么传递请求
用户浏览器 → Nginx → [WSGI/ASGI 接口] → Python 应用 |
你的 Flask/FastAPI 代码不能直接接收网络请求,需要一个中间人(服务器)翻译 HTTP 请求再传给你的代码。WSGI/ASGI 就是这个”翻译协议”
| WSGI | ASGI | |
|---|---|---|
| 全称 | Web Server Gateway Interface | Asynchronous Server Gateway Interface |
| 年代 | 2003年 | 2019年 |
| 支持 async | ❌ | ✅ |
| 代表框架 | Flask, Django | FastAPI, Starlette |
| 代表服务器 | gunicorn, uWSGI | uvicorn, daphne |
WSGI 是同步的,意味着一个请求没处理完,这个线程就干不了别的。所以 Flask 要支持并发,只能靠多开线程——来100个请求,就需要100个线程同时跑,线程多了内存消耗大,切换开销也大。
ASGI 一个线程,靠”遇到等待就切换”,处理大量并发,不需要开很多线程,也不需要任何补丁。
高并发请求进来 |
差异集中在三个维度:并发模型、类型系统、开发效率。
Flask 是同步 WSGI 框架,并发依赖多线程或 gevent patch;FastAPI 基于 ASGI,原生 async/await,在高 I/O 并发场景(如数据库、外部 API 调用)下吞吐量显著更高。
FastAPI 强制使用 Type Hints + Pydantic,数据校验、序列化、文档在编写函数签名时同步完成,减少大量样板代码;Flask 需要手动引入 Marshmallow 等库。
选型:若项目是 I/O 密集型、需要自动文档、团队接受 type hint 规范 → FastAPI;若项目遗留代码多、依赖大量同步 Flask 插件生态 → Flask。
3. FastAPI 的依赖注入和普通函数调用有什么本质区别?
本质区别在于生命周期管理和自动解析。
普通函数调用是命令式的,调用者负责创建和销毁资源。Depends 是声明式的——FastAPI 的 DI 系统在请求处理前自动解析依赖图、按顺序执行、在请求结束后自动调用 yield 依赖的清理逻辑(finally 块)。
此外,同一个依赖在同一请求中默认只执行一次(缓存),可通过 use_cache=False 关闭。这对数据库连接复用至关重要。
依赖注入还使单元测试变得简单:可以通过 app.dependency_overrides 在测试中替换真实依赖(如数据库)为 mock。
4. 在 async 中调用了一个同步阻塞的库会发生什么, 如何解决?
async def 路由运行在事件循环的主线程中。若在其中调用同步阻塞操作(如 requests.get()、time.sleep()),会阻塞整个事件循环,导致所有并发请求被挂起,彻底丧失异步优势。
解决方案有两种:
- 换用异步库:将
requests替换为httpx(async 模式)或aiohttp - 用线程池卸载:使用
asyncio.get_event_loop().run_in_executor(),FastAPI 会自动将其放到线程池执行,不阻塞事件循环。
# 推荐:直接用普通 def,FastAPI 自动处理 |
5. 如何在 FastAPI 中实现 JWT 认证?依赖注入如何配合使用?
HTTP 是无状态协议,每次请求服务器都不认识你。所以需要一种机制,让你每次请求都”带着身份证”过来。历史上有两种方案:
| 方案 | 原理 | 问题 |
|---|---|---|
| Session | 服务器存你的登录状态,给你一个 ID | 服务器要存储,难以横向扩展 |
| JWT | 身份信息直接存在 Token 里给你 | 服务器不需要存任何东西 |
JWT本质是个字符串, 分三段,用 . 隔开:
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMjN9.abc123signature |
Signature:用服务器私钥对前两段签名,防止篡改。Payload 是公开的,但没有私钥就无法伪造签名,所以服务器只要验证签名合法,就能信任里面的数据。
整体分三层:Token 签发 → Token 解析 → 路由保护。
① 登录 用户 → POST /login {username, password} → 服务器验证 → 返回 JWT Token
② 携带 Token 请求 用户 → GET /profile Header: Authorization: Bearer → 服务器
③ 服务器验签 服务器拿私钥验证签名 → 合法 → 从 Payload 取出 user_id → 知道你是谁
from fastapi.security import OAuth2PasswordBearer |
OAuth2PasswordBearer 会自动从 Authorization: Bearer <token> 头提取 token,并在 Swagger UI 中生成认证按钮。认证逻辑通过 Depends 注入,所有需要保护的路由只需声明依赖,无需重复代码
6. 如何对 FastAPI 应用做性能优化?从架构到代码层面回答
代码层:确保所有 I/O 操作使用异步驱动(如 asyncpg 代替 psycopg2、motor 代替 pymongo);避免在 async def 中混用同步阻塞调用;使用 response_model_exclude_unset=True 减少不必要的序列化。
应用层:CPU 密集型任务(ML 推理、图像处理)使用 BackgroundTasks 或推入消息队列(Celery/Redis)异步处理,不阻塞请求响应;合理使用连接池(数据库连接池大小 = worker 数 × 并发量估算)。
部署层:用 gunicorn -k uvicorn.workers.UvicornWorker -w 4 多进程启动,充分利用多核;前置 Nginx 做静态资源缓存和限流;高频幂等接口加 Redis 缓存层。
监控:接入 OpenTelemetry + Prometheus,通过 /metrics 端点暴露请求延迟、错误率,实现可观测性驱动优化,而不是凭感觉调参。
LangChain
7. LangChain介绍
在企业级应用中,我们不再把 LangChain 看作简单的“大模型 API 封装库”,而是把它视作一个面向大模型工作流的声明式编排框架。它的核心基础被严谨地划分为四个基石:标准协议(Runnable)、数据流转(Model I/O)、状态管理(Memory/History) 以及 检索架构(RAG Pipeline)
7.1 大一统的 Runnable 协议与 LCEL
这是现代 LangChain 的灵魂。为了解决旧版本中组件之间互相调用极度混乱、流式输出(Streaming)无法穿透的问题,LangChain 引入了 Runnable 接口。
你可以把Runnable理解为一个标准化的“黑盒”。无论这个黑盒是一个 Prompt、一个大模型、一个输出解析器,还是一个检索器,它们在底层都继承自 Runnable,并强制实现了同一套方法:
.invoke(input): 同步单次调用.stream(input): 流式输出(返回生成器).batch([input1, input2]): 批量处理(底层自动并发)- 以及它们的异步版本
.ainvoke,.astream,.abatch
LCEL (LangChain Expression Language) 的本质:
当你使用管道符 | 将两个 Runnable 连在一起时(例如 A | B),LCEL 在底层实际上创建了一个 RunnableSequence。它会自动处理数据的输入输出校验,并且智能地透传流式生成——即 A 每吐出一个字,就立刻喂给 B,而不是等 A 全部生成完再传给 B。
from langchain_core.prompts import ChatPromptTemplate |
7.2 Model I/O 的现代化设计
Model I/O 处理的是大模型应用的“咽喉”地带:怎么把人的话结构化地喂给模型,又怎么把模型的话结构化地提取出来。
- 从 String Prompt 到 Chat Prompt
现代大模型(GPT-4, Claude-3)都是基于角色(Role)的对话模型。我们不再向模型塞一整段长字符串,而是传递一个包含 System, Human, AI 区分的消息列表(Message List)。
prompt = ChatPromptTemplate.from_messages([ |
- 结构化输出的终极解法:
.with_structured_output()
过去,开发者为了让模型输出 JSON,要在 Prompt 里苦口婆心地写“请严格输出 JSON,不要带额外的文字…”。
现在,LangChain 深度整合了各大厂商的 Function Calling / Tool Calling 底层能力。你只需要定义一个 Pydantic 类,LangChain 会自动将其编译为底层的 JSON Schema 传给模型,并自动完成反序列化。
from pydantic import BaseModel, Field |
7.3 状态管理(记忆)的彻底解耦
面试官常问:“大模型本身是没有记忆的,LangChain 是怎么实现多轮对话的?” 本质上,记忆 = 历史记录提取 + Prompt 动态注入。
在旧版中,ConversationBufferMemory 被死死地绑定在 LLMChain 内部,这导致在构建支持百万用户的 Web 后端时,极难实现基于数据库的分布式存储。
现代架构中,引入了 RunnableWithMessageHistory。它是一个装饰器/中间件,把业务逻辑和存储逻辑彻底切分开来。
from langchain_core.runnables.history import RunnableWithMessageHistory |
7.4 RAG 组装函数的变迁
在 RAG(检索增强生成)场景下,我们通常需要先查向量库,再组装 Prompt,再调模型。
旧版的 RetrievalQA 已经被官方强烈建议弃用。现在官方提供了更底层的“工厂函数”来拼装 LCEL 链:
- **
create_stuff_documents_chain**:负责把检索到的多篇文档(Documents)“塞”(stuff)进 Prompt 中。 - **
create_retrieval_chain**:负责协调外围流程:拿用户问题 -> 调 Retriever -> 把文档交给上面的文档链 -> 输出最终结果。
from langchain.chains import create_retrieval_chain |
这种分离带来的巨大好处是:如果你想在中途加入一个“重排查(Reranker)”节点,或者想在拿到答案后进行“涉黄涉暴校验”,你可以直接通过 LCEL 轻松地在中间插入对应的 Runnable 节点,这在以前的黑盒 API 中是根本做不到的。
Advanced RAG 与生产级向量数据库
学习内容:
- Advanced RAG 技术: Query Transformation, Re-ranking, Hybrid Search
- RAG 评估: 使用 RAGAs, TruLens 进行自动化评估
- 生产级向量数据库: Milvus/Zilliz Cloud 部署与使用
- 数据处理: Unstructured.io 解析复杂文档
手撕系列:
- 实现 BM25 + 向量的混合检索
- 引入 Cohere Rerank 模型提升检索精度
- 使用 RAGAs 评估 RAG 系统的 Faithfulness 和 Answer Relevancy
- Docker 部署 Milvus 并进行增删改查操作
解锁技能:
- 掌握 10+ 种 RAG 优化策略
- 能够建立 RAG 系统的自动化评估流水线
- 熟练使用生产级的分布式向量数据库 Milvus
- 具备处理复杂、非结构化文档的能力
Agent 开发与 Tool Calling
学习内容:
- Agent 核心: ReAct 框架, Planning, Tool Use, Memory
- Tool Calling: OpenAI Function Calling, Tool Schema 定义
- 工具开发: 如何将 API, 数据库查询等封装为 Agent 可用的工具
- 错误处理: 工具调用失败的重试、降级策略
手撕系列:
- 实现 3个 自定义工具 (天气查询, SQL数据库查询, API调用)
- 基于 LangChain 构建一个可以链式调用工具的 Agent
- 使用 OpenAI Function Calling 实现结构化数据提取
解锁技能:
- 深刻理解 Agent 的”思考-行动”工作流
- 能够开发、测试、维护自定义工具集
- 掌握 Function Calling 的原理与应用
- 具备构建能处理真实世界任务的 Agent 的能力
系统性能优化
学习内容:
- 缓存策略: Redis 缓存 LLM 响应和 Embedding 结果
- 异步处理:
asyncio,aiohttp实现高并发- 批处理优化: Embedding 和 LLM 调用的批处理
- 推理加速: vLLM, TensorRT-LLM 部署与使用
手撕系列:
- 为 RAG 系统引入 Redis 缓存,对比优化前后性能
- 将 FastAPI 的同步接口改造为异步接口
- 部署 vLLM 并通过 API 进行推理
解锁技能:
- 掌握 LLM 应用的核心性能优化手段
- 能够将系统的 QPS 提升 10 倍以上
- 熟练使用 Redis 进行缓存设计
- 具备部署和使用高性能推理引擎的能力
监控、可观测性与部署
学习内容:
- Agent 链路追踪: LangSmith, OpenTelemetry
- 指标监控: Prometheus 监控业务和系统指标
- 可视化: Grafana 创建监控大盘
- 日志系统: ELK Stack (Elasticsearch, Logstash, Kibana)
- 容器化部署: Docker, Docker Compose
手撕系列:
- 为 Agent 应用集成 LangSmith,追踪每一步的调用和延迟
- 使用 Prometheus 暴露自定义指标 (如 Token 消耗, 缓存命中率)
- 使用 Docker Compose 将 FastAPI + Milvus + Redis 整套系统一键部署
解锁技能:
- 具备构建完整 LLM 应用可观测性体系的能力
- 能够快速定位和诊断线上问题
- 掌握基于 Docker 的容器化部署和编排
- 拥有完整的 DevOps for LLM Apps 经验
Multi-Agent 系统开发
学习内容:
- Multi-Agent 框架: AutoGen vs. CrewAI
- Agent 角色定义: 如何设计具有不同职责和能力的 Agent
- 通信机制与工作流: GroupChat, Sequential/Hierarchical flow
- 状态管理: 如何在多个 Agent 之间共享和传递状态
手撕系列:
- 使用 AutoGen 构建一个“研究员-程序员-测试员”协作的软件开发团队
- 使用 CrewAI 构建一个“旅行规划师-本地向导-预订专员”的旅行 Agent
解锁技能:
- 掌握至少两种主流的 Multi-Agent 开发框架
- 能够根据复杂业务需求,设计和实现多智能体协作系统
- 理解不同协作模式 (如层级式 vs. 对话式) 的优缺点