Files
AI/온톨로지플랫폼_통합설계서.md
LASTA_DEV01\lasta 9e88f4c7ad ontology
2026-05-13 19:57:34 +09:00

791 lines
43 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 범용 온톨로지 구축 플랫폼 통합 설계서
작성일: 2026-05-13
대상: 본 문서를 받아 실제 구현을 수행할 모든 AI 에이전트 및 개발자
근거 자료: `C:\Users\lasta\MyProject\AI\오픈소스분석자료` 의 8개 분석 명세 (Crawl4AI, Firecrawl, Guardrails, Knowledge Agent, Neo4j GraphRAG, OntoCast, OpenDeepResearcher, Trafilatura)
---
## 0. 본 문서의 사용 규칙 (Agent Instruction)
본 문서를 받는 AI 에이전트는 다음을 준수한다.
1. 본 문서는 8개 분석 자료를 바탕으로 도출된 **최종 통합 설계**다. 개별 분석 자료와 본 문서가 충돌할 경우 본 문서가 우선한다.
2. 본 문서가 "그대로 사용"이라고 명시한 모듈은 원본 소스를 가급적 수정하지 않고 라이브러리 또는 vendored copy 형태로 도입한다. "어댑터 작성"이라고 명시한 부분만 우리 코드로 만든다.
3. "통합은 한 번에 하나씩"의 원칙을 지킨다. Phase N의 검수 게이트(Acceptance Gate)를 통과하기 전에는 Phase N+1로 진행하지 않는다.
4. 코드 작성 시 어느 분석 자료의 어느 절을 근거로 했는지 PR 설명에 명시한다. 예: `OntoCast 분석 §6 GraphUpdate 모델`.
5. 본 문서가 "제외(Excluded)"라고 명시한 프로젝트는 코드/의존성에 포함하지 않는다.
---
## 1. Executive Summary (한눈에 보는 결론)
| 항목 | 결정 |
|---|---|
| **시작 프로젝트(Base)** | **OntoCast** — RDF/온톨로지 코어 엔진, LangGraph 워크플로우, GraphUpdate 증분 갱신, Renderer/Critic 루프, Entity Aggregation, TripleStoreManager가 이미 갖추어져 있어 "온톨로지 구축 플랫폼"의 골격으로 가장 적합 |
| **통합 대상 (총 4개)** | ① Trafilatura ② Crawl4AI ③ Guardrails ④ Neo4j GraphRAG |
| **부분 차용 (코드 아닌 패턴/프롬프트)** | Knowledge Agent — LangGraph 멀티에이전트 패턴, LightRAG 추출 프롬프트 |
| **제외** | Firecrawl (TS 스택 분리 부담, Crawl4AI와 기능 중복), OpenDeepResearcher (`eval()` 보안 문제, Knowledge Agent로 대체 가능) |
| **총 통합 프로젝트 수** | **5개** (Base 1 + 통합 4) — 사용자의 "적은 수의 프로젝트" 요구 충족 |
핵심 원칙: **OntoCast = 두뇌, Crawl4AI = 손, Trafilatura = 눈, Guardrails = 안전벨트, Neo4j GraphRAG = 거울/도서관.**
---
## 2. 8개 오픈소스 강점 매트릭스 (Strength Matrix)
각 소스가 "가장 잘하는 영역" 하나씩만 추려서 기능 중복을 정리한 표.
| # | 프로젝트 | 카테고리 | 대체 불가 강점 | 라이선스 | 언어 | 채택 여부 |
|---|---|---|---|---|---|---|
| 1 | **OntoCast** | 온톨로지 코어 | **GraphUpdate 기반 SPARQL 증분 갱신** + Renderer/Critic retry loop + Entity aggregation(embedding + URI 정규화 + owl:sameAs) | Apache 2.0 | Python 3.12+ | **Base** |
| 2 | **Trafilatura** | 본문 추출 | 본문/메타데이터/날짜/저자/언어 추출의 **산업 표준 정밀도**. XML body tree 보존, SimHash fingerprint, feed/sitemap discovery | Apache 2.0 | Python | **통합** |
| 3 | **Crawl4AI** | 크롤링 | **동적 페이지(Playwright)+LLM 친화 Markdown** 변환의 결정판. Deep crawl(BFS/DFS/Best-First) + URL Seeder + Adaptive crawler + browser pool/dispatcher/cache | Apache 2.0 | Python 3.10+ | **통합** |
| 4 | **Guardrails** | 검증 | **Pydantic 기반 LLM 출력 강제 + on_fail 정책(reask/fix/filter/refrain) + JSON path field validator** | Apache 2.0 | Python 3.10+ | **통합** |
| 5 | **Neo4j GraphRAG** | KG 저장/검색 | **GraphSchema + GraphPruning + Neo4jWriter + EntityResolver + Vector/Hybrid/Text2Cypher Retriever + GraphRAG** | Apache 2.0 | Python 3.10+ | **통합** |
| 6 | Knowledge Agent | 멀티에이전트 | LangGraph 기반 Analyst→Researcher→Curator→Auditor→Fixer→Advisor 패턴 + LightRAG 엔티티/관계 추출 프롬프트 | 비명시 | Python | **패턴/프롬프트만 차용** |
| 7 | Firecrawl | 크롤링 API | scrape/map/crawl/search/parse API 명세 우수, fire-engine fallback | AGPL 의심 | TypeScript | **제외** (스택 분리 부담 + 라이선스 리스크 + Crawl4AI와 중복) |
| 8 | OpenDeepResearcher | 검색 루프 | LLM 기반 검색어 생성 + 자기확장 루프 + `<done>` 판단 | MIT | Python (notebook) | **제외** (`eval()` 보안 문제 + Knowledge Agent의 Researcher가 더 구조화됨) |
---
## 3. 시작 프로젝트(Base)로 OntoCast를 선택한 근거
| 비교 항목 | OntoCast | Knowledge Agent | Neo4j GraphRAG |
|---|---|---|---|
| 사용자 목표 적합성("온톨로지 구축") | ◎ RDF/OWL 중심 | △ 지식그래프 보조 도구 | ○ Property Graph 중심 |
| 핵심 자산의 대체 난이도 | ◎ GraphUpdate 증분 갱신은 다른 어디서도 못 구함 | △ LangGraph 패턴은 재작성 용이 | ○ Library 형태로 갖다 쓰면 됨 |
| Renderer/Critic retry loop | ◎ 내장 | △ Refiner 비슷한 개념만 | × 없음 |
| Entity Aggregation/URI 정규화 | ◎ 내장 (`tool/agg/`) | × 없음 | △ Resolver 있으나 단순 |
| LangGraph 워크플로우 | ◎ 내장 (`stategraph/`) | ◎ 내장 | × 없음 |
| Triple Store 추상화 (Fuseki/Neo4j/FS) | ◎ 내장 | × LightRAG에 종속 | △ Neo4j만 |
| ToolBox dependency container | ◎ 내장 | × | × |
| 라이선스 명확성 | ◎ Apache 2.0 | × 비명시 | ◎ Apache 2.0 |
| 코드 안정성 | ○ 일부 버그 (§13.1) | × 다수 버그 (Curator/Auditor/Fixer/Advisor) | ◎ 테스트 광범위 |
**결론**: OntoCast의 "GraphUpdate 증분 갱신 + Renderer/Critic 루프 + Entity Aggregation"은 다른 소스로 대체 불가능한 차별 자산이다. 이를 Base로 두고 나머지를 라이브러리로 흡수한다.
---
## 4. 통합 아키텍처 (Layered Architecture)
```
┌──────────────────────────────────────────────────────────────────┐
│ L7. UI Layer (Ontology Studio, Review Console, Search UI) │
│ — 새로 작성 (React/Next.js 등 자유 선택) │
├──────────────────────────────────────────────────────────────────┤
│ L6. Platform API (FastAPI) │
│ — 새로 작성. /projects, /jobs, /sources, /ontology, │
│ /review, /search, /admin │
├──────────────────────────────────────────────────────────────────┤
│ L5. Job Orchestration (Job Queue + Worker) │
│ — 새로 작성. Celery/RQ/Arq 중 선택, Redis/Postgres state │
├──────────────────────────────────────────────────────────────────┤
│ L4. Ontology Core Engine │
│ ★ OntoCast (Base, 거의 원형 유지) │
│ — stategraph/, agent/, onto/, tool/, toolbox.py │
├──────────────────────────────────────────────────────────────────┤
│ L3. Quality & Validation Gate │
│ ★ Guardrails (라이브러리로 통합) │
│ — Guard.for_pydantic(OntologyExtractionResult) │
│ — Renderer/Critic 출력 검증, reask 루프 │
├──────────────────────────────────────────────────────────────────┤
│ L2. Content Acquisition Layer │
│ ★ Crawl4AI (라이브러리, 동적/대량 크롤링) │
│ ★ Trafilatura (라이브러리, 본문/메타데이터 정밀 추출) │
│ — Crawl4AI 우선, Trafilatura는 후처리 정밀화 옵션 │
├──────────────────────────────────────────────────────────────────┤
│ L1. Storage Layer │
│ • Fuseki (Canonical RDF Store, OntoCast TripleStoreManager) │
│ • Neo4j (Projection / Vector / Fulltext, GraphRAG) │
│ ★ Neo4j GraphRAG (라이브러리, Projection/Retriever 담당) │
│ • PostgreSQL (Job/User/Project/Review 메타데이터) │
│ • Object Storage (raw HTML, PDF, screenshot 등 artifact) │
└──────────────────────────────────────────────────────────────────┘
```
### 4.1 데이터 흐름 (Document → Ontology → Search)
```
[Source URL/File]
→ [L2 수집] Crawl4AI (동적/대량) or Trafilatura (정적/메타데이터 정밀)
→ [L2 정제] Trafilatura bare_extraction(output_format="python") + metadata
→ [L4 코어] OntoCast pipeline
CONVERT → CHUNK → SELECT_ONTOLOGY →
(BOOTSTRAP|RENDER_ONTOLOGY_UPDATE) →
[L3 검증] Guardrails Guard 통과 →
NORMALIZE → CONSOLIDATE → RENDER_FACTS →
[L3 검증] Guardrails Guard 통과 →
MERGE (Entity Aggregation) → SERIALIZE
→ [L1 저장]
Fuseki: Canonical RDF (Ontology TTL + Facts TTL)
Neo4j: Projection via Neo4j GraphRAG KGWriter
+ Chunk vector index + Lexical graph (Document/Chunk)
Postgres: Job metadata, review state
Object Storage: raw HTML/PDF
→ [L6 API] /search 호출 시 Neo4j GraphRAG의
VectorCypherRetriever + Text2CypherRetriever + GraphRAG
```
### 4.2 RDF ↔ Property Graph 이중 저장 근거
| 저장소 | 역할 | 근거 |
|---|---|---|
| **Fuseki (Canonical RDF)** | 진실 원본 (source of truth). OntoCast `GraphUpdate`가 SPARQL UPDATE로 직접 반영. OWL/SHACL 추론 가능 | OntoCast §12.3 |
| **Neo4j (Projection)** | 검색/시각화/RAG 전용. Fuseki 변경 시 비동기로 동기화. Lexical graph(Document/Chunk) + Entity 노드 + Chunk embedding property | Neo4j GraphRAG §7.8, OntoCast §12.4 |
**중요 원칙**: RDF가 진실, Neo4j는 사본. 양쪽에 동시 쓰지 않는다. Fuseki에 commit → Worker가 Neo4j Projection 갱신.
---
## 5. 단계별 통합 로드맵 (Phased Integration Plan)
각 Phase의 마지막에 **Acceptance Gate**(검수 게이트)가 있다. Gate를 통과해야 다음 Phase 진행.
### Phase 0: Base 안정화 (OntoCast만)
**목표**: OntoCast를 단독으로 실행 가능한 상태로 만든다. 다른 통합은 시작하지 않는다.
**작업**:
1. OntoCast 저장소를 vendored copy 형태로 `platform/core/ontocast/`에 배치 (Apache 2.0 license 고지 유지)
2. OntoCast 분석 §13.1에 명시된 버그 수정:
- `select_ontology.py`의 None 선택 index 불일치 수정 (analyst가 `num_ontologies + 1` 인덱스를 반환할 때 None으로 처리)
- API version 표기 불일치 정리 (`pyproject.toml``/health`, `/info` 응답 통일)
3. `convert_document()`의 "one file at a time" 제약을 다중 파일 처리 가능하도록 확장
4. Robyn 서버는 제거하고 FastAPI 로 재작성 (기존 ToolBox/AgentState/stategraph는 그대로 사용)
5. 환경설정: `.env` + `Config` (Pydantic Settings) 유지, Fuseki/filesystem/Neo4j 중 **filesystem만 활성화**하여 시작
6. 기본 데이터셋: `data/` 폴더의 예제 PDF/JSON으로 end-to-end 1회 실행 성공
**Acceptance Gate 0**:
- [ ] 단일 PDF 또는 JSON 입력 → ontology TTL + facts TTL이 filesystem에 생성됨
- [ ] `/health`, `/info`, `/process` (FastAPI 버전) 정상 동작
- [ ] BudgetTracker가 LLM call/triple count를 정확히 기록
- [ ] LangGraph 워크플로우(CONVERT→CHUNK→...→SERIALIZE) 전 노드가 traceable
### Phase 1: Trafilatura 통합 (정적 본문/메타데이터 정밀화)
**목표**: 입력이 URL일 때 원본 페이지에서 본문/제목/저자/날짜/언어/canonical URL을 정확히 뽑아 `ContentUnit` metadata에 채워 넣는다.
**선택 이유 (Trafilatura 먼저 통합하는 이유)**:
- **가장 작은 통합**: 단일 함수(`bare_extraction`) 호출만으로 끝남. 전역 상태 외에는 의존성 거의 없음.
- 즉시 가치: OntoCast의 chunk metadata가 빈약했던 부분이 메워짐 (Trafilatura 분석 §11).
- 라이선스 동일 (Apache 2.0).
**작업**:
1. 의존성 추가: `trafilatura[all]>=2.0.0`
2. `platform/core/extractors/web_extractor.py` 신설. Trafilatura 분석 §17의 `extract_for_ontology` 함수를 거의 그대로 가져와 어댑터로 사용
3. OntoCast의 `ConverterTool`에 URL/HTML 입력 분기 추가: HTML이면 Trafilatura로 1차 정제 후 `text`, `Document.body` XML tree, metadata를 `ContentUnit`에 주입
4. `ContentUnit`에 다음 필드 추가:
- `source_url` (canonical)
- `title`, `author`, `publish_date`, `language`, `sitename`
- `fingerprint` (SimHash, Trafilatura `content_fingerprint`)
5. 중복 문서 감지: `fingerprint` 기반 near-duplicate check를 OntoCast 처리 전에 수행 (이미 처리한 문서는 skip)
6. Trafilatura의 전역 LRU cache는 배치 작업 종료 시 `trafilatura.meta.reset_caches()` 호출
**Acceptance Gate 1**:
- [ ] URL 입력 → 본문/메타데이터가 정확히 추출되어 `ContentUnit`에 저장됨
- [ ] 한국어 뉴스/블로그/쇼핑 페이지 각각 1개씩 본문 추출 정확도 수동 검증
- [ ] 동일 URL 재입력 시 fingerprint 기반 dedup으로 skip
- [ ] Phase 0의 모든 기능이 여전히 정상 동작 (회귀 없음)
### Phase 2: Crawl4AI 통합 (동적/대량 수집)
**목표**: Trafilatura가 못 다루는 동적 페이지(JS rendering), 사이트 전체 수집(deep crawl), URL seeding을 Crawl4AI로 처리한다.
**작업**:
1. 의존성 추가: `crawl4ai>=0.x` (분석 시점 최신 안정)
2. `platform/core/crawler/crawl4ai_adapter.py` 신설. `AsyncWebCrawler` + `CrawlerRunConfig` 팩토리 작성
3. 수집 Profile 정의 (Crawl4AI 분석 §21.2의 권장 profile 그대로 채택):
- `fast_static`: HTTP fetch만, Trafilatura로 정제
- `dynamic_page`: Playwright + JS wait
- `full_capture`: screenshot/PDF/MHTML
- `structured_extract`: CSS/XPath schema
- `deep_discovery`: URL Seeder + Deep crawl (BFS)
4. **결정 규칙** (어떤 Profile 선택할지):
- URL이 robots.txt에서 JS-heavy로 알려진 도메인 → `dynamic_page`
- URL이 sitemap에 등록되어 있음 → `deep_discovery` + `fast_static`
- 기본 → `fast_static`
5. Crawl4AI 결과의 `markdown` 또는 `cleaned_html` → Trafilatura 후처리 → `ContentUnit` 생성
6. 새 API 추가:
- `POST /sources/{id}/crawl` — 사이트 단위 deep crawl 작업 시작
- `POST /sources/{id}/seed` — URL seeding (sitemap/Common Crawl) 미리보기
- `GET /jobs/{job_id}/progress` — 진행 상황 스트리밍 (Crawl4AI dispatcher monitor 활용)
7. 캐시: Crawl4AI의 `CacheMode.ENABLED` 기본 + `check_cache_freshness=True`
**Acceptance Gate 2**:
- [ ] JS 렌더링이 필요한 동적 페이지 1개 정상 수집 (수동 지정)
- [ ] sitemap이 있는 사이트의 deep crawl 100페이지 이내 완료
- [ ] URL Seeder로 후보 URL 미리보기 정상 동작
- [ ] 메모리 누수 없이 50회 연속 크롤 가능 (browser pool 관리)
- [ ] Phase 0~1 기능 회귀 없음
### Phase 3: Guardrails 통합 (LLM 출력 검증 게이트)
**목표**: OntoCast의 Renderer(`render_ontology`, `render_facts`)와 Critic(`criticise_*`)이 생성하는 LLM 응답을 Guardrails로 강제 검증한다. 잘못된 응답이 RDF graph에 들어가는 것을 차단한다.
**작업**:
1. 의존성 추가: `guardrails-ai>=0.x` (Hub/telemetry 비활성화 설정 필수)
2. `platform/core/validation/` 신설:
- `guards.py`: `OntologyGuard` facade
- `validators.py`: 온톨로지 전용 validator (Guardrails 분석 §15.4 그대로 채택)
3. Pydantic 모델 정의 (Guardrails 분석 §15.5):
```python
class OntologyEntity(BaseModel):
id: str
label: str
type: Literal["class","individual","object_property","data_property"]
description: str | None = None
aliases: list[str] = []
evidence: list[OntologyEvidence] = []
confidence: float
class OntologyRelation(BaseModel):
id: str
source_id: str
predicate: str
target_id: str
evidence: list[OntologyEvidence] = []
confidence: float
class OntologyExtractionResult(BaseModel):
entities: list[OntologyEntity]
relations: list[OntologyRelation]
warnings: list[str] = []
```
4. OntoCast의 LLM 호출부 (`tool/llm.py`)를 래핑:
- Ontology Renderer 출력 → `Guard.for_pydantic(OntologyDelta)`로 검증
- Facts Renderer 출력 → `Guard.for_pydantic(FactsDelta)`로 검증
- `num_reasks=1`, `full_schema_reask=False` (부분 reask 우선)
5. Validator 활성화 (Guardrails 분석 §15.4):
- `EntityIdFormatValidator` (fix)
- `UniqueEntityIdValidator` (reask)
- `RelationEndpointExistsValidator` (reask)
- `ConfidenceRangeValidator` (fix)
- `EvidenceExistsValidator` (filter)
- `NoSelfRelationValidator` (filter)
6. Guard 실패 시 OntoCast의 critic suggestions에 추가하여 다음 retry에 반영
**Acceptance Gate 3**:
- [ ] LLM이 의도적으로 스키마를 위반한 응답(예: confidence > 1.0) → Guardrails가 자동 fix
- [ ] 존재하지 않는 entity ID를 참조한 relation → Guardrails가 reask 또는 filter
- [ ] reask 횟수가 `num_reasks` 한도 안에서 종료, 무한 루프 없음
- [ ] Guardrails Hub/telemetry 의존성이 비활성화되어 외부 통신 없음
- [ ] Phase 0~2 기능 회귀 없음
### Phase 4: Neo4j GraphRAG 통합 (Projection + 검색/RAG)
**목표**: Fuseki에 commit된 RDF를 Neo4j Property Graph로 projection하고, Neo4j GraphRAG의 Retriever/GraphRAG로 검색/QA 기능을 추가한다.
**작업**:
1. 의존성 추가: `neo4j-graphrag[openai,experimental]==1.16.0` (버전 고정)
2. APOC core 설치된 Neo4j 5.18.1+ 배포 (Docker compose 추가)
3. `platform/core/projection/rdf_to_neo4j.py` 신설:
- Fuseki의 `Ontology` + `Facts` graph → `Neo4jGraph(nodes, relationships)` 변환
- `KGWriter`로 `Neo4jWriter` 사용해 upsert
- Lexical graph(Document/Chunk) + Entity 노드를 `LexicalGraphBuilder` 표준에 맞춰 생성
4. Chunk embedding:
- OntoCast의 청킹 결과(`ContentUnit.text`)에 `OpenAIEmbeddings` 또는 `SentenceTransformerEmbeddings` 적용
- Neo4j chunk vector index 자동 생성 (`indexes.py`)
5. 검색 API 신설:
- `POST /search/vector` → `VectorRetriever`
- `POST /search/hybrid` → `HybridRetriever`
- `POST /search/text2cypher` → `Text2CypherRetriever` (read-only 강제)
- `POST /search/graphrag` → `GraphRAG` 답변 생성
6. Text2Cypher 보안 (Neo4j GraphRAG 분석 §13.4):
- read-only 검사 + 허용 schema 제한 + query timeout + result limit
7. Entity Resolver:
- `SinglePropertyExactMatchResolver` 기본 활성화
- OntoCast Entity Aggregation 결과(`owl:sameAs`)와 함께 사용해 중복 병합
**Acceptance Gate 4**:
- [ ] Fuseki commit 후 5초 이내 Neo4j projection 동기화 완료
- [ ] Lexical graph(Document/Chunk/Entity)와 provenance(`FROM_CHUNK`) 정상 생성
- [ ] Vector 검색 결과의 chunk → entity provenance 추적 가능
- [ ] Text2Cypher가 write/delete 쿼리를 차단
- [ ] GraphRAG 답변에 evidence chunk URL 포함
- [ ] Phase 0~3 기능 회귀 없음
### Phase 5: Knowledge Agent 패턴 차용 (멀티 에이전트 워크플로우)
**목표**: Knowledge Agent의 Analyst→Researcher→Curator→Auditor→Fixer→Advisor 패턴을 OntoCast의 기존 LangGraph에 통합하여 "유지보수 루프"를 추가한다. **코드를 통째로 가져오지 않고 LangGraph 노드 정의와 프롬프트만 차용한다** (Knowledge Agent 코드에 다수의 버그 존재 — 분석 §9.1).
**작업**:
1. OntoCast의 기존 `stategraph/`에 신규 노드 추가:
- `AnalystNode`: 현재 ontology + facts graph의 지식 공백 식별
- `ResearcherNode`: 공백별 검색 계획 생성 → Crawl4AI search/seed 호출
- `CuratorNode`: 수집된 URL 평가 → 선별 URL을 OntoCast `/process`로 투입
- `AuditorNode`: graph 품질 감사 (Neo4j GraphRAG의 schema validation 활용)
- `FixerNode`: 감사 이슈 수정 (사람 승인 게이트 필수)
- `AdvisorNode`: 반복 문제 분석 + 시스템 개선 제안
2. 프롬프트는 Knowledge Agent의 `prompts/*.txt`를 base로 시작하되, OntoCast의 `OntologyExtractionResult` 스키마에 맞게 수정
3. LightRAG 엔티티/관계 타입(Knowledge Agent §7.1, §7.2)을 **프로젝트별 설정으로 분리**. 기본 타입 팩 + 사용자 정의 타입 팩 지원
4. 사람 승인 게이트(Fixer):
- 자동 승인: confidence ≥ 0.95 + non-destructive
- 검토 큐: 그 외 모두 → Review UI에서 승인/반려
5. 새 API:
- `POST /projects/{id}/maintenance/run` — 전체 유지보수 루프
- `POST /projects/{id}/maintenance/analyze` — 분석만
- `POST /projects/{id}/maintenance/fix` — 수정만
**Acceptance Gate 5**:
- [ ] 의도적으로 만든 지식 공백(특정 entity의 predicate 누락) → Analyst가 식별 → Researcher가 검색 수행 → Curator가 URL 선별 → 신규 facts 추가
- [ ] Auditor가 중복 entity 후보를 정확히 식별 (Neo4j GraphRAG resolver 활용)
- [ ] Fixer가 destructive 변경 시 사람 승인 없이 진행하지 않음
- [ ] Advisor 보고서에 "반복 실패한 entity type/predicate" 통계 포함
- [ ] Phase 0~4 기능 회귀 없음
---
## 6. 상용 제품 수준 기능 명세 (Functional Spec)
기능 ID 체계: `[영역코드]-[순번]`. 영역코드: PROJ, ACQ, ONT, REV, SRCH, OPS, GOV.
### 6.1 프로젝트/멀티테넌트 관리 (PROJ)
| ID | 기능명 | 설명 | 우선순위 |
|---|---|---|---|
| PROJ-001 | 온톨로지 프로젝트 생성 | 이름, 도메인, 기본 언어, 기본 타입 팩, Neo4j DB/Fuseki dataset 매핑 | P0 |
| PROJ-002 | 멤버/권한 관리 | Owner/Admin/Editor/Reviewer/Viewer 역할 | P0 |
| PROJ-003 | LLM Profile 선택 | provider/model/api_key/temperature/max_tokens (Neo4j GraphRAG `LLMConfig` 차용) | P0 |
| PROJ-004 | Embedding Profile 선택 | provider/model/dimension (cohere/openai/sentence-transformers) | P0 |
| PROJ-005 | 비용 예산 설정 | LLM call/token/검색 호출 일일·월간 한도 (OntoCast BudgetTracker 확장) | P1 |
| PROJ-006 | 프로젝트 fork/복제 | 기존 프로젝트의 스키마/설정만 복제 | P2 |
| PROJ-007 | 프로젝트 export/import | 전체 RDF + 설정을 zip으로 export, import | P1 |
### 6.2 데이터 수집 (ACQ)
| ID | 기능명 | 사용 컴포넌트 | 우선순위 |
|---|---|---|---|
| ACQ-001 | 단일 URL scrape | Crawl4AI `fast_static` + Trafilatura | P0 |
| ACQ-002 | 동적 페이지 scrape | Crawl4AI `dynamic_page` | P0 |
| ACQ-003 | 사이트 deep crawl | Crawl4AI `deep_discovery` (BFS/DFS/Best-First) | P1 |
| ACQ-004 | sitemap/feed 발견 | Trafilatura `sitemap_search`, `find_feed_urls` | P1 |
| ACQ-005 | URL seeding 미리보기 | Crawl4AI `AsyncUrlSeeder` | P1 |
| ACQ-006 | 파일 업로드 (PDF/DOCX/MD) | OntoCast converter + docling | P0 |
| ACQ-007 | 배치 URL import (CSV) | URL 목록 업로드 → 큐잉 | P1 |
| ACQ-008 | 중복 문서 dedup | Trafilatura SimHash fingerprint | P0 |
| ACQ-009 | 도메인 allow/block list | 프로젝트별 정책 DB | P0 |
| ACQ-010 | robots.txt 준수 모드 | strict/respect/ignore (감사 로그 필수) | P0 |
| ACQ-011 | 변경 감지 (changeTracking) | 주기 재크롤 + fingerprint 비교 | P2 |
| ACQ-012 | screenshot/PDF archive | Crawl4AI `full_capture` Profile | P2 |
### 6.3 온톨로지 구축 (ONT)
| ID | 기능명 | 사용 컴포넌트 | 우선순위 |
|---|---|---|---|
| ONT-001 | 수동 스키마 작성 | Neo4j GraphRAG `GraphSchema` 모델 그대로 사용 + UI | P0 |
| ONT-002 | 자동 스키마 추출 | Neo4j GraphRAG `SchemaFromTextExtractor` 또는 OntoCast `BOOTSTRAP_ONTOLOGY` | P0 |
| ONT-003 | 자유 추출 | OntoCast `schema="FREE"` 모드 | P1 |
| ONT-004 | 온톨로지 증분 갱신 | OntoCast `GraphUpdate` SPARQL (핵심 차별 기능) | P0 |
| ONT-005 | 온톨로지 비평/재시도 | OntoCast Critic loop + Guardrails | P0 |
| ONT-006 | 사실(facts) 추출 | OntoCast `RENDER_FACTS` + Guardrails | P0 |
| ONT-007 | Entity Aggregation | OntoCast `tool/agg/` (embedding clustering + URI 정규화 + owl:sameAs) | P0 |
| ONT-008 | Entity Resolver (사후) | Neo4j GraphRAG `FuzzyMatchResolver` + 검수 큐 | P1 |
| ONT-009 | 스키마 버전 관리 | OntoCast `GraphVersionManager` + draft/published/deprecated | P1 |
| ONT-010 | 스키마 diff 뷰어 | 버전 간 class/property/pattern 변경 | P1 |
| ONT-011 | 스키마 마이그레이션 | rename/merge/split + facts auto-migration | P2 |
| ONT-012 | SHACL/OWL 검증 | rdflib + owlready2 | P2 |
| ONT-013 | 다국어 label 관리 | rdfs:label + lang tag (ko/en/...) | P1 |
### 6.4 검수/승인 (REV)
| ID | 기능명 | 설명 | 우선순위 |
|---|---|---|---|
| REV-001 | 추출 후보 큐 | Renderer 결과를 Fuseki commit 전 검토용으로 저장 | P0 |
| REV-002 | Evidence 하이라이트 | entity/relation → `FROM_CHUNK` → 원문 텍스트 표시 (Neo4j GraphRAG lexical graph) | P0 |
| REV-003 | 단위 승인/반려 | node/relationship/property 단위 | P0 |
| REV-004 | Pruned 후보 검토 | Neo4j GraphRAG `GraphPruning`에서 제거된 후보를 schema 후보로 제안 | P1 |
| REV-005 | Merge 후보 검토 | Resolver 후보 그룹의 시각화 + 승인/반려 | P1 |
| REV-006 | 일괄 승인 정책 | confidence ≥ X + source 신뢰도 ≥ Y → 자동 승인 | P1 |
| REV-007 | 변경 이력 (audit) | 누가/언제/무엇을/왜 변경 (RDF reification 또는 별도 audit log) | P0 |
| REV-008 | 롤백 | 특정 시점의 RDF graph로 복원 | P2 |
### 6.5 검색/RAG (SRCH)
| ID | 기능명 | 사용 컴포넌트 | 우선순위 |
|---|---|---|---|
| SRCH-001 | Vector 검색 | Neo4j GraphRAG `VectorRetriever` | P0 |
| SRCH-002 | Hybrid 검색 (vector+fulltext) | `HybridRetriever` | P0 |
| SRCH-003 | Graph 확장 검색 | `VectorCypherRetriever` (chunk → entity → neighbor) | P0 |
| SRCH-004 | Text2Cypher (NL → Cypher) | `Text2CypherRetriever` (read-only) | P1 |
| SRCH-005 | SPARQL 직접 질의 | Fuseki SPARQL endpoint (관리자 권한) | P1 |
| SRCH-006 | GraphRAG QA | `GraphRAG` + evidence URL 포함 | P0 |
| SRCH-007 | Faceted 탐색 | entity type/predicate별 filter | P1 |
| SRCH-008 | Entity 상세 페이지 | 모든 property + 인입/인출 relation + evidence | P0 |
| SRCH-009 | Subgraph 시각화 | Neo4j Browser embed 또는 Cytoscape.js | P1 |
| SRCH-010 | 저장된 질의 (saved query) | 즐겨찾기 + 알림 | P2 |
### 6.6 운영/관측 (OPS)
| ID | 기능명 | 설명 | 우선순위 |
|---|---|---|---|
| OPS-001 | Job Queue/Worker | 모든 비동기 작업의 큐잉/재시도/취소 | P0 |
| OPS-002 | Job 진행률 스트리밍 | WebSocket/SSE로 실시간 진행 | P0 |
| OPS-003 | BudgetTracker | LLM call/token/검색/크롤 호출 비용 추적 | P0 |
| OPS-004 | LLM Response Cache | OntoCast `Cacher` 그대로 사용 | P0 |
| OPS-005 | Prometheus metrics | Crawl4AI 분석 §16.4 패턴 | P1 |
| OPS-006 | 감사 로그 | 모든 RDF 변경 + 사용자 액션 | P0 |
| OPS-007 | 에러 알림 | webhook + email + slack | P1 |
| OPS-008 | 백업/복구 | Fuseki + Neo4j + Postgres 일관성 있는 백업 | P1 |
| OPS-009 | 멀티 환경 | dev/staging/prod 분리 | P0 |
### 6.7 거버넌스/보안 (GOV)
| ID | 기능명 | 설명 | 우선순위 |
|---|---|---|---|
| GOV-001 | 인증 (OAuth2/OIDC) | Google/GitHub/Azure AD | P0 |
| GOV-002 | RBAC | 프로젝트별 역할 (PROJ-002) | P0 |
| GOV-003 | API Key | 외부 시스템 연동용 | P0 |
| GOV-004 | Rate Limiting | 사용자별/IP별 | P0 |
| GOV-005 | Text2Cypher 샌드박스 | read-only + timeout + result limit + allowlist | P0 |
| GOV-006 | 비밀(secret) vault | LLM API key 암호화 저장 | P0 |
| GOV-007 | 데이터 보존 정책 | raw HTML/PDF 보존 기간 + zero-retention 모드 | P1 |
| GOV-008 | 라이선스/출처 표기 | source별 license metadata 저장 + 결과에 노출 | P1 |
---
## 7. 데이터 모델 표준 (Canonical Data Models)
본 절은 5개 소스를 잇기 위한 공통 데이터 계약이다. 모든 어댑터는 이 모델로 변환한다.
### 7.1 ContentUnit (문서 청크의 표준 표현)
```python
class ContentUnit(BaseModel):
id: str # UUID
project_id: str
source_id: str
source_url: str | None # canonical URL (Trafilatura)
file_path: str | None
document_type: Literal["html","pdf","markdown","docx","inline_text"]
text: str # 정제된 본문
body_xml: bytes | None # Trafilatura Document.body (lxml serialized)
markdown: str | None # Crawl4AI markdown 또는 변환본
chunk_index: int
total_chunks: int
title: str | None
author: str | None
publish_date: str | None # ISO-8601
language: str | None
sitename: str | None
fingerprint: str | None # Trafilatura SimHash
content_hash: str # SHA-256 of text
metadata: dict # raw provider metadata
retrieved_at: str # ISO-8601
extracted_by: str # "crawl4ai+trafilatura"
```
### 7.2 OntologyExtractionResult (Guardrails 검증 대상)
Guardrails §15.5 그대로 채택. 위 §5 Phase 3 참조.
### 7.3 GraphUpdate (OntoCast 그대로)
OntoCast `sparql_models.GraphUpdate`를 그대로 사용. 변경 금지.
### 7.4 Job
```python
class Job(BaseModel):
id: str
project_id: str
type: Literal["scrape","crawl","extract","project","resolve","maintenance"]
status: Literal["queued","running","paused","completed","failed","cancelled"]
progress: float # 0.0 ~ 1.0
input: dict # 작업 입력 (URL, options, etc.)
output: dict | None # 결과 요약
started_at: str | None
finished_at: str | None
budget: BudgetTracker # OntoCast 그대로
error: str | None
audit_log_id: str
```
### 7.5 ReviewItem
```python
class ReviewItem(BaseModel):
id: str
project_id: str
job_id: str
target_type: Literal["entity","relation","property","merge_group","prune_candidate"]
target_data: dict # 후보 데이터
evidence: list[dict] # chunk_id + text span
confidence: float
source_trust: float
status: Literal["pending","approved","rejected","auto_approved"]
decided_by: str | None # user_id
decided_at: str | None
reason: str | None
```
---
## 8. API 표준 (RESTful, 일부 WebSocket)
전체는 OpenAPI 3.1 spec으로 별도 관리. 여기서는 핵심 endpoint만 명시.
| Method | Path | 설명 | 인용 근거 |
|---|---|---|---|
| POST | `/projects` | 프로젝트 생성 | PROJ-001 |
| GET | `/projects/{id}` | 프로젝트 조회 | - |
| POST | `/projects/{id}/sources` | 데이터 소스 등록 | ACQ |
| POST | `/projects/{id}/sources/{sid}/scrape` | 단일 URL scrape | ACQ-001 |
| POST | `/projects/{id}/sources/{sid}/crawl` | deep crawl | ACQ-003 |
| POST | `/projects/{id}/sources/{sid}/seed` | URL seeding preview | ACQ-005 |
| POST | `/projects/{id}/upload` | 파일 업로드 | ACQ-006 |
| GET | `/projects/{id}/schemas` | 스키마 목록 | ONT-001 |
| POST | `/projects/{id}/schemas` | 스키마 작성 | ONT-001 |
| POST | `/projects/{id}/schemas/extract` | 자동 스키마 추출 | ONT-002 |
| POST | `/projects/{id}/schemas/{sid}/publish` | 스키마 발행 | ONT-009 |
| POST | `/projects/{id}/process` | 문서 처리 (전체 OntoCast 워크플로우) | OntoCast §13.3 |
| GET | `/jobs/{job_id}` | Job 조회 | OPS-001 |
| GET | `/jobs/{job_id}/progress` (WS) | 진행률 스트리밍 | OPS-002 |
| POST | `/jobs/{job_id}/cancel` | Job 취소 | OPS-001 |
| GET | `/projects/{id}/review` | 검수 큐 | REV-001 |
| POST | `/projects/{id}/review/{rid}/approve` | 승인 | REV-003 |
| POST | `/projects/{id}/review/{rid}/reject` | 반려 | REV-003 |
| POST | `/projects/{id}/search/vector` | Vector 검색 | SRCH-001 |
| POST | `/projects/{id}/search/hybrid` | Hybrid 검색 | SRCH-002 |
| POST | `/projects/{id}/search/text2cypher` | NL → Cypher | SRCH-004 |
| POST | `/projects/{id}/search/graphrag` | QA | SRCH-006 |
| GET | `/projects/{id}/entities/{eid}` | Entity 상세 | SRCH-008 |
| POST | `/projects/{id}/maintenance/run` | 유지보수 루프 | Phase 5 |
---
## 9. 어떤 코드를 어디서 가져오는가 (Module Map)
각 5개 소스에서 가져올 모듈을 정확히 명시. **"그대로"=수정 금지, "어댑터"=얇은 래퍼만 작성**.
### 9.1 OntoCast (Base)
| 가져올 모듈 | 방식 | 수정 사항 |
|---|---|---|
| `ontocast/onto/state.py` (AgentState) | 그대로 | - |
| `ontocast/onto/unit_states.py` | 그대로 | - |
| `ontocast/onto/sparql_models.py` (GraphUpdate) | 그대로 | - |
| `ontocast/onto/rdfgraph.py` | 그대로 | - |
| `ontocast/onto/ontology.py` | 그대로 | - |
| `ontocast/stategraph/` | 그대로 | Phase 5에서 노드 추가만 |
| `ontocast/agent/render_*.py` | 그대로 | - |
| `ontocast/agent/criticise_*.py` | 그대로 | - |
| `ontocast/agent/select_ontology.py` | **버그 수정** | None index 불일치 (분석 §13.1) |
| `ontocast/agent/convert_document.py` | **확장** | 다중 파일 처리 (분석 §13.1) |
| `ontocast/tool/agg/` | 그대로 | - |
| `ontocast/tool/triple_manager/` | 그대로 | - |
| `ontocast/tool/llm.py` | **래핑** | Guardrails Guard 통과 (Phase 3) |
| `ontocast/tool/cache.py` | 그대로 | - |
| `ontocast/toolbox.py` | 그대로 | - |
| `ontocast/cli/serve.py` (Robyn) | **재작성** | FastAPI로 (Phase 0) |
### 9.2 Trafilatura
| 가져올 함수 | 방식 |
|---|---|
| `bare_extraction(output_format="python")` | 그대로 import |
| `extract_metadata` | 그대로 import |
| `sitemap_search` | 그대로 import |
| `find_feed_urls` | 그대로 import |
| `content_fingerprint`, `Simhash` | 그대로 import |
| `trafilatura.meta.reset_caches` | 그대로 import (배치 종료 시 호출) |
신규 어댑터: `platform/core/extractors/web_extractor.py` (§17 Trafilatura 분석의 `extract_for_ontology` 그대로)
### 9.3 Crawl4AI
| 가져올 클래스 | 방식 |
|---|---|
| `AsyncWebCrawler` | 그대로 |
| `BrowserConfig`, `CrawlerRunConfig`, `CacheMode` | 그대로 |
| `CrawlResult` | 그대로 |
| `LLMExtractionStrategy`, `JsonCssExtractionStrategy` | 그대로 |
| `BFSDeepCrawlStrategy`, `BestFirstCrawlingStrategy` | 그대로 |
| `AsyncUrlSeeder`, `SeedingConfig` | 그대로 |
| `MemoryAdaptiveDispatcher` | 그대로 |
| Docker FastAPI 서버 코드 | **사용 안 함** (자체 FastAPI 사용) |
신규 어댑터: `platform/core/crawler/crawl4ai_adapter.py` (Crawl4AI 분석 §21.1의 권장 계층 구조)
### 9.4 Guardrails
| 가져올 모듈 | 방식 |
|---|---|
| `guardrails.Guard.for_pydantic` | 그대로 |
| `guardrails.AsyncGuard` | 그대로 |
| `guardrails.classes.validation_outcome.ValidationOutcome` | 그대로 |
| `guardrails.actions.*` | 그대로 |
| `guardrails.types.on_fail.OnFailAction` | 그대로 |
| `guardrails.validator_base.Validator` (커스텀 validator 작성용 base) | 그대로 |
| `guardrails.hub.*` | **사용 안 함** (외부 통신 차단) |
| `guardrails.telemetry.*` | **사용 안 함** |
| `guardrails.cli.*` | **사용 안 함** |
신규 작성: `platform/core/validation/validators.py` (Guardrails 분석 §15.4의 12개 validator)
### 9.5 Neo4j GraphRAG
| 가져올 클래스 | 방식 |
|---|---|
| `GraphSchema`, `NodeType`, `RelationshipType`, `Pattern`, `ConstraintType` | 그대로 |
| `SimpleKGPipeline` | **사용 안 함** (OntoCast 워크플로우가 우선) |
| `LLMEntityRelationExtractor` | **사용 안 함** (OntoCast Renderer가 우선) |
| `Neo4jWriter`, `Neo4jGraph`, `Neo4jNode`, `Neo4jRelationship` | 그대로 (Projection 용) |
| `LexicalGraphBuilder` | 그대로 |
| `SinglePropertyExactMatchResolver`, `FuzzyMatchResolver` | 그대로 |
| `VectorRetriever`, `HybridRetriever`, `VectorCypherRetriever` | 그대로 |
| `Text2CypherRetriever` | 그대로 (read-only 강제) |
| `GraphRAG` | 그대로 |
| `embeddings/*`, `llm/*` | 그대로 (선택적) |
신규 어댑터: `platform/core/projection/rdf_to_neo4j.py` (Fuseki RDF → `Neo4jGraph` 변환)
### 9.6 Knowledge Agent (패턴/프롬프트만)
| 가져올 자산 | 방식 |
|---|---|
| `prompts/analyst_prompt.txt` | **수정 후 사용** (OntoCast `OntologyExtractionResult` 스키마에 맞춤) |
| `prompts/planner_prompt.txt` | 수정 후 사용 |
| `prompts/refiner_prompt.txt` | 수정 후 사용 |
| `prompts/summarizer_prompt.txt` | 수정 후 사용 |
| `prompts/search_ranker_prompt.txt` | 수정 후 사용 |
| `prompts/ingester_prompt.txt` | 수정 후 사용 |
| `lightrag/prompt.py` (엔티티/관계 추출 프롬프트) | **참고만** (OntoCast Renderer가 이미 있음) |
| 코드 전체 | **사용 안 함** (다수 버그 — 분석 §9.1) |
---
## 10. 예상 리스크와 대응
| 리스크 | 영향 | 대응 |
|---|---|---|
| OntoCast `select_ontology.py` 버그 | 워크플로우 실패 | Phase 0에서 즉시 수정 |
| Crawl4AI/Playwright 메모리 누수 | 운영 장애 | `max_pages_before_recycle` 설정 + browser pool monitor |
| Trafilatura 전역 LRU cache 충돌 | 다중 테넌트에서 결과 오염 | 작업 단위 `reset_caches()` |
| Guardrails Hub 외부 통신 | 보안/네트워크 의존 | Hub/telemetry 비활성화 환경변수 강제 |
| Neo4j GraphRAG `experimental` API 변경 | upstream 호환성 | 버전 고정 (`==1.16.0`) + 우리 코드는 어댑터로만 접근 |
| Fuseki ↔ Neo4j 동기화 지연 | 검색 결과와 진실 불일치 | "Last sync at" 표시 + 강제 동기화 API |
| LLM 비용 폭주 | 운영 비용 | OPS-003 BudgetTracker 한도 + 자동 차단 |
| Text2Cypher 인젝션 | 보안 | read-only 강제 + allowlist + timeout (GOV-005) |
| robots.txt 위반 | 법적 리스크 | ACQ-010 strict 모드 기본 + 감사 로그 |
| 라이선스 (특히 AGPL 회피) | 배포 제약 | Apache/MIT만 채택. Firecrawl 제외 결정 근거 |
---
## 11. 기술 스택 요약 (전체)
| 영역 | 선택 |
|---|---|
| 언어 | Python 3.12+ (OntoCast 요구사항이 가장 높음) |
| API | FastAPI (모든 통합 소스가 OpenAPI 친화) |
| LangGraph 워크플로우 | OntoCast 기존 사용 |
| Validation | Pydantic v2 + Guardrails |
| 비동기 | asyncio (Crawl4AI/Trafilatura 모두 지원) |
| Job Queue | Arq (Redis 기반, 가벼움) 또는 Celery (대규모) |
| 메타데이터 DB | PostgreSQL 16+ |
| Canonical RDF Store | Apache Jena Fuseki 5+ |
| Property Graph | Neo4j 5.18.1+ with APOC core |
| Object Storage | S3 호환 (MinIO 로컬, AWS S3 운영) |
| 캐시 | Redis 7+ |
| 관측 | OpenTelemetry + Prometheus + Grafana |
| 컨테이너 | Docker Compose (개발) / Kubernetes (운영) |
| 인증 | Authlib + OAuth2/OIDC |
| 프론트엔드 | (자유 선택, 권장 Next.js 14 + shadcn/ui) |
---
## 12. 작업 단위 분해 (다른 AI 에이전트가 받아 작업할 단위)
각 Phase 내부에서 PR 단위로 쪼갠 예시. 에이전트는 이 순서로 작업한다.
### Phase 0 작업 단위
- **0.1** OntoCast vendored copy + Apache 2.0 NOTICE 추가
- **0.2** `select_ontology.py` 버그 수정 + 회귀 테스트
- **0.3** `convert_document.py` 다중 파일 처리 확장
- **0.4** Robyn → FastAPI 재작성 (`/health`, `/info`, `/process`, `/flush`)
- **0.5** Pydantic Settings 기반 `Config` 정리 (filesystem 모드만 활성)
- **0.6** End-to-end 통합 테스트 (예제 PDF 1개 → ontology TTL + facts TTL)
- **0.7** Acceptance Gate 0 체크리스트 확인
### Phase 1 작업 단위
- **1.1** `trafilatura[all]` 의존성 추가
- **1.2** `web_extractor.py` 어댑터 작성 (Trafilatura §17 인용)
- **1.3** `ContentUnit` 모델 확장 (title/author/date/fingerprint 등)
- **1.4** OntoCast `ConverterTool` 분기 추가 (URL/HTML 입력)
- **1.5** Fingerprint 기반 dedup 로직
- **1.6** 한국어 페이지 3종 추출 검증
- **1.7** Acceptance Gate 1 체크리스트 확인
### Phase 2 작업 단위
- **2.1** `crawl4ai` 의존성 + Playwright 설치
- **2.2** `crawl4ai_adapter.py` 작성 + 5개 Profile 정의
- **2.3** Crawl Profile 결정 규칙 구현
- **2.4** `/sources/{id}/crawl`, `/seed` API 추가
- **2.5** Job Queue 통합 (Arq 또는 Celery)
- **2.6** WebSocket 진행률 스트리밍
- **2.7** 메모리 누수 stress test
- **2.8** Acceptance Gate 2 체크리스트 확인
### Phase 3 작업 단위
- **3.1** `guardrails-ai` 의존성 + Hub/telemetry 비활성화 설정
- **3.2** `OntologyExtractionResult`/`OntologyDelta`/`FactsDelta` Pydantic 모델
- **3.3** 12개 온톨로지 validator 작성 (Guardrails §15.4)
- **3.4** OntoCast `tool/llm.py` 래핑 (Renderer 호출에 Guard 적용)
- **3.5** reask 결과 → critic suggestions 반영 통합
- **3.6** 실패 시나리오 테스트 (스키마 위반 응답 자동 차단)
- **3.7** Acceptance Gate 3 체크리스트 확인
### Phase 4 작업 단위
- **4.1** `neo4j-graphrag==1.16.0` + Neo4j Docker compose 추가
- **4.2** APOC 설치 검증 스크립트
- **4.3** `rdf_to_neo4j.py` projection 어댑터
- **4.4** Chunk embedding 파이프라인
- **4.5** Vector/Hybrid/Text2Cypher/GraphRAG endpoint
- **4.6** Text2Cypher 보안 (read-only + allowlist)
- **4.7** Fuseki commit hook → Neo4j 동기화
- **4.8** Acceptance Gate 4 체크리스트 확인
### Phase 5 작업 단위
- **5.1** Knowledge Agent 프롬프트 6종 import + OntoCast 스키마 맞춤 수정
- **5.2** LangGraph 신규 노드 6개 (Analyst/Researcher/Curator/Auditor/Fixer/Advisor)
- **5.3** 사람 승인 게이트 (Fixer destructive 동작)
- **5.4** Maintenance API 3종
- **5.5** Advisor 통계 보고서 생성
- **5.6** Acceptance Gate 5 체크리스트 확인
---
## 13. 다른 AI 에이전트를 위한 체크리스트
본 설계서를 받은 AI 에이전트가 작업을 시작하기 전 확인할 항목.
- [ ] 본 문서의 §1~§12를 모두 읽었는가?
- [ ] 8개 분석 자료 중 본 Phase에 해당하는 것을 정독했는가? (해당 분석 자료 경로: `C:\Users\lasta\MyProject\AI\오픈소스분석자료\`)
- [ ] 작업할 Phase의 Acceptance Gate를 명확히 이해했는가?
- [ ] "그대로 사용" 모듈을 수정하려 하고 있지 않은가?
- [ ] "제외(Excluded)" 프로젝트의 코드를 가져오려 하고 있지 않은가? (Firecrawl, OpenDeepResearcher)
- [ ] PR 설명에 어느 분석 자료의 어느 절을 근거로 했는지 명시할 준비가 되었는가?
- [ ] 이전 Phase의 회귀 테스트가 통과하는지 확인할 계획이 있는가?
- [ ] License 고지(Apache 2.0 NOTICE)가 vendored copy에 포함되는가?
---
## 14. 마지막 한 마디
이 설계의 본질은 다음 한 문장으로 요약된다.
> **"OntoCast의 RDF 증분 갱신 두뇌에, Crawl4AI/Trafilatura의 수집 손과 눈, Guardrails의 안전벨트, Neo4j GraphRAG의 검색 도서관을 붙인다."**
각 소스의 가장 잘하는 부분만 가져오고, 나머지는 과감히 버린다. 통합은 한 번에 하나씩. 사용자가 강조한 "버그 가능성 최소화"는 이 원칙을 지키는 것에서 시작한다.