시맨틱 검색
시맨틱 검색은 키워드 매칭이 아닌 의미를 기반으로 의미적으로 유사한 콘텐츠를 찾기 위해 벡터 임베딩을 사용하는 GitLab 프레임워크입니다. 시맨틱 검색은 텍스트를 벡터 임베딩으로 변환하고 벡터 저장소에 저장합니다. 시맨틱 코드 검색은 시맨틱 검색 프레임워크의 첫 번째 구현입니다.
시맨틱 검색은 키워드 매칭이 아닌 의미를 기반으로 의미적으로 유사한 콘텐츠를 찾기 위해 벡터 임베딩을 사용하는 GitLab 프레임워크입니다. 이를 통해 Duo Chat과 같은 AI 기능이 사용자 쿼리에 대한 관련 컨텍스트를 검색할 수 있습니다.
개요#
시맨틱 검색은 텍스트를 벡터 임베딩으로 변환하고 벡터 저장소에 저장합니다. 사용자가 쿼리를 만들면 쿼리도 임베딩으로 변환되어 저장된 벡터와 비교하여 가장 유사한 결과를 찾습니다. 이 접근 방식은 의미적 의미를 포착하여 정확한 키워드가 일치하지 않아도 관련 콘텐츠를 찾을 수 있습니다.
시맨틱 코드 검색#
시맨틱 코드 검색은 시맨틱 검색 프레임워크의 첫 번째 구현입니다. Duo Chat 및 기타 AI 기능이 저장소에서 관련 코드 스니펫을 찾을 수 있게 합니다. 이 기능은 GitLab Duo Agent Platform 및 기타 AI 플랫폼에서 사용할 수 있는 MCP 도구(semantic_code_search)로 제공됩니다.
자세한 내용은 시맨틱 코드 검색 아키텍처를 참조하세요.
아키텍처#
시맨틱 검색 프레임워크는 gitlab-active-context 젬으로 구동됩니다. 이 젬은 다양한 벡터 저장소(Elasticsearch, OpenSearch, pgvector를 사용한 PostgreSQL)에 대한 변환 레이어를 제공하여 벡터 저장소별 구현 없이도 동일한 코드가 지원되는 모든 벡터 저장소와 작동할 수 있게 합니다.
이 프레임워크는 확장 가능하며 여러 유형의 시맨틱 검색을 지원하도록 설계되었습니다. 각 시맨틱 검색 유형은 다음을 사용하여 구현됩니다:
- 컬렉션 (
Ai::ActiveContext::Collections::): 인덱싱되는 콘텐츠와 저장 방법을 정의합니다 - 참조 (
Ai::ActiveContext::References::): 콘텐츠 업데이트를 위한 임베딩을 추적하고 관리합니다 - 쿼리 (
Ai::ActiveContext::Queries::): 벡터 저장소에서 유사한 콘텐츠를 검색합니다 - 큐 (
Ai::ActiveContext::Queues::): 임베딩 생성의 비동기 처리를 관리합니다 - 마이그레이션: 벡터 저장소의 스키마 변경 및 데이터 변환을 실행합니다
다른 콘텐츠 유형(예: 머지 리퀘스트 또는 문서)에 이러한 컴포넌트를 구현하면 새 시맨틱 검색 유형을 추가할 수 있습니다.
임베딩 생성#
임베딩은 Ai::ActiveContext::References::Code와 같은 참조 클래스를 사용하여 큐 시스템을 통해 비동기적으로 생성됩니다:
- 참조 추적: 콘텐츠가 생성되거나 업데이트되면 적절한 참조 클래스에서 임베딩 참조가 추적됩니다
- 배치 처리: 참조는
Ai::ActiveContext::BulkProcessWorker에 의해 배치로 처리됩니다 - 벡터 저장: 생성된 임베딩은 구성된 벡터 저장소에 저장됩니다
BulkProcessWorker는 매 분마다 실행되고 큐에서 임베딩 참조를 처리하는 크론 작업입니다. 참조를 가져와서 임베딩을 생성하고 큐에서 제거합니다. 처리 후 큐가 비어있지 않으면 워커는 처리를 계속하기 위해 자신을 다시 큐에 넣습니다. 임베딩 생성이 실패하면 한 번 재시도하고 그 후 데드 큐에 배치됩니다.
임베딩 모델#
현재 시맨틱 검색은 임베딩 생성을 위해 Vertex AI의 text-embedding-005 모델을 사용합니다. 모델 구성은 컬렉션 클래스(예: Ai::ActiveContext::Collections::Code)에 정의되어 있습니다.
셀프 호스팅 AI Gateway 설정에서 임베딩 모델을 설정하는 지원은 에픽 20110에서 계획되어 있습니다. 사용 가능하게 되면 셀프 호스팅 AI Gateway가 있는 Self-Managed 인스턴스의 관리자가 자체 임베딩 모델을 선택할 수 있게 됩니다.
쿼리 실행#
쿼리가 실행될 때:
- 임베딩 생성: 사용자의 쿼리는 인덱싱된 콘텐츠와 동일한 모델을 사용하여 임베딩으로 변환됩니다
- 벡터 검색: k-최근접 이웃(KNN) 검색을 사용하여 임베딩을 저장된 벡터와 비교합니다
- 필터링: 결과는 관련 기준(예: 프로젝트, 파일 경로)으로 필터링됩니다
- 인가: 결과는 사용자가 접근 권한이 있는 콘텐츠만 포함하도록 필터링됩니다
- 결과 제한: 기본적으로 10개의 가장 유사한 결과가 반환됩니다
마이그레이션#
시맨틱 검색 프레임워크는 연결된 벡터 저장소에 대한 스키마 변경 및 데이터 변환을 관리하기 위한 마이그레이션 시스템을 사용합니다. 마이그레이션은 데이터베이스에서 추적되고 워커 프로세스에 의해 비동기적으로 실행됩니다.
Ai::ActiveContext::MigrationWorker는 5분마다 크론 작업으로 실행하여 완료되지 않은 마이그레이션을 실행합니다.
벡터 저장소#
인스턴스는 다음 벡터 저장소 중 하나를 사용할 수 있습니다:
- Elasticsearch
- OpenSearch
- pgvector를 사용한 PostgreSQL
시맨틱 검색을 사용하려면 벡터 저장소 연결을 생성해야 합니다. 연결을 구성하는 두 가지 방법이 있습니다:
옵션 1: GitLab UI 사용
Advanced Search에서 사용하는 Elasticsearch 또는 OpenSearch 클러스터의 경우:
- Admin > Settings > Search로 이동합니다
- Advanced Search 클러스터에 연결하는 버튼을 클릭합니다
- 연결이 자동으로 생성되고 구성됩니다
옵션 2: Rails 콘솔 사용
connection = Ai::ActiveContext::Connection.create!(
name: "os",
options: { url: ["http://localhost:9202"] },
adapter_class: "ActiveContext::Databases::OpenSearch::Adapter"
)
connection.activate!
PostgreSQL의 경우 pgvector 확장을 사용합니다:
-
PostgreSQL 데이터베이스에서 확장을 생성합니다:
CREATE EXTENSION vector; -
Rails 콘솔에서 연결을 생성합니다:
connection = Ai::ActiveContext::Connection.create!( name: "postgres", options: { host: 'localhost', port: 5432, user: 'postgres', password: 'password' }, adapter_class: "ActiveContext::Databases::Postgresql::Adapter" ) connection.activate!
자세한 내용은 pgvector 문서를 참조하세요.
지원되는 어댑터 클래스:
ActiveContext::Databases::Elasticsearch::AdapterActiveContext::Databases::OpenSearch::AdapterActiveContext::Databases::Postgresql::Adapter
options 해시에는 벡터 저장소에 특정한 연결 세부 정보(URL, 자격 증명 등)가 포함되어야 합니다.
시맨틱 코드 검색 아키텍처#
인덱싱 워크플로우#
초기 인덱싱#
아직 인덱싱되지 않은 프로젝트에 대해 시맨틱 코드 검색 도구가 호출될 때:
- 저장소 레코드 생성:
pending상태의Ai::ActiveContext::Code::Repository레코드가 생성됩니다 - 인덱스 워커:
Ai::ActiveContext::Code::RepositoryIndexWorker가pending저장소를 처리합니다 - 초기 인덱싱:
Ai::ActiveContext::Code::InitialIndexingService가Ai::ActiveContext::Code::Indexer를 호출합니다Indexer는gitlab-elasticsearch-indexer를 실행하여 Gitaly에서 저장소의 파일을 가져오고 코드를 청크로 분할하여 벡터 저장소에 청크를 인덱싱합니다InitialIndexingService는 임베딩 생성을 위해 인덱싱된 콘텐츠의 참조/ID를 큐에 넣습니다
- 비동기 처리: 큐에 있는 콘텐츠 참조는 비동기
Ai::ActiveContext::BulkProcessWorker를 통해 임베딩 생성에 사용됩니다. - 도구 사용 불가: 사용자에게 인덱싱이 진행 중이며 몇 분 후에 다시 시도해야 한다고 알립니다.
- 준비 확인:
Ai::ActiveContext::Code::MarkRepositoryAsReadyEventWorker는 10분 크론 스케줄(SchedulingService경유)로 실행되며 모든 임베딩이 생성되었는지 확인합니다. 모든 임베딩이 준비되면 저장소를ready로 표시합니다 - 쿼리 가능: 다음에 도구가 호출될 때 저장소가 준비되어 시맨틱 검색 쿼리에 사용할 수 있습니다
증분 인덱싱#
코드가 기본 브랜치에 병합될 때:
- 푸시 이벤트: 푸시 이벤트가
BranchPushService를 통해 증분 인덱싱 프로세스를 트리거합니다 - 인덱스 워커:
Ai::ActiveContext::Code::RepositoryIndexWorker가readyActiveContext 저장소를 처리합니다 - 증분 인덱싱 - 변경된 파일만 처리됩니다
Ai::ActiveContext::Code::IncrementalIndexingService가Ai::ActiveContext::Code::Indexer를 호출합니다Indexer는gitlab-elasticsearch-indexer를 실행하여 Gitaly에서 변경된 파일을 가져오고 코드를 청크로 분할하여 벡터 저장소에 청크를 인덱싱합니다. 또한 벡터 저장소에서 고아 데이터를 삭제합니다.IncrementalIndexingService는 임베딩 생성을 위해 인덱싱된 콘텐츠의 참조/ID를 큐에 넣습니다
- 비동기 처리: 큐에 있는 콘텐츠 참조는 비동기
Ai::ActiveContext::BulkProcessWorker를 통해 임베딩 생성에 사용됩니다.
삭제 워크플로우#
네임스페이스가 더 이상 인덱싱에 적합하지 않은 경우 Ai::ActiveContext::Code::ProcessInvalidEnabledNamespaceEventWorker가 이를 받아 EnabledNamespace 레코드를 삭제합니다.
저장소가 더 이상 인덱싱에 적합하지 않은 경우 Ai::ActiveContext::Code::MarkRepositoryAsPendingDeletionEventWorker가 이를 pending_delete로 표시합니다. Ai::ActiveContext::Code::RepositoryIndexWorker는 그런 다음 저장소를 처리하고 gitlab-elasticsearch-indexer를 호출하여 벡터 저장소에서 프로젝트의 문서를 삭제하고 저장소 레코드를 삭제합니다.
gitlab-elasticsearch-indexer#
gitlab-elasticsearch-indexer Go 프로젝트는 다음을 처리합니다:
- Gitaly에서 저장소의 파일 가져오기
- 파일 청크 분할
- 벡터 저장소에 청크 콘텐츠 인덱싱
- 고아 데이터 삭제
- 프로젝트의 모든 데이터 삭제
청크 분할
gitlab-elasticsearch-indexer는 gitlab-code-parser 라이브러리를 사용하여 코드를 논리적 청크로 분할합니다.
청크 분할 프로세스는 두 단계 접근 방식을 사용합니다:
- AST 인식 청크 분할: 코드 청크 분할기가 각 파일을 파싱하고 논리적 분할 지점(함수 정의, 클래스 정의 등)을 식별합니다
- 크기 기반 폴백: AST 분할 지점을 사용할 수 없는 경우 청크 분할기는 최대 바이트 크기를 존중하면서 줄 경계에서 분할하는 폴백을 사용합니다
이 접근 방식은 임베딩 생성을 위한 크기 제한을 유지하면서 청크가 의미적으로 의미 있게 유지되도록 합니다.
네임스페이스 적격성#
모든 네임스페이스가 시맨틱 코드 검색에 적합한 것은 아닙니다. 적격성은 두 워커를 통해 관리됩니다:
Ai::ActiveContext::Code::CreateEnabledNamespaceEventWorker (SchedulingService를 통해 매일 실행)
- 적합한 네임스페이스를 식별하고 활성화합니다
- 적합한 네임스페이스에 대한
EnabledNamespace레코드를 생성합니다
GitLab.com에서 네임스페이스가 적합하려면:
- 네임스페이스 설정에서 AI 기능이 활성화되어 있어야 합니다
- 지원되는 AI 플랜(Premium 이상)이 있어야 합니다
- 구독이 만료되지 않아야 합니다
셀프 매니지드 인스턴스에서 다음 경우 모든 최상위 그룹 네임스페이스가 적합합니다:
- 인스턴스 수준 AI 베타 기능이 활성화되어 있어야 합니다(
instance_level_ai_beta_features_enabled) - 라이선스에서 AI 기능이 사용 가능해야 합니다
**Ai::ActiveContext::Code::MarkRepositoryAsPendingDeletionEventWorker**는 더 이상 적격성 기준을 충족하지 않는 저장소를 삭제용으로 표시합니다.
**Ai::ActiveContext::Code::ProcessInvalidEnabledNamespaceEventWorker**는 더 이상 적격성 기준을 충족하지 않는 네임스페이스에 대한 EnabledNamespace 레코드를 정리합니다.
지원되는 파일 유형#
시맨틱 코드 검색은 저장소의 모든 파일을 인덱싱합니다. 현재 결과는 프로젝트의 제외 규칙에 일치하는 파일을 제외하기 위해 사후 필터링됩니다. 향후 버전에서는 효율성 향상을 위해 제외된 파일을 아예 인덱싱하지 않을 것입니다.
MCP 구현#
GitLab MCP 구현 및 사용 가능한 클라이언트에 대한 자세한 정보는 GitLab MCP 문서 및 런북을 참조하세요.
현재 시맨틱 코드 검색 도구는 GitLab MCP가 구성된 IDE에서 사용 가능합니다. mcp_client 기능 플래그의 배포와 함께 웹에서도 사용 가능하게 됩니다.
시맨틱 검색 확장#
시맨틱 검색 프레임워크 확장에 대한 자세한 정보는 gitlab-active-context 젬 문서를 참조하세요.
새 시맨틱 검색 유형(예: 머지 리퀘스트 또는 문서)을 추가하려면 다음 컴포넌트를 구현하세요:
- 컬렉션 (
Ai::ActiveContext::Collections::): 컬렉션 이름, 큐, 참조 클래스 및 인가 처리 방법을 정의합니다 - 참조 (
Ai::ActiveContext::References::):ActiveContext::Reference를 확장하여 임베딩을 추적하고 콘텐츠 및 임베딩 생성을 위한 전처리기를 정의합니다 - 쿼리 (
Ai::ActiveContext::Queries::): 벡터 저장소를 검색하기 위한 쿼리 로직을 구현합니다 - 큐 (
Ai::ActiveContext::Queues::): 비동기 처리 관리를 위한 큐를 정의합니다 - 워커: 새 시맨틱 검색 유형의 인덱싱, 처리 및 수명 주기 관리를 위한 워커를 생성합니다
이러한 컴포넌트가 함께 작동하는 방법의 완전한 예시는 시맨틱 코드 검색 구현을 참조하세요.
시맨틱 코드 검색 활성화#
사전 요구 사항#
- 벡터 저장소 연결 구성(Elasticsearch, OpenSearch 또는 pgvector를 사용한 PostgreSQL)
- 임베딩 생성을 위한 Vertex AI 자격 증명 구성
- 인스턴스에 대한 베타 실험 기능 설정 활성화
사전 요구 사항 확인#
벡터 저장소 연결
벡터 저장소 연결이 작동하는지 테스트합니다:
ActiveContext::adapter.search(
user: current_user,
collection: ::Ai::ActiveContext::Collections::Code,
query: ActiveContext::Query.all
)
오류 없이 결과가 반환되어야 합니다.
Vertex AI 자격 증명
임베딩 생성이 구성되었는지 테스트합니다:
Ai::ActiveContext::Embeddings::Code::VertexText.new(["test"]).execute
벡터가 반환되어야 합니다.
베타 실험 기능
네임스페이스에 베타 실험 기능이 활성화되어 있는지 확인합니다:
namespace.experiment_features_enabled?
true를 반환해야 합니다.
시맨틱 코드 검색 비활성화#
시맨틱 코드 검색을 비활성화하면 삭제할 저장소 레코드가 많을 경우 긴 데이터베이스 잠금이 발생할 수 있습니다. 프로덕션 환경에서 주의해서 사용하세요. 향후 작업에서 안전하게 비활성화할 수 있게 될 것입니다. 이슈 582787을 참조하세요.
인덱스 및 컬렉션 레코드 삭제:
ActiveContext.adapter.executor.drop_collection(:code)
연결 및 관련 레코드 삭제:
::Ai::ActiveContext::Connection.active.destroy!
개발자 가이드#
MCP 로컬 설정#
개발 및 테스트를 위해 MCP 서버를 로컬로 설정하려면 MCP 서버 개발 가이드를 참조하세요.
Tip: 도구가 사용되도록 하려면 프롬프트에서 semantic_code_search 도구를 명시적으로 요청하세요.
시맨틱 코드 검색 사용#
콘솔에서 시맨틱 검색을 호출하려면 Ai::ActiveContext::Queries::Code 클래스를 사용합니다:
# 시맨틱 코드 검색이 사용 가능한지 확인
Ai::ActiveContext::Queries::Code.available?
# 시맨틱 검색 수행
result = Ai::ActiveContext::Queries::Code.new(
search_term: "user authentication logic",
user: current_user
).filter(
project_id: project.id,
path: "app/controllers/", # 선택 사항: 디렉토리로 필터링
knn_count: 10, # 비교할 벡터 수
limit: 10 # 반환할 결과 수
)
큐에 있는 항목 관리#
처리를 기다리는 모든 큐 항목 보기:
ActiveContext::Queues.all_queued_items
크론 워커를 기다리지 않고 모든 큐 항목을 즉시 처리:
ActiveContext.execute_all_queues!
벡터 저장소 검색#
벡터 저장소의 모든 항목 찾기:
ActiveContext::adapter.search(
user: current_user,
collection: ::Ai::ActiveContext::Collections::Code,
query: ActiveContext::Query.all
)
연결 초기화#
새 연결로 새로 시작하려면 모든 기존 데이터를 삭제하고 재생성합니다:
active_connection = ::Ai::ActiveContext::Connection.active
active_connection.migrations.destroy_all
active_connection.repositories.destroy_all
active_connection.enabled_namespaces.destroy_all
active_connection.collections.destroy_all
active_connection.destroy
그런 다음 새 연결을 생성하고 활성화합니다. Rails 콘솔에서 마이그레이션을 생성할 때 다음을 실행하세요:
connection.activate!
새 임베딩 모델 지원#
시맨틱 검색에 새 임베딩 모델이 지원되려면:
- 평가
- AI Gateway에서 지원
- Rails LLM 모듈에서 지원
- ActiveContext 컬렉션에 등록
평가#
각 새 모델은 적절히 평가되어야 합니다. GitLab은 특정 이유(예: 법적, 성능 등)로 모델 지원을 거부할 수 있습니다.
평가 후 다음 정보를 가지고 있어야 합니다:
- 모델 공급자 - 예: Vertex, Anthropic, Fireworks 등
- 특정 모델 및 버전 - 예:
gemini-embedding-001,all-MiniLM-L6-v2
모델 평가에 대한 자세한 내용은 에픽 17749를 참조하세요.
AI Gateway에 API 지원 추가#
:construction: :construction: :construction:
Rails LLM 모듈에 요청 래퍼 클래스 추가#
:construction: :construction: :construction:
ActiveContext 컬렉션에 모델 등록#
:construction: :construction: :construction:
트러블슈팅#
시맨틱 검색에서 결과가 반환되지 않음#
가능한 원인:
- 저장소가 아직 인덱싱되지 않음(상태가
embedding_indexing_in_progress)- 확인:
Ai::ActiveContext::Code::Repository.find_by(project_id: project.id).state - 해결: 인덱싱이 완료될 때까지 기다리거나
ActiveContext.execute_all_queues!를 실행하여 수동으로 처리를 트리거합니다
- 확인:
- 네임스페이스가 적합하지 않음
- 확인:
Ai::ActiveContext::Code::EnabledNamespace.exists?(namespace_id: project.root_namespace.id) - 해결: 네임스페이스가 적격성 기준을 충족하는지 확인합니다
- 확인:
- 벡터 저장소 연결이 구성되지 않음
- 확인:
Ai::ActiveContext::Connection.active.present? - 해결: 벡터 저장소 연결을 구성합니다
- 확인:
데드 큐 항목 지우기#
임베딩 생성이 반복적으로 실패하면 항목이 데드 큐에 배치될 수 있습니다. 다음을 사용하여 지웁니다:
# 모든 데드 큐 항목 지우기
ActiveContext::DeadQueue.clear_tracking!
# 또는 특정 큐 지우기
Ai::ActiveContext::Queues::Code.clear_tracking!
