🏠 总目录📚 本教程 02 · 一个 AI 产品的解剖
📑 本页目录(点开跳转)

02 · 一个 AI 产品的解剖

30 分钟 | 🗺️ 全板块的地图 | 看完你在后面任何一章都知道「自己站在哪」


🎯 一句话

把上一章那个两小时上线的东西剖开,里面是十来个零件——没有一个是 AI 特有的,但 AI 让其中四件事格外难。 这一章不教你做任何东西,它只做一件事:把零件摆开、标上章号,顺便说清哪四件事值得你后面一路提防。


🗺️ 一、跟着一个请求走一遍

用户在输入框敲完问题、按下回车。到他看见第一个字为止,中间经过这些地方:

一次请求的一生(括号里的数字是章号) 浏览器 敲下回车 反向代理 / TLS 14 章 鉴权:你是谁 08 章 限流 · 配额 12 章 业务编排 03 章 调用层 超时 · 重试 · 缓存 04 模型 API 上游 · 会慢会限流 落库 对话 · 用量 06 · 07 流式往回吐 05 章 浏览器逐字渲染 10 章 队列 · Worker 慢任务绕开请求 11 全程贯穿:日志 · 指标 · trace_id(15 章) 出了事能不能查清楚,全看这一层有没有
一次请求的一生。虚线是「不在主链路上、但必须存在」的两条:慢任务被甩进队列(11 章),日志与 trace 贯穿全程(15 章)。⭐ 右下角那个箭头是从「业务编排」下来的 —— 它不是流程的下一步,是流程的岔路

注意图上有两种箭头。实线是同一个请求真的走过去了;虚线是「这件事不跟着这个请求走」——队列里的活儿要过几秒甚至几分钟才有结果,日志则是每一步都往旁边掉一份。分不清这两种,你会把该异步的东西写成同步,然后一个长任务卡住所有人(11 章整章在讲这件事)。


🧩 二、每个零件:解决什么问题,不要它会怎样

零件 解决什么问题 不要它会怎样 在第几章
反向代理 / TLS 收 HTTPS、发静态文件、把流量转给后端进程 你的应用进程要自己处理证书;⚠️ 而且它默认会缓冲响应,是流式头号杀手 14
鉴权 回答「你是谁」,把请求绑到一个用户和一个租户上 分不清谁的对话是谁的;越权只差一个查询参数 08
限流 · 配额 回答「你还能不能再来一次」 一个脚本十分钟刷爆你的额度,账单第二天才告诉你 12
业务编排 一次对话该做哪几步:取历史、检索、拼提示词、调模型、校验 这些步骤散落在路由函数里,改一处要在五个地方同步 03
调用层 把「调模型」这件事包成一个你自己的函数:超时、重试、记账、缓存、可替换 换模型要改十处;出了事没有一行记录说这次花了多少钱 04
流式往回吐 让用户在 1 秒内看到第一个字,而不是盯着空白等 20 秒 用户以为卡死了,5 秒就重刷——重刷还会再烧一次钱 05 · 10
落库 对话、用量、检索用的向量,得有地方放 刷新页面对话就没了;月底算不出这个用户花了多少 06 · 07
队列 · Worker 把「跑几分钟才有结果」的活儿从请求里搬出去 一个长任务占着连接,别人全在排队等 11
日志 · 指标 · trace 出事之后能查清楚「那一次到底发生了什么」 用户说「刚才报错了」,你查无可查——这是最先咬你的一个 15
配置与密钥 同一份代码在三个环境跑,且密钥不进代码库 换个 Key 要重新提交代码;测试环境不小心连了生产库 13

这张表和 01 章末尾那张「缺什么」表是同一张地图的两面:那张说「不补会怎样」,这张说「补的是什么形状」。


⚠️ 三、⭐⭐ 这些零件都不是 AI 特有的

上面十个零件,随便找一本讲后端的书都会讲。那本板块存在的意义是什么?

答案是:AI 应用让其中四件事从「需要注意」变成了「主要矛盾」

这四件事 普通 Web 应用 AI 应用 后果
响应时长 几十到几百毫秒 秒到分钟,慢一到两个数量级 所有默认超时、连接数、部署形态的假设全部失效
成本 一次请求的边际成本约等于 0 每次请求真的花钱,且和输入输出长度成正比 限流从「保护服务器」变成「保护钱包」
流式 可有可无的优化 必需品 返回方式、错误处理、代理配置全部要重做
不确定性 同样输入必然同样输出 同样输入不同输出 缓存变难、测试变难、复现 bug 变难

四件事各自把哪些零件搞复杂了:

① 响应长且慢。 一次生成跑 30 秒是家常便饭。于是:Serverless 的执行时限直接把你踢出去(01 章第六节)、连接池和超时的默认值全都太短(04 章)、「同步等结果」这个最自然的写法在几分钟量级的任务上直接不成立(11 章)。⚠️ 最阴的一点:慢本身不报错,它表现为「偶尔有人说卡」。

