Skip to main content

OpenSearch와 OpenAI를 연동한 벡터 검색 구현

카카오클라우드 Advanced Managed Search와 OpenAI API를 연동하여 텍스트를 벡터(Embedding)로 변환하고, 의미 기반 벡터 검색(Vector Search)을 구현하는 방법을 설명합니다.

기본 정보
  • 예상 소요 시간: 30분
  • 권장 운영 체제: MacOS, Ubuntu
  • 사전 준비 사항
    • Advanced Managed Search 클러스터 생성
    • OpenSearch API 접근 정보 (마스터 사용자)
    • OpenAI API Key 발급

시나리오 소개

이 튜토리얼에서는 Advanced Managed Search와 OpenAI Embedding API를 연동하여 텍스트 데이터를 벡터로 변환하고, 의미 기반 검색(Vector Search)을 구현합니다.

기존의 키워드 기반 검색은 단어가 정확히 일치하지 않으면 원하는 결과를 찾기 어렵지만, 벡터 검색은 문장의 의미를 기반으로 유사한 문서를 찾아낼 수 있습니다. 이를 통해 FAQ 검색, 문서 추천, 지식 검색, RAG 기반 질의응답과 같은 AI 검색 시나리오를 구현할 수 있습니다.

주요 내용은 다음과 같습니다.

  • OpenAI Embedding API를 활용한 텍스트 벡터화
  • OpenSearch ML Connector를 통한 외부 AI 모델 연동
  • 벡터 인덱스(knn_vector) 구성 및 문서 색인
  • 의미 기반 유사도 검색(Vector Search) 구현

시작하기 전에

이 튜토리얼을 진행하기 앞서, 먼저 클러스터 생성 및 관리를 참고하여 Advanced Managed Search 클러스터를 생성해 주세요.

info

이 튜토리얼에서 사용하는 모든 OpenSearch API 요청은 Advanced Managed Search 클러스터 엔드포인트를 기준으로 호출합니다.

클러스터 상세 정보 페이지에서 엔드포인트(Endpoint)마스터 사용자 계정 정보를 확인한 뒤, 아래 예시의 API 경로(/...) 앞에 클러스터 엔드포인트를 붙여서 요청을 실행하세요.

예: https://<AMS_ENDPOINT>/_plugins/_ml/connectors/_create

시작하기

Step 1. OpenAI Model Group 생성

OpenSearch ML 플러그인에서 사용할 모델 그룹을 생성합니다.

POST /_plugins/_ml/model_groups/_register
{
"name": "openai",
"description": "OpenAI Model Group"
}

응답에 포함된 MODEL_GROUP_ID를 Step 3에서 사용합니다.

Step 2. OpenAI Embedding Connector 생성

OpenAI Embedding API를 호출하는 Connector를 생성합니다.

POST /_plugins/_ml/connectors/_create
{
"name": "OpenAI Embedding Connector",
"description": "Connector for OpenAI Embedding API",
"version": 1,
"protocol": "http",
"parameters": {
"endpoint": "api.openai.com",
"model": "text-embedding-ada-002"
},
"credential": {
"OPENAI_API_KEY": "${OPENAI_API_KEY}"
},
"actions": [
{
"action_type": "predict",
"method": "POST",
"url": "https://${parameters.endpoint}/v1/embeddings",
"headers": {
"Authorization": "Bearer ${credential.OPENAI_API_KEY}",
"Content-Type": "application/json"
},
"request_body": "{ \"model\": \"${parameters.model}\", \"input\": ${parameters.input}, \"encoding_format\": \"float\" }",
"pre_process_function": "connector.pre_process.openai.embedding",
"post_process_function": "connector.post_process.openai.embedding"
}
]
}
환경변수설명
OPENAI_API_KEY🖌OpenAI에서 발급한 API Key

응답에 포함된 CONNECTOR_ID를 다음 단계에서 사용합니다.

Step 3. 모델 등록 및 배포

POST /_plugins/_ml/models/_register?deploy=true
{
"name": "OpenAI Embedding Model",
"function_name": "remote",
"model_group_id": "${MODEL_GROUP_ID}",
"description": "OpenAI embedding model",
"connector_id": "${CONNECTOR_ID}"
}
환경변수설명
MODEL_GROUP_ID🖌Step 1에서 반환된 Model Group ID
CONNECTOR_ID🖌Step 2에서 반환된 Connector ID

응답에 포함된 MODEL_ID를 다음 단계에서 사용합니다.

Step 4. Embedding 테스트

POST /_plugins/_ml/models/${MODEL_ID}/_predict
{
"parameters": {
"input": ["Ian is not cool"]
}
}
환경변수설명
MODEL_ID🖌Step 3에서 반환된 Model ID

Step 5. Embedding Ingest Pipeline 생성

PUT _ingest/pipeline/embedding_pipeline
{
"description": "Convert text to embedding using OpenAI",
"processors": [
{
"text_embedding": {
"field_map": {
"text": "embedding"
},
"model_id": "${MODEL_ID}"
}
}
]
}
환경변수설명
MODEL_ID🖌Step 3에서 반환된 Model ID

Step 6. 벡터 인덱스 생성

PUT my-index
{
"settings": {
"default_pipeline": "embedding_pipeline",
"index.knn": true
},
"mappings": {
"properties": {
"text": { "type": "text" },
"embedding": {
"type": "knn_vector",
"dimension": 1536
}
}
}
}

Step 7. 문서 색인

POST my-index/_doc
{ "text": "Ian is cool!" }

POST my-index/_doc
{ "text": "Ian is super cool!" }

POST my-index/_doc
{ "text": "Ian is not cool!" }

Step 8. 벡터 검색

GET my-index/_search
{
"_source": { "excludes": ["embedding"] },
"query": {
"neural": {
"embedding": {
"query_text": "Ian is cool?",
"model_id": "${MODEL_ID}",
"k": 2
}
}
}
}
환경변수설명
MODEL_ID🖌Step 3에서 반환된 Model ID

결과 예시

{
"hits": {
"hits": [
{ "_source": { "text": "Ian is cool!" } },
{ "_source": { "text": "Ian is super cool!" } }
]
}
}
tip

1. 의미 기반 검색: 위 결과에서 질의어(Ian is cool?)와 가장 의미가 가까운 문서들이 상위 결과로 반환되었습니다. "Ian is not cool!"은 단어 구성은 비슷하지만 의미가 반대이기 때문에 유사도 점수가 낮게 측정되었습니다.

2. K 값의 역할: 쿼리에서 k 값을 2로 설정했기 때문에, 유사도가 가장 높은 상위 2개의 문서만 결과에 포함되었습니다. 만약 더 많은 결과를 보고 싶다면 k 값을 조절해 보세요.