想象你认识一位顶级大厨,他的菜好吃到让人排队三小时。可如果你直接把他拉到大街上开餐厅,大概率第一天就倒闭——为什么?因为他只会颠勺,不懂装修门面、安排传菜员、设计菜单、办理会员卡、接通收银台,更不知道如何让十桌客人同时点单时不打架。 图像生成模型就是那位大厨。你费尽千辛万苦训练出一个能画出惊艳图片的 AI 模型,但它只是“会做菜的手艺”。要让它变成一门能收费、能服务上千家客户的 SaaS 生意,你需要给它配上完整的“餐厅”:前端是门面和菜单,后端是传菜员和后厨流水线,用户管理是会员卡,计费系统是收银台,多租户隔离是包间分区,监控运维是每天巡场的店长。这篇文章,就是教你如何把“一口炒锅的大厨”变成“一家能稳定赚钱的餐厅”。

岗位关联

对 AI 从业者而言,掌握从模型到商业产品的工程化落地能力,意味着你不再只是“会炼丹的算法工程师”,而是能端到端交付价值、扛起营收指标的全栈 AI 工程师——这是从技术岗迈向产品负责人最硬的一座桥。

目录
  1. 可视化演示
  2. 全栈架构蓝图
  3. 前端交互设计
  4. 后端服务设计
  5. 用户账户管理
  6. 订阅计费系统
  7. 多租户隔离方案
  8. 投产运维优化
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示三层架构设计、订阅计费模型与多租户隔离方案,呈现从技术原型到商业化产品的工程化路径。

本节配有交互动效(进入视口后自动加载,约 3KB)。

全栈架构 前端/API/服务三层 协同工作 将AI模型能力转化为商业化服务。

全栈架构蓝图

开餐厅的第一步不是请大厨,而是画图纸:前厅放几张桌、后厨的灶台怎么摆、传菜口朝哪开。图纸画好了,客人和菜才不会在过道里撞成一团。做全栈 AI SaaS 也一样,动工之前先画“架构蓝图”——它是决定这家店能开到多大的地基。

图像生成 SaaS 的蓝图分三层。前端交互层是门面和菜单,用户在这里输入提示词、看到生成结果;后端服务层是传菜员和后厨,负责接单、排队、调用大厨炒菜;存储与算力层是冷藏库和灶台,存放成品图、提供 GPU 推理。三层之间通过 API 这条“传菜通道”衔接。

其中最关键的决策是引入异步任务队列。图像生成通常要花三五秒到十几秒,如果后端死等模型算完才回复前端,客人的浏览器一直转圈,轻则超时重则以为餐厅死机。正确做法是:先收下订单,回一张“排队号”,任务丢进队列,大厨(GPU 模型)算完再通过回调或查询通知结果。

图纸画好了,每个环节各就各位,客人再多也不会堵在门口。架构蓝图的价值,就是让餐厅的高峰期也像平峰期一样顺畅。

Ttotal=Tupload+Tqueue+Tinfer+Tdownload\displaystyle T_{\text{total}} = T_{\text{upload}} + T_{\text{queue}} + T_{\text{infer}} + T_{\text{download}}
这条公式把“从点菜到吃到嘴里”的总时间拆成四段,让你一眼看出优化该往哪里使劲——高峰期省排队时间,比优化炒菜那几秒更划算。
  1. T_total 总延迟一趟完整请求从用户按下“生成”到图片展示在屏幕上的总时间,是四个环节耗时之和。
    TtotalT_{\text{total}}
  2. T_upload 上传耗时提示词和参数从浏览器传到后端的时间,通常只有几十毫秒。
    TuploadT_{\text{upload}}
  3. T_queue 排队耗时任务进入队列等待 GPU 空闲的时间,高峰期主要花在这里。
    TqueueT_{\text{queue}}
  4. T_infer 推理耗时模型在 GPU 上真正“作画”的时间,通常 3 到 15 秒,是大头。
    TinferT_{\text{infer}}
  5. T_download 回传耗时图片从对象存储下载到用户浏览器的耗时,取决于图片大小和带宽。
    TdownloadT_{\text{download}}

前端交互设计