② 每次请求真的花钱。 普通 Web 里限流是防打垮服务器,AI 里限流是防止某人一个下午花掉你一个月预算。而且账单是延迟到达的——你今天写的一个死循环重试,可能明天才在账单上出现。所以 04 章要求每次调用都记 token 和成本,12 章要求在花钱之前先扣配额

③ 流式不是优化,是必需。 用户不会盯着空白屏幕等 20 秒。但流式一旦成为必需品,它就会往上游反噬:状态码在第一帧发出去时就定死了(05 章)、任何缓冲层都会把它悄悄破坏掉(05 章那三个凶手)、重试从「用户无感」变成「要推翻用户已经看见的字」(04 章)。

④ 同样输入不同输出。 这条最容易被低估。它意味着:缓存的前提没了(只有 temperature=0 且输入完全一致时才敢缓存,04 章)、测试断言写不出来(不能 assert reply == "...",只能断言结构和范围,15b 章)、线上 bug 常常复现不了(所以 15 章要求每次调用都留下能对上的指纹:输入的哈希 + 字符数 + 脱敏后的开头 —— ⚠️ 默认恰恰不要把 prompt 和回复原样打进日志,隐私、体积、合规三条理由任意一条都够。哈希已经够回答「是不是同一段输入在反复失败」,长度够排查截断;确实需要完整内容时另走一条通道:短留存期、独立权限、默认关闭、按比例采样)。

⭐⭐ 把这四条记住,这个板块的每一章你都能猜到它为什么存在。 后面每一章开头,你都可以先问一句:它在处理这四件事里的哪一件?


🧮 四、一次请求的时间和钱花在哪

⚠️ 我不会给你一组延迟数字——那要看模型、区域、长度和当天的负载,任何写死的数字都会骗你。能给的是结构

环节 量级来自哪里 你能做什么
代理 + 鉴权 + 限流 本机 / 内网操作,毫秒级 基本不用管
取历史 + 检索 一到几次数据库往返 06 / 07 章:索引和连接池
模型生成 跨网 + 逐 token 生成,秒级起 04 章:超时和重试;05 章:让用户提前看到字
落库 + 日志 毫秒级,且可以不挡着响应 15 章:别把日志写成同步阻塞

结论是个数量级判断,不是实测:模型生成是跨网络、逐 token 产出的,其余环节是本机或内网的一次性操作——所以除非你的数据库写得很糟,否则优化其余环节的收益,会被模型生成那一段完全淹没

那怎么知道自己的应用到底慢在哪?自己量,而且量的位置是固定的两处:在调用层记下每次模型调用的耗时(04 章),用同一个 trace_id 把一次请求里的各段串起来(03 章埋点、15 章看图)。💀 没有这两处,你只能靠猜——而人对「哪里慢」的直觉在 AI 应用里几乎总是错的,因为大家会本能地去优化自己写的代码,而时间其实全花在等别人。


🚧 五、什么不在这个板块里

这个板块只回答一类问题:「模型已经好了,但少了它产品就上不了线」。不是这类的,都在别处,而且都比这里讲得深:

你想问的 去哪 分界线
模型准不准、上线后有没有退化 《模型上线之后》 本板块管「服务健不健康」,那边管「模型准不准」
推理引擎怎么选、怎么把吞吐榨出来 《AI基础设施》20 章 那边是「怎么跑模型」,这边是「怎么调它」
RAG 怎么切块、怎么重排、怎么评 《大模型全景导论》08 章 那边讲策略,本板块 07 章讲怎么真的存进库里
向量检索的 HNSW / IVF 是什么原理 《推荐算法》10 章 本板块只讲工程选型,不讲索引结构
数据该不该留、怎么脱敏 《数据这一关》19 章 本板块 08 章只讲「怎么隔离」,不讲「该不该留」

🔄 六、换个栈怎么对应

零件是概念,换语言只换名字

零件 Python / FastAPI Node(Express / Hono) Go
每请求都做的事 Depends(...) 中间件 中间件 + context.Context
分批往外写 StreamingResponse res.write() / ReadableStream w.Write() + ⭐ Flusher.Flush()
后台跑长任务 队列 + Worker 进程 队列 + Worker 进程 goroutine 也能扛一部分,但重启就丢
取消传播 asyncioCancelledError AbortSignal context.ContextDone()

反向代理那一层三个栈完全一样 —— Nginx / Caddy 和你用什么语言无关。

这张表想说的是:最容易咬到你的那两个零件——反向代理的缓冲取消传播——在三个栈里长得完全不同,但它们是同一个问题。换栈重写时,人们通常记得搬业务逻辑,忘了搬这两件。


🔗 这一章连到哪里

去哪 为什么
01 · 第一天:两小时上线 那一章末尾「缺什么」表的每一行,就是这张图上的一个零件。先跑通再看图,比先看图有用
03 · 后端骨架 图上「业务编排」那个框展开就是下一章:边界、async、依赖注入、错误形状
04 · 调用层 图上标了重点的那个框——四件难事里的成本超时主要在这一层解决
05 · 流式输出 另一个标了重点的框——四件难事里的流式在这一层解决
智能体工程 16c · 接进真实产品 ⭐ 最近的邻居。那边讲「为什么要流式、护栏怎么设计」,本板块讲「这条链路怎么搭、坑在哪」
模型上线之后 · 目录 第五节那条分界:本板块管服务健不健康,那边管模型准不准。两套监控都要有
AI基础设施 20 · 推理服务化 图上「模型 API」那个框,在对面是一整个系统。想自建就得读那边

