AI 애플리케이션, 훈련이 아닌 사용자 데이터로 답변하는 방법

발행: (2026년 6월 6일 PM 03:26 GMT+9)
12 분 소요
원문: Dev.to

Source: Dev.to

왜 **Retrieval‑Augmented Generation(검색 보강 생성, RAG)**이 유용한 AI를 만들기 위한 기본 패턴이 되었는지—그리고 실제로 어떻게 동작하는지.

대형 언어 모델(LLM)은 인상적이다. 글을 쓰고, 추론하고, 요약하고, 방대한 주제에 대해 설명할 수 있다. 하지만 한계가 있다: 모델이 학습한 시점 이후의 지식은 알 수 없다는 점이다. 그 날짜 이후에 일어난 일, 회사 고유의 내용, 코드베이스 혹은 문서 등은 모델이 전혀 모른다.

가장 단순한 해결책은 데이터를 바로 프롬프트에 붙여넣는 것이다. 짧은 내용이라면 통한다. 하지만 프롬프트에는 길이 제한이 있다. 모델이 한 번에 처리할 수 있는 텍스트 양은 한정돼 있고, 그 한도 안에서도 너무 많은 컨텍스트를 넣으면 품질이 떨어진다. 모델은 중간에 끼어 있는 정보를 놓치고, 비슷한 구절을 혼동하며, 읽어야 할 때 추측을 시작한다.

RAG—Retrieval‑Augmented Generation은 이 문제를 제대로 해결한다. 모든 정보를 모델에 보내고 운에 맡기는 대신, 질문에 실제로 필요한 부분만을 모델에 전달한다.

RAG가 바로 이해되는 비유: 오픈북 시험을 보는 학생을 떠올려라. 학생은 교과서를 전부 외우지 않는다. 질문을 보면 해당 장을 찾아 관련 부분을 읽고, 방금 읽은 내용으로 답을 적는다. 추측이 아니라, 원본 자료에 근거한 답이다.

RAG도 바로 이와 같다. 사용자가 질문을 하면 시스템이 데이터 중 가장 관련성 높은 조각들을 찾아서 그 조각들을 LLM에 컨텍스트로 제공하고, 모델은 그 컨텍스트만을 근거로 답한다. 결과는 정확하고, 근거가 명확하며, “어디서 나온 답인지”를 바로 가리킬 수 있다.

전체 흐름은 두 단계로 나뉜다: Ingestion(수집) 단계와 Retrieval(검색) 단계.

Ingestion – 사전 준비 단계

사용자가 질문을 하기 전에 데이터를 미리 처리하고, 나중에 빠르고 정확하게 검색할 수 있도록 저장한다.

  1. Chunking(청크 나누기) – 문서를 작은 조각으로 쪼갠다. 이것이 파이프라인 전체에서 가장 중요한 결정이다. 청크의 품질이 이후 모든 단계의 품질을 좌우한다.

    • 나쁜 방법: 고정 문자 수(예: 1,000자)마다 청크를 만든다. 문장은 청크 경계에서 끊기고 의미가 손실된다. 정의가 두 청크에 걸쳐 있으면 어느 쪽에서도 찾기 힘들다.
    • 좋은 방법: 문단 구분, 섹션 헤더, 주제 전환 등 자연스러운 경계에서 나누고, 인접 청크 사이에 약간의 겹침을 둔다. 일반적으로 150~200자를 겹치게 하면 경계에 있던 문장이 두 청크에 모두 포함돼 정보가 빠지는 일을 방지한다.
  2. Embedding(임베딩) 생성 – 각 청크를 벡터 임베딩으로 변환한다. 여기서 RAG의 진정한 힘이 발휘된다.

    • 임베딩은 텍스트를 수백·수천 개의 숫자 리스트로 표현한 것이다. 이 숫자는 임의가 아니라, 의미가 비슷한 텍스트가 수치 공간에서 가깝게 배치되도록 학습된 모델이 만든다.
    • 예시: “구독을 취소하려면 어떻게 해야 하나요?”와 “계정을 해지하는 절차는?”은 거의 같은 의미이므로 임베딩이 서로 가깝게 나온다. 반면 배송 물류에 관한 청크는 멀리 떨어진다.
  3. Vector Database(벡터 데이터베이스) 저장 – 임베딩을 저장하고, 대규모 유사도 검색을 빠르게 수행할 수 있게 한다. 쿼리 벡터를 넣으면 수백만 개의 엔트리 중 가장 유사한 벡터를 밀리초 단위로 찾아준다.

    • 대표적인 서비스: Pinecone, Weaviate, Qdrant, 그리고 PostgreSQL을 이미 쓰는 팀이라면 pgvector. 선택은 규모와 인프라 선호도에 따라 달라지지만, 모두 고차원 벡터 공간에서 nearest‑neighbor(최근접 이웃) 검색을 지원한다.
    • 실무 팁: 반드시 데이터 소스별로 필터링한다. 멀티테넌트 환경에서는 특정 사용자의 문서만 검색하도록 메타데이터 필터링을 활용한다. 벡터 DB는 유사도 검색과 메타데이터 필터링을 한 번에 처리할 수 있다.

