S22-X16 · 模型谱系与路由层:BGE-small、Qwen3、SDXL-Turbo 与 GPT-4V 的位置
模型名看多了会失焦:Qwen3-4B、BGE-small、SDXL-Turbo、GPT-4V 分属四类不同的东西,并列成"候选"再按强弱排序,等于把螺丝刀和扳手按长度排。决定选型的是三个坐标:结构(Encoder-Decoder 还是 Decoder-only)、参数量与对齐方式、输入模态。
1. 三个坐标,先给模型定位
| 模型 | 结构 | 规模量级 | 输入 | 典型用途 |
|---|---|---|---|---|
BGE-small |
Encoder-only(双向) | 小(数十 M 到百 M 级参数) | 文本 | 向量化、检索召回、重排 |
Qwen3-4B |
Decoder-only | 4B 级 | 文本 | 端侧/私有化、低延迟问答 |
Qwen3-32B-RL |
Decoder-only | 32B 级,经 RL 对齐 | 文本 | 复杂推理、质量优先 |
SDXL-Turbo |
UNet + VAE(扩散) | 图像生成专用 | 文本提示 → 图像 | 出图、批量草稿 |
GPT-4V |
多模态(视觉输入) | 闭源未公开 | 文本 + 图像 | 图像理解、截图解析 |
这张表的价值是排除法:要向量别看 Qwen3,要出图别看 BGE,要读图别指望纯文本模型。
先排除再比较:要向量只剩 BGE-small,要出图只剩 SDXL-Turbo,要读图只剩视觉输入模型,剩下的文本档才在 Qwen3-4B 与 Qwen3-32B-RL 之间按成本决定。
2. Encoder-Decoder:结构决定它能不能做检索
Encoder 是双向注意力,每个 token 能看到左右;Decoder 是因果注意力,只能看左侧。差别直接决定用途:
| 结构 | 注意力 | 输出 | 适合 |
|---|---|---|---|
| Encoder-only | 双向 | 定长向量或逐 token 分类 | 检索、分类、NER、相似度 |
| Decoder-only | 因果 | 下一个 token 的概率分布 | 生成、对话、推理 |
| Encoder-Decoder | 编码双向 + 解码因果 | 序列到序列 | 翻译、摘要(经典 T5 形态) |
BGE-small 属第一类:输出是句向量,"意思相近的句子向量也相近"。Qwen3-* 属第二类:输出是 token 序列,句向量只是副产物,质量与专用 embedding 模型不可比。
"用生成模型做检索"常不如小模型:目标函数不同,检索要可比的距离,生成要下一个词的概率。
检索链路:query --BGE--> 向量 --ANN--> top-k 文档 --生成模型--> 答案
↑ 这一步不该由 Decoder-only 承担
3. BGE-small:小模型的三个工程优势
BGE-small 这类小 embedding 模型的优势不在效果上限,而在三件工程事实:
| 维度 | 表现 | 工程含义 |
|---|---|---|
| 显存/内存 | 小,可 CPU 推理 | 检索服务不必占用 GPU |
| 延迟 | 单条毫秒级(典型量级) | 可放在同步链路里 |
| 批处理 | 一次编码多条,吞吐随 batch 上升 | 索引构建可离线批量跑 |
用法上有两个必须做对的细节:
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer("BAAI/bge-small-zh-v1.5")
def embed(texts, is_query: bool):
# 检索型模型通常要求 query 加指令前缀,文档不加
if is_query:
texts = ["为这个句子生成表示以用于检索相关文章:" + t for t in texts]
v = model.encode(texts, normalize_embeddings=True, batch_size=64)
return np.asarray(v, dtype="float32")
- 归一化。
normalize_embeddings=True之后,内积等于余弦相似度,索引侧可以直接用 IP(内积)度量,省一次除法。 - query 与 document 处理不对称。很多检索模型对 query 要求加指令前缀、对文档不加;两侧都加或都不加,召回率会掉。按模型卡片核对。
维度与索引一起定:数百维用 HNSW 或 IVF 都够;维度越大,内存与构建时间从线性涨到超线性。
4. Qwen3-4B 与 Qwen3-32B-RL:同族两档,怎么分工
同一家族的 4B 与 32B 不是"大的一定更好",而是能力边界不同、成本差一个量级。名字里的 RL 说明这一档经强化学习对齐,差别体现在长链推理与格式遵循,不在知识量。
| 维度 | 4B 档 | 32B(RL 对齐)档 |
|---|---|---|
| 部署 | 单卡或 CPU 量化可跑 | 多卡或大显存 |
| 延迟 | 低,适合同步交互 | 高,适合异步任务 |
| 长链推理 | 容易中途跑偏 | 更稳,仍需校验 |
| 格式遵循 | 简单结构可靠,复杂 schema 漏字段 | 复杂 schema 成功率更高 |
| 成本 | 低 | 高,按实际部署核对 |
| 适合任务 | 分类、抽取、改写、路由判定 | 多步推理、代码、评审 |
分工的做法是分层:便宜模型先做意图与难度判定,难判的才升级到贵模型,平均成本由流量分布决定而非最贵模型。
请求 → 4B 档:意图分类 + 难度打分
├─ 简单(占比高)→ 4B 档直接答
└─ 困难(占比低)→ 32B 档,带 4B 产出的结构化上下文
小模型做路由判定的另一好处:判定可本地化,不把用户原文发给外部服务。
5. LLMRouter:路由层的四类策略与降级链
一个可用的 LLMRouter 要处理四件事:按能力、按成本、按负载、按失败降级。
llm:
router:
default: qwen3-4b
rules:
- when: { intent: "code_review", tokens_gt: 2000 }
target: qwen3-32b-rl
- when: { intent: "retrieval" }
target: bge-small # 向量化走独立分支
- when: { has_image: true }
target: gpt-4v
fallback:
- qwen3-32b-rl
- qwen3-4b
limits:
max_retries: 1
timeout_ms: 20000
budget_usd_per_hour: 12
| 策略 | 判据来源 | 风险 |
|---|---|---|
| 按能力 | 意图分类、是否含图、上下文长度 | 分类错了会把难任务发给弱模型 |
| 按成本 | 预算、当前时段花费 | 预算耗尽时的降级要提前定义 |
| 按负载 | 队列深度、错误率、P99 延迟 | 只按负载切会把请求打散到弱模型,质量断崖 |
| 按失败降级 | 超时、限流、内容拒答 | 降级链要有终点,否则无限重试 |
def call_with_fallback(req):
for name in [route(req, STATE)] + FALLBACK:
try:
return invoke(name, req)
except (TimeoutError, RateLimitError):
continue
raise AllModelsFailed(req.id)
两条容易忽略的约束:
- 降级不能降能力。把复杂推理降到 4B 档,得到的不是"稍差的答案"而是"格式都不对"。顺序应是先降并发、再降上下文、最后才降档位。
- 路由决策要可观测。记录"选了谁、为什么、耗时、token 数",否则成本异常难以归因。
6. SDXL-Turbo 与 GPT-4V:输入输出两端的模态扩展
SDXL-Turbo 是扩散模型的少步采样变体:步数压到个位数,用质量换速度,适合草稿与批量预览而非终稿。
| 维度 | SDXL-Turbo | 说明 |
|---|---|---|
| 显存 | 高(按分辨率与批大小核对) | 与文本模型争抢同一张卡时要做配额 |
| 延迟 | 低步数带来低延迟,典型量级为秒级 | 适合交互式预览 |
| 可控性 | 依赖提示词与固定种子 | 种子与提示词一起入版本管理 |
| 批量 | 批内共享模型加载开销 | 批量出图比单张摊薄成本 |
GPT-4V 这类视觉输入模型解决的是把图像变成可推理的文本结构:读截图、报表比自建 OCR 更省人力,但它是"理解"不是"精确转录",精确数值仍要靠 OCR 与结构化校验。
# 视觉输入的最小请求形态:图像 + 明确的任务约束
payload = {
"model": "gpt-4v",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "读出图中表格的每一行,输出 JSON 数组,不要解释"},
{"type": "image_url", "image_url": {"url": image_data_url}},
],
}],
"temperature": 0,
}
7. Top_logprobs:把"模型有多确定"变成可用的信号
多数 API 支持返回每个位置概率最高的若干候选 token 及其对数概率(top_logprobs),这是不额外花钱就能拿到的置信度信号。
| 用途 | 读法 | 阈值怎么定 |
|---|---|---|
| 结构化输出校验 | 关键字段位置的 top-1 概率 | 低于阈值就重试或转人工 |
| 分类任务置信 | 首个 token 的概率分布 | 按验证集画 ROC 定阈值 |
| 幻觉初筛 | 实体名位置的低概率 | 只作提示,不作判决 |
| 路由升级 | 低置信请求升级到大模型 | 与成本预算联动 |
resp = client.chat.completions.create(
model="qwen3-4b",
messages=[{"role": "user", "content": prompt}],
logprobs=True,
top_logprobs=3,
temperature=0,
)
first = resp.choices[0].logprobs.content[0].top_logprobs
conf = math.exp(first[0].logprob) # 概率 = e^{logprob}
注意:概率是模型内部的,不是校准过的正确率;temperature 不为 0 时分布被软化,阈值要重定;不同模型的 logprob 尺度不可直接比较。
8. 排错:六个"选对了模型但结果不对"的场景
| 现象 | 原因 | 处理 |
|---|---|---|
| 检索召回很差 | query 没加前缀或未归一化 | 按模型卡片对齐两侧处理 |
| 同一问题两次答案差异大 | 走了不同路由分支 | 记录决策,评估时固定分支 |
| 成本突然翻倍 | 降级链失效,全走大模型 | 加预算闸门与路由日志 |
| 图像任务答非所问 | 提示词没约束输出格式 | 明确"只输出 JSON,不解释" |
| 结构化输出漏字段 | 小模型对复杂 schema 遵循不足 | 拆小 schema 或升级档 |
| 阈值失效 | temperature 变了但阈值没重定 |
阈值与采样参数一起版本化 |
9. 边界:什么时候该换思路而不是换模型
| 场景 | 为什么换模型没用 | 该做什么 |
|---|---|---|
| 需要精确计算 | 语言模型不做算术保证 | 调工具/写代码执行 |
| 需要最新事实 | 权重里的知识有截止时间 | 检索增强或查库 |
| 需要严格格式 | 概率生成天然不稳定 | 约束解码 + 校验重试 |
| 需要确定性复现 | 采样与并行都会引入差异 | 固定种子 + 温度 0 + 缓存 |
| 图像需要精确数值 | 视觉模型做理解不做转录 | OCR + 结构化校验 |
一句话:选型是坐标问题,不是排行榜问题;路由层把坐标变成决策。
11. 自测
- Decoder-only 模型做句向量为什么不如专用 embedding 模型?
BGE-small的 query 与 document 处理为什么不对称?- 降级链为什么不直接把复杂任务降到小模型档位?
SDXL-Turbo适合草稿而不适合终稿的原因是什么?top_logprobs给出的概率可以直接当正确率用吗?- 视觉模型读表格,精确数值为什么仍要 OCR 复核?