LangChain

[LangChain] 임베딩과 코사인 유사도의 이해

sian han 2026. 4. 28. 09:18

 

LLM은 환각(잘못된 정보를 출력하는 현상)을 일으키고 부정확한 정보를 제공할 가능성이 높다.

이른 프롬프트를 수정하는 것으로 해결할 수 없으며, 그 이유는 모델의 지식한계로 생기는 문제이기 때문이다. 

 

LLM에 데이터를 제공할 때 가장 문제가 되는 요소는 바로 입력 크기 제한이다. 방대한 텍스트를 LLM 에 전부 전달할 수 없는데, 이때 아래와 같은 의문이 생긴다.

  • 특정 부분만 선택해야 하는데 어느 부분을 전달해야할까 ?
  • LLM이 질문에 답할 때 참고하기에 가장 적합한 텍스트는 어떻게 선정해야할까 ? 

이 문제는 인덱싱검색으로 해결할 수 있다. 

  • 인덱싱 : 애플리케이션이 질문에 가장 적합한 자료를 손쉽게 탐색할 수 있도록 문서를 전처리한다.
    • 문서를 거대 언어 모델이 이해하고 검색할 수 있는 형식으로 사전 처리 하는 것
  • 검색 : LLM이 데이터를 바탕으로 정확한 답변을 생성하도록 인덱스에서 외부 데이터를 가져와 컨텍스트로 전달한다.

인덱싱에서 문서를 전처리 한다고 했는데, 이 과정이 왜 필요할까 ? 

LLM에 특정 문서를 제공하고, 관련한 질문을 했을때, 이에 대한 답변을 받기 위해서는 네 가지 핵심 단계가 필요하다.

 

  • 1. 문서에서 텍스트를 추출한다
  • 2. 텍스트를 효율적으로 처리할 수 있도록 적절한 단위로 분할한다.
  • 3. 텍스트를 컴퓨터가 이해할 수 있는 숫자 체계로 변환한다.
  • 4. 문서에서 주어진 질문에 대한 부분을 손쉽고 신속하게 조회할 수 있도록 텍스트의 숫자 표현을 적절한 위치에 저장한다.

이 과정을 인제스천이라고 부른다.

 

인제스천(Ingestion)

인제스천은 기본적으로 데이터 엔지니어링의 ETL 구조를 따른다. 

 

1. Extract 추출 - Document Loaders

다양한 소스에서 raw 데이터를 긁어온다

  • 종류 : PDF, CSV, JSON, Notion, SQL DB 등
  • 역할 : 각기 다른 포맷의 데이터를 랭체인의 공통 규격인 Document 객체로 변환한다. 

 

2. Transform 변환 - Text Splitters

LLM 은 한 번에 읽을 수 있는 양이 정해져 있는데, 그래서 긴 문서를 의미있는 단위로 쪼개야 한다. 

이때 핵심은 단순히 글자 수로 자르는 게 아니라,

문맥이 끊기지 않도록 재귀적 분할이나 의미론적 분할 (그니까 암튼 분할을 알잘딱깔센으로 잘한다는 거임) 을 수행한다.

이때 데이터를 너무 크게 쪼개면 노이즈가 섞이고, 너무 작게 쪼개면 문맥이 사라진다. Chunk Size 를 최적화 하는 것이 인제스천 설계의 핵심 역량이다. 

 

3. Load 적재 - Vector Stores

쪼개진 텍스트를 숫자의 형태(Embedding)로 바꾸어 벡터 데이터베이스에 저장한다.

  • 도구 : Chroma, Pinecone, FAISS 등
  • 목적 : 나중에 사용자가 질문했을 때, 유사한 문맥의 데이터를 빠르게 검색하기 위함이다. 

인제스천문서를 컴퓨터가 이해하고 분석하기 좋은 숫자 데이터로 전환한 뒤, 이를 효율적인 검색 증강 생성을 위해 특화된 데이터베이스에 저장하는 전체 프로세스를 의미한다. 여기서 숫자 데이터는 임베딩이라고 부르고, 특수한 유형의 데이터베이스를 벡터 저장소라고 부른다. 임베딩이 무엇이고 왜 중요한지 알아보자

 

임베딩

임베딩은 컴퓨터가 자연어의 의미와 맥락을 이해할 수 있도록 텍스트를 다차원 공간상의 수치(벡터)로 변환하는 과정이다. 

  • 임베딩은 텍스트를 긴 숫자 시퀀스로 표현한다. 
  • 이 과정에서 손실이 발생한다.
  • 숫자 시퀀스에서 원본 텍스트를 복원할 수 없다.
  • 따라서 보통 원본 텍스트와 해당 숫자 시퀀스를 함께 저장한다. 

왜 원본 텍스트를 저장하는데 굳이 숫자 데이터를 따로 만들어야 할까 ? 

텍스트를 숫자로 변환하면 숫자의 유연함과 강력함을 얻을 수 있다. 

 