客人点完菜之后最怕什么?干等。好的餐厅会告诉你“您的菜正在制作中”,甚至给你一个沙漏看进度。前端交互的全部功夫,就花在这份“让人安心等待”的体验上。

具体到图像生成产品,交互动作就像点菜:用户在输入框里写下提示词,相当于点了一道“赛博朋克风猫娘”的菜;点击生成按钮,相当于下单;接下来前端每隔两三秒向后端问一次“好了吗?”,这就是任务状态轮询。轮询得到“排队中”“生成中”“已完成”三态,界面据此展示不同的提示。

轮询间隔不是越短越好——0.1 秒刷一次,相当于客人每 6 秒就拽一次服务员问“菜好了没”,服务员什么也别干了。1 到 3 秒是黄金区间。结果展示也有讲究:用画廊布局平铺生成的多张图,点击可放大,配“重新生成”和“下载原图”按钮,这属于结果展示优化。

好的点菜体验不只是“上菜快”,更是“让人安心地等”。前端交互就是把这份安心感,变成留得住用户的竞争力。

P(finish≤t)=1−e−λt\displaystyle P(\text{finish} \le t) = 1 - e^{-\lambda t}
这条公式告诉你:在某个时刻之前,任务完成的概率有多大。用它指导前端轮询频率的设计,比拍脑袋定间隔靠谱得多。
  1. P 完成概率在 t 秒内任务已经完成的概率,取值范围是 0 到 1。
    P(finish≤t)P(\text{finish} \le t)
  2. e 自然常数约等于 2.718,指数分布的基本底数,描述“等待第一个事件发生”的规律。
    ee
  3. λ 出图速率每秒平均能完成的图片数,比如 λ=0.2 表示平均 5 秒出一张图。
    λ\lambda
  4. λt 累计期望t 秒内完成的平均任务数,它决定了概率增长的快慢。
    λt\lambda t

后端服务设计

传菜员(API 网关)接过点菜单,喊一嗓子“一份回锅肉”,后厨(模型服务)开火炒菜,出菜后放在传菜口(对象存储),再端回客人桌上。后端服务设计的本质,就是把这条“点单到上菜”的流水线安排得明明白白。

后端服务分四步走。第一步,API 网关统一收单,完成身份鉴权和限流,防止有人在门口大喊大叫;第二步,网关把任务路由给图像生成服务,也就是“喊话后厨”;第三步,模型在 GPU 上推理出图,把成品写入对象存储;第四步,返回一个可访问的图片 URL,前端拿着 URL 直接展示,不用经过后端转手传大文件。

这里有个容易踩的坑:模型服务调用是同步还是异步?答案是“网关同步收单,模型异步干活”。网关收到请求后立刻返回 task_id,模型在后台慢慢画图,前端拿着 task_id 来查。至于结果存储回传,用 S3/OSS 这类对象存储保存图片,再生成带签名的临时 URL 给前端下载,既高效又安全。

传菜员勤快、后厨不堵,餐厅才能在高朋满座时依然出菜稳定。后端服务就是把“每桌都上菜”变成可预期的工程能力。

QPS=CTresp\displaystyle \text{QPS} = \frac{C}{T_{\text{resp}}}
QPS 是每秒能处理的请求数。它告诉餐厅:同时接待多少桌客人(并发),决定了一晚上能翻几次台。
  1. QPS 吞吐量每秒能处理的请求数,衡量系统承载能力的核心指标。
    QPS\text{QPS}
  2. C 并发数同一瞬间在途的请求数量,就像同时有几位传菜员在走廊里跑。
    CC
  3. T_resp 响应时间单个请求从进入系统到返回结果的平均秒数,传菜员跑一趟的耗时。
    TrespT_{\text{resp}}

用户账户管理

餐厅会给熟客发会员卡,卡上记着口味偏好和消费记录。下次来一亮卡,服务员就知道“老地方请,少辣”。SaaS 里的用户账户管理,就是这套会员卡体系——它决定谁能进店、进店能干什么。

