模型名停用与分层降级:一次 LLM 链路的失败面设计

模型名停用与分层降级:一次 LLM 链路的失败面设计

主题:LLM 链路的契约漂移与分层降级

先说结论

在 LLM 参与的链路里,"失败"是常态而不是异常;更隐蔽的是"契约漂移"------ 你一行代码没改,模型名、参数语义、响应格式已经变了。

别的地方怕的是 500;这一块最怕的是 200 ------ 但答案是错的、或者链路其实没生效。

我最终落到的结构是这样:

arduino 复制代码
             ┌─ 契约层:把"模型侧的不确定"实测钉成契约(模型名/参数/响应格式)
LLM 链路 ────┼─ 降级层:六层降级,分界是"是否已经写给用户"
             └─ 边界层:把模型当"不可信输入",工具只给只读能力

一、问题:生产依赖一个"已公告停用"的模型名

官方更新日志写明:旧的模型别名 deepseek-chat / deepseek-reasoner 将于某日停止使用。而现实是:

时点 事实
公告日 官方宣布旧别名"三个月后停用"
名义停用日 实际未执行,兼容层仍在
项目某次提交 因为线上问题,把 chat 模型改成了这个旧别名
排查当天 实测仍 HTTP 200(可用),但这是"欠着的债"

一旦兼容层撤销 :意图提取、重排、偏好提取、RAG、对比会全线降级(降级路径能兜住不 500,但 AI 功能等于失效)。

怎么把"生效值"钉死(这一步比结论重要)

  1. 别读文档也别读代码猜 ------ 解包生产容器里的 jar ,直接看 application.yml;
  2. 确认 prod 配置没有覆盖这个段(否则读到的还是默认值);
  3. git log 找到是哪次提交改的;
  4. 向模型服务商发最小请求 (max_tokens=1,只读、成本可忽略)探测兼容层还剩多少。

第 4 步的附带发现是决定性的:

请求的 model HTTP 响应里回显的 model 是否返回 reasoning 字段
deepseek-chat 200 deepseek-flash 无
deepseek-v4-flash 200 deepseek-flash 有
deepseek-reasoner 200 deepseek-flash 有
deepseek-v4-pro 200 deepseek-v4-pro 有

⇒ 两个别名底层已经是同一个模型 ,差异只来自"思考模式开/关" 。这直接指向:应该用官方显式的思考开关,而不是靠换模型名。

⚠️ GET /models 不是权威清单 :它不含那两个旧别名,但两者都能调。不能据它判断可用性 ------ 这条如果不实测,很容易得出反向结论。

根因(历史上为什么这么改) :推理型模型对"重排 / 意图提取"这类 JSON 小任务过度思考 ,且思考量随 max_tokens 水涨船高 (实测 max_tokens=1000 就想满 1000,4000 就想满 4000)→ 思考吃满预算 → content 为空或被截断 → JSON 解析失败 → 降级。当时用"换模型名"间接控制思考开关,方向对但手段过时。


二、方案:把契约实测成"硬约束"

改造本身不复杂(用官方思考开关),值钱的是实测出来的几条契约:

  • 工具轮与 JSON 输出模式互斥 ------ 工具轮上不能同时要求结构化输出;
  • 思考模式必须回传推理内容 ------ 不回传直接 400;
  • 工具轮不需要长思考 ------ 工具选择是结构化决策,一律关掉思考;
  • 流式下的工具调用分片 ------ arguments 会被切成十几段 ,必须按 index 拼接连缀 ;同一次响应里还会先来一批正文分片(preamble)再来工具调用;
  • 强制工具调用是支持的 ------ 但只对"商品意图"用:永远强制会让"你好"也去检索。

改完用路由日志确认"恰好路由 1 次"(防双调用/双 bean)。


三、⭐ 更深一层的认知:降级的分界是"是否已经写给用户"

这是整篇设计里最值钱的一段 ------ 六层降级,每一层都有明确的触发条件与用户可见行为:

层 触发 行为 用户看到
① 工具级 工具异常 / 未知工具 / 参数非法 转成可读 observation 回灌,循环继续 正常回答(换个方式或如实说)
② 未写出内容就失败 首轮调用异常(流式:尚未写出任何分片) 降级到旧的固定流水线 与升级前一致
③ 已写出内容后失败 流式回合中途断流 如实报错收尾,绝不降级 error + done(不会两段回答拼接)
④ 轮数用尽 模型一直调工具 摘掉工具,追加"请立即作答"再问一次 正常回答
⑤ 预算超限 当日成本超限 入口直接拒绝 "服务繁忙"
⑥ 空答复 收敛轮正文为空 再问一次;仍空 → 降级话术 降级文案(不返回空)

💡 ②③ 的分界是核心 :"已经写给用户的东西不能装没发生" ------ 所以必须在写第一个字节之前 决定"这条链路还能不能降级"。 为此流式路径专门缓冲正文 ,并把商品事件排在第一个正文分片之前 。这不是优化,是降级能力的前提。

