Understanding RAG Before Applying It to ERP Systems
Beginning
최근 회사 ERP 솔루션에서 LLM을 활용해 번역, CHATBOT, RAG를 통합 지원하는 AI 서비스를 제공하고자 하며 ERP 내부 DB 정보는 LLM이 알 수 없기 때문에 RAG 기반 검색 서비스를 도입하여 정확한 최신 답변을 제공하려 합니다.
이번 프로젝트를 진행하며 공부하고 적용한 내용을 정리하고자 합니다.
Index
RAG (Retrieval-Augmented Generation)
- Issue : LLM은 훈련 데이터 이후의 최신 정보나 회사 특화 지식을 항상 알지 못한다
- Solution : RAG(LLM이 알지 못하는 정보를 외부지식 저장소에서 실시간으로 검색해 LLM에게 제공) → 응답에 근거하여 답변 생성
Conecption
- RAG는 검색(retrieval) 과 생성(generation) 을 결합해 특정 도메인 지식을 LLM 답변에 반영하는 패턴 → LLM + 검색 기반 정보 보강
- LLM은 학습하지 않은 최신 정보나 도메인 특화 지식에 취약 → 외부 문서/DB 검색 후 동적으로 참조하여 정보 보강 후 답변 생성
- 단순 LLM 호출보다 신뢰성과 정확성 향상
- 사용시 이점 : 최신성 확보, 모델 재학습 불필요, 정확도 향상
Process
- Document Loader → Preprocessing → Chunking → Embeddings → Vector DB → Retriever+QA
Document Loader (Data → Document)
- 다양한 형태의 데이터(Markdown, PDF, HTML, DB)를 Document(text + metadata) 표준으로 통일 및 전달
- 모든 Document에 일관된 metadata(source, path, sha256, last_modified, doc_type) 필요
- 원본의 section/header/table/code 같은 구조 정보를 최대한 보존
- 데이터에 맞는 적절한 Loader 선택 필요
- PDF/HTML는 단순 텍스트 추출할 경우 섹션 구조, 표, 캡션 정보가 유실될 수 있음
Library/Usage
- langchain.document_loaders, TextLoader, MarkdownLoader, PyPDFLoader: LangChain 생태계 내 통합 Loader
- unstructured: 복잡한 PDF/문서 레이아웃 추출
- pdfplumber, PyMuPDF(fitz): 정밀 PDF 텍스트/테이블 추출
- BeautifulSoup, lxml`: HTML 파싱/클린징
- pymssql, psycopg2, mysql-connector-python, sqlalchemy: DB → 텍스트
- python-frontmatter`: Markdown front-matter 파싱
Preprocessing
- Dcoument Loader가 만든 Document 객체의 page_content를 Embedding에 적합한 포맷으로 정리
- 텍스트 정규화(줄바꿈, 공백, 인코딩) → HTML 태그 제거 → PII 탐지·마스킹
Library/Usage
- 기본 정규화: re, html
- HTML 클린징: BeautifulSoup, bleach
- NER/전처리: spaCy, NLTK, stanza
- PII 탐지/익명화: presidio
- 테스트용 더미 데이터: Faker
Chunking / Tokenization
- 문서를 LLM Context(Token) 한계에 맞는 검색 단위(Chunk)로 분해
- Chunk : 기본 단위(Token 기준 지향 / 문자 수 지양)
- tiktoken을 Token 수를 계산 해서 적당한 Chunk Size 및 Chunk Overlap 지정
- Overlap : Chunk의 10% 권장(문맥 유실 완화용)
- 각 청크에 meta를 남긴다
- Chunk Meta : chunk_id, start_offset, end_offset, parent_section
- 섹션 헤더 우선 분할 → 섹션 내 토큰 분할
Library/Usage
- tiktoken: 모델별 Tokenizer(정확한 토큰 수 계산)
- langchain.text_splitter.RecursiveCharacterTextSplitter: 빠른 Prototype
- spaCy, nltk.sent_tokenize: 문장 경계 보조
Embeddings (모델)
- 각 Chunk를 고차원 Vector로 변환하여 의미 기반 검색(semantic search) 지원
- Query와 Chunk 간 유사도 계산의 기초
Library/Usage
- OpenAIEmbeddings (langchain_openai): 관리형(품질 편의성)
- sentence-transformers (Hugging Face): 로컬/GPU 실행(프라이버시/비용절감)
- Cohere, Anthropic 등: 대체 상용 제공자
- tenacity/backoff: 안정적인 재시도 구현
Vector DB (검색 인덱스)
목적
- Embedding Vector와 Meta를 저장/인덱싱해 빠른 ANN 검색 제공
- 검색 결과와 함께 원문 및 META를 LLM에 제공
Library/Usage
- FAISS: 로컬/POC용(단일 머신)
- Chroma: 로컬 친화적 벡터 스토어
- Qdrant: 페이로드 관리가 쉽고 프로덕션에 적합
- Milvus, Weaviate: 분산/대규모 환경
- Pinecone: 매니지드 서비스
Retriever + QA Chain(LLM)
목적
- 쿼리를 임베딩 → vector DB에서 후보 검색 → LLM Chain에 문맥 전달 → 답 생성 + 출처 포함 반환
- 어떻게 검색결과를 정제하고 LLM에 주느냐가 최종 신뢰도/정확도를 결정
Library/Usage
- langchain: RetrievalQA, load_qa_chain, PromptTemplate 등 체인 구성
- LlamaIndex (GPT Index): 인덱스·질의 고수준 도구(대체/보완)
- Haystack: 엔터프라이즈 파이프라인(리트리버+리더)
- sentence-transformers.CrossEncoder: re-ranker
- LLM: OpenAI, Anthropic, Llama 등
Chain Type
- stuff: 모든 문맥을 LLM에 넣어 처리(단순하지만 토큰·비용 이슈)
- map_reduce: 문서별 요약 → 합성(긴 컨텍스트에 유리)
- refine: 초안 응답을 반복 보완
Initial Tech Stack
- Backend/Frontend : FastAPI(Python) & React
- WAS: Uvicorn
- WebServer: Nginx
- DevOps: Docker(FastAPI, Nginx Container)
- Python Framework: LangChain
- DB Format: Markdown, VectorDB
- LLM: ChatGPT-4
- MCP: Translator, RAG, Chatbot 통합 제공