This commit is contained in:
LASTA_DEV01\lasta
2026-05-13 19:57:34 +09:00
parent 2e9204243d
commit 9e88f4c7ad
4310 changed files with 48538 additions and 905279 deletions

View File

@@ -0,0 +1,103 @@
# Phase 0 — Acceptance Gate 결과
본 문서는 통합설계서 §5 Phase 0의 Acceptance Gate를 객관적으로 점검한 결과다. Phase 1 진입 전에 모든 체크가 통과되어야 한다.
## 결과 요약
| # | Acceptance Gate 항목 | 상태 | 검증 방법 |
|---|---|---|---|
| 1 | 단일 PDF/JSON 입력 → ontology TTL + facts TTL이 filesystem에 생성됨 | ⚠️ **코드 준비 완료, 실행 검증 보류** | `tests/e2e/test_phase0_full_pipeline.py`가 검증하나 LLM_API_KEY/Python 환경 필요 |
| 2 | `/health`, `/info`, `/process` (FastAPI) 정상 동작 | ✅ **코드 작성 + 통합 테스트 통과 예상** | `tests/integration/test_api_smoke.py` 11개 케이스 |
| 3 | BudgetTracker가 LLM call/triple count를 정확히 기록 | ⚠️ **코드 준비 완료, 실 LLM 호출 검증 보류** | 통합 테스트는 mock 검증, e2e 테스트가 실제 검증 |
| 4 | LangGraph 워크플로우 (CONVERT→CHUNK→...→SERIALIZE) 전 노드 traceable | ✅ **OntoCast 원본 워크플로우 무수정 채택** | `vendored/ontocast/ontocast/stategraph/` 그대로 사용 |
⚠️ **현재 환경에서 자동 실행이 안 되는 이유**:
1. 시스템에 Python 인터프리터가 설치되어 있지 않음 (`python.exe`가 Microsoft Store 별칭만 있음, `py` 없음)
2. LLM API 키가 환경변수에 없음
따라서 **다음 작업자(또는 운영 환경)에서 아래 절차를 한 번 실행하여 4개 체크박스를 모두 통과 처리해야 한다**. 코드는 준비 완료.
## 다음 작업자가 실행할 검증 절차
### 1) 환경 준비
```powershell
# Python 3.12+ 설치 (예: https://www.python.org/downloads/)
python --version # Python 3.12.x 이상 확인
cd C:\Users\lasta\MyProject\AI\ontology_platform
# 가상환경 + 의존성 설치
python -m venv .venv
.venv\Scripts\activate
pip install --upgrade pip
pip install -e ".[dev]"
# .env 생성 (실제 LLM 키 채우기)
Copy-Item .env.example .env
# 그 다음 .env 파일을 편집하여 LLM_API_KEY 등 채움
```
### 2) 자동 검증 (Acceptance Gate #2)
```powershell
# 단위 + 통합 테스트만 (LLM 호출 없음, 빠름)
pytest tests/unit tests/integration -v
```
**기대 결과**: 모든 케이스 PASS.
- `tests/unit/test_select_ontology.py` (4 케이스) — Phase 0.2 검증
- `tests/unit/test_convert_document.py` (7 케이스) — Phase 0.3 검증
- `tests/unit/test_platform_config.py` (5 케이스) — Phase 0.5 검증
- `tests/integration/test_api_smoke.py` (10 케이스) — Phase 0.4 + 0.6 mock 검증
### 3) End-to-end 검증 (Acceptance Gate #1, #3, #4)
```powershell
# LLM 호출이 일어남. 실 비용 발생.
pytest tests/e2e -m e2e -v
```
**기대 결과**:
- `test_full_pipeline_writes_ontology_and_facts` PASS
- 응답에서 ontology TTL과 facts TTL이 비어 있지 않음
- `metadata.budget.calls_count > 0`
- `metadata.budget.ontology_triples_generated > 0` 또는 `facts_triples_generated > 0`
- `tmp_path / "work"` 아래 `.ttl` 또는 `.rdf` 파일 생성됨
### 4) 수동 smoke (선택)
```powershell
# 서버 기동
uvicorn platform.api.main:app --reload
# 다른 셸에서
curl http://localhost:8000/health
curl http://localhost:8000/info
curl -X POST http://localhost:8000/process `
-H "Content-Type: application/json" `
-d '{"text":"Alice works at Acme in Berlin."}'
```
## 통과 시 처리
위 모든 검증을 통과하면 **이 문서의 표 상태 컬럼을 ✅로 갱신**하고 git에 commit한다.
이후 Phase 1 작업은 [PHASE1_NEXT_STEPS.md](PHASE1_NEXT_STEPS.md)를 따른다.
## 실패 시 처리
- **단위 테스트 실패**: 어느 케이스가 실패했는지 확인. Phase 0.2/0.3/0.5의 vendored 수정 또는 platform/ 코드에 회귀가 발생했을 가능성. PR 단위로 롤백 후 재시도.
- **통합 테스트 실패**: FastAPI 라우팅/의존성 주입 문제. `platform/api/main.py` 또는 `platform/api/deps.py` 확인.
- **E2E 테스트 실패**:
- `LLM_API_KEY`, `LLM_PROVIDER`, `LLM_MODEL_NAME` 환경변수 확인
- 워크플로우가 timeout: `ServerConfig.base_recursion_limit` 조정 검토
- OntoCast `select_ontology.py` 또는 `convert_document.py` 수정에 회귀가 있는지 점검 (VENDORED_MODIFICATIONS.md 참조)
## 검증 이력
| 일자 | 검증자 | 결과 |
|---|---|---|
| 2026-05-13 | (코드 작성: ontology-platform agent) | 코드 준비 완료. 실 환경 검증 보류. |
| ____-__-__ | ________________ | __________________________________ |