컴퓨터는 "사과" 라는 글자가 과일인지, 컴퓨터 회사인지 알지 못한다.

그러나 이를 특정 차원의 숫자로 변환하는 순간, 수학적 공간에서의 관계가 형성된다. 텍스트를 숫자로 바꾸면, 단어와 단어 사이의 추상적인 관계를 벡터 산술 연산으로 풀 수 있다

 

  • 원본 텍스트 : 사용자에게 보여주기 위한 용도
  • 숫자 데이터(Embedding) : 수백만 개의 데이터 사이에서 가장 관련 있는 것을 0.01 초 만에 찾아내기 위한 색인 용도

 

▶ LLM 이전의 임베딩 : BoW 모델

참고 : https://www.youtube.com/watch?v=e9U0QAFbfLI&t=182s

 

 

▷ 코사인 유사도

단어가 얼마나 많이 나타났는지 보다는 어떤 단어들이 공통으로 나타났는지 측정한는 지표이다. 

 

▷ 코사인 유사도 계산 절차

 

1. 단어 빈도수 표 작성

비교하려는 두 문장에 나타난 모든 단어의 갯수를 세어 표로 만든다.

예를 들어 hello world 와 hello 라는 구절이 있다면 아래와 같은 표를 만든다. 

 

 

2. 벡터의 방향 측정

  • 이 숫자들을 그래프 상의 점으로 찍고 원점에서 그 점까지 선을 긋는다. 
  • 이때 코사인 유사도 수식은 이 두 선 사이의 각도를 계산한다.
  • 두 문장이 완전히 같다면 각도는 0도가 되며, 코사인 값은 1이 된다.
  • 두 문장에 공통된 단어가 하나도 없다면 각도는 90도가 되며, 코사인 값은 0이 된다.
  • 위의 경우  "hello world" 와 "hello" 는 hello 라는 단어를 공통으로 가지고 있어, 코사인 값은 71도가 된다.

이는 단어의 빈도만을 따져서 벡터화 하는 전통적인 방식이다.

문장의 길이나 단어의 반복횟수에 영향을 받지 않고, 오직 방향(각도) 에만 집중한다. 

이와 같이 단어의 빈도만을 따져서 벡터화 하는 전통적인 방식을 Bag of Words 모델이라고 부른다. 

 

▶ LLM 기반 임베딩

LLM 이전에 벌어진 모든 머신러닝 발전사는 과감히 생략(BoW, 희소 임베딩, 희소 벡터 ..) 하고,

LLM 기반의 임베딩 모델을 학습해보자. LLM 은 단어를 다른 단어와 조합하는 방식을 파악하여 텍스트 문맥에서 단어와 문장의 의미를 이해한다.(단어의 맥락과 속뜻을 숫자로 압축한다).

 

▷ 임베딩 모델

임베딩 모델은 단순히 단어를 숫자로 치환하는 것이 아니라, Transformer 아키텍쳐 (주로 BERT 계열)을 사용하여 문장 내 단어 간의 관계를 분석한다. 또 그 문장의 의미를 수백~수천개의 숫자로 된 밀집 벡터로 변환한다. 

 

ex ) "배가 맛있다" vs "배를 탄다"

주변 단어들 (맛있다 vs 탄다)을 함께 분석하여 첫번째 배는 광리 공간에, 두번째 배는 탈것 공간에 가깝게 배치한다. 

 

  LLM 기반 임베딩의 핵심 특징

 

1. 의미론적 추론 (Semantic Reasoning)

  • BoW 모델과 같은 단순한 키워드 일치가 없이도 검색이 가능하다. 
  • 각 단어에는 그와 상응하는 의미론적 임베딩이 나란히 배치된다. 

 

의미 유사성이 높은 단어나  문장을 표현하는 숫자 배열은 관련성이 없는 경우보다 가깝게 구성된다. 

이때 각 숫자는 부동소수점 값으로, 의미론적 차원(시맨틱 차원)을 나타낸다. 

3차원 공간에 모든 벡터를 배치하면 아래와 유사한 형태가 나타난다. 

 

두 벡터 사이의 각도가 작거나 거리가 짧을수록 더욱 유사하다고 판단한다. 

이때 두 벡터간 유사도를 산출하는 효과적은 방법은 위에서 설명한 코사인 유사도이다. 

 

2. 다국어 정렬

최신 LLM 모델들은 여러 언어를 같은 공간에 매핑한다. 따라서 다국어 검색 시스템 구축이 매우 쉬워진다. 

 

3. 정보 압축

수만 페이지의 텍스트도 고정된 크기(ex. 1536 개 숫자)의 벡터로 압축된다. 

이는 벡터 DB 를 통해 고속으로 검색할 수 있는 기반이 된다. 

 

이제 큰 그림을 이해했으니, 문서 전처리 과정의 첫 단계인 인덱싱을 다시 살펴보도록 하자 ~