账户管理有四件事。注册认证是“办卡”,用户用邮箱或手机号开户,密码要加盐哈希存储;会话与权限是“亮卡”,登录后服务端签发一张 JWT 令牌,令牌里写着用户 ID 和角色,前端每次请求带上它,后端验签即认身份,不用查数据库;RBAC 角色权限控制则像“金卡、银卡、员工卡”,普通用户只能生成图片,管理员才能看用量报表。用户画像沉淀是加分项,记录用户常用的风格、分辨率偏好,下次自动填充参数,像熟客一进门服务员就端上他爱喝的茶。

密码安全是账户系统的底线。明文存储等于把保险柜钥匙挂在门口;简单哈希也不够,因为黑客可以用彩虹表反查。业界标准是用 bcrypt 这类加盐哈希算法,让每个用户的哈希值都带上随机的“盐”,就算数据库泄露,破解成本也高到让人放弃。

会员卡发放容易,难的是让访客安全、让熟客感到被尊重。用户账户系统,就是那张既安全又有温度的会员卡。

HashingCost=2cost×thash\displaystyle \text{HashingCost} = 2^{\text{cost}} \times t_{\text{hash}}
这条公式解释 bcrypt 为什么“贵”——成本因子每加 1,破解者的工作量就翻一倍,让暴力破解在算力上变得不划算。
  1. HashingCost 哈希成本验证一次密码所需的总计算开销,越大越难被暴力破解。
    HashingCost\text{HashingCost}
  2. cost 成本因子bcrypt 的工作因子,工程上通常取 10 到 12,每加 1 开销翻倍。
    cost\text{cost}
  3. 2^cost 迭代次数成本因子决定的哈希迭代轮数,这是开销翻倍的来源。
    2cost2^{\text{cost}}
  4. t_hash 基础耗时成本因子为 0 时一次基础哈希的耗时,乘以迭代次数得到总成本。
    thasht_{\text{hash}}

订阅计费系统

餐厅靠收银台赚钱。有的菜按份收钱,对应按量计费;有的客人办月卡随便吃,对应订阅套餐。计费系统就是那台聪明的收银机——它必须算得清楚、记得明白,一分钱都不能差。

订阅计费要解决三件事。第一件是套餐定价:免费版给 50 张/月,专业版 500 张/月,企业版不限量,不同档位对应不同的“饭量上限”;第二件是计费事件追踪:注意,是按“用户成功生成一张图”记一笔,而不是按“用户点了按钮”记——生成失败要退还要重试,不能啥都没做成就收钱;第三件是支付网关对接:用 Stripe 这类成熟服务处理银行卡、订阅续费和发票,支付网关通过 webhook 异步通知你“这桌客人续费成功”。

配额截停是计费的兜底。用户的用量配额用 Redis 之类的原子计数,每生成成功一张就加一,超过配额后下单选单直接被拒,提示“本月额度已用完,升级套餐即可继续”,既保护算力成本,也逼着用户往上升级。

收银台最关键的是“每一笔都算得清、记得明”。计费系统一乱,客人会走,生意会亏,它是整个餐厅的商业心脏。

MRR=∑i=1NPi×Si\displaystyle \text{MRR} = \sum_{i=1}^{N} P_i \times S_i
MRR 是月度经常性收入,是 SaaS 公司最关心的数字之一。它等于所有套餐的价格乘上各自的订阅人数再求和。
  1. MRR 月度经常性收入每月从所有订阅用户那里稳定收到的经常性营收。
    MRR\text{MRR}
  2. P_i 套餐月费第 i 档套餐的每月价格,比如专业版 99 元/月。
    PiP_i
  3. S_i 订阅用户数当前购买第 i 档套餐的付费用户数量。
    SiS_i
  4. Σ 求和符号把每一档套餐的收入全部加起来,得到公司当月总订阅收入。
    ∑i=1N\sum_{i=1}^{N}

多租户隔离方案

餐厅常被公司包场团建,你对 A 公司说“包间在左边”,对 B 公司说“包间在右边”,两家公司看不到对方点了什么菜、账也各结各的。多租户隔离,就是给每个客户一间看不见隔壁的包间。

隔离方案有两个层次。逻辑隔离是主流做法:所有数据库表都带上 tenant_id 字段,查询时强制叠加“只许看本租户数据”的过滤条件,代码层面杜绝串门。物理隔离则给大客户单独部署一套环境,像给 VIP 一个独立别墅,成本高但隔离彻底。绝大多数 SaaS 用逻辑隔离加物理隔离混合。

