
이 글은 여러 형태의 RAG중 1개의 예제로 구성하는 형태에 대한 설명을 위한 글입니다.
2025년 2/4분기에 큰 인기를 얻는 Notebook-LM처럼 만드려고 했지만, 다 로컬(HP notebook)에서 실행해야하기에 가능한 부분만 구현하였습니다.
Ollama와 4Gbyte크기의 LLM으로만 구현하여, 인터넷과 무관하게 동작합니다.
생성 시, 참조하는 위치에 대한 정보는 오른쪽에 해당 서적, 해당 페이지를 표시하는 방법으로 변경하였습니다.
GUI는 ‘Streamlit’로 구현했습니다.
주요 기능
– 질문언어와 답변언어를 분리하였습니다.
– 원하는 서적에서 검색하도록 제한 할 수 있습니다.
– 생성을 위한 과정에서 어떤 서적의 어떤 페이지를 참조하는지 히스토리를 볼 수 있습니다.
– 여러 명이 동시에 사용할 수 있도록 작성 되었습니다.
– 관련 문서 찾는 기능과 질문에 대한 답변을 생성하는 기능을 LangChain에 권장 구조로 작성했고, 2차에 걸친 검토 후에 답변하도록 되어 있습니다.
(Operating Environment: Laptop from 2022, 8GB RAM, GTX 1650 VRAM 4GB)
(WEB 시스템의 사정으로 이미지가 분할됩니다.)
LLM을 이용하여, PDF내용을 검색하는 화면입니다 (LLM Search).
주요기능
– DB화 된 PDF를 선택적으로 검색할 수 있습니다.
– DB마다 검색할 페이지 수와 사용자에게 표시할 페이지 수를 선택할 수 있습니다.
– 검색된 페이지를 번역하여 내용을 알 수 있게 합니다.




이런 코드는 AI 서비스를 이용해서 만드시면 됩니다.
DeepSeek를 질문을 해서 코드를 만드는 것을 올립니다.
import streamlit as st
import os
# 세션 상태 초기화
if 'messages' not in st.session_state:
st.session_state.messages = []
if 'answer' not in st.session_state:
st.session_state.answer = ""
if 'selected_language' not in st.session_state:
st.session_state.selected_language = "Korean"
if 'selected_book' not in st.session_state:
st.session_state.selected_book = ""
# 페이지 설정
st.set_page_config(layout="wide")
# 책 목록 파일 읽기 함수
def load_booklist():
try:
with open('booklist.txt', 'r', encoding='utf-8') as f:
return [line.strip() for line in f.readlines()]
except FileNotFoundError:
st.error("booklist.txt 파일을 찾을 수 없습니다.")
return []
except Exception as e:
st.error(f"파일 읽기 오류: {str(e)}")
return []
# 레이아웃 구성
col1, col2, col3 = st.columns([0.2, 0.5, 0.3])
# 좌측 컬럼 (설정 및 책 선택)
with col1:
st.header("Settings")
# 언어 선택
language = st.radio(
"Select Language",
["Korean", "English"],
index=0 if st.session_state.selected_language == "Korean" else 1
)
st.session_state.selected_language = language
# 책 목록 로드 및 선택
books = load_booklist()
if books:
selected_book = st.selectbox(
"Select a Book",
books,
index=books.index(st.session_state.selected_book) if st.session_state.selected_book in books else 0
)
st.session_state.selected_book = selected_book
# 중앙 컬럼 (질문 & 답변)
with col2:
st.header("Q&A")
# 질문 입력
question = st.text_input("Enter your question:")
# 답변 표시 영역
answer_placeholder = st.empty()
if st.session_state.answer:
answer_placeholder.markdown(st.session_state.answer)
# 처리 버튼 (실제 RAG 연결 부분)
if st.button("Submit"):
# 여기에 실제 RAG 처리 코드 추가
mock_answer = f"Selected: {st.session_state.selected_book} ({language})\n\nQuestion: {question}\n\nAnswer: This is a sample response."
st.session_state.answer = mock_answer
answer_placeholder.markdown(mock_answer)
# 메시지 패널에 로그 추가
st.session_state.messages.append(f"Question processed: {question[:20]}...")
# 우측 컬럼 (메시지 패널)
with col3:
st.header("Processing Messages")
# 메시지 표시 영역
messages_placeholder = st.container()
# 메시지 표시
with messages_placeholder:
for msg in st.session_state.messages[-10:]: # 최근 10개 메시지만 표시
st.info(f"• {msg}")
# 메시지 초기화 버튼
if st.button("Clear Messages"):
st.session_state.messages = []
st.experimental_rerun()
윤영기 (尹泳祺, YOON, Young-Ki)
younggiyoon@hotmail.com
newton@eqboard.com