RAG 챗봇 만들기 완벽 실전: LangChain으로 내 문서에 답하는 AI 구축 6단계

RAG 챗봇을 LangChain과 무료 오픈소스 조합으로 직접 만드는 실전 가이드입니다. 파이프라인 원리부터 최소 코드 실습, 사내 문서 검색 봇 PoC 확장까지 — API 키 0개, 비용 0원 경로로 정리했어요.


RAG 챗봇, 사내 문서 수백 장을 아직도 Ctrl+F로 뒤지고 계신가요?

회의 5분 전, 작년 온보딩 문서 어딘가에 있던 정책 조항을 찾으려고 PDF 서른 장을 Ctrl+F로 뒤져본 적 있으실 거예요. ChatGPT에게 물어보면 그럴듯한데 틀린 답, 이른바 환각(Hallucination)이 돌아오죠. 이 문제를 정면으로 푸는 게 바로 RAG 챗봇입니다. 내 문서를 근거로 답하고, 출처까지 달아주는 방식이거든요.

이 글은 머신러닝 독학 완벽 로드맵 연재 7화예요. 스타 3.2k짜리 자료집의 LangChain 섹션(튜토리얼 8개 수록)을 기반으로, 실제로 Colab에서 돌아가는 최소 구성을 확인하며 정리했습니다. 이 글만 봐도 완결되도록 썼어요. 😊

⚡ 이 글의 핵심만 먼저 보기 (Key Takeaways)

  • RAG의 본질: LLM에게 ‘오픈북 시험’을 보게 하는 구조 — 내 문서에서 근거를 검색해 답하므로 환각이 크게 줄어듭니다
  • 파이프라인 6단계: 문서 로드 → 청킹 → 임베딩 → 벡터DB 저장 → 검색 → LLM 답변 생성
  • 비용 0원 조합: Hugging Face 오픈소스 임베딩 + 로컬 벡터DB Chroma + 로컬 LLM Ollama면 유료 API 키 없이 완주 가능
  • 품질의 8할: 모델이 아니라 청킹 크기(chunk_size)와 검색 개수(k) 튜닝이 답변 품질을 좌우합니다
  • 신뢰의 조건: 답변에 출처(source) 표기를 붙이고, 결과는 반드시 사람이 검수해야 실무에 쓸 수 있어요
  • 당장 할 것: PDF 1개로 질의응답 데모를 만들어보기 — 사내 문서 검색 봇 PoC는 하루면 충분합니다

📌 목차

  1. RAG가 뭐길래 환각을 줄일까
  2. RAG 챗봇 파이프라인 6단계 원리
  3. LangChain 핵심 구성요소 6가지
  4. 실습: 비용 0원으로 PDF 질의응답 챗봇 만들기
  5. 품질을 좌우하는 튜닝 포인트
  6. 사내 문서 검색 봇 PoC로 확장하기
  7. 이런 분들께 적극 추천합니다
  8. 자주 묻는 질문 (FAQ)

1. RAG가 뭐길래 환각을 줄일까

RAG(Retrieval-Augmented Generation, 검색 증강 생성)는 LLM이 답하기 전에 관련 문서를 먼저 검색해서, 그 내용을 근거로 답을 생성하게 하는 구조예요. LLM의 기억력에 의존하는 게 아니라 매번 근거 자료를 손에 쥐여주는 거죠.

① Retrieval-Augmented Generation — LLM에게 오픈북 시험 보게 하기

암기 시험은 기억이 왜곡되면 틀린 답이 나오지만, 오픈북 시험은 책에서 찾은 내용을 옮기면 됩니다. RAG가 정확히 이 구조예요. 질문과 관련된 문서 조각을 찾아 프롬프트에 넣어주면, LLM은 ‘아는 척’ 대신 주어진 근거 안에서만 답하게 됩니다. 여기서 핵심이 있어요. 환각이 완전히 사라지는 건 아니지만, 근거가 명시되니 검증 가능한 답변이 된다는 점이죠.

