📜AI 서비스/Tool 시리즈
  • 돌아가기
  • 아래로
  • 위로
  • 목록
  • 댓글
프로필 보기 [레벨:15]diamondbigworker128

RAG 서비스 소개

잡담 조회 수 350 댓글 3 3 복사 복사

RAG (Retrievel Augmented Generation)
사내 정보시스템으로 LLM 과 조합됩니다.
사내에 있는 수천~수만개의 pdf, xls, doc, ppt 등의 문서파일에서 '답변' 을 추출해줍니다.

 

현재 기본 얼개는 갖춰졌는데, 하드웨어가 좀 받쳐줘야 합니다.
하지만 고가의 gpu 까지는 필요없고 맥미니 M4 32GB 정도면 필요충분합니다.

RAG 에서 부하가 크게 걸리는 부위는 아래와 같습니다

** Ingestion 단계 (문서를 vector 화하는 작업)
  -- Marker 모듈 (여기서 문서 레이아웃 분석 & OCR 작업을 all-in-one 으로 해줍니다)
    ## cpu 로는 20page 문서 하나 작업에 8 vcpu 준 상태에서 2시간 넘게 걸립니다
  -- Figure/Image/Schematic 인식 & 캡션 : cpu 로는 불가능하다 보심 됩니다.
  -- GraphRAG : 각 문장, 키워들간에 '관계' 를 추출해서 별도로 저장합니다. cpu 로 불가

** Search 단계 (사용자의 query 를 바탕으로 vector / graph db 에서 검색후 답변 생성)
  -- HyDE : 사용자의 '모호한 query' 를 LLM 을 통해 가상답변을 만들고 이를 검색 query 로 활용하여 답변품질 up
  -- 답변생성 : 12B 급 모델정도면 기본적인 reasoning 은 됩니다. (cpu 로 돌리는 4B 급 에서도 기본논리는 갖춰주더라구요)
  -- SelfRAG : 사용자의 최초 query 와 위의 '답변' 을 비교후 제대로 된 답변인지 2차 검토 (by LLM)

위 과정들을 보시면 아시겠지만 DL 모델들 범벅, LLM 범벅입니다.

구축하실분들 참조하실 수 있게 guide MD 문서 2개 올립니다.

<< guide_ingestion.md >>

 

# Ingestion Pipeline Guide

본 문서는 문서(PDF, Office 등)가 시스템에 업로드되어 벡터 데이터베이스(Qdrant)에 저장되기까지의 **Ingestion(데이터 적재)** 과정을 상세 기술합니다.

## 1. 기술 스택 및 라이브러리 (Technologies)

각 기술의 선정 이유와 장단점은 다음과 같습니다.

