8.4 KiB
8.4 KiB
crawler_platform 책임 분리 리포트 (AI=Semantic Extractor)
작성일: 2026-05-11
대상: C:\Users\lasta\MyProject\AI\crawler_platform
1. 결론 요약
현재 구조는 동작은 하지만, 제어 책임이 API Route / SiteCrawler / CrawlPipeline / Repository에 분산되어 있습니다.
특히 SiteCrawler와 CrawlPipeline이 탐색, 분석 판단, AI 호출, 저장까지 동시에 수행하고 있어 확장성과 테스트 경계가 약합니다.
핵심 정리:
- AI(
LLMJsonExtractor)는 현재 DB/크롤 흐름을 직접 알지 않으며, 대체로 “의미 추출기” 역할을 수행 중. - 하지만 시스템 전체 orchestration 주체가 부재하여 Route/Crawler/Pipeline에 제어가 분산됨.
- Repository는 저장소를 넘어 일부 정책(신뢰도 결합/병합 전략)을 포함.
2. 구성요소별 실제 책임 진단
API Route (app/api/routes.py)
현재 책임:
- 요청/응답 처리 외에 다음까지 수행
- config 로딩 및 의존 객체 생성 (
CrawlPipeline,SiteCrawler)- 근거: 149-195
- crawl 파라미터 정책 적용(
max_depth/max_pages보정)- 근거: 188-191
- discovery 흐름 직접 수행(robots/fetch/discover)
- 근거: 197-212
- claim confidence 갱신 정책(0~1 clamp)
- 근거: 274-284
- entity merge 비즈니스 로직 직접 수행(Claim/Relation 재매핑)
- 근거: 286-308
- 추천 태그 집계 규칙 직접 수행
- 근거: 310-343
판단:
- Route가 단순 진입점을 넘어 서비스/도메인 로직 조립 및 정책 수행자 역할까지 맡음.
- “얇은 Route + Service 호출” 원칙과 불일치.
SiteCrawler (app/core/crawler/site_crawler.py)
현재 책임:
- 사이트 탐색(queue/depth/visited/discover)
- 근거: 70-117
- same-domain 필터, robots 차단 판단
- 근거: 89-100
- 페이지 유형 분류 및 분석 여부 판단
- 근거: 105, 119-120, 201-224
- AI/Extractor 호출
- 근거: 120
- 저장 호출(page/claim/evidence/log)
- 근거: 121-135
- crawl_jobs 상태 생성/완료 처리
- 근거: 83, 172-188
판단:
SiteCrawler가 “웹 탐색기”를 넘어 페이지 처리기 + 저장 오케스트레이터까지 수행.- 요청하신 기준(탐색 전용) 대비 책임 과다.
분리 후보:
classify_page,analyze_page_types판단 로직extractor.extract(...)호출repository.upsert_page/save_extraction_bundle(...)저장 호출_create_job/_finish_job실행 추적
CrawlPipeline (app/core/crawler/pipeline.py)
현재 책임:
- robots 정책 판단
- 근거: 34-35
- fetch + parse + extract
- 근거: 37-41
- 프로젝트/소스 동기화 및 페이지/추출 결과 저장
- 근거: 43-55
판단:
- 단일 URL 처리기 역할을 하면서도 저장 정책까지 포함.
- 이름은 Pipeline이지만 사실상 PageProcessor + 저장 orchestration을 동시에 수행.
분리 후보:
crawl_url를PageProcessor.process(url)와CrawlService.persist(processed_page)로 분리- robots 허용/재시도/저장 여부 판단은 Service 계층으로 이동
Extractor (app/core/extractor/ai_provider.py, factory.py)
현재 책임:
- LLM 호출 및 JSON 파싱/복구
- ontology predicate normalize
- 실패 시 rule-based fallback
주요 근거:
- AI 추출 핵심: 42-107, 148-247
- ontology normalize: 75-78
- fallback: 109-131
- provider 선택(facade):
factory.py11-17
판단:
- 크롤링 큐, 링크 탐색, DB 저장을 직접 알지 않음(좋음).
- 다만
LLMJsonExtractor내부 fallback은 “추출 품질 보완” 범주로는 허용 가능하나, 책임을 더 엄격히 분리하려면 fallback도 외부 orchestration(Service)로 이동 가능.
요약:
- 치명적 위반 없음(crawl/storage/pipeline orchestration은 알지 않음).
Repository (app/core/database/repository.py)
현재 책임:
- pages/entities/claims/evidence/extraction_logs 저장 및 upsert
- claim hash 기반 dedup/merge
- relation upsert 및 support_count 증가
- confidence 결합 규칙(extraction + source trust)
주요 근거:
- 저장/병합 중심: 140-226, 228-306
- 신뢰도 결합 규칙: 163, 322-323
- claim hash 전략: 164-176, 326-342
판단:
- 저장 인터페이스 역할은 수행하지만, **정책성 로직(신뢰도 결합 비율 0.7/0.3, max merge, relation support 전략)**이 포함됨.
- “Repository는 저장소” 원칙을 엄격히 적용하면, 정책 계산은 Service(또는 Domain Policy)로 이동하는 것이 바람직.
분리 후보:
combine_confidence- claim update 시
max(confidence)전략 - relation
support_count증가 규칙
session_scope (app/core/database/session.py)
현재 책임:
- commit/rollback/close 트랜잭션 경계
근거: 40-51
판단:
- 요청하신 기준과 일치. 변경 우선순위 낮음.
3. 현재 가장 큰 책임 혼재 지점
SiteCrawler가 탐색기 + 처리기 + 저장 오케스트레이터를 모두 수행CrawlPipeline이 처리기 + 저장기를 동시에 수행API Route가 서비스 조립/정책/집계/병합 로직을 직접 수행Repository가 저장소를 넘어 정책 일부까지 포함
4. 목표 아키텍처 제안
권장 호출 구조:
FastAPI Route -> CrawlService -> SiteCrawler -> PageProcessor -> Fetcher -> Parser -> Extractor -> Repository
역할 재정의:
- Route: request 검증, service 호출, response 변환
- CrawlService: 전체 orchestration/정책 판단/재시도/저장 여부 결정
- SiteCrawler: 링크 탐색(queue/depth/domain/link discovery)만 수행
- PageProcessor: 단일 URL의 fetch/parse/extract만 수행
- Extractor: 텍스트 -> 구조화 JSON/Entity/Claim 변환만 수행
- Repository: 저장/upsert 인터페이스만 수행 (정책 계산 제외)
5. 리팩터링 설계(코드 대규모 변경 전)
Phase 0: 인터페이스 고정
PageProcessorResultDTO 정의url/final_url/status_code/title/clean_text/page_type/entities/claims/raw_output/errors
CrawlDecisionPolicy(분석 여부/저장 여부 판단) 초안 분리
Phase 1: Service 계층 도입
app/core/services/crawl_service.py신설- Route는
CrawlService.crawl_url(...),CrawlService.crawl_site(...)만 호출 - 기존 로직은 내부적으로 재사용하되 외부 인터페이스 먼저 고정
Phase 2: SiteCrawler 축소
SiteCrawler반환을 “발견된 URL 작업 목록” 중심으로 전환- 페이지 분류/분석 여부/AI 호출/저장은
CrawlService로 이동
Phase 3: CrawlPipeline -> PageProcessor 전환
CrawlPipeline.crawl_url를PageProcessor.process로 대체- PageProcessor는 fetch/parse/extract까지만 수행, DB 접근 제거
Phase 4: Repository 정책 분리
combine_confidence, merge rule을app/core/services/policies/*.py로 이동- Repository는 저장/조회/upsert만 수행
Phase 5: Route 슬림화
/crawl,/crawl-site,/discover,/entities/merge,/claims/{id}/confidence를 Service 호출형으로 변환
6. 안전한 단위 리팩터링 파일 목록과 변경 순서
app/core/services/crawl_service.py(신규)app/core/services/crawl_dto.py(신규)app/core/services/policies.py(신규; confidence/merge 정책)app/core/crawler/pipeline.py(PageProcessor 역할로 축소 또는page_processor.py로 분리)app/core/crawler/site_crawler.py(탐색 전용으로 축소)app/core/database/repository.py(정책 제거, 저장 전용화)app/api/routes.py(Service 호출만 남기기)app/cli/main.py(Route와 동일 Service 재사용)tests/(서비스 단위/계층 경계 테스트 추가)
7. 테스트 전략(리팩터링 안전장치)
- 계약 테스트:
Extractor입력/출력 계약 유지 - 단위 테스트:
SiteCrawler: URL discovery/queue/depth/domain 필터만 검증PageProcessor: fetch/parse/extract 파이프만 검증(저장 없음)CrawlService: 분석 여부 판단/저장 호출/재시도 정책 검증Repository: pure upsert/조회만 검증
- 회귀 테스트:
/crawl,/crawl-siteAPI 응답 필드 변화 없음- claim/entity 수 및 dedup 결과 일관성 확인
8. 즉시 적용 가능한 최소 원칙
- AI는
clean_text -> structured data만 담당 - “저장 여부, 재시도, 정책 판단”은 Service가 담당
- Repository에서 정책 계산 로직 분리
- Route에서 SQL/병합 규칙 직접 처리 제거