임베딩
임베딩은 데이터를 벡터화된 형식으로 표현하는 방법으로, 유사한 문서를 쉽게 찾을 수 있습니다.
현재 임베딩은 문제(issue)에 대해서만 생성되며, 이를 통해 다음과 같은 기능을 제공합니다.
아키텍처
임베딩은 Elasticsearch에 저장되며, 이는 고급 검색에도 사용됩니다.
이 프로세스는 Search::Elastic::ProcessEmbeddingBookkeepingService
에 의해 구동되며, Redis 큐에 추가하고 가져오는 작업을 수행합니다.
임베딩 큐에 추가하기
다음 프로세스 설명은 문제를 예로 들고 있습니다.
문제의 임베딩은 내용 "issue with title '#{issue.title}' and description '#{issue.description}'"
에서 생성됩니다.
Search::Elastic::IssuesSearch
에서 정의된 ActiveRecord 콜백을 사용하여, 임베딩 참조가 생성되거나 제목이나 설명이 업데이트될 때, 그리고 임베딩 생성 가능할 경우 임베딩 큐에 추가됩니다.
임베딩 큐에서 가져오기
Search::ElasticIndexEmbeddingBulkCronWorker
크론 작업자는 매 분마다 실행되며 다음 작업을 수행합니다.
따라서 우리는 항상 16개의 동시 프로세스가 동시에 임베딩을 생성하더라도 분당 450개의 임베딩이라는 비율 제한 설정을 초과하지 않도록 보장합니다.
백필링
고급 검색 마이그레이션은 백필링을 수행하는 데 사용됩니다. 이는 본질적으로 큐에 배치로 참조를 추가하며, 이후 위에서 설명한 대로 크론 작업자에 의해 처리됩니다.
새로운 임베딩 타입 추가하기
다음 과정은 임베딩을 생성하고 Elasticsearch에 저장하는 단계를 설명합니다.
- Elasticsearch 클러스터가 임베딩 생성을 처리할 수 있는지 또는 추가 리소스가 필요한지 확인하기 위해 비용 및 리소스 계산을 수행합니다.
- 임베딩을 저장할 위치를 결정합니다. Elasticsearch의 기존 인덱스를 확인하고 적합한 기존 인덱스가 없는 경우, 새 인덱스를 생성합니다.
- 인덱스에 임베딩 필드를 추가합니다: 예시.
- 새로운 타입에 맞게 콘텐츠 생성 방법을 업데이트합니다.
- 새로운 단위 원시 타입을 추가합니다: 여기와 여기.
-
Elastic::ApplicationVersionedSearch
를 사용하여 콜백에 접근하고 임베딩을 생성해야 할 때 필요한 검사를 추가합니다.Search::Elastic::IssuesSearch
를 예시로 참조하세요. - 임베딩을 백필합니다: 예시.
로컬에서 이슈 임베딩 추가하기
전제 조건
- Elasticsearch가 실행되고 있는지 확인합니다.
-
기존 Elasticsearch 설정이 있는 경우, 다음을 실행하여
AddEmbeddingToIssues
마이그레이션이 완료되었는지 확인합니다:Elastic::MigrationWorker.new.perform
- 로컬 환경에서 GitLab Duo 기능을 실행할 수 있는지 확인합니다.
-
rails 콘솔에서 다음을 실행했을 때 임베딩(768차원의 벡터)이 출력되는지 확인합니다. 출력되지 않으면 AI 설정에 문제가 있습니다.
Gitlab::Llm::VertexAi::Embeddings::Text.new('text', user: nil, tracking_context: {}, unit_primitive: 'semantic_search_issue').execute
백필 실행하기
프로젝트의 이슈에 대한 임베딩을 백필하기 위해, rails 콘솔에서 다음을 실행합니다:
Gitlab::Duo::Developments::BackfillIssueEmbeddings.execute(project_id: project_id)
이 작업은 이슈들을 큐에 추가하고 일괄로 처리하여 Elasticsearch에 임베딩을 인덱싱합니다.
분당 450개의 임베딩에 대한 속도 제한을 준수합니다. 문제가 있는 경우 @maddievn
또는 Slack의 #g_global_search
에 문의하세요.
확인하기
다음이 0을 반환하면 프로젝트의 모든 이슈에 임베딩이 있습니다:
curl "http://localhost:9200/gitlab-development-issues/_count" \
--header "Content-Type: application/json" \
--data '{"query": {"bool": {"filter": [{"term": {"project_id": PROJECT_ID}}], "must_not": [{"exists": {"field": "embedding"}}]}}}' | jq '.count'
PROJECT_ID
를 프로젝트 ID로 교체합니다.