Hybrid KMS · 설계 사상

Hybrid KMS 설계 사상

단일 PostgreSQL 위에서 pgvector(의미 검색)Apache AGE(지식 그래프)를 동시에 운용하고, 문서 수집 시 통제된 온톨로지를 만들며, 검색 시 벡터 + 그래프를 융합(HybridRAG)하여 문서를 더 잘 찾는 지식관리 시스템의 기술 사상입니다.

버전 0.2.1 PostgreSQL · pgvector · Apache AGE HybridRAG / GraphRAG SQL = Source of Truth

목차

설계 문서의 핵심 축을 한눈에 볼 수 있도록 구성했습니다.

1. 핵심 설계 사상

세 가지 원칙이 전체 구현을 관통합니다.

원칙 내용 구현 반영
Unified Data Plane 벡터 DB와 그래프 DB를 쪼개지 않고, 하나의 PostgreSQL에서 관계형·벡터·그래프를 함께 다룬다. 이중 기록(dual-write)과 정합성 지연을 제거한다. pgvector + Apache AGE 동일 인스턴스
Ontology before Graph LLM이 문서마다 임의 타입을 쏟아내는 것을 금지한다. 허용 목록(allowlist) 온톨로지로 추출하고, 모르는 타입은 검수 큐로 보낸다. 2-tier ontology · closed-world IE
Hybrid Retrieval 의미 검색만으로는 multi-hop 관계가 약하고, 그래프만으로는 fuzzy 매칭이 약하다. 둘을 진입→확장→융합한다. BM25 + Dense + Graph + RRF
SQL SoT, Graph Projection 권위 있는 원본은 SQL 테이블이다. AGE 그래프는 재구축 가능한 파생 투영(projection)이다. entity_relations → AGE MERGE
LLM outside TX 임베딩·추출·생성 등 느리고 비결정적인 LLM I/O는 DB 트랜잭션 밖에서 수행한다. 짧은 TX로 SQL+AGE만 기록한다. ingest worker 단계 분리
한 줄 요약. “문서를 넣으면 온톨로지 제약 하에 지식을 구조화하고, 찾을 때는 의미와 관계를 동시에 쓰는 KMS.”

2. 해결하려는 문제

단일 접근만으로는 기업 지식 검색이 자주 실패합니다.

접근 강점 약점 Hybrid KMS의 대응
Pure VectorRAG 의미적으로 비슷한 문장·문서를 잘 찾음 명시적 관계·다단 추론 약함 Stage A dense + Stage B graph expansion
Pure GraphRAG 관계·multi-hop 질의에 강함 표현이 다른 동의 질의·신규 문서 커버리지 약함 벡터 진입점 후 그래프 확장
이종 스토어 분리
Vector DB + Neo4j 등
각 엔진 최적화 가능 dual-write, consistency lag, ops 복잡도 단일 Postgres 트랜잭션 경계
무통제 LLM 추출 초기 커버리지 빠름 ontology explosion (5문서 → 17 타입 등) allowlist + candidate review queue

HybridRAG 포지셔닝

