为什么仅靠小模型无法降低推理成本

你以为把大模型换成一堆小模型,账单就会直线下降?很多团队都是这么做的,结果月底一看云账单,GPU费用几乎没动。问题不在模型单价,而在整套推理流水线:每多一个小模型,就多一块长期占用的GPU。要真正在生产环境里省钱,关键不是“用小”,而是“怎么用”。

据一些云厂商公开数据,企业在生成式AI上的基础设施支出,超过一半都花在长期闲置的GPU时间上,而不是模型本身的调用费用。

传统流水线:从“一大模型吃到饱”到“一堆小模型排队”

多步任务是怎么把成本堆上去的

生产级AI系统,很少是一个模型一把梭,更多是多个任务串起来的流水线,每一步都用“最擅长那件事”的模型来处理。

示意图

一个典型请求可能会经历:

  • 文档或图片解析成干净文本
  • 文本嵌入成向量,用于检索
  • 对检索结果按相关性重排序
  • 抽取字段、实体或标签
  • 在返回用户前做安全与策略检查

传统AI流水线

过去很多团队图省事,几乎所有步骤都丢给一个大模型,推理能力是够了,但每次调用都在烧钱。最近一两年,大家开始醒悟:解析、嵌入、重排序这些,其实用小模型就够用,没必要每次都上SOTA大模型。

大模型调用

于是流水线从“一个大模型”变成“多个小模型”:每个任务一个专用SLM,调用单价确实便宜了。但很多团队忽略了一个现实:模型便宜不等于系统便宜,因为你要为这些模型常驻的GPU时间付费。

成本真正来自哪里:不是token,而是GPU时间

从账单视角看,模型成本有两块:

  • 每次调用的费用(按token或请求计费)
  • 为了随时响应调用而常驻的硬件成本

当你把一个大模型拆成四个小模型,流水线变成四段:

  • 每段调用更便宜
  • 但你现在要同时服务四个模型

如果每个模型都单独占一块GPU,你的GPU数量翻了四倍。哪怕每个模型的吞吐量都很低,这些GPU也得一直开着,成本自然下不来。

为什么“多模型共用一块GPU”说起来简单,做起来难

理论上很美好:一块卡顶四块卡

很多人第一反应是:那就把多个小模型塞到一块GPU上不就好了?

从计费逻辑看,这个想法完全说得通。GPU厂商不会按你跑了多少FLOPs收费,只按“你占了这块卡多久”计时。

GPU计费公式

图里的 C 是每秒GPU价格,T是你持有的时间。四个模型各占一块卡,就有四条计费项。如果一块L4就能扛住四个模型的流量,那你理论上可以把账单砍掉75%。

多模型单卡示意

内存也不是问题。一个小型嵌入模型、一个交叉编码器重排序器、一个实体抽取器加起来也就几GB。L4有24GB显存,装下它们绰绰有余。

GPU内存示意

那为什么现实里,几乎没人这么干?原因有点扎心:从服务框架到底层驱动,整个软件栈几乎都是按“一模型一GPU”设计的。

现实里发生了什么:四个进程互相“看不见”

以常见的推理服务器为例:

  • TEI(Hugging Face Text Embeddings Inference)专门做嵌入和重排序,启动时只能指定一个 --model-id

TEI GitHub

  • vLLM 的引擎同样是围绕单模型构建

你想在一张卡上跑四个模型,只能起四个独立进程。它们互相不知道对方存在,也不会协调显存使用。以vLLM为例:

  • --gpu-memory-utilization 默认是 0.9
  • 启动时直接预分配90%显存
  • 不会根据实时负载动态调整

vLLM内存分配

官方文档也写得很清楚:这是“每实例”的限制,完全不管同一张卡上还有没有别的vLLM实例。你要跑两个实例,只能手动改成0.5,纯靠人算。激活内存又会随batch size和序列长度波动,你只能按最坏情况预留。

结果就是:

  • 四个模型各自预留一块“最坏情况显存切片”
  • 这些切片大部分时间是空的
  • 但你已经为它们付了钱

