실무 Multi-Agent 오케스트레이션 13장 · 임베딩과 벡터 DB 4 / 7 ← 이전목차다음 → TechLead Cro

13장. 임베딩과 벡터 DB

유사도 검색과 거리 읽기 — 점수는 작을수록 가깝다

한 줄 요약

유사도 검색(similarity search) 은 질문 벡터와 가장 가까운 청크 k개를 돌려줍니다. Chroma가 함께 주는 점수는 유사도가 아니라 거리(distance) 여서 작을수록 가깝습니다. 그리고 검색은 관련이 있든 없든 항상 k개를 돌려줍니다.


1. 검색하는 코드

results = vectorstore.similarity_search_with_score(q, k=2)
for doc, score in results:
    print(score, doc.metadata.get("article"), doc.page_content)
부분 뜻
q 질문 문장. 안에서 embed_query로 벡터가 됩니다
k=2 가까운 순서로 몇 개를 가져올지
doc 찾은 청크. page_content(본문)와 metadata(출처)가 들어 있습니다
score 질문과 그 청크 사이의 거리

검색에는 LLM이 끼지 않습니다. 임베딩 모델이 질문을 벡터로 바꾸고, Chroma가 거리를 계산할 뿐입니다. 그래서 같은 질문에는 같은 결과가 나옵니다.


2. 유사도와 거리 — 방향이 반대다

가까움을 나타내는 숫자에는 두 종류가 있습니다.

종류 가까울수록 같은 문장이면
유사도(similarity) 커진다 1
거리(distance) 작아진다 0

Chroma의 similarity_search_with_score는 이름에 similarity가 들어 있지만 거리를 돌려줍니다. 점수를 읽기 전에 항상 어느 쪽인지부터 확인합니다.

Chroma가 기본으로 쓰는 거리는 제곱 L2 거리입니다. 두 벡터의 같은 자리 숫자끼리 뺀 값을 제곱해 모두 더한 것입니다. 우리 임베딩 모델의 벡터는 길이가 모두 1이어서, 이 거리와 코사인 유사도 사이에는 간단한 관계가 있습니다.

거리 = 2 − 2 × 코사인 유사도

「따라하기」에서 "교환 배송비 누가 내나요?"의 1위 청크는 거리가 0.464로 나옵니다. 같은 질문과 청크의 코사인 유사도를 따로 계산하면 0.768이고, 2 − 2 × 0.768 = 0.464로 맞아떨어집니다.

코사인 유사도 거리 느낌
1.0 0.0 같은 문장
0.77 0.46 이번 장에서 본 가장 가까운 축
0.62 0.77 정책과 상관없는 질문("오늘 날씨 어때요?")의 1위

3. 검색은 항상 k개를 돌려준다

"오늘 날씨 어때요?"를 검색하면 무엇이 나올까요? 아무것도 안 나오는 것이 아닙니다. 정책 청크 가운데 그나마 가까운 것이 거리 0.768로 나옵니다.

유사도 검색이 하는 일은 "가장 가까운 k개"를 고르는 것입니다. "충분히 가까운" 것만 고르는 일은 하지 않습니다.

검색 결과가 나왔다는 것은 "관련 있는 청크를 찾았다"는 뜻이 아닙니다. "12개 중에 이것들이 제일 가까웠다"는 뜻일 뿐입니다.

그래서 검색 결과를 받아 답을 쓰는 쪽에서 "이 발췌에 정말 답이 있는가"를 따로 판단해야 합니다. 그 일이 14장의 내용입니다.


4. k를 몇으로 할 것인가

k 좋은 점 나쁜 점
작게 (1~2) 프롬프트가 짧다. 비용이 적다 정답 청크가 2위, 3위에 있으면 놓친다
크게 (8~) 정답 청크를 놓칠 일이 줄어든다 상관없는 청크까지 프롬프트에 들어가 비용이 늘고 답을 흐린다

이번 장에서는 결과를 눈으로 보기 쉽게 k=2로 확인합니다. 14장에서 답변을 만들 때는 여유를 두어 k=4를 씁니다. 정해진 정답은 없고, 문서의 크기와 청크의 크기에 따라 실험해서 정하는 값입니다.


5. 결과를 읽을 때 조심할 것 — 꼬리표와 미리보기

「따라하기」의 검색 결과는 한 줄에 세 가지를 보여 줍니다.

(거리 0.464) [제8조 (배송 지연 보상), 제9조 (분쟁 처리), 자주 묻는 질문 (FAQ)] 서 제외된다. 제9조 (분쟁 처리) 반품·교환·환불에 관하여 ...
  • 꼬리표 [제8조 …, 제9조 …, 자주 묻는 질문 (FAQ)]는 12장에서 붙인 메타데이터입니다. 그 청크에 내용이 담긴 조항 제목이 모두 적혀 있습니다.
  • 청크 본문은 전체를 출력합니다.

청크 하나는 500자 안팎이고, 그 안에 조항이 두세 개 들어갑니다. 미리보기는 그중 맨 앞부분만 보여 줍니다. 그러니 무엇이 들어 있는 청크인지는 꼬리표로 읽고, 더 확인하고 싶으면 청크 전체를 열어 봅니다.


핵심 정리

  • similarity_search_with_score(질문, k=개수)는 가까운 청크 k개와 거리를 돌려줍니다.
  • 거리는 작을수록 가깝습니다. 유사도와 방향이 반대입니다.
  • Chroma의 기본 거리는 제곱 L2이고, 우리 모델에서는 2 − 2 × 코사인 유사도와 같습니다.
  • 검색은 관련이 없어도 항상 k개를 돌려줍니다. "가장 가까운 것"이지 "충분히 가까운 것"이 아닙니다.
  • 무엇이 든 청크인지는 꼬리표와 청크 전체로 판단합니다.
← 이전 절벡터 DB와 Chroma — 벡터를 저장하고 꺼내는 곳다음 절 →따라하기 — 청크를 벡터 DB에 넣고 검색하기
오명운 · macro@prag-ai.com