본문 바로가기
Q&A해결2026년 7월 26일1분 읽기

pgvector로 코사인 유사도 검색하는데 관련 없는 청크가 자꾸 상위로 올라옵니다

r
rag_hyerin
조회 790댓글 1

사내 문서 RAG를 pgvector로 붙이고 있습니다. 임베딩은 text-embedding-3-small로 뽑고, 문서를 1000자 단위로 잘라서 넣었고, 검색은 코사인 유사도 top-5로 가져옵니다. 그런데 질문이랑 명백히 관련 있는 문단을 놔두고, 별로 상관없는 청크가 상위에 올라오는 일이 잦아요.

쿼리는 이렇게 날리고 있어요.

SELECT content, embedding <=> $1 AS dist
FROM docs
ORDER BY dist
LIMIT 5;

청크 자체를 눈으로 보면 정답이 담긴 문단이 분명히 테이블에 있는데, 검색 결과에는 안 잡히거나 3~4등으로 밀려요. 임베딩 모델 문제인가 싶기도 하고, 자르는 방식 문제인가 싶기도 한데 어디부터 손대야 할지 모르겠습니다. 인덱스는 만들긴 했는데 이게 정확도에도 영향을 주나요?

댓글 1

김김영삼3개월 전
원인이 한 군데가 아니라 몇 개가 겹쳐 있을 가능성이 높아요. 하나씩 봅시다.

1) 청킹부터가 제일 큰 원인일 겁니다. 1000자 고정 커팅은 문장이나 문단 중간을 뚝 자르기 때문에, 정답이 두 청크에 반씩 걸쳐 있으면 어느 쪽도 온전한 의미를 못 담아요. 임베딩이 흐려집니다. 문단이나 헤딩 기준으로 자르고 청크 사이에 100~200자 정도 오버랩을 주세요. 그거 하나만 바꿔도 체감이 큽니다.

2) 연산자 확인하세요. pgvector에서 <=> 는 코사인 거리 맞는데, 임베딩을 저장할 때 정규화가 안 돼 있으면 의도한 유사도랑 어긋날 수 있어요. text-embedding-3 계열은 정규화돼 나오는 편이지만, 직접 전처리를 넣었다면 쿼리 벡터랑 저장 벡터가 같은 방식으로 처리됐는지 꼭 맞추세요. 쿼리 임베딩도 문서랑 똑같은 모델로 뽑아야 하고요.

3) 인덱스는 속도용이라 정확도를 오히려 떨어뜨릴 수 있습니다. ivfflat이면 lists랑 probes 값에 따라 근사 검색이라 진짜 최근접을 놓쳐요. 데이터가 크지 않으면 인덱스 빼고 풀스캔으로 정확도부터 확인해 보세요. hnsw면 ef_search를 올리고요.

4) 그래도 순수 벡터 검색만으론 한계가 있어요. 고유명사나 코드, 숫자가 많은 문서는 벡터가 약합니다. Postgres 풀텍스트 검색(tsvector)이랑 하이브리드로 섞고, 최종 상위 후보를 리랭커로 다시 정렬하면 상위권 품질이 확 올라갑니다. 여기까지 가면 대부분 잡혀요.
Ctrl+Enter로 등록