AI Agent/AI Agent의 이해

3. RAG 개념 이해

427paul 2026. 5. 27. 21:09

Vector DB 구성

Loader

1) TextLoader

  • LangChain에서 가장 기본적인 데이터 로더 중 하나
  • 일반적인 텍스트 파일(.txt)에서 데이터를 불러오는 역할
  • txt 파일을 읽고, 이를 LangChain에서 사용할 수 있는 문서 객체(Document)로 변환
from langchain.document_loaders import TextLoader

# 텍스트 파일 경로 지정
file_path = "인사관리규정.txt"

# TextLoader를 이용하여 문서 로드
loader = TextLoader(path+file_path)
documents = loader.load()

# 로드된 문서 출력
print(documents)

2) Document

  • LangChain에서 텍스트 데이터(문서)를 구조적으로 표현하는 기본 단위
  • 주요 속성
    • metadata : 문서의 출처, 태그, 카테고리 등의 부가 정보
    • page_content : 문서의 실제 텍스트 내용
  • Loader로 로딩한 후 저장하거나, 직접 Document 생성 가능
from langchain.schema import Document

doc = Document(
    page_content="이것은 LangChain의 Document 객체 예제입니다.",
    metadata={"source": "sample.txt", "category": "example"}
)
doc
doc.metadata
doc.page_content
text = documents[0].page_content
text

Splitter

  • 긴 문서를 작은 단위인 청크(chunk)로 나누는 텍스트 분리 도구
    • 텍스트를 분리하는 작업 : 청킹(chungking)
      • LLM 모델의 입력 토큰의 개수가 정해져 있기 때문
      • 텍스트가 너무 긴 경우에는 핵심 정보 이외에 불필요한 정보들이 많이 포함
        • RAG 품질 저하 요인
      • 핵심 정보가 유지될 수 있는 적절한 크기로 나누는 것이 중요
  • 텍스트 분할 의미
    • 텍스트를 나눌 때 각 청크가 독립적으로 의미를 갖도록 나눠야 한다
    • 이를 위해 문장, 구절, 단락 등 문서 구조를 기준으로 나눌 수 있다
  • 청크 크기
    • 각 청크의 크기를 직접 조정
    • LLM 모델의 입력 크기와 비용 등을 종합적으로 고려하여 애플리케이션에 적합한 최적 크기를 결정하는 기준
    • 예 : 단어 수, 문자 수 등 기준
text_splitter = CharacterTextSplitter(
    chunk_size = 500,#500 글자씩 나누기
    chunk_overlap  = 100,#100글자씩 겹치기
    separator = '',   # 어떤 기준 없이 무조건 500자 단위로 나누라
)

split_texts = text_splitter.split_text(text)

# 결과 확인
for i, chunk in enumerate(split_texts[:5]):  # 처음 5개 청크만 출력
    print(f"청크 {i+1}, 길이 {len(chunk)}: {chunk}\\n")
text_splitter = CharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=100,
    separator="."  # 문장 단위로 분할
)

split_texts = text_splitter.split_text(text)

# 결과 확인
for i, chunk in enumerate(split_texts[:5]):  # 처음 5개 청크만 출력
    print(f"청크 {i+1}, 길이 {len(chunk)}: {chunk}\\n")
text_splitter = CharacterTextSplitter(
    chunk_size = 500,
    chunk_overlap  = 100,
    separator = '\\n',   # \\n 줄바꿈 문자 기준으로 자르기,
)

split_texts = text_splitter.split_text(text)

# 결과 확인
for i, chunk in enumerate(split_texts[:5]):  # 처음 5개 청크만 출력
    print(f"청크 {i+1}, 길이 {len(chunk)}: {chunk}\\n")

