본문 바로가기
생성형 AI/랭체인으로 RAG 개발하기: VectorRAG & GraphRAG

5. VectorRAG 실습 : OpenAI API 사용 - 7

by Toddler_AD 2025. 10. 4.

5.7 VectorRAG에 부적합한 사례

  • 마지막으로 알아볼 것은 VectorRAG에 부적합한 사례입니다. 물론, 앞에서도 VectorRAG를 이용했을 때 정확히 답변을 못하는 상황을 확인했습니다. 하지만, 이번 예제에서는 VectorRAG를 사용하기에 부적합한 데이터 형태를 알아봅니다. 
  • 먼저 필요한 라이브러리를 설치합니다.
%pip install langchain langchain_openai chromadb
  • 설치 결과는 다음과 같습니다.
Requirement already satisfied: langchain in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (0.3.25)
Requirement already satisfied: langchain_openai in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (0.3.6)
Requirement already satisfied: chromadb in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (0.6.3)
Requirement already satisfied: langchain-core<1.0.0,>=0.3.58 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain) (0.3.60)
Requirement already satisfied: langchain-text-splitters<1.0.0,>=0.3.8 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain) (0.3.8)
Requirement already satisfied: langsmith<0.4,>=0.1.17 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain) (0.3.10)
Requirement already satisfied: pydantic<3.0.0,>=2.7.4 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain) (2.11.4)
Requirement already satisfied: SQLAlchemy<3,>=1.4 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain) (2.0.38)
Requirement already satisfied: requests<3,>=2 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain) (2.32.3)
Requirement already satisfied: PyYAML>=5.3 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain) (6.0.2)
Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain) (4.0.3)
Requirement already satisfied: openai<2.0.0,>=1.58.1 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain_openai) (1.63.2)
Requirement already satisfied: tiktoken<1,>=0.7 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from langchain_openai) (0.9.0)
Requirement already satisfied: build>=1.0.3 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (1.2.2.post1)
Requirement already satisfied: chroma-hnswlib==0.7.6 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (0.7.6)
Requirement already satisfied: fastapi>=0.95.2 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (0.115.12)
Requirement already satisfied: uvicorn>=0.18.3 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.34.0)
Requirement already satisfied: numpy>=1.22.5 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (1.26.4)
Requirement already satisfied: posthog>=2.4.0 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (3.15.0)
Requirement already satisfied: typing_extensions>=4.5.0 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (4.12.2)
Requirement already satisfied: onnxruntime>=1.14.1 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (1.20.1)
Requirement already satisfied: opentelemetry-api>=1.2.0 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (1.30.0)
Requirement already satisfied: opentelemetry-exporter-otlp-proto-grpc>=1.2.0 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (1.30.0)
Requirement already satisfied: opentelemetry-instrumentation-fastapi>=0.41b0 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (0.51b0)
Requirement already satisfied: opentelemetry-sdk>=1.2.0 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from chromadb) (1.30.0)
...
Requirement already satisfied: humanfriendly>=9.1 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from coloredlogs->onnxruntime>=1.14.1->chromadb) (10.0)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from sympy->onnxruntime>=1.14.1->chromadb) (1.3.0)
Requirement already satisfied: pyreadline3 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from humanfriendly>=9.1->coloredlogs->onnxruntime>=1.14.1->chromadb) (3.5.4)
Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in c:\users\jyseo\anaconda3\envs\rag\lib\site-packages (from pyasn1-modules>=0.2.1->google-auth>=1.0.1->kubernetes>=28.1.0->chromadb) (0.6.1)
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
  • OpenAI의 GPT-4o 모델을 설정하고 사용할 수 있도록 준비합니다.
import os
os.environ["OPENAI_API_KEY"] = "sk" #openai 키 입력

from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
    model="gpt-4o",
    temperature = 0,
)
  • CSVLoader를 사용하여 로컬 CSV 파일(football.csv) 파일의 내용을 읽어 docs라는 변수에 저장합니다.