资源配额管控是防挤占的关键。每个租户的并发请求数、每月生成张数都有限额,防止一个客户的双十一活动把全平台的 GPU 都抢走。数据安全边界则要求:备份和日志同样按租户隔离,导出报表时也要确认归属,确保 A 公司永远看不到 B 公司生成的图片。

包间隔断做好了,客人越多的餐厅越不会混乱。多租户隔离,是 SaaS 从“能跑”走向“能规模化”的地基工程。

Qtenant=RtotalNtenants×Ssafety\displaystyle Q_{\text{tenant}} = \frac{R_{\text{total}}}{N_{\text{tenants}} \times S_{\text{safety}}}
这是给租户分配额的经验公式:总资源除以租户数,再留出安全余量,防止某个租户突发流量把别人挤垮。
  1. Q_tenant 租户配额每个租户最多能同时占用的资源量,比如同时 5 个生成任务。
    QtenantQ_{\text{tenant}}
  2. R_total 总算力集群拥有的全部生成能力,比如 100 张 GPU 卡时。
    RtotalR_{\text{total}}
  3. N_tenants 租户数当前入驻的租户总数,包间数量。
    NtenantsN_{\text{tenants}}
  4. S_safety 安全系数预留的资源余量,通常取 1.5 到 3,让系统扛得住突发流量。
    SsafetyS_{\text{safety}}

投产运维优化

店长每天开门先看数据:今天翻台率多少、哪道菜退单最多、后厨有没有窝工。餐厅经营靠数据说话,AI SaaS 的投产运营也一样——上线只是开始,持续的灰度、监控和成本优化,决定了这家店能活几年。

灰度发布是“先让 5% 的用户尝新菜”。新版代码先切一小部分流量试运行,观察错误率和延迟,没问题再逐步扩大到 50%、100%,出问题立刻自动回滚,把炸厨房的风险控制在最小范围。监控告警体系是“厨房里的火警器”,至少盯住四个指标:QPS 吞吐量、响应延迟、错误率和队列积压长度,一旦越线马上报警。

成本优化是经营的精髓。GPU 是餐厅最贵的“食材”,要让每张卡都物尽其用:闲时把生成服务缩容到零,用多少开多少;把多个小请求合并成一次批量推理,省掉排队空转;给不同套餐分配不同优先级的推理队列,免费用户排队等,付费用户插队先出图。

开店容易守店难。运维就是那个每日巡场、看数据调菜单的店长——只有不断优化的餐厅,才能在竞争里活下来。

Availability=UupUtotal×100%\displaystyle \text{Availability} = \frac{U_{\text{up}}}{U_{\text{total}}} \times 100\%
可用性就是“一年里多少时间能正常营业”。99.95% 看起来只比 99.9% 高一点,但一年下来少宕机 4 个多小时。
  1. Availability 可用性系统在统计周期内真正可用的时间占比,越高代表越可靠。
    Availability\text{Availability}
  2. U_up 正常运行时长统计周期内没有任何故障,服务正常运转的时间。
    UupU_{\text{up}}
  3. U_total 总时长统计周期的总时间,通常按一年 365 天、8760 小时计算。
    UtotalU_{\text{total}}

AI 应用场景

电商海报自动生成工具

阶段:后端服务设计 + 异步任务队列

解决的问题:电商卖家做一张促销海报,传统方式要请设计师、改三版、等两天,成本高周期长。AI 方案让卖家上传商品图和一句文案,系统自动调用图像生成模型产出多张海报初稿,卖家选一张下载即可,全程不到一分钟。

具体案例:某独立开发者做了一个“海报工坊”SaaS:用户在 Web 前端输入文案、选风格,后端把任务丢进 RabbitMQ 队列,GPU 推理服务完成后把海报写入 OSS,前端轮询到“已完成”状态后展示结果。免费用户每天 3 张,付费用户每月 200 张,Stripe 自动扣费。上线三个月,积累了 800 个付费卖家。

设计团队私有化协作平台

阶段:多租户隔离方案 + 资源配额管控

解决的问题:一家 SaaS 公司同时服务几十个企业设计团队,每个团队都有几十人,如果大家共用一套生成队列,大团队会挤垮小团队的出图速度,而且设计稿属于商业机密,绝不能跨团队泄露。多租户隔离让每个团队拥有独立的配额和不可见的数据边界。

具体案例:某企业内部平台向 30 个部门开放 AI 设计能力。每个部门是一个租户,数据库表全部带 tenant_id,查询强制过滤;配额系统给每个部门分配每月 5000 张的生成额度,用完自动暂停。某电商部门大促期间冲量,配额用完立刻引导到管理员审批扩充,其他部门完全不受影响。

独立开发者的付费文生图 API

阶段:订阅计费系统 + 支付网关对接

解决的问题:传统 API 售卖靠人工对账,月底花几天算账单,还有坏账风险。接入支付网关后,订阅、计费、发票全自动,开发者只需关注模型质量。

具体案例:一位独立开发者把开源的文生图模型封装成 REST API,按调用次数订阅收费:19 美元/月含 1000 次调用,99 美元/月含 10000 次。Stripe 负责收钱,webhook 通知订阅状态,后端按“生成成功”事件扣减配额,超量自动截停。三个月做到月入 4000 美元。

Python 演示

python77 行
import timeimport uuidfrom collections import deque  class ImageSaaSTenant:    """单个租户:好比餐厅的包间,有自己的配额和账单。"""     def __init__(self, tenant_id, plan, monthly_quota):        self.tenant_id = tenant_id        self.plan = plan        self.monthly_quota = monthly_quota        self.used_count = 0        self.billing_events = []     def can_generate(self):        return self.used_count < self.monthly_quota     def record_usage(self, prompt, status):        self.used_count += 1        self.billing_events.append({            "event_id": uuid.uuid4().hex,            "prompt": prompt,            "status": status,            "ts": time.time(),        })  class ImageGenPipeline:    """图像生成 SaaS 后端管线:从请求到计费的完整链路。"""     def __init__(self):        self.tenants = {}        self.task_queue = deque()        self.worker_busy = False     def register_tenant(self, tenant_id, plan, monthly_quota):        self.tenants[tenant_id] = ImageSaaSTenant(            tenant_id, plan, monthly_quota        )     def submit_request(self, tenant_id, prompt):        tenant = self.tenants.get(tenant_id)        if tenant is None:            return {"error": "unknown tenant"}        if not tenant.can_generate():            return {"error": "quota exceeded"}        task_id = uuid.uuid4().hex        self.task_queue.append({            "task_id": task_id,            "tenant_id": tenant_id,            "prompt": prompt,            "ts": time.time(),        })        return {"task_id": task_id, "status": "queued"}     def process_next_task(self):        if self.worker_busy or not self.task_queue:            return None        self.worker_busy = True        try:            task = self.task_queue.popleft()            time.sleep(0.2)            tenant = self.tenants[task["tenant_id"]]            tenant.record_usage(task["prompt"], "succeeded")            return {"task_id": task["task_id"], "status": "done"}        finally:            self.worker_busy = False  if __name__ == "__main__":    pipe = ImageGenPipeline()    pipe.register_tenant("t-001", "pro", 100)    res = pipe.submit_request("t-001", "a cute robot chef")    print(res)    print(pipe.process_next_task())    print(pipe.tenants["t-001"].used_count)
目的:用 60 行代码模拟“图像生成 SaaS 从请求进队到计费记录”的完整后端闭环,让你看清多租户配额、任务队列、计量计费这三个核心概念如何协作。
  1. self.task_queue = deque()后厨的点单队列,任务是先进先出。
  2. def can_generate(self):包间检查器,确认这个租户本月还有没有剩饭量。
  3. task_id = uuid.uuid4().hex给每个请求发一张独一无二的“排队号”。
  4. self.task_queue.append(...)传菜员把点单贴到后厨流水线上。
  5. task = self.task_queue.popleft()后厨取走最前面一单开始做。
  6. time.sleep(0.2)模拟模型推理的耗时,真实场景是 GPU 在算。
  7. tenant.record_usage(...)收银台记一笔账,用量加一,账单落库。

常见误区

