diff --git a/docs/graph-rag-flow.md b/docs/graph-rag-flow.md new file mode 100644 index 000000000..dbd55b891 --- /dev/null +++ b/docs/graph-rag-flow.md @@ -0,0 +1,134 @@ +# GraphRAG Flow + +## [Step 1: Document - 데이터 수집] + +1. **Loader** + * **Goal**: 원본 데이터(공지사항, 게시글 등)를 시스템으로 로드 + * **Process**: + * site: 지웰홈스왕십리(1000024) + * board: 공지사항(1000039), FAQ(1000038), 입주안내(1000087) etc + * site의 board를 가져와서 Document/Image로 저장 + +2. **Vision (이미지 처리)** + * **Goal**: 이미지 내 텍스트를 추출하여 검색 및 답변에 활용 + * **Input**: Image URL + * **Process**: + * **Prompt**: + * 검색 / 답변 생성에 사용 가능한 구조화된 텍스트를 추출 + * raw text: 이미지의 모든 텍스트 추출 + * **Output**: OCR 또는 Vision Model을 사용하여 추출한 이미지의 모든 텍스트(Raw Text) + * 텍스트를 Image에 업데이트 (원본 보존) + +## [Step 2: Transform - 데이터 변환] + +1. **Build Document Content** + * **Strategy**: `MD2` (Markdown Conversion) + * **Process**: `Document` 및 `Image` 데이터를 그래프 구축에 적합한 Markdown 형식의 텍스트로 변환 + +## [Step 3: Graph Storage - 지식 그래프 구축] + +1. **Extract Nodes (Phase 1)** + * **Goal**: 5W1H(육하원칙)에 따라 엔티티를 추출하고 분류 + * **Prompt Rules**: + * **Language**: 한국어(Korean) 필수 + * **Entity Types (14 types)**: + * **Who**: `ACTOR` (행위자), `AUTHOR` (작성자) + * **What**: `OBJECT` (대상), `EVENT` (사건), `IMAGE` (이미지), `WEB` (웹사이트), `CATEGORY` (카테고리) + * **How**: `PROCEDURE` (절차) + * **Why**: `CONDITION` (조건) + * **Where**: `LOCATION` (위치) + * **When**: `DATETIME` (날짜/시간), `YEAR`, `MONTH`, `DAY` + * **Attributes**: + * `type`: 엔티티 유형 + * `context`: 엔티티가 포함된 문맥 + * **Output**: Entity Nodes + +2. **Normalize Nodes** + * **Goal**: Entity Nodes의 정규화 + * **Rules**: + * **Surfcae match** (텍스트 표면 일치 및 맥락 유사도 검사) + * `base score`: `SequenceMatcher`를 통해 이름(name)이 형태적으로 얼마나 유사한지 측정 (70% 비중) + * `타입 검증 (Strict Filter)`: 이름 유사도가 높더라도 Type(Labels)이 다르면 서로 다른 존재로 간주함 (base score * 0.3) + * `맥락 보정(Context Boost)`: `SequenceMatcher`를 통해 노드의 context가 형태적으로 얼마나 유사한지 측정 (feature_match_score) (70% 비중) + * **DBSCAN** (Density-Based Spatial Clustering Of Applications With Noise) + * 밀도 기반 군집화: 계산된 유사도 score로 데이터 중심의 군집화 수행 + * 거리 변환 (Distance Metric): $Distance = 1 - Similarity\_Score$ + * 자동 군집화: 임계값(0.75) 이내의 밀도를 가진 노드들을 하나의 그룹으로 모음 + + * **Canonicalization (대표성 추출 및 병합)** + * 그룹화된 Entity들을 하나의 `Node`로 재구성 + * 대표 이름 결정: 군집 내에서 가장 빈번하게 등장한 이름을 엔티티의 공식 명칭(Canonical Name)으로 선택 + * 데이터 통합: 속성(attributes)과 특징(features) 데이터에서 중복을 제거한 뒤 하나로 구성 + * **Output**: Normalized Entity Nodes + +3. **Extract Edges (Phase 2)** + * **Goal**: 엔티티 간 인과관계 및 시간적 계층 구조 설정 (BFS 최적화) + * **Prompt Rules**: + * **Language**: 한국어(Korean) 필수 + * **Hub Node Strategy**: + * **Temporal Hub**: 주요 노드(OBJECT, EVENT) -> DATETIME 연결 + * **Hierarchy**: DATETIME -> DAY -> MONTH -> YEAR 연결 + * **Edge Types**: + * `EXECUTED_BY`: (Procedure/Event/Object) -> (Actor/Author) + * `SCHEDULED_ON`: (Any) -> (Datetime) + * `PART_OF`: (Datetime/Day/Month) -> (Day/Month/Year) + * `DEPENDS_ON`: (Object/Procedure) -> (Condition/Datetime) + * `TRIGGERS`: (Event) -> (Procedure/Event) + * `LOCATED_IN`: (Any) -> (Location) + * `HAS_DETAIL`: (Object) -> (Image/Web/Category) + * **Output**: Entity Edges + +4. **Summarize Nodes (Phase 3)** + * **Goal**: 검색 품질(BM25) 향상을 위한 노드 요약 및 키워드 추출 + * **Process**: + * **Prompt Rules**: + * **Language**: 한국어(Korean) 필수 + * LLM을 활용하여 Vision 텍스트를 포함하여 중요 키워드 추출 + * LLM을 활용하여 노드 관련 내용을 요약 + * **Output**: Attributes와 Summary가 포함된 최종 Entity Nodes + +5. **Add Episode (저장)** + * **Goal**: 그래프 데이터와 원본 데이터를 통합 저장 + * **Structure**: + * **Group ID**: `site-{siteId}-{strategy}` + * **Episode Body**: 원본 텍스트(Markdown) 및 Vision 추출 텍스트 보존 (답변 생성의 근거) + * **Graph**: 추출된 Node 및 Edge 저장 + +## [Step 4: Graph RAG - 검색 및 답변 생성] + +1. **Query Rewrite** + * **Goal**: 질문 재작성 + * **Prompt Rules**: + * 질문을 검색 및 답변에 용이한 완전한 문장으로 작성 + * **Output**: 재작성된 질문 텍스트 + +2. **Graph Retrieve (Fused Search)** + * **Strategy**: Text(BM25) + Vector + Graph(BFS) 결합 + * **Flow**: + * a. **BM25 Search (Text)**: 키워드 기반 노드 검색 (Weight: 02) + * b. **Vector Search (Embedding)**: 의미 기반 노드 검색 (Weight: 04) + * c. **BFS Expansion (Graph)**: Vector 검색 상위 노드를 Seed로 하여 연결된 노드(날짜, 상세 정보 등) 확장 (Weight: 04) + * d. **Fusion**: RRF(Reciprocal Rank Fusion) 방식으로 최종 순위 결정 및 상위 N개 노드 도출 + +3. **Prompt Construction** + * **Components**: + * **System Prompt**: 페르소나 및 답변 규칙 + * **User Prompt**: + * quesiton: Original Query (사용자 질문) + * nodes: Retrieved Nodes (그래프 맥락) + * documents: Episode Body (원본 문서 및 Vision 텍스트) + +4. **Generate Response** + * **Process**: LLM이 구성된 프롬프트를 바탕으로 사용자 질문에 대한 최종 답변 생성 + * **Output**: 생성된 최종 답변 + +--- + +## 요약 + +1. **저장 (Indexing)** + * `Document` -> `Loader`/`Vision` -> `Transform(MD2)` -> `Graph Extraction` -> `Storage (Graph + Episode)` +2. **검색 (Retrieval)** + * `Query` -> `Rewrite` -> `Fused Search (BM25 + Vector + BFS)` -> `Context Construction` +3. **생성 (Generation)** + * `Context` + `Query` -> `LLM` -> `Answer` diff --git a/docs/graph-rag.md b/docs/graph-rag.md new file mode 100644 index 000000000..f624123b6 --- /dev/null +++ b/docs/graph-rag.md @@ -0,0 +1,231 @@ +# Graph RAG Experiment + +## 1. 목적 + +기존 RAG의 한계를 개선하는 것을 목표로 Graphiti 기반의 Graph RAG 구조를 적용하여, Knowledge Graph가 검색 품질과 문맥 향상에 미치는 영향을 검증한다. + +구체적으로 다음을 확인한다. + +1. Graph RAG 적용에 따른 연관 문서 검색 정확도 +2. 엔티티 관계 기반 탐색을 활용한 복합 질의 처리 성능 +3. 필터링 적용한 검색으로 단지 및 날짜별 정확도 + +이 과정을 통해, Graph 기반 검색 구조가 기존 벡터 기반 RAG의 구조적 한계를 넘어 높은 연관성의 문서 검색이 가능하다는 것을 검토한다. + +--- + +## 2. 배경 + +### 2.1 기존 응답 사례 분석 + +* 문서 간 관계나 시점 정보를 인식하지 못함 +* 단순 벡터 유사도에 의존한 검색 → 부정확한 맥락 + 불필요한 정보 포함 + +| 질의 내용 | 검색 결과 | 실제 응답 | 기대 응답 | 주요 문제점 | +| -------------------- | ------------------------------------------- | ----------------- | ----------------------- | -------------------------------------------------- | +| 이번 7월 가정식 메뉴 알려줘 | '2024년 7월'로 질문 재작성됨 → 2025년 7월 가정식 메뉴 문서 검색 | 2025년 메뉴 내용 출력 | 2025년 7월 가정식 메뉴 | **재작성 오류 + 검색 시점 인식 실패의 복합 오류**. 내부 과정의 **시점 불일치** | +| 라운지 시설 어떻게 이용할 수 있어? | ‘냉장/냉동고 정리안내’, ‘라운지 이용 설문조사’ 문서 검색 | 냉장고 정리 및 설문 관련 내용 | ‘라운지 시설은 예약제로 이용 가능하다.’ | 관련 문서가 없음에도 **유사도 스코어 기반으로 비관련 문서 선택** | + +### 2.2 문제 유형 + +| 유형 | 원인 | 영향 | +| --------- | ---------------- | ---------------- | +| 시점 인식 오류 | 날짜·기간 메타정보 반영 부족 | 잘못된 연도·기간의 응답 생성 | +| 비관련 문서 선택 | 유사도 점수 기반 검색 | 질문 의도와 무관한 응답 생성 | + +--- + +## 3. 실험 환경 + +### 3.1 모델 설정 + +* 임베딩: `text-embedding-3-small` +* LLM: `gpt-5-mini` + + * Entity 추출 및 Edge 생성, 응답 생성 + +### 3.2 검색 및 랭킹 (Updated) + +기존의 “Doc Entry Node → Graph 확장” 중심에서, **Fused Search + Graph(BFS) 확장** 중심으로 변경됨. + +* **Text 검색 (BM25)** + +* **Vector 검색 (Cosine Similarity)** + +* **Graph 검색 (BFS, multi-hop)** + + * Vector 결과 상위 N개를 origin으로 잡고 + * `NodeSearchMethod.bfs`, `bfs_max_depth = N`로 확장 + +* **Fusion(RRF 스타일 가중 합산)** + + * text: `0.2` + * vector: `0.4` + * graph: `0.4` + * 각 소스별 랭크에 대해 `1/(rank+1) * weight`로 점수 누적 후 최종 정렬 + +> 결과적으로, “의미 기반(벡터) + 정확 키워드(BM25) + 관계 기반(BFS)”를 한 번에 결합해 **비관련 문서의 비중을 낮추고 관련 문서의 비중을 높게**한다. + +### 3.3 데이터 저장 (Episodes) + +* Group: `site:{site_id}` +* 각 Episode는 Markdown 포맷으로 변환되 텍스트를 **episode_body로 저장** +* LLM이 원문으로부터 엔티티를 추출하여 Graph로 구조화 + +### 3.4 Entity / Edge 스키마 (Updated) + +#### Entity Types + +* **Who(주체/작성)** + + * `Actor`(부서/기관/업체 등 행위 주체) + * `Author`(개인 작성자) +* **What(대상)** + + * `Object`(공지/문서/자산/식단/메뉴 등 핵심 대상) +* **How(절차)** + + * `Procedure`(신청/업무 단계/지침) +* **Why(근거/조건)** + + * `Condition`(규정/자격/법령) +* **Event(사건/행사)** + + * `Event` +* **Where(장소)** + + * `Location` +* **When(시간 계층)** + + * `Datetime`(정규화된 시점) + * `Year`, `Month`, `Week`, `Day`(시간 계층 노드) +* **기타** + + * `Concept`(전문 용어/도메인 지식) + * `Image`(첨부 이미지) + * `Web`(외부 링크) + * `Category`(게시판/분류) + +#### Edge Types + +* `EXECUTED_BY` : 작성자/실행 주체 연결 (Who) +* `SCHEDULED_ON` : 특정 시점 할당 (When) +* `PART_OF` : 시간 계층 구성 (Datetime–Day–Month–Year 등) +* `DEPENDS_ON` : 조건/근거 참조 (Why) +* `TRIGGERS` : 인과/유발 관계 (Event 중심) +* `LOCATED_IN` : 장소 연결 (Where) +* `HAS_DETAIL` : 이미지/링크/카테고리/컨셉 등 상세 연결 (Metadata) + +#### Edge Type Mapping(규칙 기반 연결) + +엔티티 조합별 허용 엣지를 제한하여 **잘못된 엣지 생성/확장을 방지**하고, multi-hop 추론을 안정화한다. + +예시: + +* (`Object` → `Author`) = `EXECUTED_BY` +* (`Object` → `Datetime`) = `SCHEDULED_ON` +* (`Datetime` → `Day`) = `PART_OF` +* (`Object` → `Image/Web/Concept/Category`) = `HAS_DETAIL` +* (`Object/Procedure` → `Condition`) = `DEPENDS_ON` + +### 3.5 선택 이유 (Updated) + +| 항목 | 설명 | +| -------------------------------------------- | -------------------------------------------------------------- | +| **Episode Body 원본 유지** | Node/Edge는 요약/속성 중심이므로, 최종 답변 근거는 원본(episode_body)이 가장 신뢰도가 높음 | +| **도메인 엔티티 확장(Object/Procedure/Condition 등)** | “누가/무엇을/어떻게/왜/언제/어디서” 질의에 구조적으로 대응 | +| **시간 계층(Year/Month/Week/Day) + Datetime** | “이번 7월”, “올해”, “3월 2주차” 같은 기간 질의를 계층적으로 필터/확장 가능 | +| **HAS_DETAIL로 메타 통합** | 이미지/링크/카테고리/컨셉을 하나의 패턴으로 연결해 확장/근거 제시에 유리 | +| **Fused Search(BM25+Vector+BFS)** | 유사도만으로 비관련 문서가 섞이는 문제를 완화하고, 관계 기반으로 재확장하여 맥락 일관성 강화 | +| **Community 요약 제공** | “테마/군집” 단위의 상위 요약을 함께 제공해 탐색성과 설명력 개선 | + +--- + +## 4. 데이터 저장 (Episodes) + +### 4.1 전체 구조 (Updated Concept) + +``` +Group (site:{site_id}) +└─ Episodic (episode_body = 원문) + └─ Extracted Entities + ├─ Object / Procedure / Condition / Event ... + ├─ Author / Actor + ├─ Datetime ─ PART_OF ─ Day ─ PART_OF ─ Month ─ PART_OF ─ Year + ├─ Location + └─ Image / Web / Concept / Category +``` + +### 4.2 Entity / Edge 예시 (Updated) + +| Entity | 의미 | 예시(Name) | +| ---------- | --------- | ---------------------------- | +| `Object` | 공지/문서/대상 | Object:관리비 납부마감안내 | +| `Author` | 작성자(개인) | Author:홍길동(생활지원센터) | +| `Actor` | 주체(부서/기관) | Actor:생활지원센터 | +| `Datetime` | 시점 | Datetime:2025-03-31 00:00:00 | +| `Month` | 월 | Month:3 | +| `Year` | 연도 | Year:2025 | +| `Category` | 분류 | Category:공지사항 | +| `Web` | 링크 | Web:/post/1000001/... | +| `Image` | 이미지 | Image:PT1000001:1000020 | + +| Edge | 의미 | +| ---------------------------------------------------- | ----------- | +| `Object -[:EXECUTED_BY]-> Author/Actor` | 작성자/주체 연결 | +| `Object -[:SCHEDULED_ON]-> Datetime` | 문서 시점 연결 | +| `Datetime -[:PART_OF]-> Day/Month/Year` | 시간 계층 구성 | +| `Object -[:HAS_DETAIL]-> Image/Web/Category/Concept` | 상세/메타 연결 | +| `Object/Procedure -[:DEPENDS_ON]-> Condition` | 규정/조건 근거 | +| `Event -[:TRIGGERS]-> Procedure/Event` | 사건 기반 유발 관계 | +| `Object/Event -[:LOCATED_IN]-> Location` | 장소 연결 | + +--- + +## 5. 검색 Flow (Updated) + +### 5.1 전체 흐름 + +``` +질문 + → BM25(Text) Node 검색 + → Vector(Cosine) Node 검색 (min_score=0.6) + → Vector seed 기반 BFS(Graph) 확장 (depth=2) + → Fusion(가중 RRF) + → 상위 N개 노드 반환 + → (선택) episode_body 원문 로딩 후 LLM 응답 생성 +``` + +### 5.2 Fused Search 세부 (search-fused) + +* 입력: `query`, `group_ids`, `max_nodes` +* 병렬: + + * Text nodes(BM25) + * Vector nodes(Cosine) +* Graph 확장: + + * Vector nodes 상위 N개 uuid를 seed로 BFS 탐색(depth=2) +* Fusion: + + * text 0.2 / vector 0.4 / graph 0.4 + * 각 소스별 랭킹 점수 누적 후 최종 정렬 +* 출력: + + * `nodes`: 최종 상위 N개 + * `facts`: 현재 미사용(None) + +--- + +## 6. 검증 포인트 (Updated) + +* 관련 노드(문서/대상) 검색 정확도 (BM25 vs Vector vs Fusion 비교) +* 복합 질의(규정/절차/시점/주체)에서 BFS 확장 효과 +* 기간 질의(올해/이번 달/몇 주차)에서 시간 계층(PART_OF) 활용 가능성 +* 카테고리/링크/이미지 등 메타 근거(HAS_DETAIL) 연결 품질 + +--- + +## 7. 결과 + +공지·게시판 검색에서는 단순 문서 유사도 기반 검색보다 **(1) 도메인 엔티티 구조화(Object/Procedure/Condition 등), (2) 시간 계층 모델링(Year/Month/Week/Day + Datetime), (3) BM25+Vector+BFS를 결합한 Fused Search**가 더 정확하고 일관된 응답을 제공한다.