更糟的是,一旦两个模型同时遇到峰值,就可能把整张卡拖死。比如抽取模型突然遇到一份超长合同,激活内存暴涨,超过预留:

  • 自己OOM
  • 顺带把OCR、嵌入、重排序一并搞挂

内存争用示意

所以“一模型一GPU”并不是硬件强制,而是软件栈默认。要真正做到多模型共享,需要的是:

  • 一个服务器承载所有模型
  • 统一管理显存,而不是手动切片
  • 能看到所有请求,按优先级和负载调度
  • 根据流量动态加载/卸载模型

这不是起四个进程能解决的问题,而是需要完全不同的架构设计。

团队常见的三条“逃生路线”,以及它们的新坑

三种常见选择:都在绕开GPU细节

很多团队意识到“一模型一GPU”不对劲后,会尝试绕路。常见有三条:

三种方式示意

  1. 托管API(OpenAI、Cohere等)
    • 优点:上手快,不用管GPU
    • 问题:
      • 规模一大,成本几乎线性增长
      • 只能用对方托管的模型,自家微调模型没法直接用
      • 每次调用都要把提示和文档发出去,网络和隐私都是隐患

托管API示意

  1. 无服务器GPU(serverless GPU)
    • 优点:只在“用的时候”付费,看起来很美
    • 实际问题:
      • 冷启动代价高,模型从零加载权重要几秒
      • 搜索场景里的重排序器等,根本等不起
      • 为了避免冷启动,只能让实例一直“热着”,又回到为闲置GPU付费
    • 很多严肃团队现在都在用这条路,说实话,是一种折中而不是终点

无服务器GPU示意

  1. 自托管GPU集群
    • 自己租GPU,在自有VPC里跑模型
    • 优点:
      • 成本结构更可控,按小时计费而不是按token
      • 数据不出墙,合规更容易
    • 隐性难点:
      • 你得自己解决调度、扩缩、监控、模型管理等一整套问题

从长期看,自托管+多模型共享GPU,是成本和控制的平衡点。但前提是,你有一套能真正“吃下多模型流水线”的推理引擎。

标准工具在多模型流水线里的两大硬伤

模型类型示意

现有主流工具,在多模型流水线里会暴露两个明显问题:

  1. 每个工具只会服务一种模型形态
    • vLLM:只管LLM
    • TEI:只管嵌入和重排序
    • OCR、视觉、文档解析:基本靠你自己用FastAPI之类包一层

模型本身不是问题,优秀的开源模型一大把:

  • 文档解析:docling、PaddleOCR
  • 视觉:SigLIP、Florence
  • 抽取:GLiNER

缺的是一个“能把这些模型统一跑起来”的服务器。结果就是:

  • 代理要做文档解析、嵌入、重排序、策略检查
  • 你得起 vLLM + TEI + OCR服务 + 自己的策略服务
  • 四个服务器、四个API、四套部署,最后再挂到一个代理后面

多服务器示意

  1. 每个工具都假设自己独占一块GPU

显存占用示意

  • vLLM 启动就吃掉90%显存
  • TEI 也要占一块
  • OCR/解析服务同样需要显存

它们互相不知道对方存在,也不会主动“还显存”。没有共享队列,没有统一优先级,实时搜索请求也没法被优先处理。你在一张卡上起四个不同工具的进程,本质上和起四个vLLM实例没什么区别。

理想中的“小模型服务架构”,到底长什么样

一个引擎,吃下所有模型类型

退一步看,如果要让小模型真正省钱,一套理想的服务架构至少要做到:

  • 通过一个API跑完代理需要的所有模型类型:
    • 嵌入
    • 重排序
    • OCR
    • 视觉
    • 抽取
    • 生成

理想架构示意

这样,原本要四个服务器的流水线,可以收敛成一个。对上层应用来说,就是一个统一的“推理网关”。

同时,这个引擎还得:

  • 充分压榨GPU,而不是粗暴填满显存
  • 有调度器,能按请求类型和延迟要求排队
  • 控制不同架构的批处理和注意力路径,减少填充浪费
  • 根据流量动态加载/卸载模型,避免冷启动和显存闲置

