Text Embeddings Inference

허깅페이스에서 제공하는 오픈소스 임베딩 및 시퀀스 분류 추론 엔진.

Rust 기반.

모델 하나 당 컨테이너 하나를 올리고, 컨테이너 하나 당 엔드포인트 하나를 서빙하는게 정석.

도커 네트워크 내부에서만 통신을 끝낼거면, 굳이 리버스 프록시를 올리지 않아도 괜찮으므로 간단함.

컨테이너:모델은 1:1

TEI 는 동시에 하나의 임베딩 모델만 서빙할 수 있다. 이는 서빙의 안정성을 위함.

동시에, TEI 엔진은 기본적으로 컨테이너 하나당 ‘풀링(Pooling) 모드’를 하나만 활성화한다. 이때, 기본값은 일반적인 밀집 벡터(Dense) 생성 모드인 cls 모드이다. 이 cls 모드에서 /embed_sparse 엔드포인트를 호출하면 이는 에러가 난다. TEI의 Sparse 검색 엔진은 내부적으로 splade라는 풀링 모드로 동작해야만 결과를 반환할 수 있기 때문이다. 이 경우 424 Failed Dependency 에러가 난다.

풀링 모드 (Pooling Mode)작동 방식 및 설명출력 벡터 형태주요 대상 모델 및 아키텍처
cls시퀀스의 첫 번째 특수 토큰인 [CLS] 토큰의 표현(Representation)만 추출하여 사용한다.Dense Vector (밀집 벡터)BERT, RoBERTa 등 인코더 기반의 표준 임베딩 모델
mean시퀀스 내의 모든 의미 있는 토큰(패딩 제외)의 벡터 값들을 평균(Mean) 내어 사용한다.Dense Vector (밀집 벡터)SBERT 계열 등 평균 풀링에 최적화된 임베딩 모델
spladeMasked LM 출력 Logit에 ReLU 및 Max-pooling을 적용하여 어휘 사전 차원의 가중치를 산출한다.Sparse Vector (희소 벡터)SPLADE 모델 (ForMaskedLM 아키텍처 한정)
last_token시퀀스의 가장 마지막 토큰(일반적으로 [EOS])의 벡터 표현만을 추출하여 최종값으로 사용한다.Dense Vector (밀집 벡터)Qwen, Mistral 등 디코더(Causal LM) 기반 임베딩 모델

컨테이너:엔드포인트는 1:1

케이스가능 여부설명
일반 dense embedding 모델을 TEI에 올림/embed 가능, /embed_sparse 사실상 불가mean, cls, last-token pooling 기반 dense 모델이면 /embed는 정상 동작하지만 /embed_sparse는 SPLADE pooling 모델이 아니므로 실패

TEI API 문서도 /embed_sparse는 “SPLADE pooling embedding model”이 아니면 424를 반환한다고 명시 (Hugging Face)
SPLADE 계열 모델을 TEI에 올림/embed_sparse 가능TEI는 --pooling splade 옵션을 제공하고, 공식 README도 SPLADE pooling 예시에서 naver/efficient-splade... 모델을 --pooling splade로 띄운 뒤 /embed_sparse를 호출 (GitHub)
하나의 TEI에서 dense + sparse를 hybrid용으로 동시에 산출일반적으로 불가TEI는 시작 시 --model-id 하나와 pooling 방식 하나를 잡는 구조

CLI 문서상 pooling 값도 cls, mean, splade, last-token 중 하나

즉 한 인스턴스에서 dense pooling과 sparse pooling을 동시에 활성화하는 구조가 아님 (Hugging Face)
BGE-M3를 올려 dense + sparse + ColBERT를 같이 쓰기TEI 기본 기능으로는 불가에 가까움BGE-M3 자체는 dense/sparse/multi-vector를 동시에 지원하지만, TEI 이슈에서는 BGE-M3의 dense는 일반 XLM-RoBERTa embedding처럼 가능하나 sparse/ColBERT는 별도 linear head와 unpooled output이 필요해서 TEI에서 바로 반환할 방법이 없다는 문제 (Hugging Face)
  • 즉 TEI 하나는, 엔드포인트 하나만을 서빙하는 구조라고 인식하는 것이 타당함