alt

week2_day3

Shared on March 22, 2026

RAG 시스템 구축과 전처리: Python 클래스와 문서 로드

개요

본 강의에서는 Retrieval Augmented Generation (RAG) 과정을 구현하기 위한 전처리 및 핵심 파이썬 코드 설계를 다룹니다.

  • OpenAI API 활용
  • 파일·폴더 접근, 날짜·시간 라이브러리
  • 임베딩(embedding)과 코사인 유사도
  • 문서 저장·검색을 위한 DocumentStore 클래스
  • 문서 로드 함수(load_text_files, load_csv_files, load_json_file)
  • RAG 파이프라인(검색→컨텍스트 제공→생성) 구현

핵심 개념

개념설명
RAGRetrieval + Augmented + Generation. 외부 지식(문서)을 검색해 LLM에 컨텍스트로 제공, 보다 정확한 답변을 생성.
임베딩(Embedding)텍스트를 고차원 벡터로 변환. text-embedding-3-small 모델 사용.
코사인 유사도두 벡터 간 유사도를 측정해 검색 결과를 정렬.
문서 스토어문서 객체(Document)를 저장하고, ID, 내용, 메타데이터를 관리. 검색·추가·수량·검색 기능 포함.
클래스 구조__init__, add, count, search, retrieve, generate 등 메소드로 기능 캡슐화.
파일 로드텍스트, CSV, JSON 파일을 읽어 Document 객체로 변환.
파인튜닝 vs RAG파인튜닝은 모델 재학습(비용·시간), RAG는 검색·컨텍스트 제공(경제적·빠름).

상세 노트

1. 환경 설정 및 라이브러리 로드

import os from pathlib import Path import csv import json from dotenv import load_dotenv from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain.schema import HumanMessage, SystemMessage from langchain.embeddings import OpenAIEmbeddings from sklearn.metrics.pairwise import cosine_similarity
  • .env 파일에서 OPENAI_API_KEY 로드
  • ChatOpenAI 모델: gpt-4o-mini
  • OpenAIEmbeddings 모델: text-embedding-3-small

2. 샘플 데이터 폴더 생성

sample_dir = Path("sample_data") sample_dir.mkdir(exist_ok=True)
  • companypolicy.txt, airreport.txt 등 예시 파일을 저장.

3. 문서 저장용 딕셔너리

documents = { "companypolicy.txt": "내용...", "airreport.txt": "내용..." } for filename, content in documents.items(): with open(sample_dir / filename, "w", encoding="utf-8") as f: f.write(content)

4. DocumentStore 클래스

class DocumentStore: def __init__(self): self.documents = [] # 리스트 of dicts self.next_id = 1 self.embedding = OpenAIEmbeddings() def add(self, content, source="default"): doc = { "id": self.next_id, "content": content, "source": source, "vector": self.embedding.embed_query(content) } self.documents.append(doc) self.next_id += 1 def count(self): return len(self.documents) def search(self, keyword): return [d for d in self.documents if keyword.lower() in d["content"].lower()] def retrieve(self, query, top_k=3): query_vec = self.embedding.embed_query(query) scores = [] for doc in self.documents: score = cosine_similarity( [query_vec], [doc["vector"]] )[0][0] scores.append((doc, score)) scores.sort(key=lambda x: x[1], reverse=True) return [doc for doc, _ in scores[:top_k]]
  • add: 문서 저장 + 벡터 생성
  • search: 키워드 기반 단순 필터
  • retrieve: 코사인 유사도 기반 상위 k 문서 반환

5. WordCounter 클래스

class WordCounter: def __init__(self): self.texts = [] def add_text(self, txt): self.texts.append(txt) def count_word(self): all_words = " ".join(self.texts).split() return len(all_words)

6. 문서 로드 함수

def load_text_files(directory: Path): docs = [] for fp in directory.glob("*.txt"): content = fp.read_text(encoding="utf-8") doc = { "source": fp.name, "content": content, "vector": None # later embed } docs.append(doc) return docs def load_csv_files(directory: Path): docs = [] for fp in directory.glob("*.csv"): with fp.open(newline="", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: content = row.get("content", "") doc = { "source": fp.name, "content": content, "vector": None } docs.append(doc) return docs def load_json_file(file_path: Path): with file_path.open(encoding="utf-8") as f: data = json.load(f) content = json.dumps(data, ensure_ascii=False, indent=2) doc = { "source": file_path.name, "content": content, "vector": None } return doc

7. RAG 파이프라인 구현

def rag_chain(query, store: DocumentStore): # 1. 검색 retrieved = store.retrieve(query, top_k=2) # 2. 컨텍스트 생성 context = "\n\n".join([doc["content"] for doc in retrieved]) # 3. LLM 호출 messages = [ SystemMessage(content="제공된 문서를 바탕으로 정확히 답변하십시오."), HumanMessage(content=f"문서: {context}\n\n질문: {query}") ] response = store.llm.invoke(messages) return response.content
  • store.llmChatOpenAI 인스턴스

8. 사용 예시

store = DocumentStore() store.add("김철수는 개발팀에 소속돼 있습니다.", source="companypolicy.txt") store.add("우리 회사의 정책은...", source="companypolicy.txt") print(store.count()) # 2 print(store.search("개발팀")) # 해당 문서 반환 answer = rag_chain("김철수 부서가 뭐야?", store) print(answer)

9. 장단점 정리

항목파인튜닝RAG
비용높음 (모델 재학습)낮음 (API 호출만)
시간오래 걸림빠름
유연성한 번 학습 후 고정실시간 검색·업데이트 가능
정확도데이터에 따라 변동검색 품질에 따라 변동

핵심: RAG는 외부 문서를 검색해 LLM에 컨텍스트로 제공함으로써 hallucination을 줄이고, 파인튜닝보다 비용·시간이 적게 든다.
실행 팁: 문서 로드 시 메타데이터(소스, 길이 등)를 포함하고, DocumentStore에서 벡터를 미리 저장해 두면 검색 속도가 크게 향상된다.