flowchart LR V["Pure VectorRAG
의미 유사도 강"] G["Pure GraphRAG
관계·multi-hop 강"] H["HybridRAG ★
vector entry → graph expand → fusion"] V -.->|약점 보완| H G -.->|약점 보완| H H --> OUT["정확·설명 가능한 검색/답변"]

3. Key Decisions (KD)

설계 리뷰를 통과한 핵심 결정입니다. 구현 시 “왜 이렇게 했나”의 기준선입니다.

ID 결정 영역 선택 근거
KD-1데이터 플레인단일 PostgreSQL + pgvector + AGE트랜잭션 일관성, ops 단순, 교차 지연 제거
KD-2그래프 언어Apache AGE openCypher표준 Cypher DX, PG 내장
KD-3온톨로지2-tier (Core + Domain 검수)ontology explosion 방지
KD-4정보 추출Closed-world first, open → review queue품질 vs 커버리지 균형
KD-5결과 융합Weighted RRF (k=60)점수 스케일 불일치에 강건
KD-6검색 단계A→B→C→D지연 예산 분리·점진 고도화
KD-7엔티티 저장SQL SoT / AGE projection재구축·ACL·감사 가능
KD-8벡터 인덱스HNSW + ACL oversampleANN 속도 + post-filter recall 보호
KD-9Entity resolutionexact/alias → trgm+cosine결정적·테스트 가능 병합
KD-10Cypher 안전allowlist + agtype 파라미터injection 방지
KD-11멀티테넌시v1 single-tenant + document ACL초기 복잡도 억제
KD-14버전 범위current_version + active onlystale chunk 오염 방지
KD-15인증API Key → principal빠른 착수, OIDC 교체 가능
KD-16청킹512 tokens / overlap 12%재현 가능한 기본값
KD-17한국어 lexicalsimple FTS + dense 가중 우세형태소 사전 없이도 hybrid 품질

4. 논리 아키텍처

클라이언트 → API → 수집/검색 서비스 → 단일 Postgres 데이터 플레인.

flowchart TB subgraph Clients UI[Web UI] API_C[API Clients] end subgraph App["Application"] API[FastAPI /api/v1] AUTH[Auth + ACL] ING[Ingest Worker] RET[Hybrid Retriever] QA[Q&A Orchestrator] end subgraph PG["PostgreSQL Data Plane"] REL[(Relational
docs/chunks/ACL/ontology)] VEC[(pgvector
chunk/entity embeddings)] AGE[(Apache AGE
kms_graph)] end UI --> API API_C --> API API --> AUTH AUTH --> ING AUTH --> RET AUTH --> QA ING --> REL ING --> VEC ING --> AGE RET --> REL RET --> VEC RET --> AGE QA --> RET

런타임 구성 요소

구성요소역할기술
API업로드, 검색, Q&A, 온톨로지, 첨부FastAPI + uvicorn
Worker비동기 파싱·임베딩·IE·그래프 기록DB job 폴링 워커
Postgres단일 데이터 플레인PG17 + vector + AGE
Storage원본·parsed.md·표 CSV로컬 볼륨 (S3 교체 가능)
LLM (옵션)IE 보강, Q&A 생성OpenAI / Claude(Anthropic)

5. 문서 수집 파이프라인

원본을 첨부파일로 보관하고, 정리된 텍스트·표를 만든 뒤 검색·그래프 인덱스를 구축합니다.

sequenceDiagram participant U as Client participant API as API participant W as Ingest Worker participant P as Parsers participant LLM as LLM optional participant DB as PostgreSQL U->>API: POST /documents (file) API->>DB: documents + version + attachment(original) API->>DB: job queued API-->>U: 202 job_id W->>DB: claim job W->>P: parse PDF/DOCX/PPTX/XLSX/HWP/... P-->>W: text + tables W->>DB: parsed.md, CSV attachments W->>W: chunk + embed_chunks (TX 밖) W->>DB: chunk_embeddings W->>LLM: ontology-constrained extract (optional) W->>DB: resolve + mentions + relations (SQL) W->>DB: AGE MERGE projection W->>W: embed_entities (TX 밖) W->>DB: job succeeded

지원 포맷과 산출물

입력파서산출 첨부검색 반영
PDFpdftotext + pypdforiginal, parsed.md청크·임베딩·엔티티
DOCXpython-docx+ 표 CSV본문 + 표 마크다운
PPTXpython-pptxparsed.md슬라이드 단위 텍스트
XLSXopenpyxl시트별 CSV시트 테이블 검색
HWP/HWPXolefile / zip+lxmlparsed.md검색용 텍스트 추출
MD/TXT/HTML/CSV내장parsed.md / CSV동일 파이프라인
TX 경계. 파싱·임베딩·LLM 호출은 트랜잭션 밖. DB에는 준비된 DTO만 짧은 트랜잭션으로 기록합니다. 그래프 기록 실패 시 SQL SoT는 유지하고 projection rebuild로 복구합니다.

6. Hybrid 검색 사상

한 번의 질의에 세 경로를 돌리고, 순위를 RRF로 융합합니다.

flowchart LR Q[User Query] --> ACL[visible_document_ids] Q --> EMB[Query embedding] ACL --> A1[Stage A BM25] ACL --> A2[Stage A Dense HNSW] EMB --> A2 Q --> EL[Entity linking] EL --> B[Stage B Graph hop0–2] ACL --> B A1 --> C[Stage C Weighted RRF] A2 --> C B --> C C --> RV[ACL + version revalidate] RV --> D[Stage D optional LLM Q&A] RV --> OUT[Top-K chunks + citations] D --> OUT

단계별 역할

Stage이름하는 일왜 필요한가
A Lexical + Dense tsvector BM25와 청크 벡터 ANN 키워드 정확 매칭 + 의미 유사 매칭
B Graph expansion 엔티티 링크 후 hop-0 직접 언급 + hop-1/2 이웃 청크 관계 기반 multi-hop 문맥
C RRF Fusion 가중 RRF로 순위 합산, ACL/버전 재검증 이종 점수 스케일 정규화
D Q&A (옵션) 상위 청크를 근거로 LLM 생성 설명형 답변 + citation

RRF 가중 (한국어 v1 기본)

소스가중치비고
Dense1.1한국어 lexical 한계 보완
Graph1.0정렬된 graph_score 순위만 투입
BM250.7정확한 키워드 신호
RRF k60표준 RRF 상수
Graph hop-0이 핵심. 시드 엔티티가 직접 언급된 청크를 먼저 넣고, 그다음 이웃으로 확장합니다. 표면형 표현이 Stage A에서 놓쳐도 Hybrid 경로로 문서를 살릴 수 있습니다.

7. 온톨로지 사상

그래프의 품질은 스키마 통제에서 결정됩니다.

2-tier 모델

티어성격변경 방식
CorePerson, Organization, Policy, Technology…시드·신중 변경
DomainService, Component, Incident…운영 중 확장 가능
CandidatesLLM이 제안한 미등록 타입검수 후 approve

추출 규칙

  • 활성 클래스/관계 allowlist만 IE에 주입
  • 미등록 타입 → ontology_candidates
  • RELATED_TO는 last-resort (남용 방지)
  • Vertex 라벨은 구조용 고정: Document/Chunk/Entity…
  • 도메인 인스턴스는 모두 Entity + class 속성
flowchart TD DOC[Document text] --> IE[Ontology-constrained IE] SNAP[Active classes/relations snapshot] --> IE IE --> OK{In allowlist?} OK -->|Yes| ER[Entity Resolution] OK -->|No| CAND[Candidate queue] ER --> SQL[(SQL entities/relations)] SQL --> AGE[(AGE projection)] CAND --> STEWARD[Steward approve/reject] STEWARD -->|approve + create_elabel| SNAP

8. 데이터 모델 사상

관계형으로 권위를 두고, 그래프·벡터는 인덱스로 취급합니다.

erDiagram documents ||--o{ document_versions : has document_versions ||--o{ sections : has documents ||--o{ chunks : has documents ||--o{ document_attachments : stores documents ||--o{ document_acls : grants chunks ||--|| chunk_embeddings : embeds chunks ||--o{ chunk_entity_mentions : mentions entities ||--o{ chunk_entity_mentions : mentioned_in entities ||--|| entity_embeddings : embeds entities }o--|| ontology_classes : typed_as entities ||--o{ entity_relations : from_to ontology_relations ||--o{ entity_relations : defines

세 저장 계층의 역할

계층저장소역할삭제/재처리 시
Relational SoT SQL 테이블 문서, 청크, ACL, 온톨로지, 멘션, 관계 권위 있는 상태 변경
Vector index pgvector 청크/엔티티 의미 검색 재임베딩 backfill
Graph projection Apache AGE 경로 설명, multi-hop 탐색 보조 SQL에서 rebuild 가능
Object storage 파일 볼륨 원본 첨부, parsed.md, 표 CSV 버전 디렉터리 단위 관리

9. 보안 · 버전 · 운영 사상

보안

위협대응
무단 문서 열람API Key → principal, document ACL, 검색 경로마다 visible_doc 필터
Cypher/SQL injection라벨 allowlist, AGE 쿼리는 dollar-quote 템플릿 + agtype 파라미터
그래프 ACL 우회그래프에 ACL 미저장; hydrate 시 SQL에서 재검증
LLM 타입 오염closed-world 검증, candidate 검수

버전 계약 (KD-14)

모든 검색은 chunks.version = documents.current_version 이고 chunks.status = 'active' 인 행만 대상입니다. 재처리 시 이전 청크는 retired 되어 stale 결과가 섞이지 않습니다.

성능 목표 (가이드)

경로목표조건
Hybrid 검색 A+B+Cp95 < 500msLLM 없음, 튜닝 후
Q&A (Stage D 포함)p95 < 5sLLM 네트워크 포함
flowchart LR subgraph SafeWrite["안전한 기록"] A1[LLM/Embed TX 밖] --> A2[DTO 준비] A2 --> A3[짧은 SQL+AGE TX] end subgraph SafeRead["안전한 읽기"] B1[ACL 계산] --> B2[Hybrid retrieve] B2 --> B3[version+ACL revalidate] B3 --> B4[응답] end

정리

질문이 시스템의 답
왜 Postgres 하나인가?벡터·그래프·메타를 한 트랜잭션으로 묶어 운영 비용을 낮춘다.
왜 온톨로지를 강제하는가?검색 가능한 지식 그래프는 스키마 품질 없이는 오래 가지 못한다.
왜 Hybrid 검색인가?의미(vector)와 관계(graph)는 서로 다른 실패 모드를 보완한다.
왜 SQL이 SoT인가?ACL, 재처리, 감사, 재구축을 결정적으로 수행할 수 있다.
문서를 넣으면?원본 첨부 + 파싱 정리본 + 청크 벡터 + 온톨로지 엔티티/관계가 쌓인다.
검색하면?BM25·Dense·Graph 순위를 RRF로 합쳐 더 잘 찾는다.

구현 코드: /srv/sites/kms.engineerstory.kr · 마크다운 설계서: docs/01-hybrid-kms-architecture.md · 앱: https://kms.engineerstory.kr/ · 매뉴얼: /manual · 분석 요약: /summary · API: /api/docs