AWS, Azure, GCP 실험
추상적인 내용
요즘 많은 GenAI 솔루션(예: RAG)에서 텍스트, 이미지, 다른 데이터 임베딩에 대한 유사성 검색을 수행하는 게 점점 더 흔해지고 있죠. 임베딩 모델 Fine-tuning, Prompt Engineering, 순위 재지정을 위한 크로스 인코더 같은 기술로 임베딩 검색을 개선하려는 시도도 많고요.
이번 글에서는 위에서 언급한 방법들을 전혀 쓰지 않고도 유사성 검색을 확 끌어올리는 아주 간단하면서도 효과적인 방법을 보여드릴게요. 샘플도 준비되어 있고, Neo4j APOC ML 절차를 써서 Azure OpenAI, Google VertexAI, AWS Bedrock, 이렇게 3대 클라우드 제공업체에서 임베딩 테스트를 해본 결과도 보여드릴 예정이에요.
텍스트 임베딩에 대해 더 자세히 알고 싶다면, 예전에 썼던 글을 참고해주세요.
텍스트 임베딩 — 무엇을, 왜, 어떻게?
목표
일반적인 RAG(Retrieval Augmented Generation) 솔루션에서 검색 과정은 주로 이런 식으로 진행돼요. (텍스트) 임베딩에 대한 유사성 검색을 하는 거죠. 여기서 임베딩은 라는 데이터 타입으로 표현되고, Knowledge Base에 저장된 콘텐츠의 텍스트 임베딩에 대한 질문(자연어 질문)을 던지는 방식이에요.
효과적인 벡터 검색을 위해서는 가 중요한데요, 이 점수가:
- 관련 있는 벡터와 관련 없는 벡터 사이에 이 있어야 하고,
- 결과에서 관련 없는 벡터를 걸러내는 데 쓰이는 이 있어야 해요.
샘플
은행 상품에 대해 몇 가지 질문이 있다고 가정해 볼게요.
1. 'tell the differences bwteen standard home loan and fixed loan'
2. 'compare standard home loan, line of credit and fixed loan'
3. 'how to calculate interest?'
4. 'what is fixed rate loan?'
5. 'can I make more replayment?'
그리고 내용을 요약하면 이 되겠죠:
문제는 은행 상품의 특징을 비교하고 차이점을 요약하는 것입니다.
자, 테스트를 시작해볼까요?
Embedding API 호출하기
Neo4j를 사용해서 Knowledge Graph에 텍스트 데이터와 벡터 데이터를 모두 저장할 거라서, 빠르게 시작하기 위해 Neo4j APOC 라이브러리의 Machine Learning 절차를 사용할 거예요. 텍스트 임베딩을 얻기 위해 세 군데 클라우드 제공업체 모두 사용해볼 겁니다.
1. AWS Bedrock
AWS에서는 텍스트 임베딩 작업을 위해 Titan Embedding G1을 제공하고 있어요. 요청에 따라 특정 지역에서 사용할 수 있다네요. AWS 액세스 키와 keyID가 필요하고요. IAM에서 사용자 계정에 AmazonBedrockFullAccess 권한을 주는 것도 잊지 마세요.
:param aws_secret_access_key=>'AWS-SECRET-ACCESS-KEY';
:param aws_key_id=>'AWS-KEY-ID';
:param region=>'us-west-2';
:param model=>'amazon.titan-embed-text-v1';
CALL apoc.ml.bedrock.embedding(['Some Text'], {region:$region,keyId:$aws_key_id, secretKey:$aws_secret_access_key, model:$model});
2. Azure OpenAI
Azure에서는 OpenAI의 text-embedding-ada-002 모델을 쓰는데, 1536차원의 텍스트 임베딩을 만들어줘요. 이걸 실행하려면 OpenAI API 키가 필요하겠죠?
CALL apoc.ml.openai.embedding(['Some Text'], $apiKey, {}) yield index, text, embedding;
3. GCP VertexAI
GCP Vertex AI의 텍스트 임베딩(모델 이름은 textembedding-gecko)은 768차원의 텍스트 임베딩을 지원하는 모델이에요. GCP 계정의 , 프로젝트 ID, 그리고 정보가 필요해요.
CALL apoc.ml.vertexai.embedding(['Some Text'], $accessToken, $project, {region:'<region>'}) yield index, text, embedding;
4. 코사인 유사도 함수
Neo4j에는 Graph Data Science 라이브러리에 Cosine 유사도 기능이 있어요. 혹시 설치되어 있지 않다면, Cypher에서 직접 만들어서 사용할 수도 있답니다.
CALL apoc.custom.declareFunction(
"cosineSimilarity(vector1::LIST OF FLOAT, vector2::LIST OF FLOAT)::FLOAT",
"WITH
reduce(s = 0.0, i IN range(0, size($vector1)-1) | s + $vector1[i] * $vector2[i]) AS dotProduct,
sqrt(reduce(s = 0.0, i IN range(0, size($vector1)-1) | s + $vector1[i]^2)) AS magnitude1,
sqrt(reduce(s = 0.0, i IN range(0, size($vector2)-1) | s + $vector2[i]^2)) AS magnitude2
RETURN
toFloat(dotProduct / (magnitude1 * magnitude2)) AS score;"
);
기준선
유사도를 계산하기 위해 아래 Cypher 구문을 사용해서 Azure OpenAI 임베딩 모델부터 시작해 볼까요?
CALL apoc.ml.openai.embedding(['The question is about comparing banking products features and summarising differences'],NULL , {})
YIELD index, text, embedding
WITH text AS text1, embedding AS emb1
CALL apoc.ml.openai.embedding(['tell the differences bwteen standard home loan and fixed loan',
'compare standard home loan, line of credit and fixed loan',
'how to calculate interest?',
'what is fixed rate loan?',
'can I make more replayment?'
],NULL , {})
YIELD index, text, embedding
WITH text AS text2, embedding AS emb2, emb1, text1
RETURN text1, text2, custom.cosineSimilarity(emb1, emb2) AS score;
결과는 다음과 같아요.
╒══════════════════════════════════════════════════════════════════════╤═══════════════════════════════════════════════════════════════╤══════════════════╕
│text1 │text2 │score │
╞══════════════════════════════════════════════════════════════════════╪═══════════════════════════════════════════════════════════════╪══════════════════╡
│"The question is about comparing banking products features and summari│"tell the differences bwteen standard home loan and fixed loan"│0.786548104272935 │
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"compare standard home loan, line of credit and fixed loan" │0.8082209952027013│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"how to calculate interest?" │0.7799410426972614│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"what is fixed rate loan?" │0.7562771823612668│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"can I make more replayment?" │0.7278839096948918│
│sing differences" │ │ │
└──────────────────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────┴──────────────────┘
초기 결과는 예상했던 대로 나왔어요. 질문 #2의 점수가 가장 높고, 그 다음이 #1, #3 순서죠. 4번과 5번은 상대적으로 점수가 낮고요. 하지만 이건 기사 시작 부분에서 정의한 목표만큼 좋진 않아요.
- 질문 1~3번은 유사성 점수가 서로 너무 가까워요.
- 사이의 거리max and min유사성 점수는 겨우0.08이에요.
- 질문 #1은 관련성은 있지만,0.8을 합리적인 기준으로 본다면 상대적으로 점수가 낮은 편이죠.
비교할 벡터의 양이 많아지면 이런 문제 때문에 검색하고 필터링하기가 더 어려워질 수 있어요.
모델의 Fine-tuning이나 정교한 Prompt Engineering 없이 간단한 기술로 이걸 개선할 방법이 있을까요?
아주 간단한 방법
OpenAI 임베딩
물론 질문에 몇 가지 키워드를 추가할 수도 있어요. 예를 들어 '질문:'을 모든 질문 앞에 추가하면 아래와 같이 약간 더 나은 결과를 얻을 수 있죠.
╒══════════════════════════════════════════════════════════════════════╤══════════════════════════════════════════════════════════════════════╤══════════════════╕
│text1 │text2 │score │
╞══════════════════════════════════════════════════════════════════════╪══════════════════════════════════════════════════════════════════════╪══════════════════╡
│"The question is about comparing banking products features and summari│"question: tell the differences bwteen standard home loan and fixed lo│0.8076027901384112│
│sing differences" │an" │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"question: compare standard home loan, line of credit and fixed loan" │0.8209218883771804│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"question: how to calculate interest?" │0.7897457504166066│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"question: what is fixed rate loan?" │0.7752367420838878│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"question: can I make more replayment?" │0.7434177316292667│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
이제 #1과 #2는 모두 0.8 이상이고, #3을 제외한 모든 질문에 대해 점수가 높아진 걸 알 수 있어요. 실제로는 감소했네요.
더 일반적이고, 매우 간단하면서 효과적인 방법은 바로 를 좀 추가하는 거예요.
예를 들어 ### 를 질문이 시작될 때마다 추가하면 점수가 더 높아진답니다.
╒══════════════════════════════════════════════════════════════════════╤══════════════════════════════════════════════════════════════════════╤══════════════════╕
│text1 │text2 │score │
╞══════════════════════════════════════════════════════════════════════╪══════════════════════════════════════════════════════════════════════╪══════════════════╡
│"The question is about comparing banking products features and summari│"###question: tell the differences bwteen standard home loan and fixed│0.8153785384022421│
│sing differences" │ loan" │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"###question: compare standard home loan, line of credit and fixed loa│0.8396923324014403│
│sing differences" │n" │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"###question: how to calculate interest?" │0.8033634786411539│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"###question: what is fixed rate loan?" │0.7924533227169328│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"###question: can I make more replayment?" │0.7517756135667428│
│sing differences" │ │ │
그래서 다양한 패턴을 테스트한 결과, 아래와 같은 요약을 생각해냈어요.