| 기술/라이브러리 | 사용 목적 | 장점 | 단점 |
| :--- | :--- | :--- | :--- |
| **PyMuPDF (fitz)** | PDF 기본 파싱, 이미지 렌더링 | 속도가 매우 빠르고 가벼움. | 복잡한 레이아웃(다단, 표) 인식에 한계가 있음. |
| **Marker** | PDF 레이아웃 분석 및 OCR | Suraya/Tesseract 등을 통합하여 정확한 레이아웃 분석 및 수식/코드 감지 우수. | 처리가 무겁고 시간이 오래 걸림 (GPU 권장). |
| **GMFT (Griffin's Magic Format Tool)** | PDF 내 테이블 감지 및 포맷팅 | PyPDFium2 기반으로 테이블을 감지하고 Markdown/CSV로 변환하는 성능이 우수함. | 완벽하지 않으며, 광학적 인식이 아닌 구조적 인식에 의존할 때가 있음. |
| **LangChain (Text Splitters)** | 텍스트 청킹 (Parent-Child) | RecursiveCharacterTextSplitter 등 검증된 분할 알고리즘 제공. | - |
| **FastEmbed / Ollama** | 임베딩 벡터 생성 | 로컬(FastEmbed)은 빠르고 가볍음. Ollama는 고성능 모델 사용 가능. | 로컬 모델은 한국어 성능이 다소 떨어질 수 있음. |
| **Qdrant** | 벡터 데이터베이스 | 고성능, 필터링 기능 강력, Rust 기반 안정성. | 설정 및 운영이 필요함 (Docker). |
| **Redis** | 작업 상태 관리 및 중복 방지 | 인메모리 키-값 저장소로 빠른 상태 조회 및 락(Lock) 관리. | 데이터 영속성 설정이 없으면 재부팅 시 데이터 유실 가능. |
| **Celery** | 비동기 작업 큐 | 긴 Ingestion 작업을 백그라운드에서 안정적으로 처리. | 브로커(Redis/RabbitMQ) 필요, 설정 복잡. |

## 2. 서브 모듈 및 역할 (Sub-modules)

특정 상황에서 사용되는 주요 모듈 설명입니다.

*   **`app/api/endpoints/ingest.py`**: Ingestion API 엔드포인트. 파일 업로드 수신, 해시 중복 체크, Celery 태스크 생성 및 작업 상태 조회(Polling)를 담당합니다.
*   **`app/services/pdf_processor.py`**: **핵심 모듈**. Marker와 GMFT를 사용하여 PDF를 심층 분석하고, 텍스트/표/이미지를 추출한 뒤 Parent-Child 전략으로 청킹합니다.
*   **`app/services/office_processor.py`**: Office 문서(docx, pptx 등)가 들어올 경우 PDF로 변환하여 `pdf_processor`로 넘겨주는 전처리 역할을 합니다.
*   **`app/services/translation_service.py`**: 다국어 처리를 담당. 한국어 텍스트가 들어오면 검색 정확도를 위해 영어로 번역(Search용)하고, 원본(Context용)은 유지합니다.

## 3. Ingestion 파이프라인 상세 (Pipeline Detail)

전체 과정은 **비동기(Async)**로 처리되며, 사용자는 `task_id`를 통해 진행률을 확인합니다.

1.  **Validaton & Hashing (동기)**
    *   파일 업로드 시 MD5 해시를 계산합니다.
    *   Redis `completed_hashes``processing_hashes`를 확인하여 중복/진행 중 파일을 차단합니다.
    *   파일을 `UPLOAD_DIR`에 저장하고 Celery Task를 시작합니다.

2.  **PDF Analysis & Extraction (비동기 - Marker)**
    *   **도구**: Marker Pipeline (별도 프로세스 실행)
    *   **Layout Analysis**: 문서의 구조(헤더, 푸터, 본문, 다단 등)를 분석합니다.
    *   **OCR**: 텍스트 레이어가 없는 이미지형 PDF의 경우 OCR을 수행합니다.
    *   **Element Extraction**:
        *   **Text**: 일반 텍스트 블록 추출.
        *   **Table**: GMFT를 사용하여 테이블 감지 -> Markdown 변환.
        *   **Figure**: 이미지를 추출하여 `static/images`에 저장하고 캡션을 찾습니다.

3.  **Chunking (Parent-Child Strategy)**
    *   검색 정확도(작은 청크)와 문맥 이해(큰 청크)를 동시에 잡기 위해 **Parent-Child Splitting**을 사용합니다.
    *   **Parent Chunk**: 약 1800 토큰. LLM에게 제공되는 문맥(Context) 단위.
    *   **Child Chunk**: 약 400 토큰. 벡터 검색(Embedding)의 대상 단위.
    *   **Special Chunk**: Table과 Figure는 그 자체로 Parent이자 Child가 됩니다.

4.  **Translation (Optional)**
    *   `detect_language` 수행.
    *   한국어일 경우:
        *   **Child Text** -> 영어로 번역 (벡터 검색 매칭률 향상 목적).
        *   **Parent Text** -> 영어로 번역 (선택적, LLM 이해도 향상 목적).

5.  **Embedding & Storage**
    *   번역된 Child Text를 임베딩 모델(Local/Ollama)을 통해 벡터화합니다.
    *   Qdrant에 데이터(Payload)와 벡터를 업로드(Upsert)합니다.

## 4. 임베딩 및 저장 구조 (Embedding & Storage Structure)

### Embedding Process
*   **Target**: `child_text_en` (번역된 Child Chunk 텍스트)
*   **Model**: 설정에 따라 Local(HuggingFace) 또는 Ollama API 사용.
*   **Normalization**: 벡터는 L2 정규화(Normalize)되어 저장(Cosine Distance 사용 최적화).

### Qdrant Data Structure (Payload)
Qdrant의 Point는 다음과 같은 Payload 구조를 가집니다.

```json
{
  "chunk_id": "filename_p1_parent_0_child_0",  // 유니크 ID
  "parent_id": "filename_p1_parent_0",         // 부모 청크 ID (Context 그룹핑용)
 
  "text": "...",              // [원본] Child Text (한국어 등)
  "text_en": "...",           // [번역] Child Text (검색용, 영어)
  "text_ko": "...",           // [소나기] Keyword 검색용 필드
 
  "parent_text": "...",       // [원본] Parent Text (LLM Context용)
  "parent_text_en": "...",    // [번역] Parent Text
 
  "filename": "guide.pdf",    // 출처 파일명
  "page": 1,                  // 페이지 번호 (0-based)
  "type": "text",             // text | table | figure
 
  "image_path": "/static/...", // type=figure일 경우 이미지 경로
  "image_caption": "..."       // type=figure일 경우 캡션
}
```

## 5. 특수 데이터 처리 (Table & Image)

### Table (표)
*   **감지**: Marker 혹은 GMFT(Griffin's Magic Format Tool)가 PDF 내 표 영역을 감지합니다.
*   **처리**: 감지된 표는 `Pandas DataFrame`을 거쳐 **Markdown Format** 텍스트로 변환됩니다.
*   **저장**: `type: "table"`로 저장되며, Markdown 텍스트 자체가 `text` 필드에 들어갑니다. 이렇게 하면 LLM이 표 구조를 텍스트로 이해할 수 있습니다.

### Figure/Image (이미지)
*   **감지**: Marker Layout Analysis가 그림/도표 영역을 식별합니다.
*   **추출**: 해당 영역을 이미지 파일(.png)로 크롭하여 서버의 `static/images/{filename}/` 폴더에 저장합니다.
*   **Captioning**: 이미지 주변의 텍스트(예: "Fig 1. Architecture")를 Regex 및 거리 기반으로 탐색하여 캡션으로 연결합니다.
*   **저장**: `type: "figure"`로 저장됩니다.
    *   `image_path`: 웹 접근 가능한 이미지 URL.
    *   `text`: "Figure/Image: {caption}" 형태의 대체 텍스트.

 

 


<< guide_rag_search.md >>

 

# RAG Search Pipeline Guide

본 문서는 사용자의 질문(Query)을 받아 벡터 데이터베이스에서 관련 정보를 검색하고, LLM을 통해 최종 답변을 생성하는 **RAG(Retrieval-Augmented Generation) Search** 과정을 상세 기술합니다.

## 1. 기술 스택 및 라이브러리 (Technologies)

각 기술의 선정 이유와 장단점은 다음과 같습니다.

| 기술/라이브러리 | 사용 목적 | 장점 | 단점 |
| :--- | :--- | :--- | :--- |
| **Hybrid Search (Dense + Sparse)** | 검색 정확도 향상 | 의미 기반(Dense) 검색과 키워드(BM25/Sparse) 검색을 결합하여 다양한 쿼리 유형에 대응. | 두 가지 검색 로직을 모두 구현해야 하므로 복잡도 증가. |
| **Cross-Encoder (Reranker)** | 검색 결과 재정렬 | Bi-Encoder보다 훨씬 높은 정확도로 문맥적 관련성을 평가. | 계산 비용이 비싸(느림) 전체 검색 대상에 적용 불가 (Top-N 재정렬용). |
| **RRF (Reciprocal Rank Fusion)** | 검색 결과 병합 | 서로 다른 점수 체계(Cosine Similarity vs BM25)를 가진 검색 결과를 공정하게 합침. | K값 튜닝 필요. |
| **Ollama (LLM)** | 답변 생성 및 번역 | 로컬에서 대규모 언어 모델(LLaMA 3, Mistral 등)을 쉽게 구동. | GPU 메모리 요구량이 큼. |
| **FastAPI StreamingResponse** | 실시간 응답 | 긴 생성 과정을 단계별(Status -> Result)로 스트리밍하여 UX 개선. | 클라이언트 측에서 NDJSON 파싱 필요. |

## 2. 서브 모듈 및 역할 (Sub-modules)

특정 상황에서 사용되는 주요 모듈 설명입니다.

*   **`app/api/endpoints/search.py`**: **핵심 모듈**. 검색 요청 처리, 파이프라인 제어, Reranking, 프롬프트 조립, LLM 호출 등RAG의 전 과정을 주관합니다.
*   **`app/services/translation_service.py`**:
    *   **Query Translation**: 한국어 질문이 들어오면 영어로 번역하여 영문 문서(Dense Index) 검색에 활용합니다.
    *   **Answer Translation**: 영문 LLM이 생성한 답변을 최종적으로 한국어로 번역하여 사용자에게 제공합니다.
*   **`app/domain_glossary.json`**: 도메인 특화 용어집. 번역 과정에서 기술 용어가 잘못 번역되는 것을 방지합니다.

## 3. RAG Search 파이프라인 상세 (Pipeline Detail)

검색 과정은 **스트리밍(Streaming)**으로 처리되어 사용자가 각 단계의 진행 상황을 실시간으로 확인할 수 있습니다.

1.  **Language Detection & Translation**
    *   사용자 질문(`Query`)의 언어를 감지합니다.
    *   **한국어 질문**: 영어로 번역(`Query_EN`)하여 Dense Search에 사용하고, 원본(`Query_KO`)은 Keyword Search에 사용합니다.
    *   **영어 질문**: 그대로 사용합니다.

2.  **Hybrid Search (Dense + Sparse)**
    *   **Dense Search (Vector)**: `Query_EN`을 임베딩하여 Qdrant에서 코사인 유사도 기반으로 상위 50개 청크를 검색합니다. (의미적 유사성)
    *   **Keyword Search (BM25)**: `Query_KO`에서 명사/키워드를 추출하여 Qdrant의 `text_ko` 필드와 매칭합니다. (단어 일치)

3.  **Result Fusion (RRF)**
    *   Dense 결과와 Keyword 결과를 **Reciprocal Rank Fusion(RRF)** 알고리즘으로 병합합니다.
    *   공식: `Score = 1 / (k + rank)`
    *   두 검색에서 모두 상위권에 랭크된 문서가 더 높은 최종 점수를 받게 됩니다.

4.  **Reranking (Cross-Encoder)**
    *   통합된 상위 50개 후보군에 대해 **Cross-Encoder** 모델을 사용하여 정밀 재순위(Reranking)를 수행합니다.
    *   단순 유사도가 아닌, "이 문서가 이 질문에 대한 정답을 포함하고 있는가?"를 직접 추론합니다.

5.  **Context Assembly**
    *   Reranking된 상위 15개 청크를 선택합니다.
    *   **Parent Document Retrieval**: 검색된 청크(Child)의 `parent_id`를 사용하여 더 넓은 문맥(Parent)을 가져옵니다.
    *   토큰 제한(예: 20000 토큰) 내에서 Context를 조립합니다.
    *   **Figure Reference**: 이미지 청크가 포함될 경우 `[FIG:이미지 경로]` 태그를 삽입합니다.

6.  **Answer Generation (LLM)**
    *   **System Prompt**: "기술 문서 분석가" 페르소나를 부여하고, "Context에 없는 내용은 답변하지 말 것", "이미지를 참조할 것" 등의 제약 조건을 설정합니다.
    *   **User Prompt**: 조립된 Context와 Query를 LLM(Ollama)에 전달합니다.
    *   LLM이 답변(`Answer_EN`)을 생성합니다.

7.  **Finalization (Translation & Glossary)**
    *   `Answer_EN`을 한국어(`Answer_KO`)로 번역합니다.
    *   `domain_glossary.json`을 사용하여 도메인 용어를 표준화/교정합니다.
    *   최종 결과(답변, 근거 문서 목록, 이미지 경로 등)를 JSON 형태로 반환합니다.

## 4. Table, Figure, Image 표시 (Display Logic)

검색 결과에서 표와 이미지가 어떻게 처리되고 표시되는지에 대한 설명입니다.

### Table (표)
*   **Markdown Rendering**: 표 데이터는 Ingestion 시 Markdown Text로 변환되어 저장되었습니다.
*   **LLM 인식**: LLM은 Markdown 표를 텍스트로 인식하고 해석하여, 답변에 표의 내용을 자연스럽게 포함시키거나 재구성하여 설명합니다.
*   **UI 표시**: 근거 문서(Source) 탭에서 해당 청크를 클릭하면 원본 PDF 페이지를 통해 표의 원형을 확인할 수 있습니다.

### Figure/Image (이미지)
*   **Context 삽입**: 문맥 조립 시, 이미지 청크가 선택되면 텍스트 사이에 `[FIG:/static/images/filename.png]` 형태의 태그가 삽입됩니다.
*   **LLM 참조**: LLM은 이 태그를 인식하여 "그림 1을 참조하면..."과 같이 답변에 인용할 수 있습니다.
*   **UI 표시**:
    1.  **답변 내 이미지**: 답변 텍스트 내에 이미지 링크/태그가 있을 경우 렌더링됩니다.
    2.  **Source Chips**: 검색 결과 하단에 `[이미지 아이콘] 파일명 (p.5)` 형태의 칩으로 표시됩니다.
    3.  **Preview Modal**: 칩을 클릭하면 `image_path`에 저장된 원본 크롭 이미지가 모달 창으로 뜹니다.
*   **Page Rendering**: 텍스트 청크의 경우에도, 사용자가 원본을 보고 싶어할 때 `/documents/{filename}/pages/{page}` 엔드포인트를 통해 해당 PDF 페이지 전체를 이미지로 렌더링하여 보여줍니다.



3
신고 공유 스크랩
facebooktwitterpinterestbandkakao story

댓글

댓글 쓰기
profile image 프로필 보기
1등 [레벨:82]gold수라 26.02.20. 08:58댓글 주소 복사
이건 당연히 로컬 llm으로 구축한거 겟죠? 사내 문서들이면... 문서 중앙화랑 합쳐서 구축하면 좋을것 같긴 합니다.
댓글
프로필 보기
[레벨:15]diamondbigworker128 26.02.20. 09:07댓글 주소 복사
@ 수라
네 local llm 기반입니다.
직원이 많지는 않아서 문서중앙화 까지는 생각 못했구요.
댓글
프로필 보기
2등 [레벨:1]키륵키누 26.03.02. 16:58댓글 주소 복사
모델은 어떤것들 쓰셧을까요? 저도 하려고 하는데 컴맹이라 ㅎㅎ ollama+command_r+, llma vision 이렇게 쓰면되나요?
댓글

댓글 쓰기 권한이 없습니다.

취소 댓글 등록
목록
번호분류 제목 글쓴이날짜조회
공지 [안내] 개인 개발 및 AI(바이브코딩) 기반 앱 공개/사용 시 유의사항 1 [레벨:121]diamond달소 26.03.28.23:38 1,642
공지 새로운 'AI 서비스/Tool' 게시판 오픈 안내 9 [레벨:121]diamond달소 26.02.03.23:10 187
135 정보/가이드
normal
[레벨:45]platinumkmw_ 3일 전13:26 453
134 후기
image
[레벨:92]platinum빨간물약 4일 전23:07 565
133 잡담
image
[레벨:7]platinum월유향 5일 전11:31 475
132 잡담
normal
[레벨:121]diamond달소 26.06.07.10:24 279
131 잡담
normal
[레벨:10]컴장수 26.06.03.13:18 142
130 정보/가이드
image
[레벨:121]diamond달소 26.05.29.23:38 506
129 정보/가이드
normal
[레벨:40]diamond화정큐삼 26.05.29.12:37 1,027
128 잡담
image
[레벨:6]EasyDev 26.05.29.10:11 377
127 잡담
normal
[레벨:154]하늘위의하늘 26.05.26.12:34 360
126 뉴스
image
[레벨:121]diamond달소 26.05.25.00:36 193
125 정보/가이드
image
[레벨:121]diamond달소 26.05.24.15:07 389
124 잡담
image
[레벨:7]나의님프로 26.05.23.23:25 286
123 잡담
normal
[레벨:7]멀티 26.05.22.15:41 320
122 잡담
image
[레벨:10]종다리 26.05.21.22:42 492
121 정보/가이드
image
[레벨:92]platinum빨간물약 26.05.20.15:16 2,286
120 잡담
image
[레벨:6]EasyDev 26.05.19.20:22 520
119 잡담
normal
[레벨:5]Breeder 26.05.19.11:12 200
118
image
[레벨:121]diamond달소 26.05.18.22:07 436
117 잡담
image
[레벨:6]njsc 26.05.17.03:43 297
116 잡담
normal
[레벨:16]자우루스 26.05.15.08:06 280