from langchain_community.document_loaders import CSVLoader
# CSV 파일 가져오기
loader = CSVLoader('d:/data/football.csv')
docs = loader.load()
docs[0] # 첫 번째 문서를 가져옴
  • 출력 결과는 다음과 같습니다.
Document(metadata={'source': 'd:/data/football.csv', 'row': 0}, page_content='sofifa_id: 158023\
nshort_name: L. Messi\nage: 33\ndob:1987-06-24\nheight_cm: 170\nweight_kg: 72\nnationality: Argentina\
nclub_name: FC Barcelona\nleague_name: Spain Primera Division\noverall: 93\npotential: 93\
nvalue_eur: 67500000\nwage_eur: 560000\nplayer_positions: RW, ST, CF\npreferred_foot: Left')
  • CharacterTextSplitter를 사용하여 문서를 작은 청크(chunk)로 분할합니다.
from langchain.text_splitter import CharacterTextSplitter

# 문서 분할 기준 설정
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)

# 문서를 청크로 나누기 (split_documents)
docs = text_splitter.split_documents(docs)
  • OpenAIEmbeddings를 사용하여 텍스트 데이터를 벡터로 변환합니다.
# OpenAI의 임베딩 모델 사용
from langchain_openai import OpenAIEmbeddings
embedding_function = OpenAIEmbeddings()
  • 문서를 벡터화하고,, ChromaDB에 저장합니다.
from langchain.vectorstores import Chroma
# docs를 embedding_function을 사용하여 벡터로 변환
db = Chroma.from_documents(docs, embedding_function)
  • 프롬프트 템플릿을 정의합니다.
# 프롬프트 템플릿 정의
template = """당신은 축구에 대한 정보를 제공하는 챗봇입니다.

{context}

제공된 소스 데이터만 사용하여 고객의 질문에 답하세요.
모르겠다면 "잘 모르겠습니다."라고 답하세요.
친절하고 예의 바르며 전문적인 어조를 사용하세요.
답변은 간결하게 유지하세요.

질문: {question}

답변: """
  • PromptTemplate을 사용하여 답변 형식을 설정합니다.
from langchain.prompts import PromptTemplate
# PromptTemplate을 사용하여 프롬프트 초기화

prompt = PromptTemplate(template=template, input_variables=["context", "question"]) 
# input_variables=["context"]: 프롬프트에서 사용할 변수(context)를 정의
  • RetrievalQA 체인을 사용하여 사용자 질의에 대한 검색 및 답변을 생성합니다.
from langchain.chains import RetrievalQA
# RetrievalQA 체인에 사용할 프롬프트 설정
chain_type_kwargs = {"prompt": prompt} # 응답할 때 사용할 프롬프트(prompt)를 지정

# RetrievalQA 체인 생성
chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=db.as_retriever(search_kwargs={"k": 10}),
    chain_type_kwargs=chain_type_kwargs, # 프롬프트 설정을 적용하여 응답 스타일 지정
)
  • 이제 질문을 해봅시다.
import textwrap
# 긴 텍스트를 보기 좋게 정리하는 함수
def print_response(response: str):
    print("\n".join(textwrap.wrap(response, width=80))) #  80자 단위로 텍스트를 자동 줄 바꿈

# 사용자 질의
query = "L. Messi의 소속팀은?"
response = chain.invoke(query)
# 답변 출력
print_response(response["result"])
  • 질문에 대한 답변을 전혀 하지 못하고 있음을 확인할 수 있습니다.
질문을 입력해 주세요. 제가 도와드리겠습니다!
  • 이번 실습에서 사용된 데이터를 살펴보면, 데이터는 행과 열로 구성되어 있으며, 질문의 행과 열이 연결되어야 답변을 해줄 수 있습니다.
  • 이러한 유형의 데이터는 VectorRAG 보다 GraphRAG를 활용하여 항목 간의 관계를 형성하고, 이를 바탕으로 답변을 생성하는 것이 더 적절합니다.