💡 실전 포인트:
RAG는 LLM을 다시 학습(파인튜닝)시키지 않아요. 문서가 바뀌면 벡터DB만 갱신하면 됩니다. 그래서 최신 정보 반영이 쉽고, 파인튜닝 대비 비용·유지보수가 훨씬 가벼워요. 실무에서 ‘우리 문서에 답하는 챗봇’을 만들 때 파인튜닝보다 RAG를 먼저 택하는 이유가 여기 있습니다.


2. RAG 챗봇 파이프라인 6단계 원리

RAG 챗봇은 결국 6단계 조립 라인입니다. 각 단계가 뭘 하는지만 잡히면 코드는 생각보다 짧아요.

단계 하는 일 도구 예시
1. 문서 로드 PDF·CSV 등을 텍스트로 읽기 PyPDFLoader, CSVLoader
2. 청킹 긴 문서를 검색 단위로 쪼개기 RecursiveCharacterTextSplitter
3. 임베딩 텍스트를 의미 벡터로 변환 Hugging Face 임베딩
4. 벡터DB 저장 벡터를 검색 가능하게 보관 Chroma, FAISS
5. 검색 질문과 유사한 조각 찾기 Retriever
6. 답변 생성 근거 + 질문으로 답 만들기 LLM + Chain

① Chunking — 품질의 절반을 결정하는 단계

청킹은 단순히 자르는 게 아니라 검색의 최소 단위를 설계하는 일이에요. 조각이 너무 크면 엉뚱한 내용까지 딸려오고, 너무 작으면 문맥이 끊깁니다. 그래서 보통 500~1,000자 단위에 overlap(겹침)을 100~200자 정도 줘서 문맥이 끊기지 않게 하죠. 이게 생각보다 중요한 이유가 있어요. 뒤에서 다룰 튜닝의 출발점이 바로 이 숫자거든요.

💡 실전 포인트:
청킹 전략은 문서 성격에 맞춰요. 조항·항목 경계가 뚜렷한 문서(규정·매뉴얼)는 그 경계를 살려 자르고, 문장이 이어지는 서술형 문서는 overlap을 넉넉히 줍니다. RecursiveCharacterTextSplitter는 문단 → 문장 → 단어 순으로 자연스러운 경계를 우선 시도하니, 처음엔 기본값(chunk_size 800 / overlap 150)으로 시작해도 무난해요.


3. LangChain 핵심 구성요소 6가지

LangChain은 위 6단계를 레고 블록처럼 조립하게 해주는 프레임워크예요. 이름만 알아두면 공식 문서가 훨씬 쉽게 읽힙니다.

  • Document Loader: PDF, CSV, 웹페이지 등 원본을 불러오는 입구
  • TextSplitter: 청킹 담당 — chunk_size와 overlap을 여기서 설정
  • Embeddings: 텍스트 → 벡터 변환기 (유료 API 또는 오픈소스)
  • VectorStore: 벡터 창고 — Chroma·FAISS는 로컬에서 무료
  • Retriever: 질문이 들어오면 관련 조각을 꺼내오는 검색기
  • Chain: 검색 결과 + 질문 + 프롬프트를 LLM까지 연결하는 조립 라인

① Retriever — 챗봇의 실력은 검색기가 정한다

많은 분들이 답변 품질이 아쉬우면 LLM을 더 좋은 모델로 바꾸려 해요. 그런데 실무에서 겪어보면 문제의 대부분은 검색 단계에서 엉뚱한 조각을 가져온 것이더라고요. Retriever가 좋은 근거를 못 찾으면 아무리 좋은 LLM도 좋은 답을 못 만듭니다. 쓰레기가 들어가면 쓰레기가 나오는 구조죠.

💡 실전 포인트:
답변이 이상할 때는 LLM을 의심하기 전에 retriever.invoke(질문)으로 검색된 조각부터 눈으로 확인하세요. 근거 조각이 엉뚱하면 답도 엉뚱합니다. 이때 처방은 모델 교체가 아니라 청킹 크기나 k값 조정이에요. 검색 단계를 먼저 고쳐야 답변이 따라옵니다.

