Agentic RAG를 두 가지의 llm으로 테스트해 봤습니다.
추론 오픈 모델 중 성능 높다고 알려진 QWQ-32B와 비추론 모델인 Llama3.3-70B입니다.
이미 Llama4도 나오긴 했으나, H100 한대로는 아직 어려워서 해보진 않았습니다. Ollama에 양자화 모델(말로는 60GB 정도 사용) 뜨면 해보겠습니다.
원래 QWQ전에 여러 모델들 테스트해 봤는데, 지금까진 Llama3.3-70B가 한국어에 무난해서 사용하고 있었습니다.

QWQ-32B를 로컬에서 실행하려면 최소 24GB VRAM이 필요합니다. 저는 H100 80GB 사용했습니다.
우선 Ollama를 사용했기에 아래 명령으로 Ollama, QWQ 설치해 줍니다.
curl -fsSL https://ollama.com/install.sh | sh # Ollama 리눅스 설치
ollama serve # Ollama 실행
ollama pull qwq:32b # QWQ 32b 다운로드
다음 아래 코드는 벡터 DB에 데이터를 저장하기 위해 폴더 안의 모든 pdf파일을 읽는 코드입니다.
국토교통부 공통설계기준 pdf 데이터를 사용했습니다.
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"
import weaviate
from langchain_weaviate.vectorstores import WeaviateVectorStore
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyMuPDFLoader
from langchain_huggingface import HuggingFaceEmbeddings
# Kicon_data 폴더 내 모든 PDF 파일 경로 가져오기
pdf_folder_path = "Kicon_data"
pdf_files = [os.path.join(pdf_folder_path, file) for file in os.listdir(pdf_folder_path) if file.lower().endswith(".pdf")]
# 1. PDF 전체 로드
all_pages = []
# PDF 로드 + 마크다운으로 표 추출
for pdf_path in pdf_files:
loader = PyMuPDFLoader(
pdf_path,
mode="page",
extract_tables="markdown", # ✅ 테이블을 마크다운 형식으로 추출
)
pages = loader.load()
all_pages.extend(pages) # 여러 파일의 페이지를 전부 모음
# 2. 텍스트 분할기 설정
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
)
# 3. 문서 분할
documents = text_splitter.split_documents(all_pages)
# Iterate over each Document object in the texts list
for page in documents:
# Replace '\x01' with an empty string in the page_content
page.page_content = page.page_content.replace('\x01', '').replace('\n', '')
허깅페이스에 로그인해 주고 embedding 모델을 입력합니다.
차원 대비 용량 효율 좋은 모델이 e5-large라 거의 e5-large multilingual을 사용합니다.
!huggingface-cli login --token 자기토큰입력
from langchain_huggingface import HuggingFaceEmbeddings
model_name = "embaas/sentence-transformers-multilingual-e5-large"
emb = HuggingFaceEmbeddings(model_name=model_name)
아래는 벡터 DB(weaviate)에 DB 저장 코드입니다.
import weaviate
from weaviate.auth import AuthApiKey
auth_config = weaviate.AuthApiKey(api_key="Weaviate 개인 키 넣기")
client = weaviate.connect_to_custom(
http_host="localhost",
http_port="9090",
http_secure=False,
auth_credentials=auth_config,
grpc_host="localhost",
grpc_port="50051",
grpc_secure=False,
)
from langchain_weaviate.vectorstores import WeaviateVectorStore
# Add to vectorDB
vector_store = WeaviateVectorStore.from_documents(
client=client,
documents=documents,
text_key="page_content", # Assuming you have stored documents with the text field named "text"
embedding=emb,
)
아래 코드로 QWQ 모델을 불러옵니다.
retriever = vector_store.as_retriever(search_type="similarity", k=4) # weaviate 벡터 데이터베이스에서 유사한 문서를 검색하는 검색기(retriever) 생성 과정
from langchain_ollama import ChatOllama
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
#llm = ChatOllama(model="llama3.3", temperature=0.2, top_p=0.2, eos_token_id=128009)
llm = ChatOllama(model="qwq", temperature=0.2, top_p=0.2, eos_token_id=128009)
#llm = ChatOllama(model="qwen2.5:72b", temperature=0.2, top_p=0.2, eos_token_id=128009)
template = "{topic} 에 대하여 간략히 설명해 줘."
prompt = ChatPromptTemplate.from_template(template)
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": "단계별 상세 지반조사에서 예비조사 목적"})
아래는 Retrieval QA를 구성하고 Agentic RAG 챗봇을 구성하는 코드입니다.
from langchain.chains import RetrievalQA
# Create the Retrieval QA chain
retrieval_qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=retriever, # weaviate 벡터 데이터베이스에서 유사한 문서를 검색하는 검색기(retriever)
return_source_documents=True # 검색된 문서(출처)를 함께 반환
)
from langchain.agents import initialize_agent, Tool, AgentType
# Combine tools and retrieval chain
tools = [
Tool(
name="Document Retrieval", # 문서 검색을 수행하는 도구
func=lambda q: retrieval_qa_chain({"query": q})["result"], # 사용자가 질문을 입력하면 retrieval_qa_chain 호출하여 답변 생성
description="Retrieve knowledge from the document database." # 문서 데이터베이스에서 정보를 검색합니다
), # Document database에서 정보를 검색하는 역할
]
# Initialize the agent
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
def chatbot_agentic_rag():
print("Agentic RAG Chatbot is running! Type 'exit' to quit.")
while True:
user_query = input("You: ")
if user_query.lower() == "exit":
print("Chatbot session ended.")
break
try:
response = agent.run(user_query)
print(f"Bot: {response}")
except Exception as e:
print(f"Error: {e}")
아래 코드로 실행
re = chatbot_agentic_rag()
- 결과
문서에서 일반 텍스트로 되어있는 부분에 대한 질문은 대부분 llm이 비슷하게 답합니다.

위와 같은 이중표가 섞여있는 표에서 차이가 발생합니다.

위 결과를 보시면 Llama3.3은 표 부분을 아얘 찾지 못함.

QWQ 모델은 추론 모델이라 혼잣말이 많은데 찾아냄.
제가 테스트해 봤을 때는 QWQ가 더 쓸만한 것 같습니다.
Qwen2.5-72b 모델도 사용해 봤는데, 중국어 답을 너무 많이 하더라고요.
요새 Qwen의 모델들 성능이 좋은 것 같아 조만간 출시될 Qwen3가 매우 기대됩니다.
'AI > LLM' 카테고리의 다른 글
| Cogito-70B llm 모델 성능 테스트 해보기 (0) | 2025.04.11 |
|---|---|
| 임베딩 모델 한국어 성능 비교(BGE-M3 vs E5-large) (0) | 2025.04.10 |
| PyMuPDF4LLM vs PyMuPDFLoader(PDF loader 비교) (0) | 2025.04.04 |
| Qwen2.5-VL-32B 모델로 image to text(이미지로 텍스트 생성) 해보기(Gemma3 비교) (0) | 2025.04.03 |
| Qwen2.5-VL-32B 모델로 OCR, 질문 답 해보기(LLM OCR) (0) | 2025.04.02 |