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

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

by Toddler_AD 2025. 10. 4.

5.6 랭체인 & 라마인덱스 비교

  • 랭체인과 유사한 역할을 하는 라마인덱스(Llamaindex)도 있습니다. 이를 이용하면 손쉽게 VectorRAG를 구현할 수 있습니다. 둘의 사용 방법을 비교해 보겠습니다.
  • 먼저 랭체인을 이용한 방법입니다. 앞에서 많이 다루었기 때문에 자세한 주석은 생략하겠습니다.
  • 필요한 라이브러리를 설치합니다.
%pip install langchain chromadb langchain-openai pandas
  • 설치 결과는 다음과 같습니다.
Requirement already satisfied: langchain in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (0.3.17)
Requirement already satisfied: chromadb in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (0.6.3)
Requirement already satisfied: langchain-openai in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (0.3.4)
Requirement already satisfied: pandas in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (2.2.3)
Requirement already satisfied: PyYAML>=5.3 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (6.0.2)
Requirement already satisfied: SQLAlchemy<3,>=1.4 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (2.0.37)
Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (3.11.11)
Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (4.0.3)
Requirement already satisfied: langchain-core<0.4.0,>=0.3.33 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (0.3.34)
Requirement already satisfied: langchain-text-splitters<0.4.0,>=0.3.3 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (0.3.5)
Requirement already satisfied: langsmith<0.4,>=0.1.17 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (0.3.2)
Requirement already satisfied: numpy<2,>=1.22.4 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (1.26.4)
Requirement already satisfied: pydantic<3.0.0,>=2.7.4 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (2.10.6)
Requirement already satisfied: requests<3,>=2 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (2.32.3)
Requirement already satisfied: tenacity!=8.4.0,<10,>=8.1.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain) (9.0.0)
Requirement already satisfied: build>=1.0.3 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (1.2.2.post1)
Requirement already satisfied: chroma-hnswlib==0.7.6 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (0.7.6)
Requirement already satisfied: fastapi>=0.95.2 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (0.115.8)
Requirement already satisfied: uvicorn>=0.18.3 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.34.0)
Requirement already satisfied: posthog>=2.4.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (3.11.0)
Requirement already satisfied: typing_extensions>=4.5.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (4.12.2)
Requirement already satisfied: onnxruntime>=1.14.1 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (1.20.1)
Requirement already satisfied: opentelemetry-api>=1.2.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (1.29.0)
Requirement already satisfied: opentelemetry-exporter-otlp-proto-grpc>=1.2.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (1.29.0)
Requirement already satisfied: opentelemetry-instrumentation-fastapi>=0.41b0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from chromadb) (0.50b0)
...
Requirement already satisfied: humanfriendly>=9.1 in c:\users\jyseo\anaconda3\envs\graph\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\graph\lib\site-packages (from sympy->onnxruntime>=1.14.1->chromadb) (1.3.0)
Requirement already satisfied: pyreadline3 in c:\users\jyseo\anaconda3\envs\graph\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\graph\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,
)
  • CSV 파일을 읽어와 벡터로 변환하여 ChromaDB에 저장합니다. 이후 ChromaDB에 저장된 데이터를 기반으로 답변을 생성합니다.
import pandas as pd
from langchain_openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.llms import OpenAI
from langchain.chains import RetrievalQA

# 데이터 불러오기
file_path = "d:/data/Disease_symptom_and_patient_profile_dataset.csv"
df = pd.read_csv(file_path)

# 데이터를 텍스트로 변환
df["text"] = df.apply(
    lambda row: f"질병: {row['Disease']}, 증상: 발열({row['Fever']}), 기침({row['Cough']}), 피로({row['Fatigue']}), 호흡 곤란({row['Difficulty Breathing']}), "
                f"연령: {row['Age']}, 성별: {row['Gender']}, 혈압: {row['Blood Pressure']}, 콜레스테롤: {row['Cholesterol Level']}, 결과: {row['Outcome Variable']}",
    axis=1
)

# OpenAI 임베딩 생성
embeddings = OpenAIEmbeddings()

# hromaDB에 데이터 저장
chroma_path = "d:/data/chroma_disease_db"
vectorstore = Chroma.from_texts(df["text"].tolist(), embeddings, persist_directory=chroma_path)

# ChromaDB에서 검색할 리트리버 생성
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 5})

# LangChain QA 체인 설정
qa_chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever, chain_type="stuff")

# 사용자 질문 
query = "기침과 발열이 있는 질병은 무엇인가요?"
response = qa_chain.invoke(query)

# 결과 출력
print("📌 질문:", query)
print("💡 답변:", response)
  • "기침과 발열이 있는 질병은 무엇인가요?"라는 질문에 대한 답변을 보여줍니다. 두 증상이 동시에 나타난 증상은 없다고 보여줍니다. 하지만, 데이터에는 두 증상이 함께 나타나는 경우가 많기 때문에 RAG에 대한 결과는 검증이 필요하다는 것을 다시 확인할 수 있습니다.