OpenAI 임베딩 모델의 경우, 질문 양쪽에 ###을 추가하면 꽤 괜찮은 결과를 얻을 수 있는 것 같아요. 이렇게 하면 관련성이 낮은 질문보다 관련 질문이 더 많아지고, 거리가 13% 이상 늘어난다니 정말 흥미롭죠?
다른 임베딩 모델은 어떨까요?
AWS Bedrock
기본 테스트에서는 Bedrock/Titan 모델이 질문 #1과 2를 OpenAI보다 더 잘 구별하는 것으로 나타났어요. 유사성 점수의 거리가 훨씬 더 크지만, 절대값도 훨씬 낮기 때문이에요.
╒══════════════════════════════════════════════════════════════════════╤══════════════════════════════════════════════════════════════════════╤═══════════════════╕
│text1 │text2 │score │
╞══════════════════════════════════════════════════════════════════════╪══════════════════════════════════════════════════════════════════════╪═══════════════════╡
│"The question is about comparing banking products features and summari│"question: tell the differences bwteen standard home loan and fixed lo│0.48950020909002845│
│sing differences" │an" │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────┤
│"The question is about comparing banking products features and summari│"question: compare standard home loan, line of credit and fixed loan" │0.49591356152310995│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────┤
│"The question is about comparing banking products features and summari│"question: how to calculate interest?" │0.3239678489106068 │
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────┤
│"The question is about comparing banking products features and summari│"question: what is fixed rate loan?" │0.32782421303093584│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────┤
│"The question is about comparing banking products features and summari│"question: can I make more replayment?" │0.10463201924339886│
│sing differences" │ │ │
└──────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────┴───────────────────┘
다양한 패턴을 적용한 결과는 다음과 같아요.