动态加载卸载示意

再往下看,还需要一层“生产级外壳”:

  • 路由与网关
  • 自动扩缩
  • GPU池管理
  • 监控与告警

裸vLLM这种东西,只是一个“引擎”,不会帮你跨副本分配负载,也不会根据流量自动加减GPU,更不会在混合GPU集群里帮你选最合适的卡。很多团队就是卡在这里:模型会跑,但要跑得省钱又稳定,就得自己造一大堆轮子。

一个不太被注意的信息差:不同模型族的“底层差异”

很多人以为“都是Transformer,批处理一下就好了”。但底层差异其实挺大:

  • BERT 和 Qwen 的位置编码、注意力实现都不一样
  • ColBERT 会为每个token返回一个向量
  • 重排序器只返回一个分数,没有向量

要做一个统一引擎,既要支持这些不同输出形态,又要高效批处理和调度,这工作量一点不小。我也不太确定是不是所有团队都意识到这一点,但这大概就是为什么之前一直没有一个“开箱即用、全模型形态统一支持”的开源包。

开源解法:Superlinked 推理引擎(SIE)

SIE 做的事:把多模型流水线“塞进一台机器”

开源项目 Superlinked Inference Engine(SIE) 就是为这个场景生的:

SIE示意

它以集群形式跑在你自己的云环境里,专门为“多个不同类型的小模型,在共享GPU上串联运行”的流水线设计。

SIE架构

它提供一个统一API,覆盖四种调用形态:

  • encode:文本/图像 → 向量
  • score:交叉编码器重排序,返回分数
  • extract:从原始文档抽取字段/实体/Markdown
  • generate:LLM生成文本,并返回token使用情况

和TEI对比:

  • TEI 只能服务单一模型
  • 嵌入和重排序就要两个部署
  • 不支持抽取、OCR、视觉、生成

SIE 一个集群就能服务所有四种模型形态,对上层来说就是一个端点。

真正省钱的地方:调度、批处理和显存管理

SIE在几个关键点上做了“省钱向”的设计:

  • 批处理策略

    • 按计算成本分组请求
    • 只对同批次里最长的请求做填充
    • 大幅减少padding浪费
  • 批次形成顺序

    • 传统堆栈:先把请求路由到某个worker,再在worker内部做小批处理
    • SIE:所有请求先进共享队列,worker从队列里拉取,拼成“满载批次”再打到GPU
  • 模型加载/卸载

    • 模型在首次请求时加载到GPU
    • 显存不够时,用LRU策略卸载最久未用的模型
    • 行为类似浏览器缓存

动态加载卸载示意

有用户反馈,在多嵌入模型场景下,单看显存占用,vLLM加载模型后能吃掉80%显存,但实际嵌入利用率不到40%。SIE通过动态加载/卸载,把这些“预留但闲置”的显存重新用起来,让你在同一条流水线上跑更多模型。

  • 生产层能力内置

    • 网关负责请求路由,流量突增时先兜住请求,再等更多worker拉起
    • worker按负载自动扩缩,低流量时可以缩到0,避免空转GPU
    • 任务可以分配到任意GPU卡,配套仪表盘监控
    • 提供Terraform脚本,支持AWS/GCP部署,从本地笔记本到集群平滑迁移
    • 支持完全离线运行,提前下载权重,适合数据不能出网的环境
  • 参数调优“预配置”

    • vLLM/Triton 需要你手动调 batch size、显存比例、精度、最大序列长度、注意力实现等
    • SIE 目录里内置了 85+ 模型的生产级配置
    • 你只要引用模型名,就能加载一套已经调好的参数
    • 换模型只需改配置指向,无需重新调优

请求打包示意

模型调优示意

一个完整流水线示例:四种模型,一台服务器

场景:检索 + 重排序 + 抽取 + 生成

下面这条小流水线,会对同一台SIE服务器发起三次调用:

  • 嵌入文本
  • 重排序
  • 抽取命名实体
  • 最后生成答案