📌 질문: 기침과 발열이 있는 질병은 무엇인가요?
💡 답변: {'query': '기침과 발열이 있는 질병은 무엇인가요?', 
'result': '주어진 문맥에서는 발열은 있지만 기침은 없는 건선(Psoriasis)에 대한 정보만 
제공되고 있습니다. 따라서 기침과 발열이 모두 있는 질병에 대한 정보는 제공되지 않았습니다. 
일반적으로 기침과 발열은 감기, 독감, 코로나19 등의 호흡기 질환에서 흔히 나타나는 증상입니다. 
하지만 정확한 진단을 위해서는 의료 전문가의 상담이 필요합니다.'}
  • 이번에는 좀 더 구체적으로 질문을 해보겠습니다.
query = "35대 여성이고, 기존에 혈압이 높았어, 어제부터 열이 있고 기침 증상이 있어. 무슨 질병을 의심해야해? 단, 데이터만 참조해서 답변해줘"
response = qa_chain.invoke(query)

# ✅ 8️⃣ 결과 출력
print("📌 질문:", query)
print("💡 답변:", response)
  • 그랬더니 다음과 같은 답변을 보여줍니다. 질병을 알려달라고 했지만 Negative라는 결과만 보여주네요.
📌 질문: 35대 여성이고, 기존에 혈압이 높았어, 어제부터 열이 있고 기침 증상이 있어. 
무슨 질병을 의심해야해? 단, 데이터만 참조해서 답변해줘
💡 답변: {'query': '35대 여성이고, 기존에 혈압이 높았어, 어제부터 열이 있고 기침 증상이 있어.
무슨 질병을 의심해야해? 단, 데이터만 참조해서 답변해줘', 
'result': '제공된 데이터에 따르면, 35세 여성으로 고혈압이 있는 경우 발열과 기침 증상이 있을 때 
결과는 "Negative"로 나타났습니다. 따라서, 이 데이터만을 참조했을 때 특정 질병을 의심할 수 있는 
정보는 없습니다. 추가적인 의학적 평가가 필요할 수 있습니다.'}
  • 이와 같이 데이터 간의 연관성이 고려해야 하는 경우라면 VectorRAG에서 정확히 답변하지 못할 수 있습니다.
  • 이번에는 라마인덱스를 사용해보겠습니다. 동일하게 필요한 라이브러리를 설치합니다. llama-index는 LLM을 활용한 문서 검색 및 데이터 연결 라이브러리 입니다.
%pip install llama-index langchain-openai pandas faiss-cpu
  • 설치 결과는 다음과 같습니다.
Collecting llama-index
  Using cached llama_index-0.12.16-py3-none-any.whl.metadata (12 kB)
Requirement already satisfied: langchain-openai in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (0.3.4)
Requirement already satisfied: pandas in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (2.2.3)
Requirement already satisfied: faiss-cpu in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (1.10.0)
Requirement already satisfied: llama-index-agent-openai<0.5.0,>=0.4.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.4.3)
Requirement already satisfied: llama-index-cli<0.5.0,>=0.4.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.4.0)
Requirement already satisfied: llama-index-core<0.13.0,>=0.12.16 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.12.16.post1)
Requirement already satisfied: llama-index-embeddings-openai<0.4.0,>=0.3.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.3.1)
Requirement already satisfied: llama-index-indices-managed-llama-cloud>=0.4.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.6.4)
Requirement already satisfied: llama-index-llms-openai<0.4.0,>=0.3.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.3.14)
Requirement already satisfied: llama-index-multi-modal-llms-openai<0.5.0,>=0.4.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.4.2)
Requirement already satisfied: llama-index-program-openai<0.4.0,>=0.3.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.3.1)
Requirement already satisfied: llama-index-question-gen-openai<0.4.0,>=0.3.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.3.0)
Requirement already satisfied: llama-index-readers-file<0.5.0,>=0.4.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.4.4)
Requirement already satisfied: llama-index-readers-llama-parse>=0.4.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (0.4.0)
Requirement already satisfied: nltk>3.8.1 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from llama-index) (3.9.1)
Requirement already satisfied: langchain-core<1.0.0,>=0.3.34 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain-openai) (0.3.34)
Requirement already satisfied: openai<2.0.0,>=1.58.1 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain-openai) (1.61.1)
Requirement already satisfied: tiktoken<1,>=0.7 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from langchain-openai) (0.8.0)
Requirement already satisfied: numpy>=1.22.4 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from pandas) (1.26.4)
Requirement already satisfied: python-dateutil>=2.8.2 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from pandas) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from pandas) (2024.2)
Requirement already satisfied: tzdata>=2022.7 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from pandas) (2025.1)
Requirement already satisfied: packaging in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from faiss-cpu) (24.2)
...
Requirement already satisfied: marshmallow<4.0.0,>=3.18.0 in c:\users\jyseo\anaconda3\envs\graph\lib\site-packages (from dataclasses-json->llama-index-core<0.13.0,>=0.12.16->llama-index) (3.26.0)
Using cached llama_index-0.12.16-py3-none-any.whl (6.9 kB)
Installing collected packages: llama-index
Successfully installed llama-index-0.12.16
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
  • CSV 데이터에서 질병 정보를 가져와서 OpenAI의 임베딩을 이용해 벡터화합니다. 이후 LLM을 활용하여 질의응답을 수행합니다. 코드에서 사용한 클래스의 역할은 다음과 같습니다.
    • VectorStoreIndex : 문서를 벡터화하여 저장하고 검색할 수 있도록 하는 벡터 저장소 인덱스 입니다.
    • Document : 텍스트 데이터를 라마인덱스에서 처리할 수 있는 문서 객체로 변환합니다.