RAG 챗봇 개발 관련 이미지

4. 실습: 비용 0원으로 PDF 질의응답 챗봇 만들기

유료 API 키 하나 없이도 됩니다. Hugging Face 오픈소스 임베딩 + 로컬 벡터DB Chroma + 로컬 LLM Ollama 조합이면 Colab 무료 티어나 내 노트북에서 전부 돌아가요. 먼저 필요한 패키지부터 설치합니다.

# 패키지 설치 (Colab / 로컬 공통)
pip install langchain langchain-community chromadb sentence-transformers pypdf
pip install langchain-huggingface langchain-chroma langchain-ollama

① 파이프라인 구축 — 로드부터 검색까지 (임베딩 무료)

여기까지는 API 키가 아예 필요 없어요. 임베딩은 오픈소스 다국어 모델(e5 계열)을 로컬에서 돌리고, 벡터DB도 로컬 Chroma를 씁니다. 아래 코드는 파이프라인 6단계 중 1~5단계(로드 → 청킹 → 임베딩 → 저장 → 검색)를 그대로 옮긴 최소 구성이에요.

from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma

# 1. 문서 로드
docs = PyPDFLoader("my_document.pdf").load()

# 2. 청킹
splitter = RecursiveCharacterTextSplitter(
    chunk_size=800, chunk_overlap=150)
chunks = splitter.split_documents(docs)

# 3. 임베딩 (무료 오픈소스, 한국어 지원)
emb = HuggingFaceEmbeddings(
    model_name="intfloat/multilingual-e5-small")

# 4. 벡터DB 저장 (로컬, persist로 재사용)
db = Chroma.from_documents(
    chunks, emb, persist_directory="./chroma_db")

# 5. 검색기 (top-k = 3)
retriever = db.as_retriever(search_kwargs={"k": 3})

# 검색 결과 확인 — 근거 조각과 출처(페이지)를 눈으로 검증
for d in retriever.invoke("환불 규정이 어떻게 되나요?"):
    print(d.metadata.get("page"), d.page_content[:80])

이 시점에서 이미 ‘검색 전용 봇’은 완성입니다. 질문을 넣으면 관련 문서 조각과 페이지 번호를 돌려주니까요. LLM을 붙이기 전에 이 단계에서 검색 품질부터 확인하는 습관을 들이면 튜닝이 훨씬 쉬워져요.

💡 실전 포인트:
persist_directory를 지정하면 벡터DB가 디스크에 저장돼요. Colab 세션이 끊기거나 노트북을 껐다 켜도, 다시 임베딩할 필요 없이 Chroma(persist_directory="./chroma_db", embedding_function=emb)로 바로 불러옵니다. 임베딩·저장·검색이 전부 로컬에서 도니 API 키가 없어도 여기까지는 완주할 수 있어요.

② Ollama로 답변 생성 — API 키 0개, 완전 무료 QA

마지막 6단계(답변 생성)까지 무료로 하고 싶다면 Ollama를 씁니다. ollama.com에서 설치한 뒤 터미널에서 모델을 한 번만 받아두면, 내 컴퓨터 안에서 LLM이 돌아가요. 문서가 밖으로 나가지 않으니 민감 자료에도 안전합니다.

# Ollama 설치 후 터미널에서 모델 받기 (최초 1회)
# ollama pull llama3.2

이제 검색된 근거만 프롬프트에 넣고, ‘근거 안에서만 답하라’고 지시한 뒤, 답변과 함께 출처 페이지를 표기하는 완결형 QA 함수예요.

from langchain_ollama import OllamaLLM
from langchain_core.prompts import ChatPromptTemplate

llm = OllamaLLM(model="llama3.2")  # 로컬 LLM, API 키 불필요

prompt = ChatPromptTemplate.from_template(
    "아래 근거만 사용해 한국어로 답하세요. "
    "근거에 없으면 '문서에서 찾을 수 없습니다'라고 답하세요.\n\n"
    "근거:\n{context}\n\n질문: {question}")

