Skip to content

L01-03 国内多模型统一适配层 ​

全局中心内容:厂商差异锁在配置层,业务代码里不该出现任何厂商名。 全局讲解主线:先看「if-else 接厂商」有多糟 → 讲清 OpenAI 兼容协议 → 做出路由 → 三家实测。


P1 · 产出页 ​

中心内容:改一个配置名换厂商,业务代码一行不改。

  • 页面内容

    • DeepSeek / 通义 / 智谱 三家可切换
    • 业务层只认 ChatClient
    • 三家都能触发工具调用
  • 讲解技巧

    • 当场演示切换:改 yml 一行 → 重启 → 同一个问题三家分别答一遍。眼见为实比任何架构图都有力。
    • 强调验收标准不是「能跑」,是「业务代码零改动」。
  • 时长:20s


P2 · 痛点页:if-else 接厂商 ​

中心内容:问题不在 if 多,在业务里出现了厂商概念。

  • 页面内容

    • 反面代码:if ("deepseek".equals(vendor)) ...
    • 三个后果:无法灰度/灾备、选项类型各自为政、工具能力要写分支
  • 讲解技巧

    • 先翻车:真的把这段 if-else 写出来跑通,然后问「现在老板要求做灾备自动切换,你要改几个类?」让大家数。
    • 类比迁移:「这就是把 MySQL 驱动名写死在 Service 里」——一次讲清依赖倒置。
  • 时长:2min 30s


P3 · 原理图:OpenAI 兼容端点 ​

中心内容:一个 starter 通吃,因为大家都说同一套协议。

  • 页面内容

    • 你的代码 → OpenAiChatModel → POST {base-url}/chat/completions
    • 下挂四家:DeepSeek / 通义 / 智谱 / OpenAI
    • 换厂商 = 换 base-url + key + model
  • 讲解技巧

    • JDBC 类比再次使用:「协议就像 JDBC 规范,各家提供驱动。你依赖的是规范,不是某家数据库」。这是贯穿全课的核心类比,要讲透。
    • 诚实说明代价:厂商独有能力用不了。什么时候该引专用 starter,给明确判据。
  • 时长:3min


P4 · 选型表:三种装配策略 ​

中心内容:B 打底 + C 收口,本课时用这个组合。

  • 页面内容

    • A 单一主模型 / B 多 Bean + Qualifier / C 路由代理
    • 推荐:先做 B 让切换可行,再用 C 做默认路由
  • 讲解技巧

    • 不要平均用力讲三种。重点讲 C,因为它是生产形态;A 一句话带过,B 说明它是 C 的地基。
    • 提问留白:「为什么不让业务代码直接 @Qualifier 选模型?」——因为那样业务就知道了厂商,又回到 P2 的坑。
  • 时长:2min 30s


P5 · 版本差异提示 ​

中心内容:starter 命名在 1.x → 2.x 变过,拉不到依赖先查命名。

  • 页面内容

    • 旧:spring-ai-openai-spring-boot-starter
    • 新:spring-ai-starter-model-openai
  • 讲解技巧

    • 这页是给踩过坑的人的安慰剂:明确说「如果你按老教程引依赖会拉不下来,不是你的错」。这种话能显著降低挫败感。
    • 顺带给出排查口诀:依赖拉不到先核名,功能不生效先核版本。
  • 时长:1min


P6 · 编码:配置外置 ​

中心内容:厂商差异全部写进 yml。

  • 页面内容

    • ai.vendors.{deepseek,qwen,zhipu} 各自 base-url / model / key / supports-tools
    • 通义的兼容端点是 /compatible-mode/v1
  • 讲解技巧

    • 重点讲通义那个路径:这是真实会让 80% 的人卡住的坑。现场演示写错 /v1 报 404,再改对。
    • 强调 supports-tools 这个字段的意义:能力差异也要配置化,不要写死在代码里。
  • 时长:4min


P7 · 编码:多 ChatModel 构建 ​

中心内容:每个厂商一个独立 OpenAiApi 实例。

  • 页面内容

    • OpenAiApi.builder().apiKey().baseUrl().build()
    • OpenAiChatModel.builder().openAiApi(api)...
    • 放进 Map<String, ChatModel>
  • 讲解技巧

    • 这是本节最容易写错的地方,要放慢:很多人试图共用一个 Api 改 url,结果打到错误地址。
    • 用一句话钉死:「base-url 和 key 绑在 Api 上,不是绑在 ChatModel 上」。
  • 时长:5min


P8 · 编码:路由代理 ​

中心内容:实现 ChatModel 接口,上层全部无感知。

  • 页面内容

    • ChatModelRouter implements ChatModel
    • call() 里按默认厂商委派
    • 注入给 ChatClient.Builder.chatModel(router)
  • 讲解技巧

    • 可视化反差:把替换前后的 ChatConfig 并排——除了 .chatModel(router) 多一行,其余一字未改。
    • 强调这就是适配层的全部价值:换实现不改调用方。
  • 时长:4min


P9 · 运行:三家逐个体检 ​

中心内容:三家都要跑,不能只跑默认那家。

  • 页面内容

    • /api/vendor 看当前厂商
    • ?vendor=qwen 指定厂商
    • 工具调用三家分别测
  • 讲解技巧

    • 必须现场翻一次车:故意只配了默认厂商的 Key,切到第二家时报错。然后讲「这就是为什么切换必须实测」。
    • 演示 /api/vendor 返回值与 yml 一致性校验——这是上线前必查项。
  • 时长:4min


P10 · 避坑与小结 ​

中心内容:工具能力必须逐模型实测,文档不可信。

  • 页面内容

    • 业务代码里不出现厂商名(判据:换掉 yml 全部厂商名能跑)
    • 超时/重试按厂商分别配置
    • 工具支持度逐模型实测,结果写进配置
  • 讲解技巧

    • 第三条要说的是「这张实测表是你的资产」。厂商文档写「支持 Function Calling」常指旗舰模型,兼容端点上的轻量模型完全不触发。
    • 结尾悬念:「现在换厂商要重启,怎么做到运行时切换?」——04-02 模型网关。
  • 时长:2min


讲师备忘 ​

项内容
课前必做三家 Key 全部确认有效;提前跑一遍 /compatible-mode/v1 的常见错误
最容易超时处P7 的 OpenAiApi 实例化,容易展开讲 Spring AI 的 Api 抽象层
学员最常问「为什么不用厂商官方 SDK?」答:官方 SDK 意味着每家一套 API,正是我们要避免的
现场备用某家 Key 失效 → 用预录的该家成功输出;不要现场调试 Key