配套的边界设计(把模型当不可信输入,而不是当函数):

  • 工具权限最小化 :只暴露 3 个只读 工具,写操作(加购/下单/退款)一个都不给 ------ 不给 AI 犯错的机会,比事后审计便宜;
  • 参数一律在工具内收敛 (白名单/截断/类型),因为模型输出是自然语言;实测模型编造的 id 会被工具优雅拒绝,循环继续不炸;
  • 轮数上限 + 成本记账每轮都做(Agent 是"多次调用",成本约为旧流水线的 2 倍);
  • 结果真实性:只把工具结果拼进上下文 ------ 让"编造"没有素材。

四、⭐ 顺带挖出的三个"死的"东西

改这一类问题时,一定会挖出**"设了但没用"的东西。它们不报错,但会误导后来人**:

类型 实例 为什么是"死的"
死参数 采样温度 官方说思考模式下温度不生效(设了不报错)→ 一直是死参数
死配置 对比模型配置项 全仓 grep 只命中定义处与配置文件各一次 → 零引用(实际用的是 chat 模型)
死代码 LLM 客户端上的 embedding 方法 没有任何注入点使用 (真正走的是另一个 embedding 客户端);而那套代码打的是 A 家的地址 + B 家的模型 + A 家的 key → 三样对不上,真被调用必然失败

五、另一条线索:4 条"不崩但不对"的生产踩坑

# 现象 根因 处置
1 部署后立刻打接口 503 No servers available 固定 sleep 早于实际启动(启动+注册 44 秒),正好卡在**"已反注册、还没重注册"的空窗** 改成轮询启动日志判据,不靠固定睡眠
2 偶发 500(鉴权异常 + "响应已提交") ⭐ 用定量对照定性:客户端 18/18 全成功 ,但日志仍出现鉴权拒绝 ⇒ 它是内部 ERROR 派发的次生现象 :请求先失败(典型是 SSE 流)→ 容器转 /error → 安全过滤器链在 ERROR 派发上又跑一遍 ,而 JWT 过滤器默认跳过 ERROR 派发 → 匿名 → 拒绝 /error 登记待办:放行 ERROR 派发类型(公共配置,需单独窗口 + 全服务回归)
3 回答正确但商品列表是空的 模型遇到与历史相似的问题时直接引用历史商品作答 ,本轮没调工具 → 没有命中数据 提示词加规则 + 首轮强制工具调用
4 库存回答张冠李戴 工具的 observation 没带商品名 → 模型只能靠猜的 id 自圆其说 工具返回里增加商品名自报家门,查不到直接报错

六、踩坑清单

认知 / 坑 说明
🔑 判"某配置的生效值"必须同时查 yml 与代码默认值 只看代码默认值会得出错误结论(我自己第一版就判错了)------ 配置文件才是生效源
🔑 停用模型名不会立刻报错 兼容期内一切正常 ⇒ 靠"调用点清单 + 定期实测"发现,别等 4xx
⚠️ /models 类接口不是权威清单 它可能不列某些仍可用的别名
⚠️ 看到 ERROR 先别改代码 用"客户端成功率 + 派发类型"定性;本例真病灶在"失败后转 /error"
⚠️ 判"服务起来了"用日志判据 + 外部探活 启动几十秒,固定 sleep 会踩 503 空窗;判据要按服务自适应(网关主类名可能不带 Application)
⚠️ 测试要离线 正确性在"循环控制/事件顺序/降级策略",与真实模型无关;用脚本化假件才能主动制造"写一半就失败"
🔑 降级必须在"写第一个字节之前"决策 流式一旦写出就不能收回

七、一句总结

LLM 链路要把"契约、降级、边界"三件事分开做:契约靠实测钉死,降级靠"是否已写给用户"分层,边界靠"只给只读能力 + 参数不可信"。


本文基于一个个人微服务电商演示项目的真实实施记录整理,涉及的环境信息已做脱敏处理。

相关推荐
橙子家1 小时前
对象状态与操作合法性异常【C# Exception 详解系列(二)】
后端
架构技术专栏2 小时前
为什么 AI 公司都想做Personal Agent ?
后端
用户761016088472 小时前
黑马RabbitMQ 从入门到可靠性:收发、持久化、死信延迟一篇打通
后端
Bazingga2 小时前
Transformer与自注意力机制:一台"全员检索"机器的说明书
人工智能·后端
星辰云-2 小时前
# 基于Spring Boot的德州特产扒鸡商城系统(毕设|源码|论文|演示视频)
spring boot·后端·课程设计
武子康3 小时前
同为7/8,错误样本却不同:Agent Grader 分歧复算
人工智能·后端·agent
茉莉玫瑰花茶3 小时前
GO [ 内存与变量逃逸分析 ]
开发语言·后端·golang
星辰云-3 小时前
基于Spring Boot的旅游景点票务系统的设计与实现(毕设项目,附完整源码)
spring boot·后端·课程设计
Rain的Java大神之路3 小时前
百万并发直播弹幕系统设计全解:看懂了扇出,你就看懂了高并发的八成
java·后端·面试