Retrieval – 질의 시점 단계

사용자가 질문을 제출하면 다음 세 단계가 진행된다.

  1. 질문 임베딩 – Ingestion 때와 동일한 모델을 사용해 질문을 벡터로 변환한다. 이 벡터는 질문의 의미를 담는다.
  2. 유사 청크 찾기 – 벡터 DB가 코사인 유사도 등을 이용해 가장 유사한 청크를 상위 N개(보통 5개) 반환한다.
  3. 컨텍스트 구성 및 LLM 호출 – 찾은 청크들을 하나의 컨텍스트 블록으로 합쳐 원 질문과 함께 LLM에 전달한다. 프롬프트에는 “제공된 컨텍스트에만 근거해 답변하라”는 명령을 명시한다. 답변이 컨텍스트에 없으면 모델은 “해당 정보가 없습니다”라고 말하도록 한다.

왜 이 마지막 지시가 중요한가?
모델은 모르는 내용에 대해 자신감 있게 꾸며내는 경향이 있다(‘hallucination’). 컨텍스트에만 답하도록 강제하면 이러한 현상이 크게 줄어든다. 모델은 구체적인 자료를 바탕으로 답하고, 우리는 모델이 그 자료를 벗어나지 않도록 제어한다.

답변이 없을 때 처리 방법

벡터 유사도 점수는 0~1 사이이며 1에 가까울수록 동일함을 의미한다. 관련 내용이 전혀 없더라도 검색 결과는 나오지만 점수가 낮다. 낮은 점수의 청크를 그대로 LLM에 넘기면 모델이 억지로 설득력 있는 답을 만들어낼 수 있다.

해결책: 최소 유사도 임계값을 설정한다. 예를 들어 최고 점수가 0.7 미만이면 LLM 호출을 건너뛰고 “해당 정보는 데이터에 없습니다”라고 반환한다. 사용자는 자신감 넘치는 오답보다 솔직한 부재를 더 신뢰한다. “모르는 것을 아는” 시스템은 제한이 아니라 기능이다.

질문 표현과 문서 표현의 불일치 문제

사용자가 “계약을 어떻게 빠져나갈 수 있나요?”라고 물으면 실제 문서에는 “계약 종료(Termination of Agreement)”라는 섹션이 있을 수 있다. 의미는 연결돼 있지만 표현이 달라 검색이 놓칠 수 있다.

HyDE(Hypothetical Document Embeddings) 기법이 여기서 유용하다.

  1. 사용자 질문을 LLM에 넘겨 가상의 문서 형태 답변을 생성한다(예: “계약 종료 절차는 …”).
  2. 그 가상의 답변을 임베딩한다.
  3. 가상의 답변은 원본 문서와 어휘가 비슷하기 때문에 벡터 검색이 올바른 청크를 더 잘 찾아준다.

이 과정은 LLM 호출을 한 번 더 추가하는 것이지만, 비용과 시간은 매우 적으며, 특히 공식적·기술적·법률적 내용에서 검색 품질을 크게 끌어올린다.

왜 RAG가 표준이 되었는가

  • 프라이빗·전문·빈번히 업데이트되는 정보를 다루는 모든 AI 애플리케이션에 적합하다.
  • Fine‑tuning은 비용이 많이 들고, 속도가 느리며, 여전히 hallucination이 발생한다. 데이터가 바뀔 때마다 다시 학습해야 한다.
  • RAG는 데이터가 바뀔 때마다 벡터 스토어만 업데이트하면 된다. 모델은 재학습 없이 최신 정보를 바로 사용할 수 있다.

이와 같이 RAG는 데이터를 미리 준비(ingest)하고, 질문이 들어올 때마다 가장 관련성 높은 조각을 찾아(context) LLM에 전달하는 흐름으로, 정확하고 검증 가능한 AI 서비스를 구현한다.

0 조회
Back to Blog

관련 글

더 보기 »

모바일 한여름 열풍

!Cover image for Mobile Midsommer Madnesshttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploa...