ontology
This commit is contained in:
790
ontology_platform/docs/통합설계서.md
Normal file
790
ontology_platform/docs/통합설계서.md
Normal file
@@ -0,0 +1,790 @@
|
||||
# 범용 온톨로지 구축 플랫폼 통합 설계서
|
||||
|
||||
작성일: 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의 검색 도서관을 붙인다."**
|
||||
|
||||
각 소스의 가장 잘하는 부분만 가져오고, 나머지는 과감히 버린다. 통합은 한 번에 하나씩. 사용자가 강조한 "버그 가능성 최소화"는 이 원칙을 지키는 것에서 시작한다.
|
||||
Reference in New Issue
Block a user