误区图像生成接口应该像普通登录接口一样,前端发请求后一直等着,接口直接返回图片 URL。我等个十几秒怎么了?

正解请把图像生成想象成“点一份现烤披萨”,而不是“拧开一瓶矿泉水”。HTTP 同步等待会让连接挂十几秒,网关和浏览器都容易超时,服务器并发连接被占满后其他用户全部排队。正确做法是异步任务:接口立刻返回 task_id,前端每 2 到 3 秒轮询一次状态,生成完成后拿到 URL 展示。这样既不让连接长期挂起,又能给用户展示“排队中/生成中”的进度感。

为何常见:日常写的 REST 接口大多是毫秒级同步返回,“同步直觉”被套用到秒级的长耗时场景,忽略了超时和连接资源两个隐患。

误区现在客户才三五个,所有用户数据放同一张表就行,等以后客户多了再加租户字段。先跑起来再说。

正解上线后再加多租户隔离是痛苦的:老表要迁移、历史数据要打标签、遗漏的查询会变成数据泄露事故。早期就在核心表(任务表、账单表、图片表)加上 tenant_id,查询强制过滤,成本极低;反之,漏一个查询接口就等于把 A 公司的设计稿发给 B 公司,这在 To B 场景是致命的信任危机。

为何常见:MVP 阶段把隔离当成“大公司才操心的事”,忽略了数据串租户一旦发生,修复成本远高于建表时多写一列。

误区用户点一次生成按钮,就算一次费用。反正他调用了,我们付出了算力,不管结果如何都得收钱。

正解图像生成是长任务,可能因为模型超时、GPU OOM、内容审核拦截而失败。按“调用次数”计费,会让用户为失败的请求买单,体验极差。正确做法是按“业务成功事件”计费:图片成功生成落库才算一次,失败自动重试,重试仍失败就扣回配额或退还次数。这就像餐厅只有菜端上桌才收钱,半路糊了的菜不能算在客人头上。

为何常见:把技术层面的“接口调用”等同于业务层面的“服务完成”,忽略了长任务天然有失败率。

误区用户密码嘛,存之前用 MD5 哈希一下,就算泄露了也是乱码,安全得很。

正解MD5 是专门为校验文件设计的,速度和“彩虹表”攻击让它对密码毫无防御力——几亿条常见密码的 MD5 值早就被预计算好了。正确做法是用 bcrypt/argon2 这类“故意慢”的加盐哈希:每次哈希都带上随机盐,相同密码在不同用户那里哈希值不同,成本因子让暴力破解慢到怀疑人生。记住:密码不是“加密存储”,而是“不可逆哈希 + 加盐”。

为何常见:混淆了“加密”(可解密)与“哈希”(不可逆)的概念,以为只要不是明文就安全了。

面试题

Q1. 图像生成 SaaS 采用异步任务队列的最主要原因是什么?

单选题 · easy

  • A.异步队列能提高模型生成的画质
  • B.生成耗时长,同步会阻塞连接← 正确答案
  • C.异步队列可以完全省去存储成本
  • D.异步队列能自动跳过用户认证

答案:B。图像生成通常要数秒到数十秒,同步等待会让 HTTP 连接长时间占用,容易超时并拖垮服务器。异步任务先返回排队号,后端处理完再通知,是最稳妥的做法。A 错在队列与画质无关,C 错在队列不省存储,D 错在队列与认证无关。

Q2. 以下哪些属于多租户隔离的常见手段?

多选题 · mid

  • A.数据库表增加租户标识字段← 正确答案
  • B.为每个租户分配独立支付网关
  • C.查询强制叠加租户过滤条件← 正确答案
  • D.每月定期清理所有历史订单

答案:AC。租户隔离的核心是“数据不串 + 资源不挤”。A 加 tenant_id 字段、C 查询强制过滤是标配。B 支付网关应统一对接而非每租户分配;D 清理订单与隔离无关且会造成数据丢失风险。

Q3. 前端轮询任务状态时,比较合适的间隔是?

单选题 · mid

  • A.0.1 秒高频轮询,实时性最好
  • B.1 到 3 秒轮询,兼顾实时与负载← 正确答案
  • C.每次点击都整页刷新,简单粗暴
  • D.完全不轮询,等用户手动刷新