流水线示意

涉及四种不同模型架构,但对客户端来说,都是同一个端点。前三步可以在CPU上跑,方便本地调试;生成步骤基于SGLang,需要GPU。

先安装并启动服务器:

pip install "sie-server[local]"
sie-server serve

健康检查:

curl http://localhost:8080/readyz     # ok

实例化客户端:

from sie_sdk import SIEClient
from sie_sdk.types import Item

client = SIEClient("http://localhost:8080")

query = "Who issued the invoice and what is the amount due?"
passages = [
    "Invoice INV-4471 was issued by Northwind Logistics on 14 March 2026.",
    "The total amount due is $18,240, payable within 30 days.",
    "The cafeteria menu changes every Monday and Thursday.",
]

后续所有步骤,都通过这个客户端和同一个端点完成。

encode:文本 → 向量

docs = client.encode(
    "sentence-transformers/all-MiniLM-L6-v2",
    [Item(text=p) for p in passages],
)

print(docs[0]["dense"].shape)
# (384,)

传入列表,返回同长度列表,每个元素的向量保存在 dense 键下。

score:交叉编码器重排序

from pprint import pprint

scores = client.score(
    "cross-encoder/ms-marco-MiniLM-L-6-v2",
    Item(text=query),
    [Item(id=str(i), text=p) for i, p in enumerate(passages)],
)
pprint(scores["scores"])
# [{'item_id': '0', 'rank': 0, 'score': 3.009},
#  {'item_id': '1', 'rank': 1, 'score': -1.061},
#  {'item_id': '2', 'rank': 2, 'score': -11.425}]

这里的分数是logits,绝对值没太大意义,排序才重要。可以看到:

  • 发票文本得分最高
  • 金额说明次之
  • 食堂菜单垫底
best_id = scores["scores"][0]["item_id"]
best = passages[int(best_id)]
# 'Invoice INV-4471 was issued by Northwind Logistics on 14 March 2026.'

extract:从上下文抽取结构化字段

result = client.extract(
    "urchade/gliner_multi-v2.1",
    Item(text=best),
    labels=["organization", "date", "amount"],
)
print(result["entities"])

[
  {
    'text': 'Northwind Logistics', 'label': 'organization', 
    'score': 0.979, 'start': 31, 'end': 50, 'bbox': None
  },
  {
    'text': '14 March 2026', 'label': 'date',
    'score': 0.951, 'start': 54, 'end': 67, 'bbox': None
  }
]

这是第三种输出形态:带标签、置信度和位置的实体列表。调用方式却和前两种完全一致。

generate:基于上下文生成最终答案

context = " ".join(
    passages[int(s["item_id")] ] for s in scores["scores"][:2]
)

answer = client.generate(
    "Qwen/Qwen3-0.6B",
    f"Answer in one sentence using only this context.\n\n"
    f"Context: {context}\n\nQuestion: {query}",
    max_new_tokens=64,
)

print(answer["text"])
# 'The invoice was issued by Northwind Logistics, and the amount due is $18,240.'

print(answer["usage"])
# {'prompt_tokens': 61, 'completion_tokens': 17, 'total_tokens': 78}

这是第四种输出形态:生成文本 + token使用量。依然是同一个客户端、同一个端点。


到这里,一条完整流水线就跑通了:

  • 四个模型族
  • 四种输出类型
  • 一个服务器,一个客户端

每个模型在首次调用时从Hugging Face加载,之后保持激活,由SIE统一调度和管理显存。

真正的增量:省钱的不是“小”,而是“共享”

用针对窄任务的小模型,是方向没错的选择:

  • 在特定任务上足够准确
  • 可以在自有环境里部署,数据不出网

但只把大模型换成小模型,并不会自动拉低推理成本。你只是把“按token计费”换成了“按GPU时间计费”。如果每个小模型都独占一块GPU,大部分时间这些卡都是闲的,你还是在为空气买单。