def ask(question):
    found = retriever.invoke(question)               # 검색
    context = "\n\n".join(d.page_content for d in found)
    answer = llm.invoke(
        prompt.format(context=context, question=question))  # 6. 답변 생성
    sources = [d.metadata.get("page") for d in found]
    return answer, sources

answer, sources = ask("환불 규정이 어떻게 되나요?")
print(answer)
print("출처 페이지:", sources)   # 답변에 출처 표기 → 검증 가능

20줄 남짓한 코드로 ‘내 PDF에 답하고 출처까지 다는 챗봇’이 완성됐어요. 유료 API를 붙이고 싶다면 OllamaLLM 자리에 상용 LLM 래퍼만 바꿔 끼우면 됩니다. 골격은 그대로예요.

💡 실전 포인트:
‘근거에 없으면 모른다고 답하라’는 한 줄이 환각을 크게 줄여줘요. 그리고 source_documents의 페이지·파일명을 답변에 함께 노출하세요. 출처가 붙는 순간 사용자가 원문을 직접 확인할 수 있어서, 챗봇 신뢰도가 완전히 달라집니다.


5. 품질을 좌우하는 튜닝 포인트

돌아가는 것과 잘 돌아가는 것은 다릅니다. RAG 챗봇 품질은 사실상 두 개의 다이얼과 한 가지 습관으로 결정돼요.

① chunk_size와 k — 두 개의 다이얼 돌리기

chunk_size(조각 크기)와 k(검색해오는 조각 개수)는 트레이드오프 관계예요. 조각이 작고 k가 크면 넓게 훑지만 노이즈가 늘고, 조각이 크고 k가 작으면 문맥은 좋지만 놓치는 게 생깁니다. 정답은 문서마다 다르니, 대표 질문 10개를 만들어놓고 설정을 바꿔가며 검색 결과를 비교하는 게 가장 빠른 길이에요. 그리고 한 가지 습관 — 답변에 출처(파일명·페이지)를 반드시 표기하세요. 출처가 붙는 순간 사용자가 스스로 검증할 수 있어서 신뢰도가 완전히 달라집니다.

💡 실전 포인트:
튜닝은 감이 아니라 측정으로 해요. 대표 질문 10개를 고정해두고, chunk_size(예: 1,500 → 800)와 k(예: 2 → 4)를 바꿔가며 ‘정답이 있는 페이지가 검색 결과에 포함됐는가’를 세어보세요. 이 검색 히트율이 답변 품질의 선행 지표라, 모델을 건드리지 않고도 체감 품질을 끌어올릴 수 있습니다.


6. 사내 문서 검색 봇 PoC로 확장하기

PDF 1개로 데모가 됐다면, 사내 문서 검색 봇 PoC까지는 거리가 짧습니다. 폴더 단위 로더로 문서 수를 늘리고, 벡터DB를 저장형으로 바꾸고, 간단한 웹 UI(Streamlit 등)만 얹으면 돼요. 폴더 전체를 한 번에 넣는 것도 어렵지 않습니다.

from langchain_community.document_loaders import PyPDFDirectoryLoader

# 폴더 안의 PDF 전부 로드 → 같은 파이프라인에 태우기
docs = PyPDFDirectoryLoader("./company_docs/").load()
chunks = splitter.split_documents(docs)
db = Chroma.from_documents(
    chunks, emb, persist_directory="./chroma_db")

1) PoC — 하루 만에 데모, 단 ‘사람 검수’는 필수

로드맵 자료집에도 ‘사내 문서 검색 챗봇 PoC를 맡은 개발자라면 LangChain의 PDF 질의응답 튜토리얼로 하루 만에 데모가 가능하다’는 케이스가 나오는데, 실제로 해보면 과장이 아니에요. 다만 PoC의 목적은 완벽한 챗봇이 아니라 우리 문서에서 이게 되는구나 보여주는 것입니다. 결과는 반드시 사람이 검수하는 프로세스를 붙이고, 민감 문서는 로컬 벡터DB로 사내망 안에서 처리하는 게 안전해요.

