RAG2026-5일10차시 · 벡터저장소 이해11 / 19← 이전목차다음 →MetaContents

10차시. 벡터저장소 이해

8. 실습 ⑤ — 8차시 코드 개선하기

출처: 원본 PDF 10차시_벡터저장소이해.pdf 17~18쪽 · 쪽 그림 17쪽 18쪽

이제 8차시의 RAG를 오늘 배운 것으로 개선합니다. 두 번째 실행부터 즉시 시작됩니다.

📝 src/rag_v2.py

출력
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from indexer import get_store          # 오늘 만든 함수
load_dotenv()
store = get_store()                    # 있으면 로드, 없으면 생성
llm   = ChatOpenAI(model="gpt-4o-mini", temperature=0)
MIN_SCORE = 0.47                       # 9차시에서 정한 임계값

def build_context(docs):
    parts = []
    for i, d in enumerate(docs, 1):
        parts.append(f"[{i}] ({d.metadata['filename']} "
                     f"p.{d.metadata['page_no']})\n{d.page_content}")
    return "\n\n".join(parts)

def ask(question, k=3):
    # 점수와 함께 검색해서 기준 미달은 걸러낸다
    pairs = store.similarity_search_with_relevance_scores(question, k=k)

    # 기준(MIN_SCORE)을 넘는 것만 하나씩 골라 담기
    good = []
    for d, s in pairs:
        if s >= MIN_SCORE:
            good.append((d, s))

    if not good:
        print("Q:", question)
        print("A: 관련 자료를 찾지 못했습니다.")
        print(f"   (최고 점수 {pairs[0][1]:.3f} < 기준 {MIN_SCORE})")
        print("-" * 55)
        return

    docs = []
    for d, s in good:
        docs.append(d)

    prompt = (
        "아래 자료만 근거로 답하세요.\n"
        "자료에 없는 내용은 '자료에서 확인할 수 없습니다'라고 답하세요.\n\n"
        f"[자료]\n{build_context(docs)}\n\n[질문] {question}"
    )
    print("Q:", question)
    print("A:", llm.invoke(prompt).content)
    print("\n※ 근거:")
    for d, s in good:
        print(f"   · {d.metadata['filename']} "
              f"p.{d.metadata['page_no']} (관련도 {s:.3f})")
    print("-" * 55)
if __name__ == "__main__":
    ask("환불은 며칠 이내에 신청해야 하나요?")
    ask("우리 회사 대표이사가 누구인가요?")

실행 결과
─────────────────────────────────────────────
→ 저장된 인덱스를 불러옵니다 (비용 0)

Q: 환불은 며칠 이내에 신청해야 하나요?
A: 상품 수령 후 7일 이내에 환불을 신청하실 수 있습니다.

   근거:
   · manual.pdf p.2 (관련도 0.812)
   · manual.pdf p.2 (관련도 0.744)
─────────────────────────────────────────────

Q: 우리 회사 대표이사가 누구인가요?
A: 관련 자료를 찾지 못했습니다.
   (최고 점수 0.284 < 기준 0.47)

🎯 8차시 대비 좋아진 점 세 가지
① 두 번째 실행부터 즉시 시작합니다
인덱스를 불러오므로 임베딩 비용이 0입니다
② 관련 없으면 LLM을 부르지도 않습니다
임계값 미달이면 바로 종료 → 비용 절약 + 환각 차단
③ 근거의 신뢰도가 숫자로 보입니다
답이 이상할 때 관련도부터 확인하면 됩니다

← 이전 절10차시 · 7. 저장소 종류와 선택 기준다음 절 →10차시 · 9. 자주 겪는 문제