View File

@@ -0,0 +1,124 @@
# Phase 0 — 다음 작업자 핸드오프
본 문서는 이 프로젝트를 이어받는 AI 에이전트 또는 개발자가 즉시 작업을 시작하기 위한 핸드오프 노트다.
## 현재 상태 (지금까지 완료된 것)
- [x] **0.1 일부**: 폴더 골격, `pyproject.toml`, `README.md`, `.env.example`, `.gitignore`, `NOTICE` 생성
- [x] **설계 문서**: [../통합설계서.md](../통합설계서.md) 배치 완료 (모든 작업의 기준)
## 즉시 시작할 작업 (순서대로)
### 0.1 (잔여): OntoCast vendored copy
**근거**: 통합설계서 §9.1, OntoCast 분석 §13.1
```powershell
# 1. 원본을 vendored/ontocast로 복사 (.git 제외)
Copy-Item -Path "C:\Users\lasta\MyProject\AI\참고\ontocast-main\*" `
-Destination "C:\Users\lasta\MyProject\AI\ontology_platform\vendored\ontocast\" `
-Recurse -Exclude ".git",".github",".venv","node_modules"
# 2. 원본 LICENSE 및 NOTICE를 vendored/ontocast/ 안에 그대로 유지
# 3. NOTICE 파일의 "(원본 저장소 URL 기입)" 부분을 실제 URL로 채우기
# 4. git init (아직 안 했다면)
cd C:\Users\lasta\MyProject\AI\ontology_platform
git init
git add .
git commit -m "Initial scaffold: folder skeleton, design doc, NOTICE"
```
**확인 사항**:
- [ ] `vendored/ontocast/` 안에 원본 LICENSE 파일이 있어야 한다
- [ ] `vendored/ontocast/pyproject.toml`은 그대로 두되, 우리 `pyproject.toml`이 우선
- [ ] NOTICE 파일의 OntoCast 항목에 실제 source URL 기입
### 0.2: `select_ontology.py` 버그 수정
**근거**: 통합설계서 §5 Phase 0, OntoCast 분석 §13.1 / §9.1 (1번)
**문제**: `vendored/ontocast/ontocast/agent/select_ontology.py`에서 None 선택 인덱스 불일치.
- 코드는 `answer_index == 0`을 None으로 처리
- 그러나 dynamic model은 `1..num_ontologies+1` 범위 사용
- 실제 None 선택은 `num_ontologies + 1`이어야 자연스러움
**조치**:
1. 해당 함수의 분기 로직을 `answer_index == num_ontologies + 1` 또는 동등한 표현으로 수정
2. **수정 사실을 파일 상단 주석으로 명시** (Apache 2.0 의무): 예) `# MODIFIED 2026-MM-DD: Fixed None index inconsistency, see docs/통합설계서.md §5 Phase 0`
3. 회귀 테스트 작성: `tests/unit/test_select_ontology.py`
- 케이스 1: ontology가 0개일 때 → None 반환
- 케이스 2: ontology가 N개, LLM이 1~N 선택 → 해당 ontology 반환
- 케이스 3: ontology가 N개, LLM이 N+1 선택 → None 반환
### 0.3: `convert_document.py` 다중 파일 처리 확장
**근거**: 통합설계서 §5 Phase 0, OntoCast 분석 §13.1 (3번) / §21.1 (4번)
**문제**: `convert_document()`가 "processing only one file"로 주석 처리되어 있고, 다중 파일 처리 시 마지막 파일 기준으로만 상태가 업데이트됨.
**조치**:
1. 입력 파일 목록을 순회하며 각 파일을 독립 `ContentUnit`으로 만들어 `AgentState.content_units`에 누적
2. 동일 corpus 내 파일들이 함께 처리되도록 보장 (각 파일이 별도 doc IRI를 가짐)
3. 회귀 테스트: 2개 PDF를 한 번에 처리 → 둘 다 처리되어야 함
### 0.4: Robyn → FastAPI 재작성
**근거**: 통합설계서 §11 (기술 스택), OntoCast 분석 §13 (API 명세)
**조치**:
1. `platform/api/main.py` 생성 (FastAPI app 인스턴스)
2. OntoCast 분석 §13.1~§13.4의 4개 endpoint를 FastAPI로 동일 시맨틱 재작성:
- `GET /health`
- `GET /info`
- `POST /process` (JSON + multipart)
- `POST /flush` (관리자 권한 + confirmation token, 분석 §21.1 #6)
3. OntoCast의 `ToolBox` 의존성 주입은 FastAPI `Depends`로 변환
4. `uvicorn platform.api.main:app --reload`로 기동 가능해야 함
**중요**: OntoCast 코어 모듈(`stategraph/`, `agent/`, `onto/`, `tool/`)은 **건드리지 않는다**. API 레이어만 재작성.
### 0.5: Pydantic Settings 정리
**근거**: 통합설계서 §5 Phase 0 (5번), OntoCast 분석 §15
**조치**:
1. `platform/config.py` 생성
2. `pydantic-settings``BaseSettings``.env` 로딩
3. **Phase 0에서는 filesystem 모드만 활성화** (Fuseki/Neo4j는 Phase 4에서):
- `STORAGE_BACKEND=filesystem` 강제
- Neo4j/Fuseki 변수가 채워져 있어도 무시
4. OntoCast의 기존 `Config` 클래스는 우리 `Settings`에서 만들어 주입
### 0.6: End-to-end 통합 테스트
**근거**: 통합설계서 §5 Phase 0 Acceptance Gate
**조치**:
1. `vendored/ontocast/data/`의 예제 JSON 또는 PDF 1개를 fixture로 복사 → `tests/fixtures/`
2. `tests/integration/test_phase0_e2e.py` 작성:
- FastAPI `TestClient``/process` 호출
- 응답에 `ontology` TTL과 `facts` TTL 둘 다 포함
- `working_directory/`에 ontology/facts 파일 생성 확인
- BudgetTracker가 LLM call/triple count를 0보다 큰 값으로 기록
### 0.7: Acceptance Gate 0 체크
통합설계서 §5 Phase 0 Acceptance Gate의 4개 체크박스를 PR에 인용하며 모두 확인:
- [ ] 단일 PDF 또는 JSON 입력 → ontology TTL + facts TTL이 filesystem에 생성됨
- [ ] `/health`, `/info`, `/process` (FastAPI 버전) 정상 동작
- [ ] BudgetTracker가 LLM call/triple count를 정확히 기록
- [ ] LangGraph 워크플로우(CONVERT→CHUNK→...→SERIALIZE) 전 노드가 traceable
## 작업 시 준수사항
1. **PR 단위**: 위의 0.1~0.7 각각을 별도 PR/커밋으로 분리. 하나의 PR에 여러 단계를 섞지 않는다.
2. **PR 설명에 근거 인용**: 예) "통합설계서 §5 Phase 0 (3번)에 따라 다중 파일 처리 확장. OntoCast 분석 §13.1 인용."
3. **vendored/ 수정 시 라이선스 의무**:
- 수정한 파일 상단에 `# MODIFIED YYYY-MM-DD: <한 줄 설명>` 주석 추가
- 원본 LICENSE/NOTICE 파일은 절대 삭제하지 않는다
4. **Phase 1로 넘어가지 말 것**: Acceptance Gate 0 통과 전까지 Trafilatura/Crawl4AI/Guardrails/Neo4j GraphRAG 의존성을 활성화하거나 import하지 않는다. (`pyproject.toml`에 명시되어 있더라도 코드에서 사용 금지)
## Phase 1 이후 핸드오프
Phase 0 완료 후, 본 폴더에 `PHASE1_NEXT_STEPS.md`를 작성하여 다음 작업자에게 동일한 형식으로 핸드오프한다. 통합설계서 §12 Phase 1 작업 단위(1.1~1.7)를 참조.