✅ 检查点

  1. 图上实线箭头和虚线箭头分别代表什么?分不清会写出什么 bug?
  2. 反向代理除了收 HTTPS,为什么在这个板块里格外危险?
  3. 「日志 · 指标 · trace」为什么被画成横贯全程的一条带,而不是链路上的一环?
  4. AI 应用让哪四件事从「需要注意」变成「主要矛盾」?
  5. 「每次请求真的花钱」让限流的目的发生了什么变化?账单为什么特别危险?
  6. 「同样输入不同输出」分别把哪三件事搞难了?
  7. 为什么说优化「取历史 + 落库」那几段的收益会被淹没?这个结论是实测还是推理?
  8. 「模型准不准」和「服务健不健康」分别归哪个板块管?
👀 答案
  1. 实线 = 同一个请求真的走过去了;虚线 = 这件事不跟着这个请求走(队列里的活要几秒到几分钟,日志是每步往旁边掉一份)。分不清就会把该异步的写成同步,一个长任务卡住所有人。
  2. 因为它默认会缓冲响应——本地逐字正常,上线变成「憋很久然后一次性全出现」。它是流式的头号杀手(05 章第四节)。
  3. 因为它不属于任何一步,而是每一步都要往旁边掉一份。它不在主链路上,但没有它,出事后你连「发生了什么」都答不出来。
  4. 响应长且慢(秒到分钟,慢一到两个数量级)、每次请求真的花钱流式是必需品不是优化同样输入不同输出
  5. 从「防止打垮服务器」变成「防止某人一个下午花掉你一个月预算」。账单危险在于它是延迟到达的——今天写的死循环重试,可能明天才在账单上出现。
  6. 缓存(只有 temperature=0 且输入完全一致才敢缓存)、测试(不能 assert reply == "...",只能断言结构和范围 —— 15b 章)、复现 bug(所以 15 章要求每次都留下指纹:哈希 + 字符数 + 脱敏后的开头 —— ⚠️ 默认把原文打进日志;完整内容只走短留存、独立权限、默认关闭、按比例采样的单独通道)。
  7. 因为模型生成是跨网 + 逐 token 产出(秒级起),其余环节是本机或内网的一次性操作(毫秒级)。⭐ 这是数量级推理,不是实测——你自己的数字要在调用层量(04 章)、用 trace_id 串起来(03 / 15 章)。
  8. 「模型准不准」归《模型上线之后》,「服务健不健康」归本板块。两套监控都要有,别互相替代。

🛑 可以停在这里

走神救援

这一章是地图,不教做任何东西。一次请求的一生:浏览器 → 反向代理/TLS(14 章)→ 鉴权(08)→ 限流配额(12)→ 业务编排(03)→ 调用层(04)→ 模型 API → 流式往回吐(05,前端在 10)→ 落库(06/07)→ 浏览器逐字渲染;旁边挂两条虚线:慢任务甩进队列(11)日志/指标/trace 贯穿全程(15)。⭐ 虚线的意思是「这件事不跟着这个请求走」——分不清实线虚线,就会把该异步的写成同步,一个长任务卡住所有人。十个零件没有一个是 AI 特有的,随便一本后端书都讲。本板块存在的理由是 ⭐⭐ AI 让其中四件事从「需要注意」变成「主要矛盾」① 响应长且慢——秒到分钟,比普通 API 慢一到两个数量级,于是 Serverless 的执行时限、默认超时、连接池假设全部失效,而且慢本身不报错,只表现为「偶尔有人说卡」;② 每次请求真的花钱——限流从「防打垮服务器」变成「防某人一下午花光一个月预算」,且账单延迟到达,所以调用层必须每次记 token 和成本,配额必须在花钱之前扣;③ 流式是必需品不是优化——它会反噬上游:状态码在第一帧发出时就定死了、任何缓冲层都会悄悄破坏它、重试从「用户无感」变成「推翻用户已经看见的字」;④ 同样输入不同输出——缓存的前提没了(只有 temperature=0 且输入完全一致才敢缓存)、测试断言写不出来(只能断结构和范围)、线上 bug 常常复现不了。时间和钱花在哪:代理/鉴权/限流是毫秒级本机操作,模型生成是秒级跨网逐 token 产出——所以优化其余环节的收益会被完全淹没;⚠️ 这是数量级推理不是实测,你自己的数字要在调用层量、用同一个 trace_id 串起来,因为人对「哪里慢」的直觉在 AI 应用里几乎总是错的。最后是边界:模型准不准归《模型上线之后》,推理引擎怎么选归《AI基础设施》20 章,RAG 策略归《全景导论》08 章——本板块只回答「模型已经好了,但少了它就上不了线」的那类问题

下一节 👉 03-后端骨架.md

打卡记录保存在你的浏览器里,首页能看到总进度