소규모 및 중규모 프로젝트를 위해 설계된 시맨틱 검색 라이브러리는 내장형 벡터 검색 및 의미론적 임베딩 기능을 제공합니다. 이 라이브러리는 복잡한 기존 검색 시스템의 번거로움 없이 강력한 의미 검색 기능이 필요한 프로젝트에 특히 적합합니다. GGUF BERT 모델을 지원하여 복잡한 임베딩 기술을 활용하면서도 시스템의 복잡성을 최소화할 수 있다는 것이 핵심 장점입니다.
주요 기능
-
llama.cpp와의 CGO 없는 통합
이 라이브러리는
purego를 활용하여llama.cpp와 함께 작동하며, CGO(C Go)를 사용할 필요가 없습니다. 이는 Go 코드에서 공유 C 라이브러리를 직접 호출할 수 있게 하여 통합, 배포 및 크로스 컴파일을 크게 간소화합니다. 덕분에 네이티브 라이브러리와 인터페이스하는 Go 애플리케이션 구축이 훨씬 쉬워집니다. -
BERT 모델 지원
llama.cpp를 통해 BERT 모델을 지원합니다. GGUF 형식으로 제공되는 다양한 BERT 모델을 활용하여 텍스트의 의미론적 유사성을 계산할 수 있습니다. -
Vulkan GPU 가속을 포함한 사전 컴파일된 바이너리
배포(
dist) 디렉터리에서 Windows 및 Linux용 사전 컴파일된 바이너리가 제공됩니다. 이 바이너리들은 Vulkan을 사용하여 GPU 가속을 지원하도록 컴파일되었습니다. 물론, 필요에 따라 GPU 지원 유무를 선택하여 직접 라이브러리를 컴파일할 수도 있습니다. -
내장형 검색 인덱스
계산된 임베딩을 기반으로 검색 인덱스를 생성하고 이를 디스크에 저장하여 나중에 로드할 수 있습니다. 이 기능은 소규모 애플리케이션에서 기본적인 벡터 기반 검색을 수행하는 데 적합하지만, 대규모 데이터셋에서는 브루트 포스(Brute Force) 검색 방식을 사용하므로 효율성 문제가 발생할 수 있습니다.
고려사항
- 대규모 데이터셋: 현재 구현은 소규모 애플리케이션을 대상으로 하며, 100,000개 이상의 항목을 가진 데이터셋에서는 브루트 포스 검색 방식 때문에 성능 병목 현상이 발생할 수 있습니다. 더 큰 데이터셋의 경우, 효율성 향상을 위해 근사 최근접 이웃(ANN) 알고리즘과 전문화된 데이터 구조를 고려해야 합니다.
- 복잡한 쿼리 요구사항: 이 라이브러리는 단순한 벡터 유사성 검색에 중점을 둡니다. 다중 필터링, 퍼지 매칭 또는 SQL과 유사한 작업과 같이 더 복잡한 검색 엔진에서 흔히 볼 수 있는 고급 쿼리 기능은 지원하지 않습니다.
- 고차원 복잡 임베딩: 대규모 언어 모델(LLM)이 생성하는 임베딩은 고차원적일 뿐만 아니라 계산 집약적입니다. 충분한 GPU 리소스가 확보되고 낮은 지연 시간 추론을 위해 최적화되지 않은 경우, 이러한 임베딩을 실시간으로 처리하는 것은 시스템에 부담을 줄 수 있습니다.
라이브러리 사용 방법
다음 예제는 라이브러리를 사용하여 텍스트에 대한 임베딩을 생성하고 간단한 벡터 검색을 수행하는 방법을 보여줍니다. 모델 로드, 텍스트 임베딩 생성, 검색 인덱스 생성 및 검색 실행 과정을 확인할 수 있습니다.
-
라이브러리 설치:
dist디렉터리에서 Windows 및 Linux용 사전 컴파일된 바이너리를 찾을 수 있습니다. 대상 아키텍처나 플랫폼이 이 바이너리에 포함되지 않은 경우, 소스 코드에서 라이브러리를 컴파일해야 합니다. 이 바이너리를/usr/lib또는 동등한 디렉터리에 배치합니다. -
모델 로드:
search.NewVectorizer함수는 GGUF 파일을 사용하여 모델을 초기화합니다. 이 예제는sentence-transformer-gguf.gguf모델을 로드합니다. 두 번째 매개변수는 활성화할 GPU 계층 수를 나타냅니다 (0은 CPU만 사용).package main import ( "fmt" "log" "github.com/your_org/semantic-search-lib/search" // 실제 라이브러리 경로로 변경 ) func main() { // 모델 로드 vecEngine, modelLoadErr := search.NewVectorizer("../models/sentence-transformer-gguf.gguf", 0) if modelLoadErr != nil { log.Fatalf("모델 로드 실패: %v", modelLoadErr) } defer vecEngine.Close() // 애플리케이션 종료 시 모델 리소스 해제 fmt.Println("벡터화 모델 로드 완료.") } -
텍스트 임베딩 및 인덱스 생성:
search.NewIndex를 사용하여 새 인덱스를 생성합니다. 여기서[string]유형 매개변수는 각 벡터가 문자열 값과 연결됨을 지정합니다. 여러 벡터와 해당 레이블을 추가할 수 있습니다.package main import ( "fmt" "log" "github.com/your_org/semantic-search-lib/search" // 실제 라이브러리 경로로 변경 ) func main() { // ... (모델 로드 코드) ... vecEngine, modelLoadErr := search.NewVectorizer("../models/sentence-transformer-gguf.gguf", 0) if modelLoadErr != nil { log.Fatalf("모델 로드 실패: %v", modelLoadErr) } defer vecEngine.Close() fmt.Println("벡터화 모델 로드 완료.") // 인덱스 생성 및 벡터 추가 dataIndex := search.NewIndex[string]() sentences := []string{ "시맨틱 검색은 의미론적 유사성을 기반으로 정보를 찾습니다.", "벡터 임베딩은 텍스트를 고차원 공간의 숫자로 표현합니다.", "이 라이브러리는 작은 규모의 프로젝트에 적합합니다.", "라마.cpp 통합으로 CGO 없이 작동합니다.", "성능 최적화를 위해 GGUF 모델을 지원합니다.", } for _, s := range sentences { currentEmbed, embedErr := vecEngine.EmbedText(s) if embedErr != nil { fmt.Printf("임베딩 오류: %v\n", embedErr) continue } dataIndex.Add(currentEmbed, s) } fmt.Println("텍스트 임베딩 및 인덱싱 완료.") } -
인덱스 검색:
Search메서드를 사용하여 검색을 실행합니다. 이 메서드는 임베딩 벡터와 검색할 결과 수를 받습니다. 이 예제는 가장 관련성이 높은 3개의 결과를 검색하고 해당 유사도 점수와 함께 출력합니다.package main import ( "fmt" "log" "github.com/your_org/semantic-search-lib/search" // 실제 라이브러리 경로로 변경 ) func main() { // ... (모델 로드 및 인덱스 생성 코드) ... vecEngine, modelLoadErr := search.NewVectorizer("../models/sentence-transformer-gguf.gguf", 0) if modelLoadErr != nil { log.Fatalf("모델 로드 실패: %v", modelLoadErr) } defer vecEngine.Close() fmt.Println("벡터화 모델 로드 완료.") dataIndex := search.NewIndex[string]() sentences := []string{ "시맨틱 검색은 의미론적 유사성을 기반으로 정보를 찾습니다.", "벡터 임베딩은 텍스트를 고차원 공간의 숫자로 표현합니다.", "이 라이브러리는 작은 규모의 프로젝트에 적합합니다.", "라마.cpp 통합으로 CGO 없이 작동합니다.", "성능 최적화를 위해 GGUF 모델을 지원합니다.", } for _, s := range sentences { currentEmbed, embedErr := vecEngine.EmbedText(s) if embedErr != nil { fmt.Printf("임베딩 오류: %v\n", embedErr) continue } dataIndex.Add(currentEmbed, s) } fmt.Println("텍스트 임베딩 및 인덱싱 완료.") // 인덱스 검색 queryText := "의미 기반 검색이란 무엇인가요?" queryVector, queryEmbedErr := vecEngine.EmbedText(queryText) if queryEmbedErr != nil { log.Fatalf("쿼리 임베딩 오류: %v", queryEmbedErr) return } topN := 3 searchMatches := dataIndex.Search(queryVector, topN) fmt.Printf("\n쿼리: \"%s\"에 대한 상위 %d개 결과:\n", queryText, topN) for i, match := range searchMatches { fmt.Printf("%d. 결과: \"%s\" (유사도: %.4f)\n", i+1, match.Value, match.Relevance) } }
라이브러리 컴파일
-
Linux에서 컴파일
C/C++ 컴파일러와 CMake가 설치되어 있는지 확인합니다. Ubuntu의 경우 다음 명령어를 사용하여 설치할 수 있습니다.
sudo apt-get update sudo apt-get install build-essential cmake그런 다음 다음 명령어를 사용하여 라이브러리를 컴파일할 수 있습니다.
mkdir build && cd build cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc .. cmake --build . --config Release이 명령어는 필요한 모든 것을 정적으로 링크하는
libsemanticsearch_go.so파일을 생성합니다. 이 파일을/usr/lib에 복사하여 라이브러리를 설치할 수도 있습니다. -
Windows에서 컴파일
C/C++ 컴파일러와 CMake가 설치되어 있는지 확인합니다. Windows의 경우, Visual Studio의 Build Tools(CLI 도구 포함 확인)와 CMake를 사용하는 것이 간단한 옵션입니다.
mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release .. cmake --build . --config ReleaseVisual Studio를 사용하는 경우, 솔루션 파일이 생성됩니다. Visual Studio에서 솔루션 파일을 열고 프로젝트를 빌드할 수 있습니다. 그러면
bin디렉터리에semanticsearch_go.dll이 포함됩니다. -
GPU 및 기타 옵션
GPU 지원(예: Vulkan)을 활성화하려면 CMake 명령에 적절한 플래그를 추가해야 합니다. 자세한 내용은
llama.cpp빌드 문서를 참조하십시오. 예를 들어, Windows에서 Vulkan 지원을 활성화하여 컴파일하려면 Vulkan SDK가 설치되어 있는지 확인한 다음 다음 명령을 실행합니다.mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release -DGGML_VULKAN=ON .. cmake --build . --config Release