FDE W7D6 学习手册 · 单一调用链设计与部署交付基础
W7 Day6 · B 级(部署交付核心)· 4h · 学完能讲清"为什么只用一层路由/重试/成本统计 + Docker 部署 AI 服务的关键点"
一、企业 AI 调用链总览:为什么需要"统一调用链"
1.1 问题来源
一个企业 AI 平台,调用会穿过多个组件:业务应用、应用框架(Spring AI)、网关(LiteLLM)、模型服务。每一层都可能"好心"地加上路由、重试、成本统计——结果就是重复做、互相冲突、账目混乱。
1.2 核心原则
每一类职责(路由 / 重试 / 成本统计 / 超时)只允许在「一层」里做,且放在最该做的那层
对企业交付,调用链清晰 = 排障路径清晰。一个请求失败,你能立刻定位"是 Spring AI 超时、还是网关拒绝、还是模型 5xx"。如果每层都重试都路由,出了问题谁都讲不清是哪个环节,SRE 会崩溃。Java 候选人要把这点讲成"工程纪律"。
统一调用链的核心是"每类职责只在一层做"。路由/重试/成本/超时各归其位,排障路径才清晰。多层重复做会导致冲突和账目混乱,是交付大忌。
① "统一调用链"不是"把所有逻辑塞一层",而是分层各管一类职责。② 成本统计若两层都做,会 double count,账单翻倍,CFO 追杀。③ 多层重试会造成"重试风暴"——一层失败触发重试,另一层又重试,请求量指数放大。
二、企业模式:业务 → Spring AI → LiteLLM → 模型
2.1 调用链
业务应用(Java) ──▶ Spring AI ──▶ LiteLLM Proxy ──▶ 厂商/私有模型服务
2.2 各层职责(企业模式)
| 层 | 负责 | 不负责 |
| 业务应用 / Spring AI | 业务编排、Prompt、工具调用、应用层超时 | 厂商 Key、预算、多租户治理 |
| LiteLLM Proxy | 路由、虚拟 Key、预算、配额、成本统计 | 业务语义、Prompt 编排 |
| 模型服务 | 推理 | 治理(除非是私有自研模型侧自带) |
企业模式把"治理"集中到网关,Spring AI 只做应用编排。好处:多业务系统共用一个网关,治理一致;换模型厂商业务零改动。Java 团队维护应用,平台团队维护网关,职责清晰。
企业模式:Java 业务经 Spring AI 调 LiteLLM 网关再调模型。治理(Key/预算/路由/成本)归网关,业务编排归 Spring AI。换厂商业务零改动。
① 企业模式前提是有网关;若没网关又想"企业级",Spring AI 就得多干治理的活,职责变重。② 两层都做成本统计是最常见的坑(Spring AI 也记、网关也记),必须只保留网关记。③ 应用层超时要设,但不能和网关超时叠成"双重超时导致提前断"——要协调。
三、学习/自研模式:业务 → 自研 Model Adapter → 模型
3.1 调用链
业务应用(Java) ──▶ 自研 Model Adapter ──▶ 厂商/私有模型服务
3.2 适用场景
对应 D4/D5 的"自研 Gateway"路线:公司没有/不用 LiteLLM,自己写一层 Model Adapter 统一各家调用、做简单路由与重试。常见于已有强 Java 治理体系、不愿引入 Python 组件的情况。
3.3 与企业的区别
- 企业模式:治理在独立网关,Adapter 很薄(Spring AI 直接对接)。
- 自研模式:治理在自研 Adapter 里,要自己实现路由/重试/(可能)成本——责任更重(呼应 D5 自研成本)。
两种模式本质都是"单一调用链",区别只在"网关是买的还是自研的"。无论哪种,路由/重试/成本仍只在一层做——自研模式里就在 Adapter 这一层做,别再在业务代码里又写一遍。
学习/自研模式是业务经自研 Model Adapter 调模型,治理在 Adapter 内。和企业模式区别只在网关是自研还是 LiteLLM,但"单一职责层"原则不变。
① 自研 Adapter 很容易"顺手"把重试、路由、成本全写进去还不规范,最后变成 D5 说的"LiteLLM 山寨版"。② 自研模式下更要警惕:业务代码里别再偷偷加一层重试,否则同样有重试风暴。③ Adapter 也要高可用(它是咽喉),别写成单点。
四、为什么只用一层路由(避免两层路由冲突)
4.1 两层路由的问题
若 Spring AI 业务侧做一层路由("这个请求走模型 A"),网关又做一层路由("这个 Key 走模型 B"),两者可能决策冲突或叠加:
- 业务选 A,网关因预算/白名单改到 B,业务不知道,结果不符合预期。
- 两层都按不同策略路由,行为不可预测、难调试。
4.2 正确做法
| 路由依据 | 放哪层 |
| 厂商/模型选择(按预算、白名单、成本) | 网关(LiteLLM)一层做 |
| 业务语义选择(如保单类型) | 在到达网关前由业务/薄路由层决定(选哪个虚拟 Key),进网关后不再二次路由 |
路由的"最终决策权"只能在一个地方。建议:业务层只决定"用哪个虚拟 Key/租户",真正的模型映射与预算路由全由网关做。这样业务简单、网关权威,不冲突。
两层路由会冲突/叠加、行为不可预测。正确做法:路由最终决策权只在一层(网关),业务层最多决定用哪个 Key,不二次路由。
① "业务选模型、网关又选模型"是典型反模式。② 若业务必须按语义选模型,应通过"选不同虚拟 Key"表达,而不是在网关外再建一套模型路由表。③ 两层路由冲突时,往往表现为"偶发走错模型",极难排查。
五、为什么只用一层重试(避免重试风暴与重复统计)
5.1 两层重试的灾难
Spring AI 重试 3 次、网关又重试 3 次 → 一次失败最多产生 3×3=9 次 实际请求。这叫重试放大 / 重试风暴:
- 模型侧压力被放大多倍,可能压垮模型或触发厂商限速。
- 成本被放大(重试也花钱)。
- 延迟叠加(每层都等超时)。
5.2 重试该放哪层
| 失败类型 | 该哪层重试 | 理由 |
| 网络抖动 / 网关 5xx / 超时 | 靠近调用方的那一层(Spring AI 或网关二选一) | 瞬时错误,重试有用 |
| 业务错误(如结构化校验失败) | 应用层(带反馈重试,见 D2) | 需改 Prompt,网关不懂业务 |
| 预算/配额拒绝(429) | 不宜盲目重试 | 应降级/排队,重试只会更快撞墙 |
重试的"总次数预算"要全局规划。经验:只在一层做网络级重试(如 Spring AI 设 maxAttempts=2),网关不再重试;或反过来网关做、应用不做。关键是不要两层都做。业务级(结构化校验)重试是另一类,单独在应用层做,不计入网络重试。
两层重试会放大成 N×M 次请求(重试风暴),压垮模型、翻倍成本、叠加延迟。正确:网络级重试只在一层做,业务级带反馈重试在应用层单独做,两类不混。
① 429(预算/限速)不要重试——只会更快撞墙,应降级或退避排队。② 网络重试和业务重试是两类,别把它们当成同一个"重试开关"乱开。③ 每层超时+每层重试会"双重等待",总延迟 = 超时×重试层数,要协调超时值。
六、成本统计只在一层做(避免 double count)
6.1 重复统计的后果
若 Spring AI 侧记录"本次花费"、网关(LiteLLM)也记录"本次花费",同一请求被记两次 → 成本报表翻倍,Chargeback 算错,业务线互相甩锅。
6.2 唯一可信来源
成本统计的唯一可信来源 = 网关(LiteLLM)落库(它掌握真实 token 用量与厂商计费)
- 网关层有真实 token 数 + 厂商单价 → 唯一权威。
- 应用层若想看成本,应从网关拉报表,而不是自己再算一遍。
- 应用层只记录"本次用了哪个模型、多少 token(估计)"用于自身 Trace,不作为结算依据。
金融客户对账单极其敏感。成本必须 single source of truth。交付时明确:网关是记账本,应用是流水账(仅调试用)。内部结算一律以网关 Spend 报表为准。
成本统计唯一可信来源是网关(它掌握真实 token 与单价)。应用层不要重复记账单,只记调试用 Trace。否则账单翻倍、结算混乱。
① "应用层也记一下成本方便看"是坑——记着记着就被当成结算依据,和网关对不上。② 网关成本依赖落库,库故障期间的成本会丢,要有补偿(如请求日志回算)。③ 项目标签伪造问题(D5)会让结算错,网关侧强制归属更可靠。
七、Docker 基础:AI 服务容器化
7.1 为什么用 Docker 部署 AI 服务
- 环境一致:开发、测试、生产同一镜像,避免"我本地能跑"。
- 隔离:模型服务/网关/业务各自容器,互不污染。
- 可移植:K8s(D7)直接编排容器。
7.2 镜像要点(AI 场景)
| 关注点 | 做法 |
| 基础镜像 | 选带 CUDA 的(GPU 推理)或 slim 版(CPU/网关) |
| 依赖 | Python 用 requirements 锁版本;Java 用多阶段构建减小体积 |
| 模型权重 | 大模型权重不要打进镜像,用挂载卷/对象存储,镜像只放代码 |
| 非 root | 容器跑非 root 用户,降攻击面 |
AI 服务镜像和一般 Java 服务不同:模型权重动辄几 GB~几十 GB,绝不能打进镜像(镜像膨胀、拉取慢、难更新)。权重走 Volume/对象存储挂载,镜像只含运行时代码。这是交付时常犯的错。
Docker 给 AI 服务环境一致、隔离、可移植。AI 镜像要点:权重别打进镜像(走挂载)、非 root 运行、GPU 用 CUDA 基础镜像、依赖锁版本。
① 把模型权重打进镜像 = 镜像几十 GB、每次更新模型要重 build 重传,极度低效。② 容器默认 root 有安全风险,金融交付会卡合规。③ 镜像体积不控,K8s 拉镜像慢,发布变龟速。
八、Docker Compose 编排多服务
8.1 什么时候用
单机演示 / PoC / 小团队:用 docker-compose.yml 一把起"网关 + 数据库 + 业务"多个容器,定义网络和依赖顺序。
# 简化示例:网关 + 数据库
services:
litellm:
image: ghcr.io/berriai/litellm:main
ports: ["4000:4000"]
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/litellm
depends_on: [db]
secrets: [litellm_master_key]
db:
image: postgres:16
volumes: ["pgdata:/var/lib/postgresql/data"]
volumes: { pgdata: {} }
8.2 局限
Compose 适合单机,没有自动扩缩容、自愈、多节点。生产上这些交给 K8s(D7)。
交付节奏:先用 Compose 给客户快速演示"整套能跑",再上 K8s 做生产。Compose 是"验收演示利器",不是"生产方案"。要清楚边界,别把 Compose 当生产架构讲。
Compose 适合单机演示/小团队,一把起多容器、定依赖。但它无扩缩容/自愈/多节点,生产交给 K8s。是演示利器非生产方案。
① Compose 的 depends_on 只管启动顺序,不管"就绪"——DB 起了但没接受连接,网关可能连不上,要配合健康检查/重试。② 把 Compose 当生产架构讲,会被问"单节点挂了怎么办"。③ Compose 的 Secret 仍建议走外部 Secret 管理,别明文写 yml。
九、环境隔离(dev / staging / prod)
9.1 为什么隔离
开发、测试、生产必须隔离,否则:测试数据污染生产、实验性 Prompt 影响真实用户、密钥混用导致越权。
9.2 隔离维度
| 维度 | 做法 |
| 网络/命名空间 | K8s namespace 或不同 VPC;dev/staging/prod 互不可达 |
| 配置 | 各环境独立配置(模型地址、预算上限不同) |
| 数据 | 测试用脱敏/假数据,生产用真实(严格授权) |
| 密钥 | 各环境独立 Key,prod Key 仅 prod 可见 |
保险客户最忌"测试环境连了生产库"。交付时环境隔离是硬合规项:namespace 隔离 + 配置分离 + 数据脱敏 + 密钥分环境。staging 要尽可能"像生产"才能暴露真实问题。
环境隔离靠 namespace/网络隔离 + 配置分离 + 数据脱敏 + 密钥分环境。保险场景测试连生产库是严重事故,必须隔离。staging 尽量像生产。
① "staging 用生产数据方便测试"是违规高风险,金融必须脱敏。② 配置若共用一套,容易把 prod 的模型地址配到 staging,影响真实计费。③ 密钥跨环境复用 = 隔离形同虚设。
十、Secret 管理(API Key / 数据库密码)
10.1 原则
- 绝不进代码/镜像/Compose 明文:厂商 Master Key、DB 密码走 Secret 管理。
- 外部 Secret 管理:K8s Secret / Vault / 云 Secret Manager,运行时注入环境变量或挂载文件。
- 最小权限:每个服务只拿到它需要的 Secret。
- 可轮换:Key 泄露能快速轮换,不重启业务(呼应 D5 虚拟 Key)。
10.2 对比
| 方式 | 风险 |
| 明文写在 yml/env | 提交到 Git 即泄露,灾难 |
| K8s Secret(base64) | 仅是编码非加密,需配合 RBAC + 加密存储(etcd 加密) |
| Vault / 云 Secret Manager | 较优,有动态秘钥、审计、轮换 |
金融交付的 Secret 审计极严。厂商 Key 若明文进 Git,是 P0 事故。交付清单里必须有"Secret 不落代码、走 Vault/云、etcd 加密、有轮换流程"。这是 Java 候选人体现"交付成熟度"的点。
Secret 绝不进代码/镜像明文,走 K8s Secret/Vault/云 Secret Manager,最小权限 + 可轮换。K8s Secret 只是 base64 编码,需配 etcd 加密和 RBAC。
① K8s Secret 默认只是 base64,不是加密,谁有 get 权限就能解,必须开 etcd 加密 + RBAC。② "临时先明文,上线再改"基本永远不会改,要一开始就不明文。③ 密钥轮换流程缺失,泄露后只能紧急改代码重发,业务中断。
十一、Health Check 与 Readiness Check 的区别
11.1 两个探针
| 探针 | 回答 | 失败后果 | AI 场景例子 |
| Liveness(存活) | 进程还活着吗 | 重启容器 | 进程卡死、死锁 |
| Readiness(就绪) | 能接流量吗 | 从负载均衡摘掉,不重启 | 模型还没加载完、依赖的网关连不上 |
11.2 为什么 AI 服务特别要区分
- 大模型加载权重要几十秒~几分钟,进程活了但模型没就绪——此时应 Readiness=false,别接流量,但别重启(Liveness=true)。
- 网关依赖的 DB 短暂不可达,Readiness=false 暂时摘流,恢复后自动加回。
很多团队把 Health 和 Readiness 混成一个接口,导致"模型没加载完就被打流量"或"依赖抖动就被杀容器"。AI 服务启动慢、依赖多,两个探针必须分开配,且阈值给足(模型加载慢)。
Liveness=进程活着否(失败重启);Readiness=能否接流量(失败摘流不重启)。AI 服务模型加载慢,进程活但没就绪,必须 Readiness=false 别接流量、别误重启。两探针分开配。
① 把 Readiness 失败当 Liveness 失败 → 容器被反复杀,模型永远加载不完(启动慢 + 被杀循环)。② 探针超时设太短,模型加载期间一直失败,误杀。③ 探针接口本身依赖外部(如查 DB),外部抖动会让探针失败、误摘流/误重启。
十二、AI 服务部署的工程交付 Checklist
12.1 上线前清单
- 镜像:权重不进镜像、非 root、依赖锁版本、体积可控。
- 配置:各环境分离,模型地址/预算按环境不同。
- Secret:走 Vault/云,不落代码,etcd 加密 + RBAC,有轮换流程。
- 探针:Liveness / Readiness 分开,阈值适配模型加载耗时。
- 调用链:路由/重试/成本各只在一层,无重复。
- 降级:网关挂了应用有兜底(换模型/人工),不卡死。
- 可观测:日志/链路追踪/Trace 串联(调用链 id 贯穿各层)。
- 资源:GPU/内存/超时按模型设限,防 OOM 拖垮节点。
这份清单就是"交付成熟度"的体检表。Java 候选人讲部署,不要只讲"docker run",要讲"我交付时会确保这 8 条都过关"。尤其调用链单一职责 + 降级 + 可观测,是区分"会跑"和"能运维"的关键。
交付清单:镜像规范、配置分离、Secret 管理、双探针、调用链单一职责、降级兜底、可观测串联、资源限配。八条全过才是"可运维交付"。
① "能 docker run 起来"≠"能交付"——缺降级和可观测,半夜出问题没人能查。② 调用链没做单一职责,上线后成本对账天天吵架。③ 资源不限(GPU/内存),一个请求 OOM 拖垮整节点,连带其他服务。
十三、面试达标线①:只用一层路由/重试/成本
| 职责 | 只在哪层 | 两层做的后果 |
| 路由 | 网关(业务只选 Key) | 两层路由冲突、走错模型、难排查 |
| 网络重试 | 一层(Spring AI 或网关二选一) | 重试风暴 N×M、压垮模型、成本翻倍 |
| 成本统计 | 网关(唯一可信来源) | 账单 double count、结算混乱 |
核心:路由最终决策权在网关一层;网络级重试只在一层(业务级带反馈重试另算);成本以网关落库为唯一可信来源。每类职责单一归属,排障清晰、账目干净。
十四、面试达标线②:Docker 部署 AI 服务的关键点
镜像(权重外挂/非root/锁版本)→ 编排(Compose演示/K8s生产)→ 隔离(ns/配置/数据/密钥)
→ Secret(Vault/etcd加密/轮换)→ 探针(Liveness≠Readiness)→ 交付清单(降级/可观测/资源限)
- 镜像:模型权重走挂载不进镜像、非 root、依赖锁版本。
- 编排:Compose 做演示,K8s 做生产(扩缩容/自愈)。
- 隔离:dev/staging/prod 网络+配置+数据+密钥全隔离。
- Secret:不落代码,走 Vault/云,etcd 加密 + RBAC + 轮换。
- 探针:Liveness(重启)与 Readiness(摘流)分开,阈值适配模型加载。
- 降级/可观测/资源限:网关挂有兜底、Trace 串联、GPU/内存设限。
十五、W7D6 自测清单
- 能画出企业模式调用链(业务→Spring AI→LiteLLM→模型)并说清各层职责。
- 能画出学习/自研模式调用链(业务→自研 Adapter→模型)并对比差异。
- 能解释"每类职责只在一层做"的原则与排障价值。
- 能讲清两层路由为何冲突、正确做法(业务只选 Key,网关做最终路由)。
- 能解释两层重试的重试风暴(N×M)及重试该放哪层。
- 能区分网络级重试与业务级带反馈重试是两类,429 不该盲目重试。
- 能说清成本统计唯一可信来源是网关,重复记会 double count。
- 能讲清 Docker 镜像对 AI 服务的特殊要求(权重外挂/非 root/锁版本)。
- 能说明 Compose 适用与局限(无扩缩容/自愈),及 depends_on 不管就绪。
- 能讲清环境隔离的维度(网络/配置/数据/密钥)。
- 能讲清 Secret 管理(不落代码/Vault/etcd加密/轮换),及 K8s Secret 只是 base64。
- 能区分 Liveness 与 Readiness,及 AI 服务为何必须分开配。
十六、高频面试题速记卡
Q:为什么只用一层路由?
两层路由会冲突/叠加、走错模型、难排查。最终路由决策权只放网关,业务只选虚拟 Key。
Q:两层重试有什么灾难?
变成 N×M 次请求(重试风暴),压垮模型、成本翻倍、延迟叠加。网络重试只在一层做。
Q:业务级重试和网络重试是一回事吗?
不是。网络重试(超时/5xx)在一层做;业务级带反馈重试(结构化校验失败)在应用层另做,不混。
Q:429 该重试吗?
不该盲目重试,会更快撞墙。应降级或退避排队。
Q:成本统计为什么要只在网关做?
网关掌握真实 token 与单价,是唯一可信来源。应用再记会 double count,结算混乱。
Q:AI 服务 Docker 镜像最大的坑?
把模型权重打进镜像(几十 GB、难更新)。权重走挂载/对象存储,镜像只放代码。
Q:Compose 能当生产架构吗?
不能。它无扩缩容/自愈/多节点,只适合单机演示。生产上 K8s。
Q:Liveness 和 Readiness 区别?
Liveness=进程活否(失败重启);Readiness=能否接流量(失败摘流不重启)。AI 模型加载慢必须分开配。
Q:K8s Secret 安全吗?
默认只是 base64 编码非加密,需配 etcd 加密 + RBAC;更优是 Vault/云 Secret Manager。
Q:环境隔离为什么对保险客户重要?
防测试连生产库、实验 Prompt 影响真实用户、密钥混用越权——是硬合规项。
FDE W7D6 学习手册 · 单一调用链设计与部署交付基础(面试级)· 配合《FDE-W7D6-评测题.md》自测
📌 待查★ 重要