Embedding & Store

  • 임베딩(Embedding)
    • 텍스트 데이터를 숫자로 이루어진 벡터로 변환하는 과정
    • 이때, 의미적인 정보를 보존하도록 설계
  • 임베딩 목적
    • 벡터 표현을 사용하면, 텍스트 데이터를 벡터 공간 내에서 수학적으로 다룰 수 있게 됨
    • 이를 통해 텍스트 간의 유사성을 계산 가능
    • 텍스트 데이터를 기반으로 하는 다양한 머신러닝 및 자연어 처리 작업 수행
  • 임베딩 모델 사용
    • OpenAI : text-embedding-3-small
  • 벡터 저장소(Vector Store)
    • 벡터 형태로 표현된 데이터, 즉 임베딩 벡터들을 효율적으로 저장하고 검색할 수 있는 DB
    • Vector DB라고 불림
  • Chroma
    • 빠르게 RAG 시스템을 구축하고 싶을 때
    • 메타데이터 기반 검색이 필요할 때
    • Python 기반 프로젝트에서 간단히 사용하고 싶을 때
  • FAISS
    • 수백만 개 이상의 벡터를 빠르게 검색해야 할 때
    • GPU를 활용한 대량의 유사도 검색이 필요할 때
    • 검색 속도를 극한을 최적화해야 할 때
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma

# Hugging Face 임베딩 모델 (sentence-transformers 기반)
embedding_model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")

# split_texts는 미리 준비한 텍스트 조각 리스트라고 가정
vectorstore = Chroma.from_texts(
    texts=split_texts,
    embedding=embedding_model,
    persist_directory="./chroma_db"
)

print("ChromaDB에 저장 완료!")

RAG 파이프라인

Retriever 선언

  • Vector DB에서 사용자의 질문과 가장 유사한 문서(청크)를 검색
  • 코사인 유사도(Cosine Similarity) 기반으로 유사한 문서 검색

LLM 모델 지정

  • 검색된 문서와 함께 질문을 받아 답변 생성할 LLM 모델 지정

메모리 선언

  • 대화의 흐름을 유지하고 ,이전 질문을 기억하여 문맥을 제공
  • 프롬프트 길이를 고려한 메모리 최적화 필요

체인 함수로 엮기

  • Retriever + LLM + Memory를 하나의 체인으로 연결하여 질문-응답 시스템 완성
# (1) 리트리버(Retriever) 생성
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 5})

# (2) GPT-4o mini 모델 설정
llm_ep = HuggingFaceEndpoint(repo_id="openai/gpt-oss-20b", task="conversational")

# HuggingFace에서 가져온 모델을 그대로 쓰지 않고,
# LangChain에서 쉽게 쓰도록 감싸는(wrapper) 단계
llm = ChatHuggingFace(llm=llm_ep)

# (3) 메모리 추가 (대화 문맥 유지)
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True, output_key="answer")

# (4) RAG 기반 ConversationalRetrievalChain 구성
qa_chain = ConversationalRetrievalChain.from_llm(
    llm=llm,
    retriever=retriever,
    memory=memory,
    return_source_documents=False  # 검색된 문서 출력 옵션
# 6. 질의
# 테스트 실행
query = "제 1장에 대한 내용을 알려줘"
response = qa_chain({"question": query})

# 응답 출력
print("답변:", response["answer"])

 

https://github.com/427paul/AI_Agent/blob/main/AI_Agent_Basic/04_RAG_%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8_%EA%B5%AC%EC%B6%951.ipynb

 

AI_Agent/AI_Agent_Basic/04_RAG_파이프라인_구축1.ipynb at main · 427paul/AI_Agent

Contribute to 427paul/AI_Agent development by creating an account on GitHub.

github.com

 

'AI Agent > AI Agent의 이해' 카테고리의 다른 글

6. LangGraph 기초1 기본 그래프2  (0) 2026.05.30
5. LangGraph 기초1 기본 그래프  (0) 2026.05.29
4. Memory  (1) 2026.05.28
2. 메모리, RAG 개념 이해  (0) 2026.05.26
1. LangChain 기초  (0) 2026.05.24