💡 실전 포인트:
PoC는 완성도가 아니라 ‘우리 문서에서 된다’를 보여주는 게 목적이에요. 그리고 민감 문서라면 임베딩과 LLM을 모두 로컬(오픈소스 임베딩 + Ollama)로 돌리세요. 데이터가 사내망 밖으로 나가지 않아 보안 검토를 통과하기 훨씬 쉽습니다. 반대로 외부 API를 쓰면 이 지점이 도입의 걸림돌이 되곤 해요.


7. 이런 분들께 적극 추천합니다

  • 사내 문서·매뉴얼 검색에 지쳐 문서 질의응답 챗봇을 직접 만들어보고 싶은 개발자
  • LLM 서비스 기획을 맡았는데 RAG가 어떻게 동작하는지 감을 잡아야 하는 기획자·PM
  • 유료 API 비용 부담 없이 Colab에서 LLM 실습을 완주하고 싶은 학생·취준생
  • ChatGPT 환각 때문에 업무 적용을 망설였던 실무자 (출처 표기형 챗봇이 해답이 될 수 있어요)
  • 머신러닝 독학 로드맵을 따라오다가 ‘이제 뭔가 만들어보고 싶은’ 단계에 도달한 학습자
  • 포트폴리오에 ‘돌아가는 LLM 프로젝트’ 한 줄이 필요한 이직 준비자

8. 자주 묻는 질문 (FAQ)

Q. 파이썬 기초만 아는데 RAG 챗봇을 만들 수 있나요?

A. 처음부터 전부 이해하려면 어렵지만, 만드는 것 자체는 가능합니다. 위 실습 코드는 20줄 남짓이고, 각 줄이 파이프라인 6단계 중 하나에 대응돼요. 먼저 돌려보고 → 청킹 숫자를 바꿔보고 → 검색 결과를 관찰하는 순서로 접근하면 개념이 자연스럽게 따라옵니다.

Q. 정말 API 키 하나 없이 무료로 돌릴 수 있나요?

A. 네. 임베딩은 Hugging Face 오픈소스 모델(multilingual-e5)을 로컬에서 돌리고, 벡터DB는 로컬 Chroma, 답변 생성은 Ollama로 받은 로컬 LLM(llama3.2 등)을 쓰면 유료 API 키가 전혀 필요 없습니다. Colab 무료 티어나 개인 노트북만 있으면 전 과정을 완주할 수 있어요.

Q. Chroma와 FAISS 중 뭘 써야 하나요?

A. 입문·PoC 단계에서는 큰 차이가 없으니 문서화가 친절한 Chroma로 시작하는 걸 권해요. 문서가 수십만 건 이상으로 커지거나 검색 속도가 병목이 되면 그때 FAISS나 관리형 벡터DB를 검토해도 늦지 않습니다.

Q. RAG를 쓰면 환각이 완전히 사라지나요?

A. 완전히 사라지지는 않습니다. 검색이 엉뚱한 조각을 가져오면 그 근거로 그럴듯한 오답을 만들 수 있어요. 다만 ‘근거에 없으면 모른다고 답하라’는 프롬프트와 출처 표기를 붙이면 사용자가 원문을 바로 확인할 수 있고, 청킹·k값 튜닝과 사람 검수를 더하면 실무에서 감당 가능한 수준까지 줄일 수 있습니다.


✍️ 글을 마치며

RAG 챗봇은 ‘LLM에게 오픈북 시험을 보게 하는 구조’라는 한 문장으로 요약됩니다. 그리고 품질은 모델이 아니라 청킹과 검색 튜닝, 출처 표기라는 지루해 보이는 디테일이 결정하더라고요.

저는 자주 찾아보는 PDF 3개를 Chroma에 넣고 검색 전용 모드부터 만들어볼 것 같아요. LLM 없이도 검색 품질을 먼저 확인할 수 있어서, 튜닝 감각을 잡기에 가장 좋은 출발점이거든요. 🙌

여러분은 어떤 문서를 가장 먼저 챗봇에 넣어보고 싶으신가요? 댓글로 자유롭게 의견 남겨주세요! 😊

댓글 남기기