Projects

BGE-m3-ko 임베딩 서비스: 벡터 생성과 검색의 책임 분리

FastAPI와 Milvus로 임베딩 서비스를 분리한 구현과, 외부 벡터 입력·모델 교체에서 유지해야 할 호환 조건을 정리한다.

문제와 담당 범위

BizKit의 직무 필터와 시맨틱 캐시에는 텍스트를 벡터로 바꾸고 비슷한 항목을 검색하는 기능이 필요했다. 메인 AI 서버가 LLM 호출과 GitHub 데이터 수집뿐 아니라 임베딩 모델 로딩과 Milvus 연결까지 맡으면 관리할 책임이 커졌다.

나는 임베딩 API와 벡터 검색 서비스를 구현하고 메인 AI 서버에서 HTTP로 호출하도록 분리했다. 이 글은 임베딩 서비스 저장소의 구현과 사용 조건을 설명한다. 모델 비교 수치는 별도 벤치마크 글에 나눴다.

모델 로딩과 API

앱 시작 시 dragonkue/BGE-m3-ko와 Milvus 클라이언트를 초기화한다. 모델은 클래스 싱글톤으로 관리하므로 같은 프로세스의 요청마다 다시 로드하지 않는다. 인스턴스 공유 범위는 해당 프로세스 안으로 제한된다.

SentenceTransformer의 인코딩에서 normalize_embeddings=True를 사용한다. 이 서비스의 기본 임베딩 차원은 1024이다.

임베딩 생성과 벡터 저장·검색의 책임임베딩 생성과 벡터 저장·검색의 책임
임베딩 생성과 벡터 저장·검색의 책임좌우로 스크롤하여 전체 보기원본 크게 보기
API역할
POST /embed단일 텍스트를 벡터로 변환
POST /embed/batch여러 텍스트를 배치로 변환
POST /collection/{name}/insert텍스트를 임베딩하거나 입력 벡터를 사용해 저장
POST /collection/{name}/search질의를 서비스 모델로 임베딩한 뒤 검색
POST /collection/{name}/search/vector이미 생성된 질의 벡터로 검색

배치 경로는 시드 데이터처럼 여러 문장을 한 번에 처리하기 위한 인터페이스이다. 단일 요청을 반복하는 방식과의 속도 차이는 별도 측정이 필요하다.

컬렉션 처리

컬렉션은 자동 생성 ID와 text, category, metadata, embedding 필드로 구성했다. 기본 벡터는 1024차원 FLOAT_VECTOR이며, 검색 metric은 COSINE이다.

삽입 시 컬렉션이 없으면 생성한다. 반면 없는 컬렉션을 검색하면 404로 반환한다. 데이터를 처음 넣는 상황과 검색할 저장소가 없는 상황을 구분한 것이다. 잘못된 이름으로도 컬렉션이 생성될 수 있으므로 호출자는 이름을 일관되게 관리해야 한다.

컬렉션 생성 코드의 인덱스 설정은 AUTOINDEX이다. 모델 비교 실험에서 평가한 IVF_FLAT·HNSW와는 설정이 다르다.

벡터 호환 조건

벡터를 직접 받는 API는 같은 벡터를 다시 계산하지 않고 검색에 사용할 수 있는 경로이다. 그러나 외부에서 생성한 벡터를 저장된 데이터와 무조건 비교할 수 있는 것은 아니다.

예를 들어 둘 다 1024차원이어도 서로 다른 모델이 만든 벡터는 좌표가 의미하는 바가 다를 수 있다. 저장된 문서와 질의는 같은 모델과 호환되는 전처리·정규화 조건을 사용해야 한다. API가 배열을 받아들인다는 것과 검색 결과가 의미 있다는 것은 별개이다.

모델을 교체할 때는 기존 문서도 새 모델로 다시 임베딩하고, 인덱스와 유사도 임계값을 새 조건에서 확인해야 한다. API 형태가 같더라도 서로 다른 공간의 벡터를 같은 컬렉션에 섞어서는 안 된다.

벡터를 직접 전달하는 호출자는 생성 모델·버전과 전처리·정규화 조건이 저장된 벡터와 호환되는지 확인해야 한다.

검색과 서비스 정책의 경계

임베딩 서비스는 가까운 항목과 유사도를 반환한다. 그 결과로 요청을 차단할지, 이전 응답을 재사용할지는 메인 AI 서버의 정책이다.

비슷한 직무 표현을 찾는 것과 완성된 자기소개를 다른 요청에 재사용하는 것은 다른 판단이다. 직무가 비슷해도 이름이나 프로젝트 내용이 다르면 같은 답변을 반환해서는 안 된다. 시맨틱 캐시는 유사도뿐 아니라 사용자별 정보와 결과에 영향을 주는 입력을 함께 고려해야 한다.

직무 필터 역시 검색 지표가 높다는 사실만으로 차단 정책이 정확하다고 볼 수 없다. 통과 대상의 오차단과 차단 대상의 잘못된 통과를 따로 확인해야 한다.

구현 결과와 적용 범위

서비스에는 모델 초기화, 정규화, 컬렉션 삽입·검색과 없는 컬렉션의 404 처리를 구현했다.

당시 모델 비교는 작은 corpus와 과제별 평가셋에서 수행했다. 서비스 전체의 필터 정확도, 캐시 안전성, GPU 비용 절감 효과는 이 검색 지표만으로 판단할 수 없다.

배운 점

임베딩 서비스를 분리한 결과 메인 AI 서버는 모델 로딩과 Milvus 연결을 직접 관리하지 않아도 됐다. 대신 HTTP 형식뿐 아니라 벡터 공간, 컬렉션, 검색 결과의 사용 정책까지 계약으로 다뤄야 했다.