RAG2026-5일15차시 · 기본 RAG 앱 만들기5 / 19← 이전목차다음 →MetaContents

15차시. 기본 RAG 앱 만들기

2. 목표 구조 — 4개 모듈

출처: 원본 PDF 15차시_기본RAG앱만들기.pdf 5쪽 · 쪽 그림 5쪽

역할별로 딱 네 개면 충분합니다.

출력
rag_app/
├── config.py

⚙️ 모든 설정값

출력
├── indexer.py

🗂️ 문서 → 인덱스 (준비 단계)

출력
├── rag.py

🧠 검색 + 생성 (핵심 로직)

출력
├── app.py

💬 사용자 인터페이스

출력
│
├── prompts.py

📝 프롬프트 보관

출력
├── data/

📁 원본 문서

출력
└── faiss_index/

💾 저장된 인덱스

파일책임바뀌는 이유
config.py설정값만 보관튜닝할 때
indexer.py문서 로딩·분할·인덱싱문서 형식이 바뀔 때
rag.py검색·생성 로직알고리즘이 바뀔 때
app.py입력받고 출력하기화면이 바뀔 때

💡 좋은 분리의 기준
"이 파일은 언제 바뀌는가?"
바뀌는 이유가 다르면 다른 파일이어야 합니다.
· 튜닝하려고 → config만 열면 됩니다
· 화면을 바꾸려고 → app만 열면 됩니다
· 검색을 개선하려고 → rag만 열면 됩니다
한 파일을 고치는데 다른 파일도 같이 고쳐야 한다면
분리가 잘못된 것입니다.

실습 코드 · rag_app/prompts.py

실습 코드: 실습/src/rag_app/prompts.py · 위의 원본 PDF 15차시 5쪽 「2️⃣ 목표 구조 — 4개 모듈」과 이어집니다.

Python
# ==============================================================
# 15차시. PPT 15차시_기본RAG앱만들기. 코드 폴더는 src/rag_app
# PPT: 15차시 문서 질의응답
# 역할: Generator에 넣을 프롬프트 세 장. {context}와 {question} 칸을 가진 문자열 틀입니다.
# 읽는 키: 없음
# 쓰는 키: 없음. PROMPTS 딕셔너리에 v1, v2, v3
# 그래프:
#   검색된 문서 문자열(context) + 질문(question)
#     |
#     v
#   PROMPTS[PROMPT_VER] --> LLM
# --------------------------------------------------------------
# v1은 자료와 질문만 있는 짧은 틀입니다.
# v2는 자료 안에 있는 내용만 답하고, 없으면 '자료에서 확인할 수 없습니다'라고 하며, 문장 끝에 [1]을 달라는 규칙이 있습니다.
# v3는 질문의 일부만 자료에 있으면 그 부분만 답하라는 문장이 추가된 틀입니다.
# rag.py의 체인은 이 틀 | LLM | 문자열 변환 순서입니다.
# ==============================================================

# ChatPromptTemplate는 {context}, {question} 칸이 있는 문자열을 프롬프트 틀로 만듭니다.
from langchain_core.prompts import ChatPromptTemplate

# ── V1: 최소 버전 (비교 대조군) ──
# 자료와 질문만 넣는 가장 짧은 틀입니다. 다른 버전과 비교하는 기준으로 둡니다.
RAG_PROMPT_V1 = ChatPromptTemplate.from_template(     
    "아래 자료를 참고해서 질문에 답해주세요.\n\n"     
    "[자료]\n{context}\n\n"
    "[질문] {question}"
)
# ── V2: 규칙 강화 버전 (권장) ──
# 자료 밖 내용 금지, 없으면 '확인할 수 없습니다', 근거 번호 달기 규칙이 들어 있습니다.
RAG_PROMPT_V2 = ChatPromptTemplate.from_template(     
    "당신은 사내 문서를 안내하는 담당자입니다.\n\n"
    "[규칙]\n"
    "1. 아래 [자료]에 있는 내용만 근거로 답하십시오.\n"     
    "2. 자료에 없는 내용은 '자료에서 확인할 수 없습니다'라고 "     
    "명시하십시오.\n"
    "3. 추측하거나 일반 상식으로 보충하지 마십시오.\n"     
    "4. 각 문장 끝에 근거 번호를 [1] 형식으로 표기하십시오.\n"     
    "5. 3~5문장으로 간결하게 답하십시오.\n\n"     
    "[자료]\n{context}\n\n"
    "[질문]\n{question}"
)
# ── V3: 부분 답변 허용 버전 (과잉 거부 방지) ──
# V2에서 규칙 2번만 바꿔, 일부만 자료에 있으면 그 부분은 답하게 합니다.
RAG_PROMPT_V3 = ChatPromptTemplate.from_template(     
    "당신은 사내 문서를 안내하는 담당자입니다.\n\n"
    "[규칙]\n"
    "1. 아래 [자료]에 있는 내용만 근거로 답하십시오.\n"     
    "2. 질문의 일부만 자료에 있다면, 있는 부분은 답하고 "     
    "없는 부분만 '자료에서 확인할 수 없습니다'라고 하십시오.\n"     
    "3. 추측하거나 일반 상식으로 보충하지 마십시오.\n"     
    "4. 각 문장 끝에 근거 번호를 [1] 형식으로 표기하십시오.\n"     
    "5. 3~5문장으로 간결하게 답하십시오.\n\n"     
    "[자료]\n{context}\n\n"
    "[질문]\n{question}"
)

# rag.py가 PROMPTS[config.PROMPT_VER]로 틀을 고릅니다. 버전을 바꿀 때는 config.py만 고칩니다.
PROMPTS = {"v1": RAG_PROMPT_V1,            
           "v2": RAG_PROMPT_V2,            
           "v3": RAG_PROMPT_V3}

실행 결과 샘플 (교안 기록. API 키가 필요한 코드는 키 없이 맞춘 예시이고, 모델의 답은 실행할 때마다 달라집니다)

출력
===== 실행 결과 샘플 =====
직접 실행 시 출력 없음
직접 실행해도 출력이 없습니다. 틀 문자열만 정의합니다.

코드 해설

Generator에 넣을 프롬프트 세 장. {context}와 {question} 칸을 가진 문자열 틀입니다.

코드 앞에서 고정해 두는 말입니다.

  • 읽는 키: 없음
  • 쓰는 키: 없음. PROMPTS 딕셔너리에 v1, v2, v3
  • 그래프:
  • 검색된 문서 문자열(context) + 질문(question)
  • |
  • v
  • PROMPTS[PROMPT_VER] --> LLM
  • v1은 자료와 질문만 있는 짧은 틀입니다.

함수로 나누지 않고 위에서 아래로 실행됩니다.

  • RAG_PROMPT_V1 = ChatPromptTemplate.from_template( — ── V1: 최소 버전 (비교 대조군) ──
  • RAG_PROMPT_V2 = ChatPromptTemplate.from_template( — ── V2: 규칙 강화 버전 (권장) ──
  • RAG_PROMPT_V3 = ChatPromptTemplate.from_template( — ── V3: 부분 답변 허용 버전 (과잉 거부 방지) ──

파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.

← 이전 절15차시 · 1. 지금 코드의 문제다음 절 →15차시 · 3. 실습 ① — config.py