答案:B。图像生成耗时数秒到十几秒,0.1 秒高频轮询会浪费大量请求资源,完全不做轮询又让用户体验断裂。1 到 3 秒的间隔既能让“生成中”状态及时刷新,又不会压垮后端,是工程上的黄金区间。

Q4. JWT 令牌在用户账户管理中的作用是什么?

单选题 · easy

  • A.代替数据库保存用户所有密码
  • B.无状态传递用户身份与权限← 正确答案
  • C.缩短图像生成模型的推理时间
  • D.统计用户每月生成图片数量

答案:B。JWT 的典型用途是登录后签发一个带签名和过期时间的令牌,后续请求凭它识别身份与角色,服务端无需查会话表,因此叫“无状态”。它不存储密码、不影响推理速度,也不负责用量统计。

Q5. 订阅计费系统需要记录哪些关键信息?

多选题 · mid

  • A.用户每次生成成功的用量事件← 正确答案
  • B.用户当前订阅套餐的档位← 正确答案
  • C.用户浏览行为的完整点击日志
  • D.支付网关返回的订阅状态← 正确答案

答案:ABD。计费核心是“额度 + 用量 + 支付状态”三件套:A 用量事件用于计量扣费,B 套餐档位决定价格与上限,D 支付状态用于自动续费和暂停服务。C 浏览日志与计费无关,属于埋点分析范畴。

Q6. 灰度发布的核心目的是什么?

单选题 · mid

  • A.一次性上线全部新功能并快速回滚
  • B.让部分用户先体验新版以降低风险← 正确答案
  • C.通过灰度发布提高模型生成精度
  • D.用灰度发布完全替代单元测试

答案:B。灰度发布先把新版本流量切给 5% 用户,观察错误率和延迟正常后再逐步放大,异常时自动回滚,把故障爆炸半径控制在最小。它是降低风险的发布手段,与模型精度和测试无关。

Q7. 某租户配额 200 张,本月已用 199 张,两个请求同时提交且配额计数未加锁,会发生什么?

单选题 · hard

  • A.两请求都通过检查,总用量超限← 正确答案
  • B.系统自动扩容 GPU 解决超限
  • C.图片生成质量自动下降省算力
  • D.计费系统自动改为按次付费

答案:A。并发场景下,两个请求同时读到 used=199,都通过 can_generate() 检查,最终 used 可能变成 201,突破配额。这就是经典的“竞态条件”,要用 Redis 原子自增或数据库行锁保证计数准确。B/C/D 都是无关干扰项。

Q8. 适合放在 AI SaaS 监控面板的核心指标有哪些?

多选题 · mid

  • A.API 平均响应时间← 正确答案
  • B.任务队列的积压数量← 正确答案
  • C.每日菜单打印的张数
  • D.GPU 服务器的利用率← 正确答案

答案:ABD。监控的核心是“用户能感受到的”与“成本最贵的”——响应时间代表体验,队列积压代表拥堵,GPU 利用率代表成本效率。C 是无关物理指标,与线上服务可靠性无关。

Q9. 用户密码存储的正确做法是什么?

单选题 · easy

  • A.明文保存,方便客服直接查看
  • B.用 MD5 哈希后保存在数据库
  • C.用 bcrypt 加盐哈希后保存← 正确答案
  • D.保存在浏览器 localStorage 中

答案:C。密码必须“不可逆 + 加盐”存储。bcrypt 加盐哈希让相同密码产生不同哈希值,且计算成本可调,能有效对抗彩虹表和暴力破解。明文和 MD5 都等于裸奔,浏览器存储更是把安全责任推给了客户端。

Q10. 为节省 GPU 算力成本,以下哪些做法是合理的?

多选题 · hard

  • A.闲时把生成服务缩容到零← 正确答案
  • B.把多个小请求合并批量推理← 正确答案
  • C.把所有图片分辨率降到 64 像素
  • D.为不同套餐分配不同推理队列← 正确答案

答案:ABD。A 用多少开多少避免闲置浪费,B 批量推理提高 GPU 吞吐,D 免费与付费队列分离让付费用户优先占坑。C 把分辨率降到 64 像素会直接摧毁产品价值,是自毁式“省钱”。