TEI 在 arm64 上无解:我们如何用 llama.cpp 在 DGX Spark 上跑 bge-reranker-v2-m3
HuggingFace Text Embeddings Inference(TEI)没有 linux/arm64 镜像,这意味着它在 DGX Spark(GB10,ARM64)上无法启动。本文记录我们如何复用同一个 llama.cpp 镜像承载 cross-encoder 重排模型,实现零业务代码改动上线,以及为真实 RAG 分片长度所做的批大小调优。
目录
问题:TEI 在 GB10 上永远起不来
我们的重排(reranker)方案原计划用 HuggingFace 的 Text Embeddings Inference(TEI),它是 RAG 领域最常见的 cross-encoder 服务框架,接口简单、社区文档也多。但 DGX Spark 的 CPU 是 ARM64(GB10 是 Grace CPU + Blackwell GPU 的统一内存架构),而我们验证发现 TEI 在 1.5–1.8 以及 cpu 系列的全部标签下都没有发布 linux/arm64 镜像——用 docker manifest inspect 逐个标签核实,结果是一致的:镜像清单里只有 amd64[1]。也就是说,不是"配置麻烦",是这条路在这台机器上根本走不通。
方案:复用已经在跑的 llama.cpp 镜像
我们没有另起一套服务栈,而是让同一个 local/llama.cpp:server-cuda 镜像(本来就在跑 LLM)多起一个实例,用它自带的 --reranking 模式服务 cross-encoder 模型[2]。具体做法:
- 下载
BAAI/bge-reranker-v2-m3的 Q8_0 GGUF 量化版本(约 600MB,一次性),来自 gpustack 的 GGUF 转换仓库; - compose 里新增一个
reranker服务,镜像复用 llama.cpp 的 base 配置,命令行加--reranking标志; - 关键的一步:llama.cpp 的
/rerank接口返回的响应形状([{"index", "score"}, ...],按分数降序排列)和 TEI 的响应形状完全一致——这意味着后端原来为 TEI 写的解析器(rag/reranker.py)不需要改一行代码就能直接吃 llama.cpp 的输出,我们用一个探测脚本现场验证了这一点[2]。
这个契约兼容性是这次切换能"零改动上线"的关键——如果响应形状不一致,我们就得同时改基础设施和业务代码,风险会高很多。
调优:为真实 RAG 分片长度重设批大小
承载方案确定后,需要按真实负载调整批参数。llama.cpp 的默认物理批大小(ubatch)是 512,而重排任务是非因果(non-causal)的:每一对"查询+分片"必须完整塞进一个物理批次,512 装不下 1024 token 的分片加查询词。压测阶段用真实长度的 RAG 分片验证后确定配置:--ctx-size 提到 8192、--batch-size/--ubatch-size 都提到 4096(覆盖 chunk_size 1024 加查询词并留足余量),槽位数从默认降到 -np 2,控制显存占用[3]。
这是引入任何 cross-encoder 服务时都要做的一步:重排的批容量约束和生成式推理完全不同,沿用 LLM 的默认批参数会在真实分片长度上直接失败。上线前用生产分片长度做一次压测,比事后调参可靠得多。
效果:两阶段检索在生产链路上的实测
上线后,聊天路径先召回 24 个候选,再交给 cross-encoder 精排出 8 个作为答案上下文,生产环境日志确认:"Chat-path rerank applied, method: cross-encoder, candidates: 24, returned: 8"[1]。REST 检索接口的抽样验证里,rerank_score 呈现出真实且有区分度的分布(例如同一批候选里的 5.47 / 5.28 / 4.72)——说明精排确实在对候选做有意义的重新排序,而不是形式上走一遍流程[1]。
常见问题
Q: ARM64 上除了 llama.cpp,还有没有别的 TEI 替代方案?
A: 我们只验证过并采用了 llama.cpp 这一条路径——它的优势是可以直接复用我们已经在跑的 LLM 服务镜像,不用新引入一套基础设施。我们没有做过对其他 arm64 原生 reranker 服务框架的穷尽调研,如果你在评估其他方案,docker manifest inspect 逐标签核实 arm64 支持是第一步,别假设"社区常用框架"默认支持 ARM64。
Q: 只用向量召回不行吗,为什么要加一层重排? A: 向量召回擅长语义粗筛,但在候选之间的细粒度排序上分辨力有限。接入 cross-encoder 后,我们观察到候选间出现真实且有区分度的分数分布,精排确实改变了最终进入答案上下文的文档集合——对带引用的企业问答来说,进上下文的是哪 8 篇,直接决定答案的准确性。
Q: --ubatch-size 从 512 提到 4096,会不会拖慢重排本身或占用更多显存?
A: 会占用更多单批次显存,这是我们把并发槽位从默认值降到 -np 2 的直接原因——用更大的批容量换取"能处理真实分片长度",同时控制槽位数不过度挤占显存。我们没有对"提升批大小前后"的重排延迟做过专门的 A/B 测量,所以这里不给具体的延迟数字,只描述配置权衡本身。
关于 HTZL.AI
HTZL.AI 是四川慧途智联科技有限公司旗下的企业级私有 AI 品牌,专注于"数据不出企业、模型不进云端"的私有化部署路径,是 NVIDIA Inception 会员企业。本文所有数据均来自我们在真实 DGX Spark 生产环境上的工程记录。