View File

@@ -0,0 +1,162 @@
# Phase 1 — Trafilatura 통합 (다음 작업자 핸드오프)
본 문서는 Phase 0이 완료된 시점에서 Phase 1 작업을 이어받는 AI 에이전트 또는 개발자가 즉시 작업을 시작하기 위한 핸드오프 노트다.
## 시작 전 확인 사항
- [ ] **Phase 0 Acceptance Gate**가 모두 ✅인가? [PHASE0_ACCEPTANCE_GATE.md](PHASE0_ACCEPTANCE_GATE.md) 참조. 통과 전에는 Phase 1 진행 금지.
- [ ] `tests/unit``tests/integration` 전체가 PASS인가?
- [ ] git log에 Phase 0 commit들이 PR 단위로 분리되어 있는가? (0.1 vendored / 0.2 bug fix / 0.3 multi-file / 0.4 FastAPI / 0.5 config / 0.6 e2e tests / 0.7 gate)
## Phase 1 목표
URL이 입력일 때 원본 페이지에서 본문, 제목, 저자, 날짜, 언어, canonical URL을 정확히 뽑아 OntoCast의 `ContentUnit` metadata에 채워 넣는다.
**근거**: 통합설계서 §5 Phase 1, Trafilatura 분석 §11~§17.
**왜 Trafilatura를 가장 먼저 통합하는가**: 가장 작은 통합 — 단일 함수 호출(`bare_extraction`)만으로 끝남. 의존성도 명확하며 라이선스 동일 (Apache 2.0).
## 작업 단위 (PR 분해)
### 1.1: Trafilatura 의존성 활성화
`pyproject.toml`에 이미 `trafilatura[all]>=2.0.0`이 명시되어 있다. 활성화 절차:
```powershell
pip install -e ".[dev]" # 의존성 재설치 시 trafilatura 자동 설치
python -c "import trafilatura; print(trafilatura.__version__)"
```
**확인**: `2.0.0` 이상이 출력되어야 한다.
### 1.2: `web_extractor.py` 어댑터 작성
**위치**: `platform/core/extractors/web_extractor.py`
**근거**: Trafilatura 분석 §17의 `extract_for_ontology` 함수를 거의 그대로 사용.
**필수 동작**:
- 입력: `html: str`, `url: str`, `lang: str | None = None`
- 출력: `ExtractedWebDocument` (dataclass)
- `url`, `title`, `author`, `date`, `sitename`, `description`
- `text` (정제 본문)
- `body_xml` (Trafilatura `Document.body`)
- `metadata` (raw dict)
- `fingerprint` (SimHash)
- 실패 시 `None` 반환
**호출 옵션** (Trafilatura 분석 §12 권장값 그대로):
```python
Extractor(
output_format="python",
url=url,
with_metadata=True,
comments=False,
tables=True,
formatting=True,
links=True,
images=True,
dedup=True,
lang=lang,
)
```
### 1.3: `ContentUnit` 모델 확장
OntoCast의 `vendored/ontocast/ontocast/onto/content_unit.py`**직접 수정하지 말고**, 우리 쪽에 wrapper 모델을 만든다.
**위치**: `platform/models/content_unit.py`
**필드** (통합설계서 §7.1 참조):
- 기존 OntoCast 필드 (`text`, `index`, `doc_iri`, `graph`, `type`, `iri`) 유지/위임
- 추가: `source_url`, `title`, `author`, `publish_date`, `language`, `sitename`, `fingerprint`, `content_hash`, `metadata`, `retrieved_at`, `extracted_by`
**호환성**: 기존 OntoCast 코드가 받는 `ContentUnit`과 인터페이스 호환되도록 `as_ontocast()` 메서드 제공.
### 1.4: OntoCast `ConverterTool` 분기 추가 (URL/HTML 입력)
**문제**: OntoCast `ConverterTool`은 PDF/DOCX/MD만 처리. URL 또는 HTML 입력은 처리 못 함.
**조치 옵션**:
- **옵션 A (권장)**: OntoCast의 `convert_document.py` 모듈에 새 분기 추가 — `.html`, `.htm` 확장자 또는 `state.source_url`이 있으면 Trafilatura로 처리. **vendored 수정이지만 매우 작음**.
- **옵션 B**: API 레이어(`platform/api/`)에서 입력이 URL이면 미리 fetch + Trafilatura 처리한 뒤 그 결과를 JSON envelope로 ToolBox에 넘김.
**권장**: 옵션 B. vendored 수정을 늘리지 않고 platform 코드로 끝낼 수 있음.
새 endpoint:
- `POST /process/url` — body: `{"url": "...", "ontology_user_instruction": "...", ...}` — 내부적으로 `web_extractor`로 본문 추출 후 OntoCast workflow 실행.
### 1.5: Fingerprint 기반 dedup
- `tests/fixtures/`에 같은 본문의 두 URL fixture 만들기
- `web_extractor` 결과의 `fingerprint`가 일치하면 OntoCast 처리 skip
- 저장 위치: 일단 in-memory set (`platform/storage/dedup_cache.py`), Phase 2에서 Redis로 이전
### 1.6: 한국어 페이지 3종 추출 검증
**테스트 fixture 수집**:
- 한국어 뉴스 1개 (예: 연합뉴스/조선/한겨레)
- 한국어 블로그 1개 (예: 네이버 블로그)
- 한국어 쇼핑 페이지 1개 (예: 쿠팡 상품 페이지)
각각 raw HTML을 `tests/fixtures/korean/`에 저장 (실제 fetch는 운영 환경에서 한 번만, 그 결과를 fixture로 박제).
**테스트**: `tests/integration/test_web_extractor_korean.py`
- 본문 길이 > 200자
- title 추출 성공
- language 감지: `ko`
- author 또는 date 중 하나 이상 추출
### 1.7: Acceptance Gate 1 체크
통합설계서 §5 Phase 1 Acceptance Gate 4개 항목:
- [ ] URL 입력 → 본문/메타데이터가 정확히 추출되어 `ContentUnit`에 저장됨
- [ ] 한국어 뉴스/블로그/쇼핑 페이지 각각 1개씩 본문 추출 정확도 수동 검증
- [ ] 동일 URL 재입력 시 fingerprint 기반 dedup으로 skip
- [ ] Phase 0의 모든 기능이 여전히 정상 동작 (회귀 없음)
Phase 0의 `tests/unit/`, `tests/integration/` 전체가 여전히 PASS여야 함.
## Phase 1에서 만들 새 산출물
```
platform/
core/
extractors/
web_extractor.py ← 1.2
models/
content_unit.py ← 1.3
storage/
dedup_cache.py ← 1.5
api/
routes/
url_ingest.py ← 1.4 (POST /process/url)
tests/
fixtures/
korean/ ← 1.6
news_yonhap.html
blog_naver.html
shop_coupang.html
unit/
test_web_extractor.py ← 1.2
test_dedup_cache.py ← 1.5
integration/
test_url_ingest.py ← 1.4
test_web_extractor_korean.py ← 1.6
docs/
phases/
PHASE1_ACCEPTANCE_GATE.md ← 1.7 (PHASE0과 동일 형식)
PHASE2_NEXT_STEPS.md ← 다음 작업자에게 넘김
```
## 작업 시 준수사항 (PHASE0과 동일)
1. **PR 단위 분리**: 1.1~1.7 각각 별도 PR/커밋.
2. **PR 설명에 근거 인용**: 예) "통합설계서 §5 Phase 1 (1.2)에 따라 Trafilatura adapter 작성. Trafilatura 분석 §17 인용."
3. **vendored/ontocast/** 수정 최소화. 본 Phase에서는 옵션 B 사용 시 vendored 수정 0건이 목표.
4. **Phase 2로 넘어가지 말 것**: Acceptance Gate 1 통과 전까지 Crawl4AI 의존성을 코드에서 import하지 않는다.
## Phase 2 이후 핸드오프
Phase 1 완료 후 다음 작업자에게 동일한 형식의 `PHASE2_NEXT_STEPS.md`를 작성한다. 통합설계서 §12 Phase 2 작업 단위(2.1~2.8)를 참조.