LangChain 챗봇6장 · 문서 기반 챗봇3 / 21← 이전목차다음 →MetaContents

6장. 문서 기반 챗봇

RAG 란 무엇인가

시험 문제를 받았는데 책을 덮고 풀어야 하면, 기억나는 대로 쓰다가 그럴듯하게 지어내기도 합니다. 책을 펴 놓고 보는 오픈북 시험이면 다릅니다. 문제에 맞는 쪽을 찾아 펴고, 거기 적힌 대로 답을 씁니다. 답 옆에 "교과서 52쪽"이라고 적어 둘 수도 있습니다. RAG 는 모델에게 오픈북 시험을 보게 하는 방법입니다.

책을 덮고 기억으로 쓰는 시험과 책에서 찾아 펴고 쓰는 오픈북 시험을 나란히 놓은 비교 그림

왼쪽 파랑 상자는 모델이 배운 것만으로 답하는 방식이고, 오른쪽 보라 상자는 질문에 맞는 문서 조각을 찾아 함께 건네는 방식입니다. 여기서 책이 우리 회사의 문서(여행 약관), 쪽을 찾아 펴는 일이 검색, 펴 놓은 쪽을 보며 답을 쓰는 일이 생성입니다. 비유와 다른 점은, 학생은 펴 놓은 쪽이 엉뚱하면 알아채고 다시 찾지만, 모델은 우리가 건넨 조각만 보고 답한다는 것입니다. 그래서 RAG 의 답은 검색이 얼마나 맞는 조각을 찾았는지에 크게 기댑니다.

모델만으로 답하기와 RAG 견주기

견줄 것모델만으로 답하기RAG
답의 바탕모델이 배운 글우리가 건넨 문서 조각
우리 회사 규정모른다(배운 적이 없다)문서에 있으면 안다
규정이 바뀌면모델을 다시 가르쳐야 한다문서만 바꿔 다시 색인한다
근거 보여 주기어렵다찾은 조각의 쪽과 조항을 보여 준다
지어낼 위험크다(1장의 환각)줄어든다. 검색이 빗나가면 여전히 있다
더 드는 것없음색인 만들기, 검색 한 번, 프롬프트가 길어진다

짧은 예시

모델은 부르지 않고, 프롬프트에 약관 조각을 넣었을 때와 넣지 않았을 때 모델이 받을 메시지를 견줍니다. 조각은 PDF 에서 "반려동물"이라는 낱말로 찾았습니다. 이 장의 약관은 연습용으로 지어낸 가상 문서입니다.

Python
from langchain_community.document_loaders import PyPDFLoader
from langchain_core.prompts import ChatPromptTemplate

question = "반려동물을 데려가도 되나요?"

# PDF 를 쪽마다 읽고, "반려동물"이 든 줄과 그다음 줄을 근거로 꺼낸다
pages = PyPDFLoader("travel_terms.pdf").load()
lines = [ln for p in pages for ln in p.page_content.split("\n")]
at = next(i for i, ln in enumerate(lines) if ln.startswith("제12조"))
context = " ".join(lines[at: at + 3])

closed = ChatPromptTemplate.from_messages([("human", "{question}")])
openbook = ChatPromptTemplate.from_messages([
    ("system", "아래 약관만 보고 답하라. 약관에 없으면 모른다고 답하라.\n\n[약관]\n{context}"),
    ("human", "{question}"),
])

for name, prompt in [("책을 덮고", closed), ("오픈북", openbook)]:
    msgs = prompt.invoke({"question": question, "context": context}).to_messages()
    print(f"[{name}] 메시지 {len(msgs)}개")
    for m in msgs:
        print(" ", m.type, "|", m.content)
출력
[책을 덮고] 메시지 1개
  human | 반려동물을 데려가도 되나요?
[오픈북] 메시지 2개
  system | 아래 약관만 보고 답하라. 약관에 없으면 모른다고 답하라.

[약관]
제12조 반려동물 반려동물은 '함께 여행' 메뉴의 동반 상품에서만 데려갈 수 있다. 몸무게 7kg 이하의 개와 고양이만 되며, 이동장에 넣어야 한다.
  human | 반려동물을 데려가도 되나요?

책을 덮은 쪽은 질문 하나만 갑니다. 모델은 구름다리여행의 규정을 배운 적이 없으니 일반적인 이야기를 하거나 지어냅니다. 오픈북 쪽은 시스템 메시지 안에 제12조가 함께 갑니다. 모델은 "7kg 이하의 개와 고양이, '함께 여행' 메뉴"라는 근거를 보고 답할 수 있습니다. 이 장의 나머지는 이 근거를 낱말 찾기 대신 검색으로 알맞게 골라 오는 법입니다.

코드가 의미하는 것

이 코드는 같은 학생에게 책을 덮고 보는 시험지와 오픈북 시험지를 차례로 내미는 장면입니다. 책에서 쪽을 찾아 펴고(PDF 읽기와 근거 꺼내기), 시험지 두 장을 만들고(프롬프트 두 개), 각 시험지가 모델에게 어떤 메시지로 가는지 펼쳐 봅니다.

코드하는 일챗봇에서 뜻하는 것
PyPDFLoader("travel_terms.pdf").load()PDF 를 쪽마다 읽는다챗봇이 기댈 책을 손에 드는 일입니다. 모델이 배운 적 없는 회사 문서가 여기서 들어옵니다
ln.startswith("제12조") 와 lines[at: at + 3]"제12조"로 시작하는 줄부터 세 줄을 근거로 꺼낸다사람이 쪽을 알고 직접 편 것입니다. RAG 에서는 이 자리를 검색기가 맡습니다
{context} 가 든 시스템 메시지근거를 넣을 빈칸을 시스템 지시 안에 둔다오픈북 시험지의 "아래 약관만 보고 답하라"입니다. 근거와 "모르면 모른다"는 규칙이 함께 갑니다
prompt.invoke({...}).to_messages()빈칸을 채워 실제로 보낼 메시지 목록을 만든다모델을 부르지 않고도 모델이 받을 글을 미리 볼 수 있습니다. RAG 를 점검할 때 가장 먼저 보는 곳입니다

결과에서 읽을 것은 두 가지입니다.

  • 메시지 수가 1개와 2개로 갈립니다. 책을 덮은 쪽은 질문만 가고, 오픈북 쪽은 제12조가 든 시스템 메시지가 하나 더 갑니다. RAG 가 모델에 더하는 것은 이 메시지 한 칸입니다.
  • 모델은 그대로이고 프롬프트만 길어졌습니다. 두 쪽 모두 같은 질문 "반려동물을 데려가도 되나요?"를 보냅니다. 답이 달라질 바탕은 오직 함께 보낸 "7kg 이하의 개와 고양이" 같은 글입니다.

주의할 점

  • RAG 는 모델을 다시 가르치는 것이 아닙니다. 요청마다 문서 조각을 프롬프트에 끼워 보낼 뿐이라, 모델 자체는 그대로입니다.
  • 위 예시는 "제12조"라는 줄을 사람이 알고 골랐습니다. 손님은 "강아지"라고 묻지 "제12조"라고 묻지 않습니다. 질문의 뜻으로 알맞은 조각을 찾는 것이 RAG 의 어려운 부분입니다.
← 이전 절6장 · 용어 짚고 가기다음 절 →6장 · RAG 파이프라인의 두 단계