#llamaindex 사용 방법
import pandas as pd
from llama_index.core import VectorStoreIndex, Document
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.settings import Settings

# CSV 데이터 불러오기
file_path = "d:/data/Disease_symptom_and_patient_profile_dataset.csv" # CSV 파일 경로 지정
df = pd.read_csv(file_path)  # CSV 파일을 Pandas DataFrame으로 로드

# 각 행(Row)에 대해 정보를 하나의 문자열로 합쳐서 저장
df["text"] = df.apply(
    lambda row: f"질병: {row['Disease']}, 증상: 발열({row['Fever']}), 기침({row['Cough']}), 피로({row['Fatigue']}), "
                f"호흡 곤란({row['Difficulty Breathing']}), 연령: {row['Age']}, 성별: {row['Gender']}, "
                f"혈압: {row['Blood Pressure']}, 콜레스테롤: {row['Cholesterol Level']}, 결과: {row['Outcome Variable']}",
    axis=1 # 각 행(Row)에 대해 적용
)

# OpenAI LLM 및 임베딩 모델 설정
Settings.llm = OpenAI(model="gpt-4o", temperature=0)
Settings.embed_model = OpenAIEmbedding()

# LlamaIndex 벡터 저장소에 데이터 추가
documents = [Document(text=text) for text in df["text"].tolist()] # CSV 데이터를 Document 객체로 변환
index = VectorStoreIndex.from_documents(documents) # 문서를 벡터화하여 저장소에 저장

# 검색 기능을 수행하는 query_engine 생성
query_engine = index.as_query_engine() # 질의응답 기능을 제공하는 엔진 생성

# 사용자가 입력한 질문을 기반으로 질의응답 수행
query = "기침과 발열이 있는 질병은 무엇인가요?"
response = query_engine.query(query) # LLM을 이용하여 질의응답 수행

# 결과 출력
print("📌 질문:", query)
print("💡 답변:", response)
  • 랭체인 사용과 유사함을 확인할 수 있습니다. 단지, FAISS나 Chroma와 같은 벡터 데이터베이스를 사용하지 않고 라마인데스에서 자체적으로 제공하는 데이터베이스만 사용한다는 차이가 있습니다. 랭체인이나 라마인데스 모두 LLM을 활용한 애플리케이션을 만드는 프레임워크이기 때문에 사용방법은 유사하다고 할 수 있습니다.
  • 질문에 대한 답변은 다음과 같습니다. 정답을 제공하지 못하네요.
📌 질문: 기침과 발열이 있는 질병은 무엇인가요?
💡 답변: 기침과 발열이 있는 질병은 제공된 정보에 없습니다.
  • 랭체인 실습에서 했던 또 다른 질문을 해봅시다.
query = "49대 여성이고, 기존에 혈압이 높고 높았어, 어제부터 열이 있고 기침 증상이 있어. 무슨 질병을 의심해야해? 단, 데이터만 참조해서 답변해줘"
response = query_engine.query(query)

# ✅ 8️⃣ 결과 출력
print("📌 질문:", query)
print("💡 답변:", response)
  • 그러면 다음과 같이 결과를 보여줍니다. 참고로 Hypertension은 고혈압을 의미합니다.
📌 질문: 49대 여성이고, 기존에 혈압이 높고 높았어, 어제부터 열이 있고 기침 증상이 있어. 
무슨 질병을 의심해야해? 단, 데이터만 참조해서 답변해줘
💡 답변: Hypertension을 의심할 수 있습니다.
  • 동일한 답변을 도출하고 있음을 확인할 수 있습니다. 반드시 랭체인만 사용해야 하는 것은 아니므로 편리한 프레임워크를 선택해서 사용하면 됩니다.