真正的成本拐点,出现在:

  • 多个模型能高效共享同一块GPU
  • 有统一引擎支撑所有模型形态
  • 有调度、批处理和动态加载/卸载,把显存和算力吃满

一旦你为每个模型选用不同的服务工具,就又回到了“一模型一服务器,一服务器一GPU”的老路。

开源的 SIE 把这件事做成了一个可直接落地的方案:

  • 让代理需要的不同模型在共享集群上运行
  • 保持GPU高利用率
  • 内置路由和自动扩缩
  • 还能无缝接入现有检索栈(Chroma、Qdrant、Weaviate、LanceDB 等)

SIE示意

如果你正打算把更多逻辑迁到小模型上,这套“统一引擎 + 多模型共享GPU”的思路,值得先收藏下来,等你下次要算账单的时候再翻出来对一对。

仓库地址:

有团队在迁移到类似架构后,GPU利用率从不到30%提升到60%以上,等于在不牺牲延迟的前提下,把同样预算下的吞吐量翻了一倍。

常见问题

Q:我现在用OpenAI API,如果改用小模型+自托管,成本大概能省多少?

A:在高并发、请求量稳定的场景下,从纯托管API迁到自托管小模型,成本通常可以下降30%~70%。原因在于:API按token计费,长上下文、多轮对话会迅速推高账单;而自托管按GPU时间计费,只要你能把GPU吃满,单位算力成本会低很多。可操作建议是:先用一周的真实流量做压测,测出当前平均token数和QPS,再用一块L4或A10做对比实验,评估在SIE这类引擎下的吞吐量和延迟,再决定是否迁移。

Q:多模型共享一块GPU,会不会导致延迟变高、尾延迟变得不可控?

A:如果只是简单地在一张卡上起多个进程,延迟确实容易失控,因为没有统一调度和优先级管理。但在有共享队列和批处理调度的引擎里,平均延迟往往会下降,尾延迟也更可控。原因是:批处理能摊薄单次调用的GPU开销,共享队列可以优先处理实时请求。建议在生产前做两类压测:一类是稳定流量下的平均延迟,一类是突发流量下的P95/P99延迟,并针对关键路径(如搜索重排序)设置更高优先级队列。

Q:动态加载/卸载模型会不会带来频繁冷启动,影响线上体验?

A:如果模型频繁被逐出显存再加载,确实会产生冷启动抖动,所以关键在于合理的缓存策略和容量规划。SIE采用类似浏览器缓存的LRU策略,并结合请求频率来决定哪些模型常驻、哪些可以按需加载。实践中,常用模型会一直留在显存里,只有长尾模型才会偶尔触发加载。建议做两件事:一是根据实际流量把“常用模型集”固定下来,保证它们有足够显存;二是在低峰期预热长尾模型,避免在高峰时首次加载。

Q:如果我的流水线里既有CPU任务又有GPU任务,统一引擎还有意义吗?

A:有意义,而且越复杂的流水线越能体现统一引擎的价值。CPU任务(如轻量级解析、简单规则判断)本身成本不高,但如果和GPU任务分散在多个服务里,会增加网络跳转和运维复杂度。统一引擎可以把CPU和GPU任务都纳入同一调度层,减少跨服务调用,同时在一个地方观测整条链路的延迟和错误。建议在设计流水线时,把“必须上GPU的步骤”和“可以留在CPU的步骤”标注清楚,再用统一引擎编排,而不是为每个小任务单独起服务。

Q:我怎么判断现在的GPU利用率已经低到值得上SIE这类引擎?

A:一个简单的判断标准是:如果你的GPU长期在线,但平均利用率低于40%,就值得认真评估统一推理引擎。原因在于:低利用率意味着你在为大量闲置算力付费,而多模型共享和更好的批处理可以把这部分浪费收回来。操作上,可以先接入监控,观察一周内的GPU利用率曲线和显存占用情况;如果发现显存常年80%+、算力却只有20%~30%,那基本可以确定:你现在是在为“预留显存”和“一模型一GPU”的架构买单,迁移到SIE一类方案的收益会比较可观。