FastAPI 响应模型与请求体学习笔记

这篇是我接着上次学 FastAPI 时整理的笔记。上次学的都是「数据怎么进来」(查询参数、请求体、校验),这次换了个方向,研究「数据怎么出去」——也就是 response_model,顺带把困扰我很久的「请求体 vs 查询参数」彻底分清楚了。 一句话总结这次的核心: response_model 是给接口出口装的筛子:你规定它只准返回哪些字段,多余的(比如密码)自动被丢掉。 下面按「响应模型 → 请求体 vs 查询参数 → 路由和参数到底是什么 → 最该记住的几点」来展开。 一、响应模型 response_model 1. 先讲痛点:返回数据会泄露敏感字段 在 FastAPI 里有条铁律:你 return 什么,前端就收到什么。 假设数据库里的用户带密码字段: class User(BaseModel): username: str password: str # 敏感字段! email: str @app.post("/users/") async def create_user(user: User): return user # 灾难:把 password 原样返回给了前端 这样写,密码就跟着 JSON 一起发出去了。response_model 就是用来堵这个漏洞的。 类比一下:Pydantic 请求体像安检进站(检查你带进来的东西);response_model 像安检出站(检查你带出去的东西,违禁品没收)。 2. 怎么用:进、出各写一个模型 经典套路是定义两个模型——一个收(带敏感字段),一个发(不带)。 from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() # 进:注册时前端要传的(含密码) class UserIn(BaseModel): username: str password: str email: str # 出:返回给前端的(不含密码!) class UserOut(BaseModel): username: str email: str @app.post("/users/", response_model=UserOut) # 关键在这 async def create_user(user: UserIn): return user # 即使返回了带 password 的对象,也会被过滤成 UserOut 神奇之处:函数里 return 的明明是带密码的 user,但前端收到的 JSON 里根本没有 password。FastAPI 在出门那一刻,按 UserOut 重新「拓印」了一份。 ...

3 min · 471 words · Jiaju

RAG 入门:在模型回答之前,先检索资料

这篇是我学 RAG 时的白板笔记整理。RAG(Retrieval-Augmented Generation,检索增强生成)是现在几乎所有"让 AI 读自己资料"产品的底层套路,比如企业知识库问答、文档助手、客服机器人。 一句话总结它的本质: 在模型回答之前,先检索资料,再基于资料生成回答。 下面按"为什么需要它 → 它怎么工作"的顺序展开。 一、为什么需要 RAG 1. 直接把所有资料喂给模型,为什么不可行? 最朴素的想法是:把全部文档塞进 prompt,让模型自己看。这条路有三个问题: 上下文窗口有限。模型一次能读的 token 数是有上限的,几百页的文档根本塞不下。 成本。就算塞得下,每次提问都把全部资料发一遍,token 费用会爆炸。 响应速度。输入越长,模型处理越慢,用户体验直线下降。 2. 模型本身也有短板 就算不考虑塞资料的问题,纯靠模型自己回答也有硬伤: 知识过时。模型的知识停留在训练截止日期,问它昨天发生的事它不知道。 私有数据。公司内部文档、个人笔记,模型训练时根本没见过。 幻觉。不知道的事情它可能一本正经地编。 RAG 的思路就是绕开这些限制:资料放在模型外面,每次只把和问题相关的一小段喂进去。 二、核心流程 整个 RAG 分两个阶段:数据准备(离线,只做一次)和用户提问(在线,每次提问都执行)。 flowchart LR subgraph prep["① 数据准备(离线,只做一次)"] direction LR A["📄 原始文档"] --> B["切分 Chunking按章节 / 段落 / 字数……"] B --> C["🧩 Chunks每一块语义相对完整"] C --> D["Embedding(向量化)"] D --> E[("向量数据库")] end flowchart LR subgraph query["② 用户提问(在线,每次提问都执行)"] direction LR Q["❓ 用户问题"] --> QE["问题也做Embedding"] QE --> S["相似度检索找距离最近的 top-k 块"] V[("向量数据库")] --> S S --> P["相关资料 + 问题拼成 Prompt"] P --> L["🤖 LLM 生成回答"] end 第一步:数据准备 切分(Chunking) 文档不能整篇存,要先切成一块块的 chunk。切分的依据可以是章节、段落、字数……没有标准答案,但有一条核心原则: ...

1 min · 207 words · Jiaju

博客开发日志(中文):改动记录与前端原理

这是一篇按日期累积的开发日志。每次改动博客,我都把"做了什么"和"学到的前端原理"记在这里,方便以后翻查。最新的改动放在最上面。 维护约定:下次改动时,在 改动模板 上面新增一个 ## 日期 — 标题 小节即可。 2026-06-09 — 接入自定义域名 + 翻译按钮升级 这次做了什么 自定义域名上线:把 GoDaddy 买的 xungirl.com 接到 GitHub Pages,配置了 DNS(4 条 A 记录指向 GitHub IP + 1 条 www 的 CNAME),清掉了 GoDaddy 默认的停放记录,最后开启了自动 HTTPS(Let’s Encrypt 证书)。 新增文章:一篇讲 A 记录 vs CNAME 记录的英文文章。 翻译按钮:保护代码与公式:点翻译时,代码块、行内代码、数学公式保持原样不被翻译。 翻译按钮:升级为双向:自动判断当前文章是中文还是英文,翻成"另一种"——英文文章翻中文、中文文章翻英文。 涉及文件:layouts/partials/extend_head.html(翻译逻辑)、content/posts/(文章)。 前端原理 这次最值得记的是几个前端基础概念,比具体代码更重要。 1. 构建期 vs 运行期(最核心的一条线) 构建期(Hugo) 运行期(浏览器 JS) 谁在做 push 后 GitHub Actions 构建一次,生成静态 HTML 访客打开页面时,浏览器实时执行 适合 文章内容、菜单、固定文案(可走 Hugo 的 {{ i18n }} 翻译) 会动的东西:计时器、实时翻译、交互 特点 生成完就定死,之后不变 每次访问都重新跑,可以随时变 为什么重要:博客底部那个"已运行 X 天 X 时"的计时器,必须用运行期 JS(因为每秒都在变,Hugo 构建一次没法让它跳动);而它显示的英文字是写死在 JS 里的,脱离了 Hugo 的翻译体系,所以切语言不会变——这不是 bug,是它本来就在另一套系统里。 ...

2 min · 304 words · Jiaju