다시###텍스트 임베딩에 더 많은 영향을 미치고 있네요.
Google VertexAI
VertexAI는 OpenAI에 비해 거리는 비슷하지만 점수가 낮아요.
══════════════════════════════════════════════════════════════════════╤══════════════════════════════════════════════════════════════════════╤══════════════════╕
│text1 │text2 │score │
╞══════════════════════════════════════════════════════════════════════╪══════════════════════════════════════════════════════════════════════╪══════════════════╡
│"The question is about comparing banking products features and summari│"question: tell the differences bwteen standard home loan and fixed lo│0.7222057116992117│
│sing differences" │an" │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"question: compare standard home loan, line of credit and fixed loan" │0.7196310737891332│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"question: how to calculate interest?" │0.6515748673785347│
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"question: what is fixed rate loan?" │0.618704888535842 │
│sing differences" │ │ │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────┼──────────────────┤
│"The question is about comparing banking products features and summari│"question: can I make more replayment?" │0.5397404750178617│
│sing differences" │ │ │
└──────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────┴──────────────────┘
일부 패턴을 적용한 후의 결과는 다음과 같아요.

VertexAI 임베딩 모델이 &&& over ### 를 선호하는 것 같네요.
요약
임베딩은 AI에 대한 지식이라고 할 수 있죠. 하지만 의미론적으로 동일한 텍스트라도 임베딩은 언어 모델의 토큰화 및 사전 학습 프로세스에 따라 결과가 크게 달라질 수 있어요. 심지어 포함된 특수 문자/기호와 같은 사소한 것들도 결과에 상당한 영향을 미칠 수 있다는 점!
일부 모델, 특히 BERT와 같은 하위 단어 기반 모델은 기호를 별도의 토큰 또는 토큰의 일부(예: BERT의 "##")로 처리해서 후속 임베딩에 영향을 줘요.
상황에 맞는 임베딩을 생성할 수 있는 모델(예: Transformer)에서 기호의 존재는 주변 단어의 맥락을 바꿔서 임베딩을 변경하게 돼요. 하지만 비공개 LLM의 경우 이에 대한 명확한 설명이 없어서, 이는 알려지지 않은 기회와 위험을 초래할 수 있다는 점을 기억해야 해요.
임베딩 및 검색 평가에 대한 보다 실용적인 지침을 얻고 싶다면, 다음 글도 도움이 될 거예요.
RAG 솔루션에서 Vector Search가 작동하지 않는 이유는 무엇일까요?
- AWS
- GCP
- OpenAI
- Search
- Semantic Search
에이치시스템즈의 LogTree는 Neo4j 기반 GraphRAG 플랫폼으로, 데이터를 자동으로 지식그래프화하고 자연어 질의로 즉시 답을 제공합니다.
'GraphRAG' 카테고리의 다른 글
| Integrating Neo4j with Google Genkit: A Practical Guide (0) | 2026.05.20 |
|---|---|
| 그래프 데이터 과학 내부자 가이드: 먼저, 간단한 개요 (0) | 2026.05.20 |
| AWS 환경에서 그래프 기술로 GenAI의 난제들을 해결하다 (0) | 2026.05.20 |
| 500마일도 걷게 만드는 Neo4j GraphRAG 활용법 (0) | 2026.05.20 |
| GraphRAG Python 패키지로 그래프 기반 RAG 애플리케이션을 위한 하이브리드 검색 구현하기 (0) | 2026.05.20 |
