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,934 @@
# Crawl4AI 프로젝트 분석 및 기능명세
분석 대상: `C:\Users\lasta\MyProject\AI\참고\crawl4ai-main`
분석일: 2026-05-13
목적: 향후 웹 크롤링/추출 플랫폼의 기준 소스로 삼기 위한 구조 분석 및 정확한 기능명세 정리
## 1. 프로젝트 개요
Crawl4AI는 Python 기반 오픈소스 웹 크롤러/스크레이퍼 SDK이다. 핵심 목표는 일반 웹페이지, 동적 웹앱, 로컬 파일, 원시 HTML을 수집한 뒤 LLM/RAG/에이전트 파이프라인에 적합한 Markdown, 구조화 JSON, 링크/미디어/메타데이터로 변환하는 것이다.
주요 특징은 다음과 같다.
- 비동기 크롤링: `AsyncWebCrawler` 중심의 async SDK
- 브라우저 크롤링: Playwright/Patchright 기반 동적 페이지 처리
- HTTP 크롤링: 브라우저 없이 빠른 HTTP fetch 처리
- Markdown 생성: 원문 Markdown, citation 포함 Markdown, 필터링된 fit Markdown 지원
- 구조화 추출: LLM 기반 의미 추출을 주요 방식으로 지원하며, CSS/XPath/LXML/Regex 기반 결정적 추출도 함께 제공
- 딥 크롤링: BFS, DFS, Best-First 전략 및 URL 필터/스코어러
- URL 시딩: sitemap, Common Crawl, HEAD 메타데이터, BM25 기반 URL 후보 생성
- 안티봇 보조: stealth, undetected browser adapter, proxy retry, fallback fetch hook
- 배포형 API: Docker/FastAPI 서버, REST API, streaming, job API, MCP bridge, monitor dashboard
- 운영 기능: 캐시, smart cache validation, browser pool, rate limit, Redis job state, webhook
## 2. 기술 스택
- 언어: Python 3.10 이상
- 브라우저 엔진: Playwright, Patchright
- HTTP: aiohttp, httpx
- HTML 처리: lxml, BeautifulSoup, cssselect
- 데이터 모델: Pydantic v2, dataclass
- 저장소/캐시: aiosqlite 기반 로컬 캐시, Docker 서버는 Redis job state 사용
- LLM 연동: `unclecode-litellm`
- 검색/랭킹: rank-bm25, snowballstemmer, numpy
- 이미지/문서: Pillow, optional PDF parser
- API 서버: FastAPI, slowapi, prometheus-fastapi-instrumentator
- 배포: Dockerfile, docker-compose, supervisord
## 3. 최상위 구조
```text
crawl4ai-main/
crawl4ai/ # SDK 본체
crawl4ai/deep_crawling/ # 딥 크롤링 전략, 필터, 스코어러
crawl4ai/crawlers/ # 특화 크롤러 예: google_search, amazon_product
crawl4ai/processors/pdf/ # PDF 처리 전략
crawl4ai/script/ # C4A script 컴파일러/검증기
deploy/docker/ # FastAPI 서버, browser pool, job, monitor, MCP
docs/ # 공식 문서/예제/릴리즈 노트
tests/ # 단위/통합/회귀/Docker/브라우저 테스트
```
패키지 공개 API는 `crawl4ai/__init__.py`에서 대부분 export한다. 앞으로 우리 프로젝트에서 사용하거나 래핑할 핵심 객체는
`AsyncWebCrawler`, `BrowserConfig`, `CrawlerRunConfig`, `CacheMode`, 추출 전략류, 딥 크롤링 전략류, `CrawlResult`이다.
## 4. 핵심 런타임 아키텍처
### 4.1 기본 흐름
```mermaid
flowchart TD
A["사용자: URL + BrowserConfig + CrawlerRunConfig"] --> B["AsyncWebCrawler.arun"]
B --> C["CacheContext: 캐시 읽기/쓰기 판단"]
C --> D{"캐시 사용 가능?"}
D -- yes --> E["캐시 결과 로드 및 optional freshness 검증"]
D -- no --> F["CrawlerStrategy.crawl"]
F --> G["Playwright 또는 HTTP fetch"]
G --> H["apocess_html: HTML 정리/스크랩/Markdown/추출"]
E --> H
H --> I["CrawlResult 반환"]
```
### 4.2 주요 컴포넌트
- `AsyncWebCrawler`: SDK 중심 클래스. lifecycle, 캐시, robots.txt, proxy retry, anti-bot retry, HTML 후처리, 단일/다중/딥 크롤링 진입점을 담당한다.
- `AsyncCrawlerStrategy`: 실제 fetch 계층의 추상화.
- `AsyncPlaywrightCrawlerStrategy`: 동적 브라우저 페이지 처리, JS 실행, wait, iframe, screenshot, PDF, MHTML, shadow DOM, network/console capture 등을 담당한다.
- `AsyncHTTPCrawlerStrategy`: 브라우저 없는 HTTP 기반 수집. raw/file/http 다운로드 및 text/file 판단을 처리한다.
- `ContentScrapingStrategy`: HTML에서 cleaned HTML, media, links, metadata, tables 등을 산출한다.
- `MarkdownGenerationStrategy`: cleaned HTML을 LLM 친화 Markdown으로 변환한다.
- `ExtractionStrategy`: Markdown/HTML/text를 구조화 데이터로 추출한다. 특히 `LLMExtractionStrategy`는 이 프로젝트가 지향하는 LLM 친화 크롤링의 핵심 추출 방식이다.
- `DeepCrawlStrategy`: 단일 URL이 아닌 graph traversal 방식의 다중 URL 크롤링을 수행한다.
- `BaseDispatcher`: 다중 URL 크롤링 시 concurrency, memory, rate limit, retry, streaming을 담당한다.
## 5. SDK 기능명세
### 5.1 `AsyncWebCrawler`
기능:
- `async with AsyncWebCrawler(...)` context manager 지원
- `start()`, `close()` 명시 lifecycle 지원
- `arun(url, config)` 단일 URL/파일/raw HTML 크롤링
- `arun_many(urls, config, dispatcher)` 다중 URL 크롤링
- `aseed_urls(...)` URL 후보 생성
- `aprocess_html(...)` fetch 이후 HTML 처리 파이프라인
- `thread_safe=True`일 때 내부 lock으로 동시 접근 직렬화
- `base_directory/.crawl4ai/cache` 캐시 디렉터리 생성
- `robots.txt` 검사 옵션 지원
- `deep_crawl_strategy`가 들어오면 `arun` 호출이 딥 크롤링으로 장식됨
입력 URL 형식:
- `http://...`, `https://...`
- `file://...`
- `raw:<html>`, `raw://<html>`
반환:
- 일반 단일 크롤: `CrawlResult`
- 딥 크롤 또는 streaming 설정: 전략/설정에 따라 `CrawlResult` 목록 또는 async stream
### 5.2 `BrowserConfig`
브라우저 인스턴스/컨텍스트 설정이다.
주요 항목:
- 브라우저 종류: `browser_type=chromium|firefox|webkit`
- 실행 형태: `headless`, `browser_mode=dedicated|builtin|docker|custom`
- CDP 연결: `cdp_url`, `browser_context_id`, `target_id`, `cache_cdp_connection`
- persistent context: `use_persistent_context`, `user_data_dir`, `storage_state`
- viewport: `viewport_width`, `viewport_height`, `viewport`, `device_scale_factor`
- proxy: `proxy_config`, deprecated `proxy`
- 다운로드: `accept_downloads`, `downloads_path`
- 인증/헤더: `cookies`, `headers`, `user_agent`
- user-agent 생성: `user_agent_mode=random`, `user_agent_generator_config`
- 성능 모드: `text_mode`, `light_mode`, `memory_saving_mode`, `max_pages_before_recycle`
- 안티봇: `enable_stealth`
- 리소스 차단: `avoid_ads`, `avoid_css`
- 초기 스크립트: `init_scripts`
주의:
- `enable_stealth`는 builtin managed browser와 함께 사용할 수 없도록 검증된다.
- `proxy` 문자열은 deprecated이며 내부적으로 `ProxyConfig`로 변환된다.
- `browser_mode=builtin|docker|custom`은 managed browser/CDP 경로를 사용한다.
### 5.3 `CrawlerRunConfig`
개별 크롤 요청 단위 설정이다. 앞으로 우리 프로젝트에서 가장 자주 매핑해야 할 객체다.
콘텐츠 처리:
- `word_count_threshold`
- `css_selector`
- `target_elements`
- `excluded_tags`
- `excluded_selector`
- `only_text`
- `keep_data_attributes`
- `keep_attrs`
- `remove_forms`
- `prettiify`
- `parser_type`
- `scraping_strategy`
추출/Markdown:
- `extraction_strategy`
- `chunking_strategy`
- `markdown_generator`
- `table_extraction`
- `table_score_threshold`
캐시:
- `cache_mode=ENABLED|DISABLED|READ_ONLY|WRITE_ONLY|BYPASS`
- `check_cache_freshness`
- `cache_validation_timeout`
- legacy 옵션 `bypass_cache`, `disable_cache`, `no_cache_read`, `no_cache_write`는 deprecated 접근 시 에러 유도
세션/프록시:
- `session_id`
- `proxy_config`
- `proxy_rotation_strategy`
- `proxy_session_id`
- `proxy_session_ttl`
- `proxy_session_auto_release`
브라우저 지역/정체성:
- `locale`
- `timezone_id`
- `geolocation`
- `user_agent`
- `user_agent_mode`
페이지 로딩/대기:
- `wait_until`
- `page_timeout`
- `wait_for`
- `wait_for_timeout`
- `wait_for_images`
- `delay_before_return_html`
- `mean_delay`
- `max_range`
- `semaphore_count`
상호작용:
- `js_code`
- `js_code_before_wait`
- `c4a_script`
- `js_only`
- `scan_full_page`
- `scroll_delay`
- `max_scroll_steps`
- `process_iframes`
- `flatten_shadow_dom`
- `remove_overlay_elements`
- `remove_consent_popups`
- `simulate_user`
- `override_navigator`
- `magic`
- `adjust_viewport_to_content`
미디어/아카이브:
- `screenshot`
- `screenshot_wait_for`
- `screenshot_height_threshold`
- `force_viewport_screenshot`
- `pdf`
- `capture_mhtml`
- `exclude_external_images`
- `exclude_all_images`
- `image_description_min_word_threshold`
- `image_score_threshold`
링크:
- `exclude_external_links`
- `exclude_internal_links`
- `exclude_social_media_links`
- `exclude_social_media_domains`
- `exclude_domains`
- `score_links`
- `preserve_https_for_internal_links`
- `link_preview_config`
디버깅/관찰:
- `verbose`
- `log_console`
- `capture_network_requests`
- `capture_console_messages`
연결/실행:
- `method`
- `stream`
- `prefetch`
- `process_in_browser`
- `check_robots_txt`
딥 크롤링/매칭:
- `deep_crawl_strategy`
- `virtual_scroll_config`
- `url_matcher`
- `match_mode=OR|AND`
안티봇 재시도:
- `max_retries`
- `fallback_fetch_function`
### 5.4 `CrawlResult`
크롤 결과 모델이다.
주요 필드:
- `url`
- `success`
- `html`
- `cleaned_html`
- `markdown`
- `extracted_content`
- `media`
- `links`
- `metadata`
- `tables`
- `screenshot`
- `pdf`
- `mhtml`
- `downloaded_files`
- `js_execution_result`
- `session_id`
- `status_code`
- `response_headers`
- `redirected_url`
- `redirected_status_code`
- `ssl_certificate`
- `network_requests`
- `console_messages`
- `dispatch_result`
- `head_fingerprint`
- `cached_at`
- `cache_status`
- `crawl_stats`
- `error_message`
`markdown`는 문자열처럼 동작하면서 내부적으로 `MarkdownGenerationResult`를 제공한다.
`MarkdownGenerationResult` 필드:
- `raw_markdown`
- `markdown_with_citations`
- `references_markdown`
- `fit_markdown`
- `fit_html`
## 6. 추출 기능명세
Crawl4AI의 추출 계층은 LLM 기반 의미 추출을 중심 기능으로 제공하고, CSS/XPath/LXML/Regex 기반 추출을 보완적인 결정적 전략으로 함께 둔다. 즉 이 프로젝트는 단순 HTML 파서가 아니라, 수집한 웹 콘텐츠를 LLM이 바로 이해하고 구조화할 수 있는 형태로 변환하는 것을 주요 방식으로 삼는다.
### 6.1 LLM 기반 추출
클래스: `LLMExtractionStrategy`
기능:
- LLM provider, instruction, schema 기반 구조화 추출
- chunk 단위 분할 후 병렬/순차 LLM 호출
- token usage 집계
- JSON schema 기반 결과 유도 가능
- Docker API의 `/llm`, `/llm/job`, `/ask`에서도 사용
사용처:
- 크롤링 결과의 기본 의미 추출 방식
- 비정형/반정형 페이지에서 의미 기반 필드 추출
- 사용자가 자연어 instruction으로 원하는 데이터 구조를 지정하는 추출
- RAG용 요약/질의응답
- schema 기반 JSON 생성 및 schema 자동 생성 보조
### 6.2 CSS/XPath/LXML 기반 JSON 추출
클래스:
- `JsonCssExtractionStrategy`
- `JsonXPathExtractionStrategy`
- `JsonLxmlExtractionStrategy`
기능:
- 반복 요소 base selector 지정
- field별 selector, type, attribute, transform 지정
- text/html/attribute/source 추출
- nested/list field 추출
- LLM을 이용한 schema 생성 보조 메서드 제공
권장 사용:
- 쇼핑몰 상품 목록, 뉴스 목록, 테이블형 반복 카드처럼 DOM 구조가 안정적인 사이트
- LLM 호출 비용을 줄여야 하거나 완전히 반복적인 DOM 패턴이 검증된 경우
### 6.3 Regex 추출
클래스: `RegexExtractionStrategy`
기능:
- email, url, phone 등 정규식 패턴 기반 추출
- 사용자 정의 패턴 지원
- plain text 변환 후 추출 가능
### 6.4 Cosine/Embedding 추출
클래스: `CosineStrategy`
기능:
- 문서 chunk embedding
- query와 유사한 문서 조각 필터링
- hierarchical clustering 보조
주의:
- optional dependency가 필요할 수 있다.
- LLM 없이 관련 섹션만 좁히는 용도에 적합하다.
## 7. Markdown 및 콘텐츠 필터링
### 7.1 Markdown 생성
클래스: `DefaultMarkdownGenerator`
기능:
- HTML을 Markdown으로 변환
- 링크 citation 및 reference 목록 생성
- content filter 적용 후 `fit_markdown`, `fit_html` 생성
- 표/코드/헤딩/링크가 LLM 입력에 적합하도록 정리
### 7.2 Content Filter
클래스:
- `PruningContentFilter`: 휴리스틱 기반 noise 제거
- `BM25ContentFilter`: query 기반 관련 콘텐츠 선별
- `LLMContentFilter`: LLM 기반 관련 콘텐츠 선별
사용 기준:
- 단순 문서 정리: `PruningContentFilter`
- 사용자 질의 중심 수집: `BM25ContentFilter`
- 의미적 판단이 중요한 고품질 추출: `LLMContentFilter`
- 우리 프로젝트의 기본 의미 필터링/추출 정책: LLM 우선, 필요 시 BM25/CSS/XPath로 비용과 속도를 보완
## 8. 브라우저 크롤링 기능명세
`AsyncPlaywrightCrawlerStrategy`가 담당한다.
지원 기능:
- Playwright browser/context/page lifecycle
- dedicated browser, managed browser, CDP 연결
- persistent profile 및 storage state
- JS 실행: 크롤 전/후 스크립트, C4A script 컴파일 결과
- selector/function 기반 wait
- iframe 처리
- shadow DOM flatten
- overlay/consent popup 제거
- full page scan 및 virtual scroll
- lazy image 대기
- screenshot 캡처
- PDF export
- MHTML 캡처
- file download 처리
- network request capture
- console message capture
- SSL certificate fetch
- navigator override 및 simulated user 동작
- stealth 적용
브라우저 관리자:
- `ManagedBrowser`는 CDP endpoint를 제공하는 browser process를 직접 띄우거나 기존 CDP에 연결한다.
- memory saving, light mode, text mode, proxy flag, debugging port, user data dir를 관리한다.
## 9. HTTP 크롤링 기능명세
`AsyncHTTPCrawlerStrategy`가 담당한다.
지원 기능:
- HTTP/HTTPS 요청
- `file://` 로컬 파일 처리
- `raw:` HTML 처리
- content-type 기반 text/file 판단
- 파일 다운로드명 추출
- proxy formatting
- hook 실행
- browser 없이 빠른 HTML 수집
제약:
- JS 렌더링, 실제 브라우저 DOM 변화, screenshot/PDF 등은 브라우저 전략 필요
## 10. 딥 크롤링 기능명세
### 10.1 전략
- `BFSDeepCrawlStrategy`: breadth-first 탐색
- `DFSDeepCrawlStrategy`: depth-first 탐색
- `BestFirstCrawlingStrategy`: URL score 기반 우선순위 탐색
공통 기능:
- `max_depth`
- `max_pages`
- stream/batch 실행
- cancellation
- link discovery
- visited/seen 관리
- resume/export state 일부 지원
- crawler의 `arun`을 decorator로 감싸 단일 호출 인터페이스와 통합
### 10.2 필터
- `FilterChain`: 여러 URL filter 조합
- `URLPatternFilter`: glob/패턴 기반 include/exclude
- `DomainFilter`: allowed/blocked domain, subdomain 판단
- `ContentTypeFilter`: 확장자/content type 기반 판단
- `ContentRelevanceFilter`: BM25 기반 관련도
- `SEOFilter`: title, meta description, canonical, schema.org, URL 품질 기반 score
### 10.3 스코어러
- `KeywordRelevanceScorer`
- `PathDepthScorer`
- `ContentTypeScorer`
- `FreshnessScorer`
- `DomainAuthorityScorer`
- `CompositeScorer`
Best-first crawling에서 우선순위 계산에 사용한다.
## 11. 다중 URL 크롤링/Dispatcher
클래스:
- `BaseDispatcher`
- `MemoryAdaptiveDispatcher`
- `SemaphoreDispatcher`
- `RateLimiter`
기능:
- URL별 config 선택: `url_matcher``match_mode`
- concurrency 제한
- memory threshold 기반 backpressure
- domain별 rate limit
- retry
- task status, memory usage, peak memory 기록
- streaming result 지원
- dispatcher monitor 연계
권장:
- 소량 병렬: `SemaphoreDispatcher`
- 대량/장시간 크롤: `MemoryAdaptiveDispatcher`
## 12. URL Seeder 기능명세
클래스: `AsyncUrlSeeder`
기능:
- sitemap 기반 URL 수집
- Common Crawl index 기반 URL 수집
- URL pattern 필터링
- live validation
- HEAD 요청으로 title/meta/canonical 등 head data 수집
- BM25/query 기반 URL relevance scoring
- nonsense URL 필터링
- cache 사용
- 여러 domain에 대한 batch seeding
설정 객체: `SeedingConfig`
주요 사용 시나리오:
- “사이트 전체 중 특정 주제/상품/문서 URL 후보를 먼저 뽑고, 선별된 URL만 실제 크롤링”
- 대규모 사이트에서 full crawl 전에 seed 후보를 줄이는 단계
## 13. Adaptive Crawler 기능명세
클래스:
- `AdaptiveCrawler`
- `AdaptiveConfig`
- `CrawlState`
- `StatisticalStrategy`
- `EmbeddingStrategy`
기능:
- 수집 상태를 누적하며 confidence 계산
- query coverage, consistency, saturation 기반 stop 판단
- 링크 relevance/novelty/authority 기반 ranking
- embedding 기반 semantic exploration
- state save/load
사용 시나리오:
- 고정 depth/page 수가 아니라 “원하는 정보가 충분히 모였을 때 멈추는” 연구형 크롤러
## 14. 캐시 기능명세
캐시 모드:
- `ENABLED`: 읽기/쓰기
- `DISABLED`: 캐시 사용 안 함
- `READ_ONLY`: 읽기만
- `WRITE_ONLY`: 쓰기만
- `BYPASS`: 해당 작업에서 캐시 우회
Smart Cache:
- `check_cache_freshness=True`일 때 ETag, Last-Modified, head fingerprint로 freshness 검증
- fresh면 `cache_status=hit_validated`
- 검증 실패 시 fallback으로 cached result 사용 가능
- stale/unknown이면 재크롤
캐시 대상:
- web URL과 file URL은 cacheable
- raw HTML은 기본적으로 cacheable 아님
## 15. 프록시 및 안티봇 기능명세
프록시:
- `ProxyConfig`
- 문자열/dict/env 기반 생성
- list proxy 지원
- `ProxyRotationStrategy`, `RoundRobinProxyStrategy`
- sticky proxy session: `proxy_session_id`, `proxy_session_ttl`
- NSTProxy API 연동 helper
안티봇:
- HTML/status 기반 block detection
- `max_retries`
- 여러 proxy 순회
- 실패 통계 `crawl_stats`
- 최후 수단 `fallback_fetch_function`
- `enable_stealth`
- `UndetectedAdapter`
- browser flags에서 automation 흔적 일부 완화
주의:
- CAPTCHA 해결 자체는 본체 기능이 아니라 예제에 가까운 외부 서비스 연동 형태다.
- 안티봇 우회는 사이트 약관/법적 제한을 반드시 확인해야 한다.
## 16. Docker/FastAPI 서버 기능명세
경로: `deploy/docker`
### 16.1 서버 구성
- `server.py`: FastAPI entrypoint
- `api.py`: crawl/md/llm 처리 로직
- `crawler_pool.py`: browser pool
- `job.py`: 비동기 job API
- `monitor.py`, `monitor_routes.py`: dashboard/metrics
- `auth.py`: JWT token 발급/검증
- `webhook.py`: job 완료 webhook 전달
- `mcp_bridge.py`: MCP schema/tool bridge
- `schemas.py`: request/response schema
### 16.2 REST endpoint
- `GET /`: playground redirect
- `POST /token`: JWT token 발급
- `POST /config/dump`: config object serialization
- `POST /md`: URL을 Markdown으로 변환
- `POST /html`: HTML 반환
- `POST /screenshot`: screenshot 반환/저장
- `POST /pdf`: PDF 반환/저장
- `POST /execute_js`: 지정 JS 실행
- `GET /llm/{url:path}`: URL + query 기반 LLM QA
- `GET /schema`: 서버/API schema
- `GET /hooks/info`: hook 지원 정보
- `GET /health`: health check
- `GET /metrics`: Prometheus metrics
- `POST /crawl`: 다중 URL 크롤
- `POST /crawl/stream`: streaming crawl
- `GET /ask`: 질문/응답형 endpoint
- `POST /llm/job`: LLM extraction background job 생성
- `GET /llm/job/{task_id}`: LLM job 조회
- `POST /crawl/job`: crawl background job 생성
- `GET /crawl/job/{task_id}`: crawl job 조회
Monitor endpoint:
- `GET /dashboard`
- `GET /health`
- `GET /requests`
- `GET /browsers`
- `GET /endpoints/stats`
- `GET /timeline`
- `GET /logs/janitor`
- `GET /logs/errors`
- `POST /actions/cleanup`
- `POST /actions/kill_browser`
- `POST /actions/restart_browser`
- `POST /stats/reset`
- `WebSocket /ws`
### 16.3 API 요청 모델
`CrawlRequest`:
- `urls: List[str]`, 1~100개
- `browser_config: Dict`
- `crawler_config: Dict`
`CrawlRequestWithHooks`:
- `CrawlRequest` + optional `hooks`
`MarkdownRequest`:
- `url`
- `f=fit|raw|bm25|llm`
- `q`
- `c`
- `provider`
- `temperature`
- `base_url`
`ScreenshotRequest`:
- `url`
- `screenshot_wait_for`
- `wait_for_images`
- `output_path`
`PDFRequest`:
- `url`
- `output_path`
`JSEndpointRequest`:
- `url`
- `scripts`
### 16.4 보안/운영
- JWT token 인증
- hooks는 기본 비활성화: `CRAWL4AI_HOOKS_ENABLED=false`
- hook code 실행은 RCE 위험이 있으므로 운영 환경에서는 비활성 권장
- global page semaphore로 동시 page 수 제한
- rate limiting
- TrustedHost/HTTPS middleware 옵션
- Redis 기반 task state 및 TTL
- Prometheus metrics
- playground와 monitor dashboard 정적 파일 제공
## 17. CLI 기능명세
entrypoint:
- `crwl = crawl4ai.cli:main`
- `crawl4ai-setup`
- `crawl4ai-doctor`
- `crawl4ai-download-models`
- `crawl4ai-migrate`
README 기준 CLI 예:
```bash
crwl https://www.nbcnews.com/business -o markdown
crwl https://docs.crawl4ai.com --deep-crawl bfs --max-pages 10
crwl https://www.example.com/products -q "Extract all product prices"
```
역할:
- 빠른 단일 URL 크롤
- Markdown 출력
- 딥 크롤 옵션
- 질의 기반 LLM 추출
- 설정 파일 기반 실행 예제 제공
## 18. C4A Script 기능명세
경로: `crawl4ai/script`
공개 API:
- `c4a_compile`
- `c4a_validate`
- `c4a_compile_file`
- `CompilationResult`
- `ValidationResult`
- `ErrorDetail`
역할:
- 사람이 읽기 쉬운 C4A script를 JavaScript로 컴파일
- `CrawlerRunConfig(c4a_script=...)`에 넣으면 `js_code`로 변환되어 브라우저에서 실행
- 폼 입력, 클릭, 스크롤, 로그인 흐름 등 반복 브라우저 작업 자동화에 적합
## 19. 특화 크롤러
경로:
- `crawl4ai/crawlers/google_search`
- `crawl4ai/crawlers/amazon_product`
역할:
- 공통 SDK 위에 특정 사이트/도메인 추출 로직을 래핑한 예시
- 향후 우리 프로젝트에서 도메인별 크롤러를 만들 때 참고할 구조
## 20. 테스트 자산
테스트는 다음 범위를 포괄한다.
- 기본 async crawler
- browser manager/context/CDP/profile
- raw HTML/file/http 처리
- caching/smart cache
- markdown/content filter
- extraction strategies
- table extraction
- link/media extraction
- deep crawling, filters, scorers, resume/cancel
- Docker API/server/hooks/security/webhook
- proxy/sticky sessions
- memory/stress
- regression tests
이 프로젝트를 기반으로 개발할 때는 기존 테스트명을 기능별 체크리스트로 활용할 수 있다.
## 21. 우리 프로젝트에 적용할 때의 권장 아키텍처
### 21.1 권장 래핑 계층
우리 코드에서 Crawl4AI를 직접 전역적으로 흩뿌려 쓰기보다 아래 계층으로 감싸는 것을 권장한다.
```text
우리 서비스
CrawlJob API / Queue
Domain Crawler Service
Crawl4AI Adapter
- BrowserConfig factory
- CrawlerRunConfig factory
- ExtractionStrategy factory
- Result normalizer
Crawl4AI SDK
```
### 21.2 우리가 정의해야 할 내부 표준
- 크롤 목적별 profile:
- `fast_static`: HTTP 또는 text/light mode
- `dynamic_page`: Playwright + JS/wait
- `full_capture`: screenshot/pdf/mhtml/network
- `structured_extract`: CSS/XPath schema
- `semantic_extract`: LLM/BM25
- `deep_discovery`: URL seeder + deep crawl
- 결과 저장 표준:
- raw html
- cleaned html
- raw markdown
- fit markdown
- extracted JSON
- media/links/tables
- crawl metadata/status/error
- 실패 표준:
- DNS/network timeout
- HTTP error
- robots blocked
- anti-bot blocked
- extraction empty
- schema mismatch
- LLM provider failure
## 22. 장점
- SDK/API/CLI/Docker를 모두 제공해 개발-운영 경로가 넓다.
- 동적 페이지 처리 기능이 풍부하다.
- Markdown과 구조화 추출이 기본 내장되어 LLM/RAG 파이프라인과 맞다.
- 딥 크롤링, URL 시딩, adaptive crawling까지 있어 단순 scraper보다 확장성이 높다.
- 캐시/dispatcher/browser pool/monitor 등 운영 기능도 상당히 갖추어져 있다.
## 23. 리스크 및 주의사항
- 코드베이스가 크고 기능이 빠르게 확장된 흔적이 있어 일부 API가 deprecated 상태다.
- README 일부 문자는 인코딩이 깨져 있어 원문 문서만 보고 자동 처리하기 어렵다.
- hook code 실행은 보안상 위험하다.
- LLM extraction은 이 오픈소스가 제공하는 주요 추출 방식이다. 우리 프로젝트에서는 크롤링 옵션으로 추출 방식을 선택할 수 있게 하되, 기본 정책은 LLM 기반 추출 우선으로 둔다. CSS/XPath/Regex/schema 기반 추출은 비용, 속도, 반복 DOM 안정성이 중요한 경우 선택 가능한 보완 전략으로 사용한다.
- 브라우저 기반 대량 크롤링은 메모리 누수/컨텍스트 정리/프로세스 recycle 정책이 중요하다.
- anti-bot/stealth/proxy 기능은 기술적으로 제공되지만 법적/약관 리스크를 별도로 관리해야 한다.
- Docker 서버는 Redis, browser pool, auth, monitor 등 운영 의존성이 있어 단순 SDK 사용보다 배포 복잡도가 높다.
## 24. 향후 개발 기준 기능명세
이 소스를 기반으로 우리 프로젝트를 진행할 때 최소 기능 기준은 다음과 같이 잡는 것을 권장한다.
### 24.1 MVP 필수
- 단일 URL 크롤
- 다중 URL 크롤
- 동적 페이지 JS 렌더링
- wait selector/function
- raw HTML 처리
- Markdown 변환
- LLM 기반 의미 추출
- CSS/XPath 기반 JSON 추출 옵션
- 캐시 모드
- screenshot 선택 캡처
- 링크/미디어/메타데이터 수집
- 표 추출
- 에러/상태/HTTP status 기록
### 24.2 1차 확장
- URL seeding
- BFS/DFS deep crawl
- domain/pattern/content-type filter
- BM25 query 기반 content filter
- proxy config
- session reuse
- persistent browser profile
- network/console capture
- smart cache validation
### 24.3 운영 확장
- Docker API 또는 자체 FastAPI 래퍼
- job queue
- streaming result
- Redis/task state
- webhook
- monitor dashboard
- Prometheus metrics
- browser pool
- rate limit
- memory adaptive dispatcher
### 24.4 고급 확장
- adaptive crawler
- best-first scoring
- embedding strategy
- C4A script 기반 브라우저 자동화
- custom domain crawler
- anti-bot retry/fallback
- MHTML/PDF archive
## 25. 결론
Crawl4AI는 단순 페이지 다운로드 도구가 아니라 “웹을 LLM 친화 데이터로 변환하는 비동기 크롤링 프레임워크”에 가깝다.
앞으로 우리 프로젝트의 기본 소스로 삼는다면 `AsyncWebCrawler + CrawlerRunConfig + ExtractionStrategy + MarkdownGenerator + DeepCrawlStrategy`
조합을 중심으로 래핑하고, Docker 서버 코드는 운영형 API 설계 참고 또는 별도 배포 모듈로 분리해 사용하는 것이 가장 현실적이다.
가장 중요한 설계 결정은 다음 세 가지다.
1. 기본 추출 방식은 Crawl4AI의 주요 설계 방향에 맞춰 LLM 기반 의미 추출을 우선한다.
2. CSS/XPath/Regex 같은 결정적 전략은 크롤링 옵션으로 제공해 비용, 속도, 반복 DOM 안정성이 중요한 경우 선택하게 한다.
3. 브라우저 크롤링은 비용이 크므로 URL seeding, cache, dispatcher, profile 재사용으로 호출량을 통제한다.

View File

@@ -0,0 +1,892 @@
# Firecrawl 프로젝트 분석 및 기능명세
분석 대상: `C:\Users\lasta\MyProject\AI\참고\firecrawl-main`
분석일: 2026-05-13
목적: 범용 온톨로지 구축 플랫폼의 웹 수집/정제/구조화 기반 소스로 Firecrawl을 거의 원형에 가깝게 재사용할 수 있는지 판단하고, 향후 구현 기준이 될 기능 명세를 정리한다.
## 1. 결론 요약
Firecrawl은 단순 크롤러가 아니라 `검색 -> URL 발견 -> 페이지 수집 -> 동적 브라우저 실행 -> Markdown/HTML/JSON/스크린샷/파일 파싱 -> 비동기 작업 관리 -> SDK 제공`까지 포함하는 웹 데이터 수집 API 플랫폼이다. 현재 프로젝트의 범용 온톨로지 구축 플랫폼에는 다음 영역이 특히 직접 재사용 가치가 높다.
- `apps/api/src/scraper/scrapeURL`: 단일 URL 수집의 핵심. Fetch, Playwright, PDF, 문서, 인덱스, Fire-engine 계열 엔진을 fallback 방식으로 선택한다.
- `apps/api/src/scraper/WebScraper/crawler.ts`: 사이트 내부 URL 탐색, sitemap, robots.txt, include/exclude path, depth, subdomain/external link 제어.
- `apps/api/src/controllers/v2/types.ts`: API 입력/출력 스키마. 특히 scrape/crawl/map/search 옵션 체계가 잘 정리되어 있다.
- `apps/api/src/controllers/v2/*`: 외부 API 기능 명세의 실제 기준. `scrape`, `crawl`, `map`, `search`, `batch scrape`, `parse`, `monitor`, `browser`, `agent`로 분리되어 있다.
- `apps/api/src/services/worker/scrape-worker.ts`, `queue-*`: 대량 수집, 크롤 작업, billing/logging/webhook/상태 관리의 운영 흐름.
- `apps/python-sdk`, `apps/js-sdk/firecrawl`: 우리 플랫폼 API 클라이언트 설계 시 참고할 수 있는 SDK 표면.
다만 Firecrawl은 Node.js/TypeScript 기반의 API 서버, Redis/BullMQ 또는 NuQ/RabbitMQ/Postgres, Playwright microservice, Supabase/Autumn/Stripe/GCS/Sentry 등 SaaS 운영 요소가 섞여 있다. 현재 Python/FastAPI/SQLAlchemy 기반 프로젝트에 그대로 병합하기보다는, Firecrawl을 별도 수집 서비스로 두고 Python 온톨로지 파이프라인이 Firecrawl API를 호출하는 구조가 가장 안전하다.
## 2. 프로젝트 성격
Firecrawl의 제품 목표는 웹 페이지를 LLM/RAG/Agent가 바로 사용할 수 있는 깨끗한 데이터로 변환하는 것이다. 제공 기능은 다음 세 가지 축으로 요약된다.
- 단일 페이지 변환: URL을 Markdown, HTML, raw HTML, link/image 목록, screenshot, structured JSON 등으로 변환한다.
- 사이트 단위 수집: seed URL에서 sitemap과 링크 그래프를 따라가며 여러 페이지를 비동기로 수집한다.
- 지능형 데이터 추출: JSON Schema, LLM prompt, browser action, search result scraping, file parsing을 결합한다.
온톨로지 구축 플랫폼 관점에서는 Firecrawl이 `웹 수집 계층``텍스트/문서 정제 계층`을 맡고, 현재 프로젝트의 Python 코드는 `도메인 어댑터`, `엔티티/관계 추출`, `Claim/Evidence 저장`, `추천/검증 UI`를 맡는 분업이 적합하다.
## 3. 최상위 구조
```text
firecrawl-main/
apps/
api/ # 핵심 API 서버, 스크래퍼, 크롤러, 큐/워커
playwright-service-ts/ # Playwright 브라우저 마이크로서비스
python-sdk/ # Python SDK
js-sdk/firecrawl/ # JS/TS SDK
php-sdk, ruby-sdk,
rust-sdk, elixir-sdk # 다언어 SDK
ui/ingestion-ui/ # ingestion UI
test-suite/ # API/load 테스트
test-site/ # 테스트용 사이트
go-html-to-md-service/ # HTML -> Markdown 변환 보조 서비스
nuq-postgres/ # NuQ 큐용 Postgres 구성
examples/ # LLM/agent/추출 예제 다수
docker-compose.yaml # self-host 전체 구성
SELF_HOST.md # 자체 호스팅 안내
README.md # 제품/SDK/API 개요
```
핵심은 `apps/api`이다. 나머지는 SDK, 배포, 예제, 테스트, UI 보조 레이어다.
## 4. 기술 스택
- 언어: TypeScript/Node.js, 일부 Rust native package, 일부 Go service
- API: Express, express-ws, Zod validation, multer multipart
- 브라우저: 별도 `playwright-service-ts`, Fire-engine CDP/TLS client 연동 가능
- HTML 처리: Cheerio, JSDOM, Turndown, joplin-turndown-plugin-gfm, Rust 기반 link filtering/extraction
- 문서 처리: PDF, DOC/DOCX/ODT/RTF/XLS/XLSX 계열 파일 처리 모듈
- 큐/상태: BullMQ, Redis, NuQ, RabbitMQ, Postgres
- 검색: Google 기본, SearXNG 대체, DuckDuckGo/v2 검색 코드
- LLM: OpenAI, Anthropic, Google, Groq, xAI, OpenRouter, Ollama/OpenAI-compatible
- 운영: Docker Compose, Kubernetes/Helm 예제, Sentry, Prometheus, logging, billing
## 5. 런타임 아키텍처
```mermaid
flowchart TD
A["Client / SDK / API"] --> B["Express v2 Router"]
B --> C["Auth / rate limit / credit / blocklist"]
C --> D{"Endpoint"}
D --> E["Scrape Controller"]
D --> F["Crawl Controller"]
D --> G["Map Controller"]
D --> H["Search Controller"]
E --> I["scrapeURL engine fallback"]
F --> J["WebCrawler URL discovery"]
J --> K["Queue scrape jobs"]
G --> J
H --> L["Search provider"]
H --> I
K --> M["Scrape Worker"]
M --> I
I --> N["Fetch / Playwright / PDF / Document / Index / Fire-engine"]
N --> O["Markdown / metadata / formats / actions"]
O --> P["Result / status / webhook / logs"]
```
### 핵심 흐름
1. API 요청은 `apps/api/src/routes/v2.ts`에서 endpoint별 controller로 라우팅된다.
2. Zod 스키마가 URL, 옵션, format, crawler option을 strict하게 검증한다.
3. 단일 scrape는 동기적으로 처리하되 내부적으로 semaphore와 worker 공통 함수를 사용한다.
4. crawl/batch scrape는 작업 ID를 반환하고 큐에 개별 scrape job을 넣는다.
5. worker는 URL별로 `scrapeURL`을 실행하고 성공/실패/robots 차단/비용/로그/웹훅을 기록한다.
6. 결과는 status endpoint, websocket, webhook, SDK polling을 통해 조회된다.
## 6. 핵심 모듈 분석
### 6.1 API 라우터
파일: `apps/api/src/routes/v2.ts`
주요 endpoint:
- `POST /v2/search`
- `POST /v2/parse`
- `POST /v2/scrape`
- `GET /v2/scrape/:jobId`
- `POST /v2/scrape/:jobId/interact`
- `DELETE /v2/scrape/:jobId/interact`
- `POST /v2/batch/scrape`
- `GET /v2/batch/scrape/:jobId`
- `DELETE /v2/batch/scrape/:jobId`
- `GET /v2/batch/scrape/:jobId/errors`
- `POST /v2/map`
- `POST /v2/crawl`
- `POST /v2/crawl/params-preview`
- `GET /v2/crawl/ongoing`
- `GET /v2/crawl/:jobId`
- `DELETE /v2/crawl/:jobId`
- `WS /v2/crawl/:jobId`
- `GET /v2/crawl/:jobId/errors`
- `POST /v2/extract`
- `GET /v2/extract/:jobId`
- `POST /v2/agent`
- `GET /v2/agent/:jobId`
- `DELETE /v2/agent/:jobId`
- `POST /v2/monitor`
- `GET /v2/monitor`
- `GET /v2/monitor/:monitorId`
- `PATCH /v2/monitor/:monitorId`
- `DELETE /v2/monitor/:monitorId`
- `POST /v2/monitor/:monitorId/run`
- `GET /v2/monitor/:monitorId/checks`
- `GET /v2/monitor/:monitorId/checks/:checkId`
- `POST /v2/browser`
- `GET /v2/browser`
- `POST /v2/browser/:sessionId/execute`
- `DELETE /v2/browser/:sessionId`
- `GET /v2/team/credit-usage`
- `GET /v2/team/token-usage`
- `GET /v2/concurrency-check`
- `GET /v2/team/queue-status`
- `GET /v2/team/activity`
우리 프로젝트에서 우선 필요한 것은 `scrape`, `crawl`, `map`, `batch scrape`, `parse`, `search`다. `billing`, `credit`, `team`, `x402`, `agent signup`, `support proxy`는 초기에는 제외 가능하다.
### 6.2 스키마와 옵션 체계
파일: `apps/api/src/controllers/v2/types.ts`
Firecrawl은 입력 옵션을 Zod로 strict validation한다. 알 수 없는 key는 거부하는 방식이라 API 안정성이 높다.
#### 공통 Scrape 옵션
- `formats`: 기본 `markdown`. 지원 format은 `markdown`, `html`, `rawHtml`, `links`, `images`, `summary`, `json`, `changeTracking`, `screenshot`, `attributes`, `branding`, `question`, `highlights`, `query`, `audio`.
- `headers`: 요청 header.
- `includeTags`, `excludeTags`: 특정 selector 포함/제외. iframe selector 변환도 처리한다.
- `onlyMainContent`: 기본 true. 본문 중심 추출.
- `onlyCleanContent`: 기본 false.
- `timeout`: 최소 1000ms.
- `waitFor`: 기본 0, 최대 60000ms, timeout의 절반 이하.
- `mobile`: 모바일 viewport 사용.
- `parsers`: PDF/문서 parser 옵션.
- `actions`: wait/click/write/press/scroll/scrape/screenshot 등 브라우저 액션.
- `location`: country/languages. 기본 country는 `us-generic`.
- `skipTlsVerification`: TLS 검증 skip.
- `removeBase64Images`: 기본 true.
- `fastMode`: 빠른 수집 모드.
- `blockAds`: 기본 true.
- `proxy`: `basic`, `stealth`, `enhanced`, `auto`. 기본 `auto`.
- `maxAge`, `minAge`, `storeInCache`: 캐시 사용 기준.
- `lockdown`: 캐시/index 기반 제한 모드.
- `profile`: 브라우저 profile 이름과 저장 여부.
중요 transform:
- JSON format이 있고 기본 timeout 30000ms이면 60000ms로 늘린다.
- stealth/enhanced/auto proxy이며 기본 timeout이면 120000ms로 늘린다.
- changeTracking은 markdown format을 요구하고 waitFor/timeout을 늘린다.
- actions + waitFor 총 대기 시간은 60초를 넘지 못한다.
#### Crawler 옵션
- `includePaths`: 포함할 path regex.
- `excludePaths`: 제외할 path regex.
- `maxDiscoveryDepth`: 발견 깊이 제한.
- `limit`: 기본 10000.
- `crawlEntireDomain`: 전체 domain 허용.
- `allowExternalLinks`: 기본 false.
- `allowSubdomains`: 기본 false.
- `ignoreRobotsTxt`: 기본 false.
- `robotsUserAgent`: robots.txt 확인 user-agent.
- `sitemap`: `skip`, `include`, `only`. 기본 `include`.
- `deduplicateSimilarURLs`: 기본 true.
- `ignoreQueryParameters`: 기본 false.
- `regexOnFullURL`: 기본 false.
- `delay`: URL 간 delay.
#### Map 옵션
Map은 URL 목록 발견용이다. 기본 `includeSubdomains=true`, `ignoreQueryParameters=true`, `limit=5000`, 최대 `100000`이다. `search`, `sitemap`, `filterByPath`, `useIndex`, `ignoreCache`, `location`, `headers`를 지원한다.
#### Search 옵션
- `query`: 검색어.
- `limit`: 기본 10, 최대 100.
- `sources`: `web`, `images`, `news`.
- `categories`: `github`, `research`, `pdf`.
- `includeDomains`, `excludeDomains`: 동시에 지정 불가.
- `lang`: 기본 en.
- `country`/`location`.
- `timeout`: 기본 60000ms.
- `asyncScraping`: 검색 결과 scraping을 비동기 job으로 반환 가능.
- `scrapeOptions`: 검색 결과 페이지를 바로 scrape할 때 사용하는 제한된 scrape 옵션.
### 6.3 단일 URL 수집 엔진
파일: `apps/api/src/scraper/scrapeURL/index.ts`, `apps/api/src/scraper/scrapeURL/engines/index.ts`
Firecrawl의 핵심은 URL과 요청 feature를 보고 엔진 후보를 만든 뒤 fallback 순서로 시도하는 구조다.
지원 엔진:
- `index`: 기존 index/cache에서 문서 조회.
- `index;documents`: 문서 index 조회.
- `fire-engine;chrome-cdp`: 고급 브라우저 엔진.
- `fire-engine;chrome-cdp;stealth`: stealth proxy 브라우저 엔진.
- `fire-engine;tlsclient`: TLS client 기반 수집.
- `fire-engine;tlsclient;stealth`: stealth TLS client.
- `playwright`: 자체 Playwright microservice.
- `fetch`: HTTP fetch 기반 빠른 수집.
- `pdf`: PDF 전용 처리.
- `document`: DOCX/ODT/RTF/XLS/XLSX 등 문서 처리.
- `wikipedia`: Wikimedia 전용 엔진.
- `x-twitter`: X/Twitter 전용 엔진.
Feature flag:
- `actions`, `waitFor`, `screenshot`, `screenshot@fullScreen`, `pdf`, `document`, `audio`, `atsv`, `location`, `mobile`, `skipTlsVerification`, `useFastMode`, `stealthProxy`, `branding`, `disableAdblock`.
선택 방식:
1. URL 확장자, option, format을 보고 필요한 feature flag를 계산한다.
2. 각 엔진이 feature를 지원하는지 확인한다.
3. quality와 feature priority를 기준으로 fallback list를 만든다.
4. 엔진별 max reasonable time을 계산하고 timeout/abort manager와 함께 실행한다.
5. HTML을 Markdown으로 변환하고 metadata, links, images, screenshot, extract 결과 등을 조립한다.
6. 실패 시 `NoEnginesLeftError`, `DNSResolutionError`, `SSLError`, `PDFOCRRequiredError`, `ActionError`, `CrawlDenialError` 등 typed error로 전달한다.
온톨로지 플랫폼에는 이 구조가 매우 유용하다. 특정 쇼핑몰/공식몰/문서/PDF마다 직접 fetcher를 분기하지 않고, Firecrawl이 feature 기반 fallback을 담당하게 할 수 있다.
### 6.4 URL 발견과 사이트 크롤링
파일: `apps/api/src/scraper/WebScraper/crawler.ts`
`WebCrawler`는 seed URL에서 사이트 내부 링크를 발견하고 filtering한다.
주요 기능:
- sitemap 로드와 sitemap 링크 제한.
- robots.txt 로드와 robots parser.
- max depth, max discovery depth 적용.
- include/exclude regex path filtering.
- backward crawling 차단.
- external link/subdomain 허용 여부 판단.
- query parameter 무시/중복 제거.
- 비웹 프로토콜, social/mailto, section anchor, 비문서 file type 제거.
- URL별 denial reason 생성.
현재 프로젝트의 `crawler_platform.app.core.crawler.discovery`, `site_crawler`, `content_zone`, `fetchers`를 Firecrawl 방식으로 강화할 수 있다. 단, Python 코드에 직접 포팅하기보다는 `POST /v2/map` 또는 `POST /v2/crawl`을 호출해 URL discovery를 위임하는 것이 빠르다.
### 6.5 Crawl 작업 처리
파일: `apps/api/src/controllers/v2/crawl.ts`, `apps/api/src/services/worker/scrape-worker.ts`
Crawl은 단일 요청에서 모든 페이지를 즉시 반환하지 않는다.
처리 절차:
1. `crawlRequestSchema`로 URL, crawler option, scrape option 검증.
2. 자연어 `prompt`가 있으면 site structure를 일부 map한 뒤 LLM으로 crawler option 생성.
3. include/exclude regex 유효성 확인.
4. credit 또는 self-host 설정에 따라 limit 조정.
5. Redis/queue에 `StoredCrawl` 저장.
6. kickoff job을 큐에 넣고 `id`, status URL을 반환.
7. worker가 URL을 발견하고 개별 scrape job으로 확장한다.
8. `GET /v2/crawl/:jobId` 또는 websocket으로 진행률과 결과를 조회한다.
응답 status:
- `scraping`
- `completed`
- `failed`
- `cancelled`
status 응답은 `completed`, `total`, `creditsUsed`, `expiresAt`, `next`, `data: Document[]`를 포함한다.
### 6.6 Search
파일: `apps/api/src/controllers/v2/search.ts`, `apps/api/src/search/*`
Search는 검색 결과를 반환하고, 옵션에 따라 각 결과 페이지를 scrape해서 markdown까지 포함한다.
온톨로지 플랫폼 활용:
- 브랜드/상품/성분/카테고리 후보 URL 발견.
- 공식 문서, PDF, research 자료 검색.
- seed URL이 부족한 신규 도메인 bootstrap.
- `includeDomains`/`excludeDomains`로 신뢰 출처 제한.
초기 MVP에서는 외부 검색 품질보다 `검색 결과 -> 후보 Source/Page -> 검토 큐` 흐름을 만드는 것이 중요하다.
### 6.7 Parse
`POST /v2/parse`는 multipart file upload를 받아 HTML/PDF/document를 scrape-like document로 변환한다. 파일 크기 제한은 50MB다.
온톨로지 플랫폼 활용:
- 로컬 PDF catalog, 제품 설명서, 성분표 문서 ingest.
- HTML fixture나 저장된 페이지 snapshot ingest.
- URL이 아닌 파일 기반 evidence 확보.
### 6.8 Browser / Interact / Actions
Firecrawl은 두 종류의 상호작용을 제공한다.
- scrape request의 `actions`: scrape 전에 wait, click, write, press, scroll, screenshot, scrape 등을 수행한다.
- `POST /v2/scrape/:jobId/interact`: scrape job에 연결된 browser session에 code 또는 prompt 기반 조작을 수행한다.
온톨로지 플랫폼 활용:
- 쿠키 배너 닫기.
- 검색/필터/더보기 버튼 클릭.
- pagination 또는 lazy-loaded product list 수집.
- 특정 selector 대기 후 수집.
주의: action 기반 수집은 재현성과 비용이 낮아질 수 있으므로, Source 단위 설정으로 제한하고 audit log를 남기는 것이 좋다.
### 6.9 Monitor
Monitor는 특정 URL/옵션을 주기적으로 실행하고 check 결과/diff를 관리하는 기능이다.
온톨로지 플랫폼 활용:
- 공식 상품 페이지 변경 감지.
- 성분/가격/품절/리뉴얼 페이지 모니터링.
- Claim evidence의 stale 여부 판단.
초기 버전에서는 Firecrawl Monitor 전체를 들여오기보다, 현재 프로젝트의 `scheduler/update_policy.py`에서 Firecrawl scrape를 주기 호출하고 content hash/changeTracking을 저장하는 방식이 단순하다.
### 6.10 SDK
Python SDK는 `apps/python-sdk/firecrawl` 아래에 있으며, v2 메서드가 `/v2/scrape`, `/v2/crawl`, `/v2/map`, `/v2/search`, `/v2/batch/scrape`, `/v2/parse`, browser interaction을 감싼다.
우리 프로젝트가 Firecrawl을 별도 서비스로 사용할 경우 Python SDK를 직접 사용하거나, 현재 FastAPI 서비스 내부에 얇은 adapter를 만드는 방식이 적합하다.
## 7. 기능명세
### 7.1 Document 모델
Firecrawl의 핵심 결과 단위는 `Document`다.
필드:
- `title`, `description`, `url`
- `markdown`, `html`, `rawHtml`
- `links`, `images`
- `screenshot`, `audio`
- `json`, `extract`, `summary`, `answer`, `highlights`, `branding`
- `attributes`: selector/attribute/value 목록
- `actions`: action 중 생성된 screenshot/scrape/javascript return/pdf
- `changeTracking`: 이전 scrape 대비 상태와 diff
- `metadata`: title, description, language, keywords, robots, OpenGraph, favicon, sourceURL, statusCode, scrapeId, contentType, proxyUsed, cacheState, cachedAt, creditsUsed 등
- `serpResults`: search result title/description/url
온톨로지 플랫폼 매핑:
- `Document.url` -> `Page.url`
- `Document.markdown` -> `Page.cleaned_text` 또는 `Page.markdown`
- `Document.html/rawHtml` -> 저장 여부 선택. 기본은 저장하지 않고 hash만 저장 권장.
- `Document.metadata.sourceURL/statusCode/contentType` -> `Page.fetch_status`, `Page.metadata`
- `Document.links/images` -> discovery 후보와 media evidence
- `Document.json/extract` -> 도메인 extractor 입력 또는 사전 추출값
- `Document.changeTracking` -> claim freshness/update scheduling
### 7.2 Scrape API 명세
Endpoint: `POST /v2/scrape`
목적: 단일 URL을 LLM-ready document로 변환한다.
필수 입력:
- `url`: HTTP/HTTPS URL. protocol이 없으면 `http://`를 보정한다.
선택 입력:
- 공통 Scrape 옵션 전체.
- `origin`: 요청 출처 tag. 기본 `api`.
- `integration`: 외부 통합 정보.
- `zeroDataRetention`: 데이터 보존 제한.
정상 응답:
```json
{
"success": true,
"data": {
"markdown": "...",
"metadata": {
"sourceURL": "https://example.com",
"statusCode": 200,
"proxyUsed": "basic"
}
}
}
```
실패 응답:
```json
{
"success": false,
"code": "ERROR_CODE",
"error": "message"
}
```
우리 플랫폼 수용 기준:
- URL 단위 수집의 기본 provider는 Firecrawl scrape로 한다.
- 기본 format은 `markdown`, 필요 시 `html`, `links`, `images`, `screenshot`, `json`을 Source config에서 켠다.
- extractor는 Firecrawl JSON을 그대로 신뢰하기보다, `markdown + metadata + sourceURL`을 현재 ontology extractor에 넣어 Claim/Evidence를 만든다.
### 7.3 Crawl API 명세
Endpoint: `POST /v2/crawl`
목적: seed URL에서 여러 URL을 발견하고 각 페이지를 scrape한다.
필수 입력:
- `url`
선택 입력:
- Crawler 옵션: `includePaths`, `excludePaths`, `limit`, `maxDiscoveryDepth`, `allowExternalLinks`, `allowSubdomains`, `ignoreRobotsTxt`, `sitemap`, `delay` 등.
- `scrapeOptions`: 각 페이지에 적용할 scrape 옵션.
- `webhook`: 상태 통지.
- `maxConcurrency`
- `prompt`: 자연어로 crawler option 생성.
정상 응답:
```json
{
"success": true,
"id": "job-id",
"url": "http://host/v2/crawl/job-id"
}
```
Status 조회:
```json
{
"success": true,
"status": "scraping",
"completed": 12,
"total": 100,
"creditsUsed": 12,
"expiresAt": "...",
"data": []
}
```
우리 플랫폼 수용 기준:
- 사이트 전체 수집은 `crawl-site` 내부 구현을 Firecrawl crawl 호출로 대체 또는 선택 가능하게 한다.
- 결과 Document[]는 Page 단위로 upsert하고, 각 Page를 ontology extraction queue로 넘긴다.
- `includePaths/excludePaths`는 Source config의 `url_patterns`로 매핑한다.
### 7.4 Map API 명세
Endpoint: `POST /v2/map`
목적: scrape 없이 URL 후보 목록만 빠르게 발견한다.
입력:
- `url`
- `search`: path/title 검색 조건.
- `sitemap`: `only`, `include`, `skip`
- `limit`: 기본 5000, 최대 100000
- `includeSubdomains`, `allowExternalLinks`, `ignoreQueryParameters`, `filterByPath`
- `useIndex`, `ignoreCache`
응답:
```json
{
"success": true,
"links": [
{ "url": "https://example.com/a", "title": "...", "description": "..." }
]
}
```
우리 플랫폼 수용 기준:
- 신규 Source 등록 시 먼저 Map을 실행해 수집 범위 preview를 보여준다.
- 사용자가 선택한 URL 패턴을 config로 저장한다.
- 대규모 크롤 전에 Map 결과로 예상 page 수와 domain/path 분포를 산출한다.
### 7.5 Batch Scrape API 명세
Endpoint: `POST /v2/batch/scrape`
목적: URL 배열을 비동기 scrape job으로 처리한다.
입력:
- `urls`: 1개 이상 URL 배열.
- 공통 Scrape 옵션.
- `webhook`, `appendToId`, `ignoreInvalidURLs`, `maxConcurrency`, `zeroDataRetention`.
응답:
```json
{
"success": true,
"id": "job-id",
"url": "http://host/v2/batch/scrape/job-id",
"invalidURLs": []
}
```
우리 플랫폼 수용 기준:
- Map으로 발견한 URL 중 우선순위가 높은 URL 묶음을 batch scrape로 실행한다.
- 실패 URL은 `crawl_errors` 또는 Page status로 저장하고 재시도 정책에 연결한다.
### 7.6 Search API 명세
Endpoint: `POST /v2/search`
목적: query 기반으로 web/news/images 결과를 얻고, 필요하면 결과 페이지 내용까지 scrape한다.
입력:
- `query`
- `limit`, `sources`, `categories`, `includeDomains`, `excludeDomains`
- `lang`, `country`, `location`
- `timeout`
- `asyncScraping`
- `scrapeOptions`
응답:
```json
{
"success": true,
"id": "job-id",
"creditsUsed": 3,
"data": {
"web": [
{
"url": "https://example.com",
"title": "Example",
"description": "...",
"markdown": "..."
}
]
}
}
```
우리 플랫폼 수용 기준:
- 자동 Source 후보 발굴 기능에 사용한다.
- `includeDomains`를 우선 사용해 공식몰/공식 문서/신뢰 출처 탐색을 제한한다.
- 검색 결과는 즉시 Claim으로 넣지 않고 Source/Page 후보 검토 큐로 넣는다.
### 7.7 Parse API 명세
Endpoint: `POST /v2/parse`
목적: 업로드 파일을 Document로 변환한다.
입력:
- multipart field `file`
- 공통 Scrape 옵션.
- 파일 최대 50MB.
- kind: `html`, `pdf`, `document`.
우리 플랫폼 수용 기준:
- 로컬 catalog/PDF/manual ingest에 사용한다.
- parse 결과는 URL source가 없을 수 있으므로 `Source.type=file`, `Page.url=file://...` 또는 별도 `documents` 테이블 정책을 정한다.
### 7.8 Monitor API 명세
Endpoint 집합:
- `POST /v2/monitor`
- `GET /v2/monitor`
- `GET /v2/monitor/:monitorId`
- `PATCH /v2/monitor/:monitorId`
- `DELETE /v2/monitor/:monitorId`
- `POST /v2/monitor/:monitorId/run`
- `GET /v2/monitor/:monitorId/checks`
- `GET /v2/monitor/:monitorId/checks/:checkId`
목적: 특정 수집 대상의 변경을 주기적으로 감시한다.
우리 플랫폼 수용 기준:
- MVP에서는 직접 도입하지 않고, Firecrawl `changeTracking` 또는 주기 scrape 결과의 content hash 비교로 대체한다.
- 장기적으로 Claim freshness, 상품 리뉴얼, 가격/품절 변경에 연결한다.
### 7.9 Browser Session API 명세
Endpoint:
- `POST /v2/browser`
- `GET /v2/browser`
- `POST /v2/browser/:sessionId/execute`
- `DELETE /v2/browser/:sessionId`
- `POST /v2/scrape/:jobId/interact`
- `DELETE /v2/scrape/:jobId/interact`
목적: 브라우저 세션을 생성하고 code/prompt 기반으로 조작한다.
우리 플랫폼 수용 기준:
- Source config에 `actions`를 저장하는 형태를 우선한다.
- 자유로운 browser execute는 보안/재현성 위험이 있으므로 관리자 전용 디버깅 기능으로 제한한다.
## 8. Self-host 구성
`docker-compose.yaml` 기준 서비스:
- `api`: Express API와 worker harness.
- `playwright-service`: 브라우저 수집 microservice.
- `redis`: queue/rate limit/cache.
- `rabbitmq`: NuQ worker messaging.
- `nuq-postgres`: NuQ 상태 저장.
필수/주요 환경 변수:
- `PORT`, `HOST`
- `USE_DB_AUTHENTICATION=false`로 self-host API key 없이 사용 가능
- `REDIS_URL`, `REDIS_RATE_LIMIT_URL`
- `PLAYWRIGHT_MICROSERVICE_URL`
- `NUQ_RABBITMQ_URL`
- `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, `POSTGRES_HOST`, `POSTGRES_PORT`
- `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `MODEL_NAME`, `OLLAMA_BASE_URL` 등 AI 기능용
- `PROXY_SERVER`, `PROXY_USERNAME`, `PROXY_PASSWORD`
- `SEARXNG_ENDPOINT`
- `BULL_AUTH_KEY`
- `MAX_CPU`, `MAX_RAM`
- `ALLOW_LOCAL_WEBHOOKS`
Self-host 제한:
- Fire-engine 고급 기능은 cloud/internal 의존성이 있어 자체 호스팅에서 제한될 수 있다.
- 기본적으로 fetch + Playwright + PDF/document 처리 중심으로 보는 것이 현실적이다.
- Supabase/Stripe/Autumn/GCS/Sentry 의존 영역은 자체 플랫폼에서는 제거하거나 stub 처리해야 한다.
## 9. 현재 프로젝트와의 통합 설계
현재 프로젝트는 Python/FastAPI 기반이며 핵심 구조는 다음과 같다.
- `crawler_platform/app/core/crawler`: fetch/discovery/clean/pipeline.
- `crawler_platform/app/core/extractor`: rule-based/AI extractor.
- `crawler_platform/app/core/ontology`: entity, relation, claim, triple store.
- `crawler_platform/app/core/database`: SQLAlchemy 저장소.
- `crawler_platform/app/core/research`: graph research loop.
- `crawler_platform/app/api/routes.py`: 관리 API.
- `configs/perfume_subscription.yaml`: Source/domain config.
권장 통합 방식:
```mermaid
flowchart LR
A["Crawler Platform FastAPI"] --> B["Firecrawl Adapter"]
B --> C["Firecrawl Self-host API"]
C --> D["Scrape / Map / Crawl / Search"]
D --> E["Document"]
E --> F["Page Upsert"]
F --> G["Ontology Extractor"]
G --> H["Entity / Claim / Evidence"]
```
### 단계별 채택 계획
1. `FirecrawlClient` adapter 추가
- Python SDK 또는 HTTP client 사용.
- `scrape_url`, `map_site`, `crawl_site`, `batch_scrape`, `search_sources`, `parse_file` 메서드 제공.
2. Source config 확장
- `fetcher: firecrawl`
- `firecrawl.formats`
- `firecrawl.actions`
- `firecrawl.crawler_options`
- `firecrawl.scrape_options`
- `firecrawl.search_options`
3. Page 저장 모델 확장
- `markdown`
- `raw_html_hash`
- `metadata_json`
- `scrape_id`
- `content_type`
- `cache_state`
- `change_status`
4. 기존 extractor 연결
- Firecrawl Document의 `markdown`을 표준 입력으로 사용.
- `metadata.sourceURL`을 evidence source로 유지.
- `links/images`를 다음 discovery 후보 또는 evidence attachment로 저장.
5. UI 기능 추가
- Map preview.
- Crawl job status.
- Page markdown preview.
- 실패 URL과 denial reason 표시.
## 10. 재사용 우선순위
### 즉시 재사용 권장
- v2 API 명세와 옵션 체계.
- `scrape`, `map`, `crawl`, `batch scrape`.
- Document 결과 모델.
- Python SDK 또는 HTTP adapter.
- Docker Compose self-host 실행 방식.
### 부분 재사용 권장
- `actions`: Source별 필요한 경우에만.
- `search`: Source 후보 발굴 단계.
- `parse`: 파일 ingest 단계.
- `monitor/changeTracking`: 업데이트 감지 단계.
- `crawler.ts`의 denial reason/URL filtering 정책: Python config validation에 반영.
### 초기 제외 권장
- billing/credit/team/account 기능.
- x402 micropayment.
- support proxy.
- agent signup.
- Supabase/Stripe/Autumn/GCS/Sentry SaaS 운영 코드.
- Fire-engine cloud 의존 기능.
## 11. 온톨로지 플랫폼 기능명세 초안
Firecrawl을 기반 수집기로 사용할 때 범용 온톨로지 구축 플랫폼은 다음 기능을 가져야 한다.
### 11.1 Source 등록
입력:
- source name
- base URL 또는 seed URL 목록
- source type: official, marketplace, review, document, search
- fetcher: `requests`, `playwright`, `firecrawl`
- Firecrawl crawler/scrape/search options
- 신뢰도 기본값
- robots 준수 정책
- update schedule
출력:
- Source record
- Map preview 결과
- 예상 page count
### 11.2 URL 발견
기능:
- Firecrawl Map 호출.
- sitemap only/include/skip 선택.
- include/exclude path regex 적용.
- subdomain/external link 정책 적용.
- query parameter 무시 여부.
- URL 후보를 Page 상태 `discovered`로 저장.
검증:
- URL 중복 제거.
- domain/path scope 위반 차단.
- robots 차단 URL 표시.
### 11.3 페이지 수집
기능:
- 단일 URL scrape.
- 다중 URL batch scrape.
- site crawl job 실행.
- Markdown, metadata, links, images 저장.
- HTML 원문 저장 여부 선택.
- screenshot 선택 저장.
상태:
- discovered
- queued
- fetching
- fetched
- failed
- blocked_by_robots
- skipped
### 11.4 문서/파일 수집
기능:
- PDF/DOCX/HTML 파일 업로드.
- Firecrawl Parse 호출.
- 문서 metadata와 markdown 저장.
- 파일 기반 evidence source 생성.
### 11.5 구조화 추출
기능:
- Firecrawl JSON format 또는 현재 Python extractor 선택.
- 기본 경로는 `Document.markdown -> ontology extractor`.
- JSON Schema 기반 추출은 도메인별 schema를 사용.
- 추출 결과는 바로 확정하지 않고 Claim/Evidence로 저장.
### 11.6 Claim/Evidence 생성
기능:
- Entity 후보 생성.
- subject-predicate-object Claim 생성.
- Evidence text와 source URL, page id, selector 또는 markdown span 저장.
- confidence score 산출.
- Source 신뢰도와 추출 방식에 따른 confidence 조정.
### 11.7 변경 감지
기능:
- Page content hash 비교.
- Firecrawl changeTracking format 사용 가능.
- 변경된 페이지만 재추출.
- 삭제/숨김/동일/변경 상태 기록.
### 11.8 검토 UI
기능:
- Source별 Map preview.
- Crawl job 진행률.
- Page markdown 미리보기.
- Claim 목록과 evidence 확인.
- confidence 수동 조정.
- entity merge.
- 실패 URL과 denial reason 확인.
## 12. 리스크와 주의점
- 라이선스: Firecrawl root LICENSE는 AGPL 계열로 보인다. 소스 자체를 서비스에 내장/수정 배포할 경우 공개 의무가 발생할 수 있으므로 별도 확인이 필요하다.
- 언어/스택 차이: 현재 프로젝트는 Python, Firecrawl 핵심은 TypeScript다. 직접 코드 병합보다 서비스 분리가 적합하다.
- 운영 복잡도: Redis, RabbitMQ, Postgres, Playwright service가 필요하다.
- Cloud 의존 기능: Fire-engine, 일부 index/search/branding/agent 기능은 self-host에서 제한될 수 있다.
- 비용/속도: Playwright/action/screenshot/stealth는 비용이 크다. Source별 정책이 필요하다.
- 데이터 보존: raw HTML/screenshot/audio 저장은 개인정보/저작권/용량 이슈가 있으므로 기본 off 권장.
- 검색 결과 신뢰도: Search는 후보 발굴용이며 Claim 근거로 바로 쓰면 안 된다.
## 13. 구현 권장안
최초 구현은 다음 범위가 좋다.
1. Firecrawl self-host를 별도 Docker Compose로 실행한다.
2. Python 프로젝트에 `FirecrawlAdapter`를 만든다.
3. `POST /crawl` 또는 CLI `crawl-url``fetcher=firecrawl` 옵션을 추가한다.
4. 단일 URL scrape 결과의 markdown을 기존 extractor로 넘긴다.
5. Map preview와 batch scrape는 두 번째 단계에서 붙인다.
6. Monitor/changeTracking/search/parse는 세 번째 단계에서 붙인다.
이 방식이면 Firecrawl의 강한 수집 능력을 거의 변형 없이 사용하면서, 현재 프로젝트의 핵심 가치인 범용 온톨로지/Claim/Evidence/추천 구조는 Python 코드에 유지할 수 있다.

View File

@@ -0,0 +1,694 @@
# Guardrails 프로젝트 분석 및 기능명세
분석 대상: `C:\Users\lasta\MyProject\AI\참고\guardrails-main`
분석일: 2026-05-13
목적: 범용 온톨로지 구축 플랫폼에서 LLM 생성 결과의 구조화, 검증, 실패 복구, 재질문, 운영형 검증 API의 기준 소스로 활용하기 위한 상세 분석
## 1. 프로젝트 개요
Guardrails는 Python 기반 LLM 신뢰성/구조화 출력 프레임워크이다. 핵심 목표는 LLM 입출력에 검증 규칙을 적용하고, 실패 시 정해진 정책에 따라 수정, 필터링, 예외, 재질문을 수행하며, 최종적으로 애플리케이션이 신뢰할 수 있는 구조화 데이터를 받도록 하는 것이다.
이 프로젝트는 온톨로지 구축 플랫폼에서 특히 유용하다. 온톨로지 생성 과정은 개념, 클래스, 속성, 관계, 제약조건, 근거 문장, provenance 같은 구조화 산출물이 필요하고, LLM 응답이 스키마를 어기거나 부정확한 관계를 만들면 이후 그래프 저장소와 추론 엔진까지 오염된다. Guardrails는 이 지점에서 “LLM 출력 검증 게이트” 역할을 그대로 수행할 수 있다.
주요 특징은 다음과 같다.
- `Guard` 중심의 LLM 호출 래퍼 및 검증 실행
- RAIL XML, Pydantic 모델, JSON Schema, 문자열 기반 출력 스키마 지원
- validator 기반 입력/출력 검증
- 실패 시 `reask`, `fix`, `filter`, `refrain`, `noop`, `exception`, `fix_reask`, `custom` 정책 적용
- JSON 출력 파싱, 타입 보정, 추가 키 제거, JSON Schema 검증
- 검증 실패 영역만 재질문하는 reask 루프
- 동기/비동기/스트리밍 검증 실행
- Guardrails Hub validator 설치/등록 체계
- CLI 및 독립 서버 실행 지원
- LangChain, LlamaIndex, LiteLLM, OpenAI, HuggingFace 등 LLM/프레임워크 연동
- telemetry, history, validator log 기반 실행 추적
- Text2SQL, document store, vector DB 같은 예시 애플리케이션 제공
## 2. 기술 스택
- 언어: Python 3.10 이상
- 데이터 모델: Pydantic v2, dataclass
- 스키마/파싱: JSON Schema 2020-12, lxml, jsonschema, jsonref
- LLM 연동: OpenAI SDK, LiteLLM, HuggingFace, Manifest optional
- CLI: Typer, Click, Rich
- 재시도/실행 보조: tenacity, contextvars
- 벡터 검색 optional: FAISS, numpy
- SQL optional: SQLAlchemy, sqlvalidator, sqlglot
- 관측성: OpenTelemetry, Guardrails Hub telemetry
- 프레임워크 통합: LangChain Core Runnable, LlamaIndex
- 서버 optional: `guardrails-api`
- 라이선스: Apache License 2.0
## 3. 최상위 구조
```text
guardrails-main/
guardrails/ # SDK 본체
guard.py # Guard 메인 엔트리포인트
async_guard.py # AsyncGuard
validator_base.py # Validator 베이스 및 registry
validator_service/ # 동기/비동기 validator 실행 엔진
run/ # Runner, StreamRunner, AsyncRunner
schema/ # RAIL/Pydantic/primitive schema 처리
actions/ # reask/filter/refrain 실패 처리 객체
classes/ # history, validation outcome/logs, execution models
llm_providers.py # LLM 호출 어댑터
formatters/ # JSON formatter, JSONFormer 어댑터
cli/ # configure/create/start/validate/hub/db/watch
hub/ # Hub validator install/registry
integrations/ # LangChain, LlamaIndex, Databricks
applications/ # Text2SQL 예시
document_store.py # 문서/페이지 저장 및 vector DB 검색 추상화
vectordb/ # VectorDBBase, Faiss
docs/ # 공식 문서, 예제, API reference
tests/ # 단위/통합 테스트
server_ci/ # 서버 Docker/CI 검증 구성
```
패키지의 실질적인 공개 API는 `Guard`, `AsyncGuard`, `Validator`, `OnFailAction`, `ValidationOutcome`, validator registry, schema 변환 함수군이다.
우리 프로젝트에서 기준 소스로 삼을 우선순위는 `guard.py`, `validator_base.py`, `validator_service/`, `run/`, `schema/`, `actions/`, `classes/validation*`, `classes/history/` 순서가 적절하다.
## 4. 핵심 런타임 아키텍처
### 4.1 기본 실행 흐름
```mermaid
flowchart TD
A["사용자: Guard 생성"] --> B["스키마 로드: RAIL/Pydantic/String/JSON Schema"]
B --> C["validator map 구성"]
C --> D["Guard.__call__ 또는 Guard.parse"]
D --> E["Runner 생성"]
E --> F["입력 메시지 검증"]
F --> G["LLM 호출 또는 기존 llm_output 사용"]
G --> H["출력 파싱: JSON/string"]
H --> I["JSON Schema 검증 및 타입 보정"]
I --> J["validator_service.validate"]
J --> K{"실패 발생?"}
K -- no --> L["ValidationOutcome 반환"]
K -- yes --> M["OnFailAction 적용"]
M --> N{"reask 필요?"}
N -- yes --> O["reask 메시지/부분 스키마 생성"]
O --> G
N -- no --> L
```
### 4.2 핵심 객체 관계
- `Guard`: 사용자 진입점. 스키마, validator, 실행 옵션, history, server/client 여부를 가진다.
- `Runner`: 한 번의 Guard 호출을 실제로 실행한다. LLM 호출, 파싱, 스키마 검증, validator 실행, reask 반복을 담당한다.
- `Validator`: 값 하나를 검증하는 규칙 단위이다. `_validate()`를 구현하고 `PassResult` 또는 `FailResult`를 반환한다.
- `ValidatorServiceBase`: validator 실행 전후 로그, 실패 정책 적용, 여러 validator 결과 병합을 담당한다.
- `SequentialValidatorService`: 동기 Guard에서 validator를 순차 실행한다.
- `AsyncValidatorService`: async validator를 병렬 실행하고 결과를 병합한다.
- `ValidationOutcome`: 최종 결과 DTO. 원본 LLM 출력, 검증된 출력, reask, 통과 여부, 오류, 검증 요약을 포함한다.
- `Call`, `Iteration`, `Inputs`, `Outputs`: 실행 history와 단계별 로그 모델이다.
- `ProcessedSchema`: RAIL/Pydantic/primitive 입력을 JSON Schema, validator 목록, validator map, execution options로 변환한 결과이다.
## 5. Guard 기능명세
### 5.1 Guard 생성 방식
`Guard`는 네 가지 생성 경로를 제공한다.
| 생성 방식 | 함수 | 입력 | 용도 |
| --- | --- | --- | --- |
| 기본 생성 후 validator 추가 | `Guard().use(...)` | validator 인스턴스 | 단순 문자열/출력 검증 |
| RAIL 파일 | `Guard.for_rail(path)` | `.rail` 파일 경로 | XML 기반 스키마/프롬프트/validator 정의 |
| RAIL 문자열 | `Guard.for_rail_string(xml)` | RAIL XML 문자열 | DB/설정에서 동적 로드 |
| Pydantic 모델 | `Guard.for_pydantic(model)` | Pydantic BaseModel 또는 모델 리스트 | Python 타입 기반 구조화 출력 |
| 문자열 출력 | `Guard.for_string(validators)` | validator 목록 | 일반 텍스트 응답 검증 |
온톨로지 플랫폼에서는 `Guard.for_pydantic()`을 우선 기준으로 삼는 것이 좋다. 개념 추출, 관계 추출, 속성 정규화, 증거 문장 연결 등은 Pydantic 모델로 명확히 표현할 수 있고, 이 모델을 그대로 API contract와 테스트 fixture에 재사용할 수 있다. RAIL은 사용자 정의 DSL/설정 파일 기반 검증을 지원할 때 보조 수단으로 쓰는 편이 적절하다.
### 5.2 Guard 실행 방식
| 실행 방식 | 함수 | 설명 |
| --- | --- | --- |
| LLM 호출 포함 | `guard(llm_api=..., messages=..., prompt_params=...)` | Guard가 LLM 호출부터 검증까지 수행 |
| 기존 출력 검증 | `guard.parse(llm_output=...)` | 이미 생성된 LLM 출력 문자열을 파싱/검증 |
| 별칭 | `guard.validate(llm_output)` | `parse()`와 동일 |
| 서버 모드 | `settings.use_server=True` 또는 `Guard(use_server=True)` | Guardrails API 서버에 검증 위임 |
| 스트리밍 | `stream=True` | `StreamRunner` 사용 |
`__call__`은 기본적으로 `messages`가 필요하다. 이미 응답을 보유한 후처리 파이프라인에서는 `parse()`를 사용해야 한다.
### 5.3 Guard 입력/출력 계약
입력 주요 필드:
- `llm_api`: OpenAI/LiteLLM/HuggingFace/사용자 callable
- `messages`: chat message 목록
- `prompt_params`: prompt template 치환 값
- `metadata`: validator에 전달되는 외부 컨텍스트
- `num_reasks`: 검증 실패 시 재질문 최대 횟수
- `full_schema_reask`: 실패 필드만 물을지 전체 스키마를 다시 생성할지 결정
- `llm_output`: LLM 호출 없이 검증할 기존 출력
출력 `ValidationOutcome`:
- `rawLlmOutput`: 원본 LLM 문자열
- `validatedOutput`: 검증과 보정이 반영된 최종 값
- `validationPassed`: 최종 통과 여부
- `reask`: 재질문이 필요한 실패 객체
- `validationSummaries`: 실패 validator 요약
- `error`: 실행 중 오류
- `callId`: history 식별자
## 6. Schema 기능명세
### 6.1 RAIL 처리
`guardrails/schema/rail_schema.py`는 RAIL XML을 JSON Schema와 validator map으로 변환한다.
지원되는 주요 RAIL 타입:
- `string`
- `integer`
- `float`
- `bool`
- `date`
- `time`
- `datetime`
- `percentage`
- `enum`
- `list`
- `object`
- `choice`
RAIL 요소의 `validators` 속성은 validator 문자열을 파싱하고, `on-fail-*` 속성은 validator별 실패 정책으로 변환된다. 객체 필드는 JSON path 형태의 validator map에 연결된다. 예를 들어 `$.entities.*.label` 같은 경로에 특정 validator를 붙일 수 있다.
온톨로지 플랫폼 적용:
- RAIL은 운영자가 UI에서 검증 정책을 XML/DSL로 저장하는 기능을 만들 때 유용하다.
- 초기 구현에서는 Pydantic 모델 기반 스키마를 우선하고, RAIL은 “고급 사용자/템플릿 import” 기능으로 뒤에 붙이는 것이 안정적이다.
### 6.2 Pydantic 처리
`guardrails/schema/pydantic_schema.py`는 Pydantic 모델을 JSON Schema로 변환하고, 필드별 validator metadata를 추출한다.
적용 가능한 온톨로지 모델 예:
```python
class OntologyEntity(BaseModel):
id: str
label: str
type: Literal["class", "individual", "property"]
description: str
evidence: list[str]
class OntologyRelation(BaseModel):
source_id: str
predicate: str
target_id: str
confidence: float
evidence: list[str]
```
이런 모델을 `Guard.for_pydantic()`에 넣으면 LLM 응답을 JSON 구조로 강제하고, 누락 필드/타입 오류/추가 키/validator 실패를 한 실행 흐름 안에서 처리할 수 있다.
### 6.3 Primitive/String 처리
`primitive_to_schema()`는 단순 문자열 또는 기본 타입 검증용 schema를 만든다. 문서 요약, label 후보, relation predicate 후보처럼 단일 문자열 출력을 검증할 때 적합하다.
## 7. Validator 기능명세
### 7.1 Validator 기본 구조
`Validator`는 모든 검증 규칙의 베이스 클래스이다.
필수 구현:
- `_validate(value, metadata) -> ValidationResult`
선택 구현:
- `_inference_local(model_input)`
- `_inference_remote(model_input)`
- `async_validate(value, metadata)`
- `validate_stream(...)`
- `async_validate_stream(...)`
반환 타입:
- `PassResult`: 검증 성공. 선택적으로 `value_override`, `validated_chunk`, `metadata` 포함
- `FailResult`: 검증 실패. `error_message`, `fix_value`, `metadata` 포함
Validator 인스턴스는 `rail_alias`로 registry에 등록되어야 한다. Guard는 validator reference를 `id`, `on`, `on_fail`, `kwargs` 형태로 직렬화한다.
### 7.2 Validator 실행 위치
Validator는 다음 위치에 붙을 수 있다.
- `output` 또는 `$`: 전체 출력
- `messages`: 입력 메시지
- JSON path: `$.field`, `$.items.*.name` 등 구조화 출력의 특정 필드
온톨로지 플랫폼에서는 다음 경로 매핑이 중요하다.
| 경로 | 검증 예 |
| --- | --- |
| `$` | 전체 ontology extraction result가 최소 엔티티/관계를 포함하는지 |
| `$.entities.*.id` | ID 형식, 중복 여부 |
| `$.entities.*.label` | 빈 문자열 금지, 길이 제한, 금칙어 |
| `$.relations.*.source_id` | 존재하는 entity ID인지 |
| `$.relations.*.predicate` | 허용 ontology predicate인지 |
| `$.relations.*.confidence` | 0.0~1.0 범위 |
| `$.relations.*.evidence.*` | 원문에 존재하는 근거 문장인지 |
### 7.3 OnFailAction 명세
| 액션 | 동작 | 온톨로지 적용 |
| --- | --- | --- |
| `exception` | 즉시 예외 발생 | 저장 전 엄격 검증, 배치 실패 처리 |
| `noop` | 실패해도 원본 유지 | soft warning만 남길 때 |
| `fix` | `FailResult.fix_value`로 교체 | label trim, confidence clipping |
| `fix_reask` | fix 후 재검증, 실패하면 reask | 자동 보정 가능하지만 위험한 필드 |
| `reask` | 실패 위치를 ReAsk 객체로 표시 | 관계/근거/타입 오류 재생성 |
| `filter` | 실패 값을 제거 | 부적합 entity/relation 삭제 |
| `refrain` | 전체 응답을 비움 | 안전성/정책 위반 시 결과 폐기 |
| `custom` | 사용자 함수 호출 | 그래프 DB 조회 기반 보정 |
온톨로지 구축에서는 `exception`보다 `reask`, `filter`, `fix`, `custom`의 조합이 실용적이다. 예를 들어 relation의 source/target ID가 존재하지 않으면 `reask`, confidence 범위 오류는 `fix`, evidence가 원문에 없으면 `filter` 또는 `reask`가 적합하다.
## 8. Runner 및 ReAsk 기능명세
### 8.1 Runner 단계
`Runner.step()`은 다음 순서로 실행된다.
1. `Inputs`, `Outputs`, `Iteration` 생성
2. 입력 메시지 준비 및 입력 validator 실행
3. LLM API 호출 또는 전달받은 `llm_output` 사용
4. 원본 출력 파싱
5. JSON Schema 검증
6. validator map 기반 검증
7. 실패 정책 후처리
8. reask 객체 수집
9. reask가 있고 예산이 남으면 다음 loop 준비
### 8.2 ReAsk 처리
`guardrails/actions/reask.py`는 실패 유형을 다음 객체로 표현한다.
- `FieldReAsk`: 특정 필드 값 검증 실패
- `SkeletonReAsk`: 전체 구조/schema 검증 실패
- `NonParseableReAsk`: LLM 출력 파싱 실패
`get_reask_setup()`은 실패 객체, 기존 출력, 스키마, validator map을 바탕으로 다음 LLM 호출에 사용할 메시지와 스키마를 만든다. 부분 reask가 가능하면 실패 필드만 다시 요청하고, `full_schema_reask=True`이면 전체 구조를 다시 요청한다.
온톨로지 플랫폼 적용:
- entity/relation 한두 개 필드 오류는 부분 reask가 비용과 품질 면에서 유리하다.
- Pydantic 모델 기반 전체 ontology extraction은 `full_schema_reask=True`가 안정적인 경우가 많다.
- production에서는 reask 횟수를 1~2회로 제한하고, 실패한 relation만 “검토 필요” 큐로 보내는 정책이 좋다.
## 9. ValidatorService 기능명세
### 9.1 동기 실행
`SequentialValidatorService`는 validator를 순차 실행한다. 동기 Guard에서 async validator를 사용하면 명시적으로 오류를 낸다. 스트리밍 검증에서는 chunk 누적, validator별 partial accumulator, fix 결과 병합을 수행한다.
### 9.2 비동기 실행
`AsyncValidatorService`는 같은 경로에 붙은 validator들을 `asyncio.gather()`로 병렬 실행한다. 결과 처리 규칙은 다음과 같다.
- `Filter` 또는 `Refrain`이 나오면 즉시 해당 값 반환
- `FieldReAsk`가 여러 개면 fail result를 병합
- `fix`, `fix_reask`, `custom` 결과가 여러 개면 diff/merge 로직으로 병합
- child object/list는 재귀적으로 검증
온톨로지 플랫폼에서 원문 근거 확인, 외부 사전 조회, 그래프 DB 중복 조회, embedding similarity 검증처럼 I/O가 많은 validator는 async 기반으로 구현하는 것이 좋다.
## 10. LLM Provider 및 Formatter 명세
### 10.1 LLM 호출 어댑터
`llm_providers.py`는 여러 호출 방식을 `PromptCallableBase` 형태로 감싼다.
지원 범주:
- OpenAI 호환 callable
- LiteLLM
- Manifest
- HuggingFace model/pipeline
- 임의 Python callable
- async callable
`get_llm_ask()``get_async_llm_ask()`는 전달된 `llm_api`, `model`, kwargs를 보고 적절한 callable wrapper를 선택한다.
### 10.2 구조화 출력 Formatter
`formatters/json_formatter.py`는 JSON Schema를 기반으로 구조화 생성을 보조한다. Pydantic 기반 Guard에서 `output_formatter="jsonformer"` 같은 방식으로 formatter를 붙일 수 있다.
온톨로지 플랫폼에서는 모델별 structured output 기능이 다르므로 다음 순서로 적용하는 것이 좋다.
1. 모델이 native JSON Schema/function calling을 지원하면 provider native 기능 사용
2. 그렇지 않으면 Guardrails prompt suffix와 JSON 파싱/검증 사용
3. 로컬 HuggingFace 모델에는 JSONFormer 같은 formatter 검토
## 11. CLI 및 서버 기능명세
### 11.1 CLI 명령
`guardrails.cli`는 다음 명령군을 제공한다.
- `guardrails configure`: `.guardrailsrc` 설정 및 Hub token/telemetry 설정
- `guardrails create`: validator 목록으로 config 템플릿 생성
- `guardrails start`: Guardrails API 서버 실행
- `guardrails validate`: RAIL과 LLM 출력 파일 기반 검증
- `guardrails hub install/list/uninstall/submit`: Hub validator 관리
- `guardrails db upgrade/downgrade`: DB migration
- `guardrails watch`: 개발 보조
온톨로지 플랫폼에서는 CLI를 직접 노출하기보다 내부 관리 명령 또는 admin API로 래핑하는 것이 좋다.
### 11.2 서버 모드
README와 `guardrails/cli/start.py` 기준으로 Guardrails는 `guardrails-api` 패키지가 설치되어 있으면 독립 서버로 실행될 수 있다. 서버는 Guard 설정을 로드하고 REST API 또는 OpenAI 호환 endpoint로 검증을 제공한다.
적용 방안:
- 단일 애플리케이션 초기 단계: 라이브러리 내장 방식 권장
- 여러 서비스가 공통 검증 정책을 공유하는 단계: Guardrails 서버를 별도 배포
- SaaS형 온톨로지 플랫폼: tenant별 guard config를 서버에 등록하고, extraction worker가 검증 API를 호출
## 12. History, Logging, Telemetry 명세
Guardrails는 각 호출을 `Call`로 기록하고, reask를 포함한 각 시도를 `Iteration`으로 남긴다. 각 validator 실행은 `ValidatorLogs`에 기록된다.
기록되는 주요 정보:
- 입력 메시지
- prompt params
- 원본 LLM 출력
- 파싱 결과
- schema 검증 결과
- validator별 시작/종료 시간
- validator별 검증 전/후 값
- 실패 메시지
- 최종 guarded output
- call status
온톨로지 구축에서는 이 history가 매우 중요하다. 엔티티/관계가 왜 생성되었고, 어떤 검증을 통과/실패했으며, 어떤 값이 자동 보정되었는지 감사 로그로 남길 수 있다. 단, 기본 history는 메모리 `Stack`이므로 production에서는 DB sink를 별도로 구현해야 한다.
## 13. DocumentStore, VectorDB, Text2SQL 분석
### 13.1 DocumentStore
`document_store.py`는 문서와 페이지를 저장하고 vector DB로 유사 페이지를 검색하는 추상화이다.
핵심 객체:
- `Document`: `id`, `pages`, `metadata`
- `Page`: `PageCoordinates`, `text`, `metadata`
- `DocumentStoreBase`: `add_document`, `search`, `add_text`, `add_texts`, `flush`
- `EphemeralDocumentStore`: SQLAlchemy metadata store + vector DB 조합
온톨로지 플랫폼에서는 이미 별도의 크롤링/문서 저장 구조가 있다면 이 모듈을 그대로 핵심 저장소로 쓰기보다는 “validator나 few-shot example retrieval용 경량 참고 구현”으로 쓰는 것이 적절하다.
### 13.2 Text2SQL
`applications/text2sql.py`는 Guardrails를 이용한 응용 예시이다. SQL 스키마와 예시 질의를 prompt에 넣고, 생성된 SQL을 RAIL validator로 검증한다.
온톨로지 플랫폼에 주는 시사점:
- LLM 생성 결과를 도메인별 validator로 감싸는 패턴이 잘 드러난다.
- 예시 검색 + Guard 검증 + reask 루프 구조는 “문서 기반 온톨로지 추출”에도 동일하게 적용할 수 있다.
- SQL 대신 ontology schema, SHACL shape, OWL/RDF vocabulary를 context로 넣으면 같은 패턴을 재사용할 수 있다.
## 14. 테스트 기반 기능 범위
테스트 폴더는 다음 기능을 검증한다.
- Guard 기본 호출, parse, validate
- AsyncGuard 및 async streaming
- RAIL 파싱, Python/Pydantic schema 변환
- JSON parsing, structured data, formatter
- on_fail action: reask, fix, filter, refrain, noop, exception
- multi reask
- validator base 및 validator service
- CLI 동작
- Guardrails server
- OpenAI/LiteLLM embedding/provider 연동
- document store
- LangChain/LlamaIndex integration
- telemetry
- Hub install/registry
즉, Guardrails의 주요 기능은 테스트로 비교적 넓게 커버되어 있다. 우리 프로젝트에서 소스 일부를 거의 그대로 가져온다면, 관련 테스트도 함께 가져와서 “원본 호환성 테스트”로 유지하는 것이 좋다.
## 15. 범용 온톨로지 구축 플랫폼 적용 설계
### 15.1 Guardrails의 역할
Guardrails는 온톨로지 플랫폼에서 다음 레이어로 배치한다.
```mermaid
flowchart LR
A["문서 수집/Crawl4AI/Firecrawl"] --> B["청킹 및 전처리"]
B --> C["LLM Ontology Extraction"]
C --> D["Guardrails 검증 게이트"]
D --> E["정규화/중복 병합"]
E --> F["Graph DB / RDF Store"]
D --> G["검토 큐 / ReAsk / 실패 로그"]
```
핵심 책임:
- LLM 응답을 지정된 ontology extraction schema로 강제
- 스키마 위반, 타입 오류, 누락 필드 차단
- entity/relation 단위 validator 실행
- 자동 수정 가능한 값 보정
- 잘못된 relation 또는 근거 없는 triple 제거
- 재질문으로 복구 가능한 오류 복구
- 검증 로그와 provenance 저장
### 15.2 그대로 사용 권장 모듈
다음 모듈은 변형 없이 또는 import 경로만 조정해서 기본 소스로 사용해도 좋다.
| 모듈 | 사용 이유 |
| --- | --- |
| `guardrails/classes/validation_outcome.py` | 결과 DTO가 잘 정리되어 있음 |
| `guardrails/classes/validation/*` | Pass/Fail/log/summary 구조 재사용 가치 높음 |
| `guardrails/actions/*` | reask/filter/refrain 표현이 범용적 |
| `guardrails/types/on_fail.py` | 실패 정책 enum 그대로 사용 가능 |
| `guardrails/utils/parsing_utils.py` | LLM JSON 파싱/타입 보정 유용 |
| `guardrails/schema/validator.py` | JSON Schema 검증 재사용 가능 |
| `guardrails/schema/pydantic_schema.py` | Pydantic 기반 schema 변환 핵심 |
| `guardrails/validator_service/*` | validator 실행/병합/실패 처리 엔진 |
| `guardrails/run/runner.py` | reask loop 기준 구현 |
### 15.3 래핑 또는 수정 권장 모듈
| 모듈 | 이유 | 권장 방식 |
| --- | --- | --- |
| `guardrails/guard.py` | OpenAI/서버/telemetry/rc 의존이 섞여 있음 | `OntologyGuard` facade로 감싸기 |
| `guardrails/validator_base.py` | Hub/remote inference/rc 의존 있음 | 온톨로지 전용 `BaseOntologyValidator` 추가 |
| `guardrails/llm_providers.py` | provider별 변화가 잦음 | 현재 프로젝트 LLM gateway에 맞춘 adapter 작성 |
| `guardrails/hub/*` | 외부 Hub 의존 | 초기에는 제외 또는 optional |
| `guardrails/telemetry/*` | 외부 OTEL 설정 필요 | 내부 audit log로 대체 가능 |
| `guardrails/cli/*` | 제품 CLI와 책임 중복 | admin command로 필요한 기능만 이식 |
| `document_store.py` | 저장소 모델이 단순함 | 기존 crawler_platform 저장소와 통합 |
### 15.4 온톨로지 전용 Validator 목록
초기 구축에 필요한 validator 명세는 다음과 같다.
| Validator명 | 대상 경로 | 기능 | 실패 정책 |
| --- | --- | --- | --- |
| `EntityIdFormatValidator` | `$.entities.*.id` | ID prefix/slug/UUID 규칙 검증 | `fix` 또는 `exception` |
| `UniqueEntityIdValidator` | `$.entities` | 엔티티 ID 중복 검증 | `reask` |
| `EntityTypeValidator` | `$.entities.*.type` | class/individual/property 등 허용 타입 검증 | `reask` |
| `LabelRequiredValidator` | `$.entities.*.label` | 빈 label, 너무 긴 label 차단 | `fix_reask` |
| `RelationEndpointExistsValidator` | `$.relations.*` | source_id/target_id가 entities에 존재하는지 검증 | `reask` |
| `PredicateVocabularyValidator` | `$.relations.*.predicate` | 허용 predicate 또는 ontology vocabulary 매핑 | `custom` 또는 `reask` |
| `NoSelfRelationValidator` | `$.relations.*` | 금지된 self-loop relation 차단 | `filter` |
| `ConfidenceRangeValidator` | `$.relations.*.confidence` | 0~1 범위 보정 | `fix` |
| `EvidenceExistsValidator` | `$.relations.*.evidence.*` | evidence가 source document chunk에 존재하는지 | `filter` 또는 `reask` |
| `NoHallucinatedClassValidator` | `$.entities.*` | 원문 근거 없는 class 생성 차단 | `reask` |
| `OntologyAcyclicValidator` | `$` | subclass hierarchy cycle 탐지 | `custom` |
| `SHACLShapeValidator` | `$` | SHACL/OWL 제약 검증 | `exception` 또는 `reask` |
### 15.5 온톨로지 추출 Guard 명세
권장 Pydantic 출력 모델:
```python
class OntologyEvidence(BaseModel):
text: str
source_id: str
start_offset: int | None = None
end_offset: int | None = None
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] = []
```
Guard 생성 정책:
- `Guard.for_pydantic(OntologyExtractionResult)`
- `num_reasks=1` 기본, 고가치 문서만 2
- schema/parsing 오류는 `full_schema_reask=True`
- field validator 오류는 부분 reask 우선
- 최종 실패 결과는 graph store 저장 금지, 검토 큐로 이동
## 16. 정확한 기능명세
### 16.1 기능: 구조화 출력 생성 검증
- 입력: LLM chat messages, ontology schema, source chunk metadata
- 처리:
- LLM 호출
- JSON 또는 문자열 파싱
- JSON Schema 검증
- 추가 키 제거
- 타입 보정
- field validator 실행
- 출력: `ValidationOutcome[OntologyExtractionResult]`
- 예외:
- 파싱 불가: `NonParseableReAsk`
- schema 불일치: `SkeletonReAsk`
- validator 실패: `FieldReAsk` 또는 on_fail 정책 결과
### 16.2 기능: 기존 LLM 출력 사후 검증
- 입력: `llm_output` 문자열
- 처리: `Guard.parse()` 경로로 LLM 호출 없이 검증
- 출력: `ValidationOutcome`
- 사용처: 비동기 worker가 이미 받은 LLM 결과를 저장 전 검증
### 16.3 기능: 입력 메시지 검증
- 입력: `messages`
- 처리: validator map의 `messages` 경로 validator 실행
- 출력: 검증된 messages
- 실패: 입력 prompt가 정책/길이/금칙어를 위반하면 LLM 호출 전 차단
- 사용처: 사용자 정의 ontology extraction prompt 안전성 검증
### 16.4 기능: Field-level 검증
- 입력: 구조화 출력의 특정 JSON path
- 처리: path에 등록된 validator 실행
- 출력: 통과 값, 수정 값, 제거 값, reask 값 중 하나
- 사용처: entity label, relation endpoint, predicate, evidence 검증
### 16.5 기능: 실패 자동 보정
- 입력: `FailResult.fix_value`
- 처리: on_fail=`fix` 또는 `fix_reask`
- 출력: 보정된 값
- 사용처: 공백 제거, 소문자화, confidence clipping, ID slug 변환
### 16.6 기능: 실패 재질문
- 입력: `FieldReAsk`, `SkeletonReAsk`, `NonParseableReAsk`
- 처리:
- 실패 위치와 오류 메시지 기반 reask prompt 생성
- 부분 schema 또는 전체 schema 생성
- LLM 재호출
- 기존 출력과 새 출력 병합
- 출력: 재검증된 `ValidationOutcome`
- 제한: `num_reasks` 초과 시 실패 상태 반환
### 16.7 기능: 실패 필터링
- 입력: validator 실패 값
- 처리: on_fail=`filter`
- 출력: 해당 값 제거
- 사용처: hallucinated relation, evidence 없는 triple 제거
### 16.8 기능: 응답 보류
- 입력: validator 실패 값
- 처리: on_fail=`refrain`
- 출력: 빈 응답 또는 None
- 사용처: 보안/정책상 온톨로지 생성을 중단해야 하는 문서
### 16.9 기능: 검증 로그 저장
- 입력: validator 실행 결과
- 처리: `ValidatorLogs` 생성
- 출력:
- validator name
- registered name
- property path
- value before/after
- validation result
- start/end time
- 사용처: ontology triple audit, 품질 대시보드, 사용자 검토 UI
### 16.10 기능: 서버형 검증 API
- 입력: guard config, validation request
- 처리: Guardrails API 서버에서 검증 수행
- 출력: serialized `ValidationOutcome`
- 사용처: extraction worker와 검증 정책 서버 분리
## 17. 통합 로드맵
### Phase 1: 내장 검증 라이브러리로 사용
- Guardrails 원본을 `참고`로 유지
- 현재 프로젝트에 `ontology_guard/` 또는 `crawler_platform/validation/` 패키지 생성
- Pydantic ontology schema 정의
- 최소 validator 5개 구현
- `Guard.for_pydantic()` 기반 extraction 검증 PoC 작성
### Phase 2: 원본 핵심 모듈 이식
- `actions`, `validation classes`, `on_fail`, `parsing_utils`, `schema validator` 이식
- Hub/telemetry/CLI 의존 제거
- 내부 LLM gateway adapter 작성
- 테스트 fixture와 원본 unit test 일부 이식
### Phase 3: 온톨로지 품질 게이트 확장
- SHACL/OWL/RDF validator 추가
- graph DB lookup validator 추가
- evidence alignment validator 추가
- reask 실패 결과 검토 큐 구현
- validator log persistence 구현
### Phase 4: 서버형 정책 엔진
- Guard config 저장소 구현
- tenant/project별 guard policy 관리
- extraction worker가 validation service 호출
- 품질 지표 dashboard 구축
## 18. 리스크 및 주의사항
- Guardrails는 외부 Hub, telemetry, `.guardrailsrc` 의존이 코드 곳곳에 있다. 그대로 제품 본체에 넣기 전 이 의존을 명확히 비활성화해야 한다.
- `Validator` 생성 시 rc 파일이 없으면 오류가 나는 경로가 있으므로, 독립 플랫폼에서는 설정 로더를 대체하거나 기본 rc를 생성해야 한다.
- 서버 모드는 별도 `guardrails-api` optional dependency에 의존한다.
- LLM provider wrapper는 외부 SDK 변화에 민감하다. 우리 프로젝트에서는 provider adapter를 별도로 두는 것이 안전하다.
- 기본 history는 메모리 기반이다. 운영 감사 로그로 쓰려면 DB 저장 계층이 필요하다.
- reask는 비용과 지연을 증가시킨다. 문서 중요도와 실패 유형별로 횟수를 다르게 설정해야 한다.
- 자동 `fix`는 편하지만 ontology 의미를 바꿀 위험이 있다. 의미적 필드는 `reask` 또는 `custom` 검증이 더 안전하다.
## 19. 결론
Guardrails는 범용 온톨로지 구축 플랫폼의 “LLM 출력 신뢰성 계층”으로 매우 적합하다. 특히 Pydantic schema 기반 구조화 출력, JSON Schema 검증, field-level validator, on_fail 정책, reask loop, ValidationOutcome/history/log 구조는 거의 그대로 기본 소스로 삼을 수 있다.
다만 원본 전체를 무비판적으로 복사하기보다는, Hub/telemetry/CLI/provider 의존이 강한 부분은 얇은 adapter로 감싸고, 온톨로지 전용 validator와 audit persistence를 추가하는 방식이 좋다. 초기 기준 구현은 `Guard.for_pydantic(OntologyExtractionResult)`와 custom ontology validators 조합으로 시작하는 것이 가장 빠르고 안정적이다.

View File

@@ -0,0 +1,943 @@
# Knowledge Agent 분석 및 기능명세
분석 대상: `C:\Users\lasta\MyProject\AI\참고\knowledge_agent-main`
작성 목적: 오픈 프로젝트 `knowledge_agent-main`을 범용 온톨로지 구축 플랫폼의 기본 소스로 활용하기 위해, 아키텍처와 기능을 상세히 분석하고 재사용 가능 범위와 보완 필요 사항을 명세한다.
## 1. 프로젝트 개요
`Knowledge Agent`는 LightRAG 지식베이스를 자동으로 분석, 확장, 정제, 감사, 개선 제안하는 멀티 에이전트형 지식 관리 시스템이다.
핵심 목표는 정적인 RAG/지식그래프 저장소를 다음과 같은 “살아있는 지식 관리 루프”로 전환하는 것이다.
1. 기존 지식베이스를 분석하여 지식 공백을 찾는다.
2. 지식 공백별 연구 주제를 생성한다.
3. 검색 계획을 세우고 외부 웹/PDF 자료를 수집한다.
4. 수집한 원문을 마크다운과 요약으로 정제하여 DB에 저장한다.
5. 적합한 URL을 선별하여 LightRAG에 적재한다.
6. 그래프 품질 문제를 감사한다.
7. 중복, 명칭 불일치, 관계 오류 등을 수정한다.
8. 반복되는 문제를 분석하여 시스템 개선안을 제시한다.
범용 온톨로지 구축 플랫폼 관점에서는 “도메인 문서 수집 → 문서 정제 → 엔티티/관계 추출 기반 지식그래프 구축 → 품질 감사 → 정제 → 운영 개선”의 기본 골격으로 활용할 수 있다.
## 2. 기술 스택 및 실행 환경
### 2.1 주요 의존성
`pyproject.toml` 기준 의존성은 다음과 같다.
| 분류 | 패키지 | 용도 |
|---|---|---|
| 에이전트 프레임워크 | `langchain`, `langgraph` | 에이전트 실행 및 상태 그래프 구성 |
| LLM 연동 | `langchain-openai` | OpenAI 호환 Chat 모델 호출 |
| MCP 연동 | `langchain-mcp-adapters` | MCP 서버의 도구를 LangChain 도구로 연결 |
| DB | `psycopg2-binary` | PostgreSQL 연결 |
| 설정 | `python-dotenv`, `pydantic` | 환경 변수 및 데이터 검증 |
| JSON 복구 | `json-repair` | LLM 출력 JSON 파싱 안정화 |
| 웹 수집 | `requests`, `trafilatura`, `playwright`, `beautifulsoup4`, `html2text` | HTML/PDF 수집 및 본문 추출 |
| PDF 처리 | `pdfplumber` | PDF 텍스트 추출 |
| 토큰 제어 | `tiktoken` | 요약 전 입력 토큰 제한 |
### 2.2 환경 변수
`.env.example`과 코드 기준으로 다음 환경 변수가 필요하다.
| 변수 | 설명 |
|---|---|
| `DATABASE_URL` | PostgreSQL 연결 문자열. `db_utils.py`에서 필수로 사용 |
| `OPENAI_MODEL_NAME` | 사용할 OpenAI 호환 모델명. 기본값은 `chat` |
| `OPENAI_BASE_URL` | OpenAI 호환 API 서버 URL. 기본값은 `http://localhost:8001/v1` |
### 2.3 MCP 서버 설정
`mcp.json`은 다음 MCP 서버를 전제로 한다.
| 서버 | 역할 |
|---|---|
| `google_search` | 외부 검색 |
| `lightrag` | LightRAG 질의, 그래프 조회, 문서 적재, 엔티티/관계 수정 |
| `fetch` | URL fetch 보조 도구 |
| `file_tools` | 파일 시스템 접근 |
| `deepwiki` | 외부 지식 검색 보조 |
이 프로젝트는 MCP 도구 이름에 강하게 의존한다. 예를 들어 `analyst``query`, `graphs_get`, `graph_labels`, `google_search`, `fetch` 도구를 찾고, `fixer``graph_update_entity`, `documents_delete_entity`, `graph_update_relation`, `documents_delete_relation`, `graph_entity_exists` 도구를 기대한다.
## 3. 전체 아키텍처
### 3.1 구조
```text
run.py
└─ knowledge_agent.py
└─ LangGraph StateGraph
├─ Analyst
├─ Researcher
├─ Curator
├─ Auditor
├─ Fixer
└─ Advisor
db_utils.py
├─ 보고서 저장 테이블 관리
└─ 수집 문서 저장/조회
tools.py
├─ URL 다운로드
├─ HTML/PDF 본문 추출
├─ 마크다운 생성
└─ 사람 승인 도구
prompts/
├─ analyst_prompt.txt
├─ planner_prompt.txt
├─ refiner_prompt.txt
├─ summarizer_prompt.txt
├─ search_ranker_prompt.txt
└─ ingester_prompt.txt
```
### 3.2 상태 모델
`state.py``AgentState`는 LangGraph 전체 상태를 정의한다.
주요 상태 필드:
| 필드 | 설명 |
|---|---|
| `messages` | LangChain 메시지 목록 |
| `task` | 실행 워크플로우명 |
| `status` | 현재 상태 메시지 |
| `timestamp` | 실행 시각 |
| `mcp_tools` | MCP 서버에서 로드한 도구 목록 |
| `model` | ChatOpenAI 모델 객체 |
| `logger` | 실행 로거 |
| `analyst_report_id`, `analyst_report` | Analyst 산출물 |
| `researcher_report_id`, `researcher_gaps_todo`, `researcher_gaps_complete`, `researcher_report` | Researcher 진행 상태 |
| `curator_report_id`, `curator_urls_for_ingestion`, `curator_url_ingestion_status`, `curator_report` | Curator 진행 상태 |
| `auditor_report_id`, `auditor_report` | Auditor 산출물 |
| `fixer_report_id`, `fixer_report` | Fixer 산출물 |
| `advisor_report_id`, `advisor_report` | Advisor 산출물 |
## 4. 실행 흐름
### 4.1 진입점
`run.py`가 실행 진입점이다.
처리 순서:
1. `.env`를 로드한다.
2. `create_tables()`로 PostgreSQL 테이블을 생성한다.
3. CLI 인자를 파싱하여 실행 태스크를 결정한다.
4. `get_mcp_tools()`로 MCP 도구를 로드한다.
5. `ChatOpenAI` 모델 객체를 생성한다.
6. `create_knowledge_agent_graph(task, mcp_tools)`로 LangGraph 워크플로우를 만든다.
7. 초기 상태를 넣고 `app.ainvoke(initial_state)`로 실행한다.
지원 CLI:
| 옵션 | 실행 태스크 |
|---|---|
| `--maintenance` | 전체 유지보수 루프 |
| `--analyze` | 지식 공백 분석 |
| `--research` | 외부 조사 및 문서 수집 |
| `--curate` | URL 선별 및 LightRAG 적재 |
| `--audit` | 그래프 품질 감사 |
| `--fix` | 품질 문제 수정 |
| `--advise` | 시스템 개선 제안 |
### 4.2 LangGraph 워크플로우
`knowledge_agent.py`가 태스크별 그래프를 구성한다.
전체 유지보수 흐름:
```text
analyst
→ save_analyst_report
→ researcher
→ curator
→ auditor
→ save_auditor_report
→ fixer
→ save_fixer_report
→ advisor
→ save_advisor_report
→ END
```
개별 태스크는 해당 노드와 저장 노드만 실행한다.
## 5. 데이터베이스 명세
`db_utils.py`는 PostgreSQL을 사용하며, 실행 시 다음 테이블을 생성한다.
### 5.1 보고서 테이블
공통 구조:
```sql
id SERIAL PRIMARY KEY
report_id VARCHAR(255) UNIQUE NOT NULL
report JSONB
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
```
테이블:
| 테이블 | 저장 대상 |
|---|---|
| `analyst_reports` | 지식베이스 요약 및 지식 공백 |
| `researcher_reports` | 지식 공백별 검색 계획 및 검색 결과 |
| `curator_reports` | 선별 URL 및 적재 상태 |
| `auditor_reports` | 그래프 품질 문제 |
| `fixer_reports` | 수정 실행 결과 |
| `advisor_reports` | 시스템 개선 제안 |
### 5.2 문서 테이블
`documents` 테이블:
```sql
id SERIAL PRIMARY KEY
url TEXT UNIQUE NOT NULL
raw_document BYTEA
markdown_content TEXT
summary TEXT
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
```
역할:
| 컬럼 | 설명 |
|---|---|
| `url` | 원본 URL. 중복 방지 기준 |
| `raw_document` | HTML/PDF 원문 바이너리 |
| `markdown_content` | 본문 추출 결과 |
| `summary` | LLM 요약 |
범용 온톨로지 플랫폼에서는 이 테이블을 `source_documents` 또는 `collected_documents`로 확장하고, `domain`, `source_type`, `crawl_status`, `content_hash`, `license`, `language`, `published_at`, `ontology_project_id` 같은 컬럼을 추가하는 것이 좋다.
## 6. 에이전트별 기능명세
### 6.1 Analyst
파일: `sub_agents/analyst.py`
프롬프트: `prompts/analyst_prompt.txt`
목적: LightRAG 지식베이스의 현재 상태를 분석하고, 지식 공백을 구조화된 연구 주제로 변환한다.
입력:
| 입력 | 설명 |
|---|---|
| `state.messages[0].content` | 분석 지시문 |
| `mcp_tools` | `query`, `graphs_get`, `graph_labels`, `google_search`, `fetch` |
| `analyst_report_id` | 실행 시각 기반 ID |
처리:
1. LightRAG 질의 및 그래프 조회 도구로 기존 지식베이스를 탐색한다.
2. 5-10개 수준의 주제 테마를 만든다.
3. 외부 검색으로 주제 지형을 보완한다.
4. 시간적/논리적 지식 공백을 식별한다.
5. 각 공백을 Researcher가 사용할 수 있는 `research_topic` 객체로 만든다.
6. JSON 보고서를 반환한다.
7. `save_analyst_report_node`가 JSON을 복구/파싱한 후 DB에 저장한다.
출력 JSON 핵심 스키마:
```json
{
"report_id": "ana_...",
"knowledge_base_summary": {
"summary": "...",
"themes": [
{
"theme_id": "T1",
"description": "..."
}
]
},
"identified_gaps": [
{
"gap_id": "G1",
"description": "...",
"research_topic": {
"title": "...",
"summary": "...",
"key_questions": [],
"keywords": [],
"sources_to_consult": [],
"sources_to avoid": []
}
}
]
}
```
재사용 판단:
| 항목 | 판단 |
|---|---|
| 지식 공백 탐지 패턴 | 거의 그대로 재사용 가능 |
| 출력 스키마 | 온톨로지 구축용으로 확장 필요 |
| 도구 의존성 | LightRAG 도구명에 의존하므로 어댑터 필요 |
온톨로지 플랫폼 확장안:
`research_topic`에 다음 필드를 추가하는 것이 좋다.
| 필드 | 설명 |
|---|---|
| `target_ontology_scope` | 구축 대상 온톨로지 범위 |
| `candidate_entity_types` | 예상 엔티티 유형 |
| `candidate_relation_types` | 예상 관계 유형 |
| `competency_questions` | 온톨로지가 답해야 하는 역량 질문 |
| `source_priority_policy` | 공식 문서, 논문, 웹문서 등 우선순위 |
### 6.2 Researcher
파일: `sub_agents/researcher.py`
프롬프트: `planner_prompt.txt`, `refiner_prompt.txt`, `summarizer_prompt.txt`
목적: Analyst가 만든 지식 공백별 연구 주제를 바탕으로 검색 계획을 세우고, URL을 검색하고, 원문을 수집/정제/요약하여 DB에 저장한다.
입력:
| 입력 | 설명 |
|---|---|
| 최신 `analyst_reports` | `initialize_researcher()`가 DB에서 로드 |
| `google_search` MCP 도구 | 검색 실행 |
| `process_url()` | URL 수집 및 문서화 |
| `summarizer_executor` | 문서 요약 |
처리 단계:
1. `initialize_researcher()`가 최신 Analyst 보고서를 읽는다.
2. `identified_gaps``researcher_gaps_todo`로 변환한다.
3. Planner가 각 `research_topic`에 대해 5개 검색 계획을 만든다.
4. 각 검색 계획을 `google_search`로 실행한다.
5. 검색 결과 URL마다 `process_url()`을 호출한다.
6. `process_url()``documents` 테이블에 URL을 추가하고 원문/마크다운을 저장한다.
7. Refiner가 검색 결과의 충분성을 평가한다.
8. 부족하면 최대 2개의 추가 검색을 수행한다.
9. 저장된 마크다운 문서를 요약한다.
10. `researcher_reports`에 공백별 검색 결과를 업데이트한다.
검색 계획 스키마:
```json
{
"searches": [
{
"search_id": "S_P1",
"query": "...",
"rationale": "...",
"parameters": {
"dateRestrict": "y1",
"sort": "date",
"num": 10
}
}
]
}
```
Refiner 출력 스키마:
```json
{
"status": "sufficient",
"rationale": "..."
}
```
또는:
```json
{
"status": "insufficient",
"rationale": "...",
"searches": [
{
"search_id": "S_R1",
"query": "...",
"rationale": "...",
"parameters": {}
}
]
}
```
요약 출력 스키마:
```json
{
"summary": "2-4 sentence summary"
}
```
재사용 판단:
| 항목 | 판단 |
|---|---|
| Planner/Refiner/Summarizer 구조 | 거의 그대로 재사용 가능 |
| URL 중복 저장 | 그대로 재사용 가능 |
| HTML/PDF 수집 | 보완 후 재사용 권장 |
| 도메인별 검색 전략 | 프롬프트만 교체/확장 |
범용 온톨로지 플랫폼에서 가장 가치가 높은 모듈이다. 특히 “지식 공백 → 검색 계획 → 검색 결과 → 문서 저장 → 요약” 흐름은 도메인별 온톨로지 구축의 자료 수집 레이어로 그대로 사용할 수 있다.
### 6.3 Content Processor
파일: `tools.py`
목적: URL을 원문 문서와 마크다운 콘텐츠로 변환한다.
함수:
| 함수 | 설명 |
|---|---|
| `fetch_and_generate_markdown(url, logger)` | URL의 Content-Type을 확인하고 HTML/PDF를 처리 |
| `process_url(url, logger)` | URL 중복 확인, 신규 URL이면 수집 후 DB 업데이트 |
| `human_approval(plan)` | 파괴적 작업 전 터미널 승인 요청 |
HTML 처리:
1. `requests.head()`로 Content-Type 확인
2. `text/html`이면 `trafilatura.fetch_url()`로 HTML 다운로드
3. `trafilatura.extract()`로 본문 추출
4. 추출 결과가 없거나 200자 미만이면 Playwright로 브라우저 렌더링
5. `main`, `#main`, `#content`, `[role="main"]`, `body` 순으로 텍스트 추출
PDF 처리:
1. `requests.get()`으로 PDF 다운로드
2. `pdfplumber`로 페이지별 텍스트 추출
3. 줄 단위로 연결하여 `markdown_content`에 저장
실패 처리:
지원하지 않는 Content-Type 또는 예외 발생 시:
```text
[MARKDOWN_GENERATION_FAILED: ...]
```
재사용 판단:
| 항목 | 판단 |
|---|---|
| URL 중복 등록 | 그대로 사용 가능 |
| Trafilatura 우선 + Playwright fallback | 그대로 사용 가능 |
| PDF 텍스트 추출 | 그대로 사용 가능 |
| 403/SSL/JS 복잡 사이트 대응 | 개선 필요 |
| Content-Type이 부정확한 서버 대응 | 개선 필요 |
| robots.txt/저작권/라이선스 정책 | 추가 필요 |
### 6.4 Curator
파일: `sub_agents/curator.py`
프롬프트: `search_ranker_prompt.txt`, `ingester_prompt.txt`
목적: Researcher의 검색 결과를 평가해 실제 LightRAG에 넣을 URL을 선별하고 적재한다.
처리:
1. `initialize_curator()`가 최신 Researcher 보고서를 읽는다.
2. 검색 결과별로 Search Ranker 에이전트를 실행한다.
3. 각 URL을 `approved` 또는 `denied`로 분류한다.
4. 승인 URL 목록을 `curator_reports.urls_for_ingestion`에 저장한다.
5. Ingester 에이전트가 LightRAG 문서 적재 도구를 호출한다.
6. URL별 적재 상태를 저장한다.
Search Ranker 출력 스키마:
```json
{
"ranked_urls": [
{
"url": "https://example.com",
"status": "approved",
"rationale": "..."
}
]
}
```
Ingester 출력 스키마:
```json
{
"url_ingestion_status": [
{
"url": "https://example.com",
"status": "ingested"
}
]
}
```
현재 코드상 주의점:
`curator.py`에서는 다음 형태로 호출한다.
```python
update_curator_report(tool_input)
```
하지만 `db_utils.py`의 실제 함수 시그니처는 다음과 같다.
```python
update_curator_report(report_id: str, job: str, results: list)
```
따라서 현재 상태로는 Curator 실행 중 타입 오류가 발생할 가능성이 높다. 다음처럼 수정해야 한다.
```python
update_curator_report(report_id, "urls_for_ingestion", approved_urls)
update_curator_report(report_id, "url_ingestion_status", curator_url_ingestion_status)
```
재사용 판단:
| 항목 | 판단 |
|---|---|
| URL 평가 기준 | 거의 그대로 재사용 가능 |
| URL 승인/거부 JSON 계약 | 그대로 사용 가능 |
| LightRAG 적재 흐름 | MCP 도구명 확인 후 사용 |
| 현재 구현 안정성 | 수정 후 사용 필요 |
### 6.5 Auditor
파일: `sub_agents/auditor.py`
프롬프트 파일: `prompts/auditor_prompt.txt`는 비어 있음
실제 프롬프트: 코드 내 문자열
목적: LightRAG 그래프를 조회하여 중복 엔티티, 정규화 오류, 관계 품질 문제를 찾는다.
사용 도구:
| 도구 | 설명 |
|---|---|
| `graphs_get` | 그래프 조회 |
| `query` | 지식베이스 질의 |
현재 구현상 문제:
1. `save_auditor_report_node()`에서 `save_auditor_report()`를 호출하지만 import하지 않았다.
2. `create_openai_tools_agent()` 결과를 `AgentExecutor`로 감싸지 않고 직접 `ainvoke()`한다.
3. 저장 시 `save_auditor_report({"auditor_report": json.dumps(report_json)})` 형태로 넘기는데, `_save_report()`는 최상위 `report_id`를 요구한다. 이 형태는 `report_id` 누락 오류를 만들 수 있다.
4. `auditor_prompt.txt`가 비어 있어 프롬프트 관리 체계와 코드가 불일치한다.
재사용 판단:
| 항목 | 판단 |
|---|---|
| 감사 에이전트 개념 | 그대로 재사용 가능 |
| 현재 코드 | 수정 필요 |
| 프롬프트 파일화 | 필요 |
| 감사 결과 스키마 | 새로 명확화 필요 |
온톨로지 플랫폼용 Auditor 권장 스키마:
```json
{
"report_id": "aud_...",
"ontology_project_id": "...",
"issues": [
{
"issue_id": "Q1",
"issue_type": "duplicate_entity | relation_conflict | weak_evidence | naming_inconsistency | schema_violation",
"severity": "low | medium | high | critical",
"entities": [],
"relations": [],
"evidence": [],
"recommended_action": "..."
}
]
}
```
### 6.6 Fixer
파일: `sub_agents/fixer.py`
프롬프트 파일: `prompts/fixer_prompt.txt`는 비어 있음
실제 프롬프트: 코드 내 문자열
목적: Auditor가 찾은 그래프 품질 문제를 수정한다.
사용 도구:
| 도구 | 설명 |
|---|---|
| `graph_update_entity` | 엔티티 수정 |
| `documents_delete_entity` | 엔티티 삭제 |
| `graph_update_relation` | 관계 수정 |
| `documents_delete_relation` | 관계 삭제 |
| `graph_entity_exists` | 엔티티 존재 확인 |
| `human_approval` | 수정 계획 승인 |
| `load_latest_report` | 최신 보고서 로드 |
현재 구현상 문제:
1. `save_fixer_report()`를 import하지 않았다.
2. `load_latest_report`는 LangChain `@tool`로 감싸져 있지 않은 일반 함수다. 도구 목록에 직접 넣으면 LangChain 도구로 인식되지 않을 수 있다.
3. `create_openai_tools_agent()` 결과를 `AgentExecutor`로 감싸지 않는다.
4. 저장 보고서 구조가 `_save_report()`의 요구 조건과 맞지 않을 수 있다.
5. CLI/자동 실행 환경에서 `input()` 기반 `human_approval`은 중단 위험이 있다.
재사용 판단:
| 항목 | 판단 |
|---|---|
| 사람 승인 후 수정 패턴 | 매우 중요, 재사용 권장 |
| 현재 코드 | 수정 필요 |
| 파괴적 작업 정책 | 플랫폼 핵심 기능으로 확장 필요 |
온톨로지 플랫폼에서는 수정 작업을 다음 세 단계로 분리하는 것이 좋다.
1. `FixPlanGenerator`: 수정 계획 생성
2. `ApprovalGate`: 사람 승인 또는 정책 기반 자동 승인
3. `FixExecutor`: 승인된 작업만 실행
### 6.7 Advisor
파일: `sub_agents/advisor.py`
프롬프트 파일: `prompts/advisor_prompt.txt`는 비어 있음
실제 프롬프트: 코드 내 문자열
목적: 감사/수정 보고서를 분석하여 반복 문제와 시스템 개선안을 제시한다.
사용 도구:
| 도구 | 설명 |
|---|---|
| `list_allowed_directories` | 접근 가능한 디렉터리 조회 |
| `list_directory` | 디렉터리 조회 |
| `search_files` | 파일 검색 |
| `read_text_file` | 파일 읽기 |
| `load_latest_report` | 최신 보고서 로드 |
현재 구현상 문제:
1. `save_advisor_report()`를 import하지 않았다.
2. `load_latest_report` 도구화 문제가 있다.
3. `create_openai_tools_agent()` 직접 호출 문제가 있다.
4. 프롬프트 파일이 비어 있다.
재사용 판단:
| 항목 | 판단 |
|---|---|
| 운영 개선 에이전트 개념 | 그대로 재사용 가능 |
| 코드 안정성 | 수정 필요 |
| 플랫폼 확장 가치 | 높음 |
온톨로지 플랫폼에서는 Advisor가 다음 개선안을 만들도록 확장할 수 있다.
| 개선 대상 | 예시 |
|---|---|
| 엔티티 타입 체계 | 특정 타입 누락, 과도한 `concept/idea` 사용 |
| 관계 타입 체계 | 관계명이 너무 일반적이거나 중복됨 |
| 수집 정책 | 특정 도메인 실패율, 저품질 출처 비율 |
| 프롬프트 | 추출 누락, 명칭 정규화 실패 |
| 스키마 | 필수 속성 누락, 식별자 정책 부족 |
## 7. LightRAG 프롬프트 분석
파일: `lightrag/prompt.py`
이 파일은 LightRAG의 엔티티/관계 추출 프롬프트를 JSON 기반으로 재정의한다. 범용 온톨로지 구축 플랫폼에서 매우 중요한 자산이다.
### 7.1 엔티티 타입
정의된 엔티티 타입:
| 타입 | 설명 |
|---|---|
| `organization/institution` | 기관, 기업, 정부, 비영리 조직 |
| `person` | 인물 |
| `location/geo` | 지리적 장소 |
| `event` | 사건 |
| `policy/proposal` | 정책, 제안, 공식 계획 |
| `law/regulation` | 법률, 규정 |
| `tax/fiscal_instrument` | 조세, 수수료, 재정 메커니즘 |
| `narrative` | 사회적 서사 |
| `misinformation/disinformation` | 허위정보, 조작정보 |
| `digital_asset` | 디지털 자산 또는 플랫폼 |
| `concept/idea` | 추상 개념 |
| `metric/score` | 수치 지표 |
| `publication/article` | 보고서, 책, 기사 |
| `political_group` | 정치적 집단 |
| `scenario/situation` | 상황/맥락 |
| `demographic/population` | 인구 집단 |
| `publisher/outlet` | 출판사/매체 |
| `time_period/era` | 시기/기간 |
### 7.2 관계 타입
정의된 관계 타입:
```text
TARGETS, EVALUATES, PRODUCES, CAUSES, IS_A, IS_PART_OF,
IS_LOCATED_IN, INFLUENCES, PUBLISHED_BY, LED_BY,
CRITICIZES, SUPPORTS, USES, INVOLVES, ESTIMATES,
AFFIRMED_BY, PAYS_INTO, REIMBURSES
```
### 7.3 출력 스키마
```json
{
"entities": [
{
"name": "...",
"type": "...",
"description": "..."
}
],
"relationships": [
{
"source": "...",
"target": "...",
"description": "...",
"type": "...",
"strength": 8
}
]
}
```
### 7.4 재사용 가치
이 파일은 범용 온톨로지 구축 플랫폼의 “기본 온톨로지 추출 프롬프트”로 활용 가치가 높다. 특히 다음 원칙이 좋다.
1. 엔티티 타입을 JSON 사전으로 명시한다.
2. 관계 타입을 고정 리스트로 제한한다.
3. `UNKNOWN` 타입을 금지하고 애매한 경우 `concept/idea`로 보낸다.
4. 관계 강도 `strength`를 함께 출력한다.
5. 결과를 반드시 JSON으로 강제한다.
다만 현재 타입 체계는 정치/사회정책 도메인에 치우쳐 있다. 범용 온톨로지 플랫폼에서는 프로젝트별 타입 팩을 주입할 수 있어야 한다.
## 8. 재사용 가능 모듈 평가
| 모듈 | 재사용 등급 | 사유 |
|---|---:|---|
| `knowledge_agent.py` LangGraph 구성 | 높음 | 워크플로우 분기와 노드 연결 구조가 명확 |
| `run.py` 실행 진입점 | 중간 | 기본 실행 구조는 좋지만 설정/모델 기본값 정리 필요 |
| `state.py` | 높음 | 멀티 에이전트 상태 전달 모델로 활용 가능 |
| `db_utils.py` 보고서 저장 | 중간 | 기본 구조는 좋지만 스키마 확장과 일부 저장 구조 수정 필요 |
| `db_utils.py` 문서 저장 | 높음 | URL 중복 방지와 원문/마크다운/요약 저장이 유용 |
| `tools.py` URL 처리 | 높음 | HTML/PDF 수집 파이프라인이 실용적 |
| `researcher.py` | 높음 | 자료 수집 자동화 핵심 모듈 |
| `analyst.py` | 높음 | 지식 공백 기반 조사 설계에 적합 |
| `curator.py` | 중간 | 개념은 좋지만 코드 수정 필요 |
| `auditor.py` | 낮음-중간 | 개념은 좋지만 구현 완성도가 낮음 |
| `fixer.py` | 낮음-중간 | 사람 승인 패턴은 좋지만 코드 수정 필요 |
| `advisor.py` | 중간 | 운영 개선 아이디어는 좋지만 구현 정리 필요 |
| `prompts/*.txt` | 높음 | JSON 계약과 역할 분리가 명확 |
| `lightrag/prompt.py` | 매우 높음 | 온톨로지 추출 프롬프트 기반으로 직접 활용 가능 |
## 9. 현재 코드의 주요 결함 및 수정 필요 사항
### 9.1 실행 오류 가능성이 높은 부분
| 위치 | 문제 | 영향 | 수정 방향 |
|---|---|---|---|
| `curator.py` | `update_curator_report()` 호출 인자 불일치 | Curator 실행 실패 | `update_curator_report(report_id, job, results)`로 수정 |
| `auditor.py` | `save_auditor_report` import 누락 | 저장 실패 | `from db_utils import save_auditor_report` 추가 |
| `fixer.py` | `save_fixer_report` import 누락 | 저장 실패 | import 추가 |
| `advisor.py` | `save_advisor_report` import 누락 | 저장 실패 | import 추가 |
| `auditor.py`, `fixer.py`, `advisor.py` | `create_openai_tools_agent()``AgentExecutor`로 감싸지 않음 | 정상 실행 불확실 | Researcher/Analyst 방식으로 통일 |
| `auditor.py`, `fixer.py`, `advisor.py` | 저장 데이터에 최상위 `report_id`가 없을 수 있음 | `_save_report()` 오류 | 보고서 스키마 통일 |
| `prompts/auditor_prompt.txt` 등 | 파일은 있으나 비어 있고 코드에 프롬프트 하드코딩 | 유지보수성 저하 | 프롬프트 파일로 이동 |
| `load_latest_report` | 일반 함수를 도구 목록에 직접 삽입 | LangChain 도구 인식 실패 가능 | `@tool` 래핑 또는 에이전트 외부에서 로드 |
### 9.2 설계상 보완점
| 영역 | 보완 필요 |
|---|---|
| 도메인 독립성 | LightRAG 도구명, 정치/정책형 엔티티 타입에 의존 |
| 수집 정책 | robots.txt, 라이선스, 출처 신뢰도, 차단 도메인 정책 부족 |
| 실패 복구 | 403, SSL 오류, JS 렌더링 실패, 빈 본문 처리 강화 필요 |
| 중복 문서 | URL 기준 중복만 처리. `content_hash` 기반 중복 제거 필요 |
| 보고서 버전 | 프로젝트/도메인/실행 단위 식별자 부족 |
| 승인 흐름 | CLI `input()` 기반 승인만 제공. 웹 UI/API 승인 필요 |
| 감사 스키마 | 품질 이슈 타입, 심각도, 수정안 스키마가 불명확 |
| 테스트 | 단위 테스트/통합 테스트 부재 |
## 10. 범용 온톨로지 구축 플랫폼 적용 설계
### 10.1 추천 플랫폼 아키텍처
```text
Ontology Project
├─ Source Discovery
│ ├─ Analyst
│ └─ Research Planner
├─ Source Collection
│ ├─ Search Executor
│ ├─ URL Processor
│ └─ Document Store
├─ Ontology Extraction
│ ├─ Entity Extractor
│ ├─ Relation Extractor
│ └─ Schema Mapper
├─ Curation
│ ├─ Source Ranker
│ ├─ Evidence Scorer
│ └─ Ingestion Manager
├─ Quality Control
│ ├─ Auditor
│ ├─ Fix Planner
│ └─ Approval Gate
└─ Continuous Improvement
└─ Advisor
```
### 10.2 기존 소스와 매핑
| 플랫폼 기능 | 기존 소스 |
|---|---|
| 프로젝트 실행 워크플로우 | `knowledge_agent.py`, `run.py` |
| 상태 전달 | `state.py` |
| 지식 공백 탐지 | `sub_agents/analyst.py`, `analyst_prompt.txt` |
| 검색 전략 생성 | `sub_agents/researcher.py`, `planner_prompt.txt` |
| 검색 결과 보완 판단 | `refiner_prompt.txt` |
| 문서 수집/정제 | `tools.py` |
| 문서 저장 | `db_utils.py``documents` |
| 요약 | `summarizer_prompt.txt` |
| URL 선별 | `curator.py`, `search_ranker_prompt.txt` |
| LightRAG 적재 | `curator.py`, `ingester_prompt.txt` |
| 그래프 감사 | `auditor.py` |
| 수정 승인/실행 | `fixer.py`, `human_approval()` |
| 시스템 개선 | `advisor.py` |
| 엔티티/관계 추출 프롬프트 | `lightrag/prompt.py` |
### 10.3 거의 변형 없이 가져갈 수 있는 기능
1. LangGraph 기반 워크플로우 분기 구조
2. `AgentState` 중심 상태 전달 방식
3. Analyst의 지식 공백 탐지 프롬프트 구조
4. Researcher의 Planner/Refiner/Summarizer 단계 구조
5. URL 중복 저장 후 원문/마크다운/요약을 관리하는 문서 저장소 구조
6. Trafilatura 우선, Playwright fallback 수집 전략
7. JSON 출력 강제 프롬프트 패턴
8. LightRAG 엔티티/관계 추출 프롬프트의 JSON 스키마 방식
9. Human approval을 거친 그래프 수정 개념
### 10.4 반드시 수정 후 가져갈 기능
1. Curator의 DB 업데이트 호출 오류
2. Auditor/Fixer/Advisor의 누락 import
3. Auditor/Fixer/Advisor의 AgentExecutor 사용 방식
4. 보고서 저장 스키마 불일치
5. 빈 프롬프트 파일과 하드코딩 프롬프트 분리
6. `load_latest_report` 도구화 방식
7. 수집 실패 및 차단 도메인 처리
8. 프로젝트/도메인 단위 멀티테넌시 스키마
## 11. 기능명세서
### 11.1 프로젝트 관리
| 기능 ID | 기능명 | 설명 | 입력 | 출력 |
|---|---|---|---|---|
| ONT-PROJ-001 | 온톨로지 프로젝트 생성 | 도메인, 목표, 기본 타입 체계를 가진 프로젝트 생성 | 프로젝트명, 도메인, 설명 | `ontology_project_id` |
| ONT-PROJ-002 | 프로젝트별 실행 설정 | 모델, MCP 도구, 수집 정책, 승인 정책 설정 | 설정 JSON | 저장된 설정 |
| ONT-PROJ-003 | 프로젝트별 실행 이력 조회 | 분석/수집/적재/감사 이력 확인 | 프로젝트 ID | 실행 목록 |
### 11.2 지식베이스 분석
| 기능 ID | 기능명 | 설명 | 입력 | 출력 |
|---|---|---|---|---|
| ONT-ANA-001 | 기존 지식베이스 요약 | 그래프와 문서를 조회하여 현재 지식 범위 요약 | 프로젝트 ID | 주제 요약 |
| ONT-ANA-002 | 지식 공백 탐지 | 시간적/논리적/출처상 공백 식별 | 지식베이스 요약 | 공백 목록 |
| ONT-ANA-003 | 연구 주제 생성 | 공백을 검색 가능한 조사 브리프로 변환 | 공백 목록 | `research_topic` 목록 |
| ONT-ANA-004 | 역량 질문 생성 | 온톨로지가 답해야 할 질문 생성 | 도메인 설명 | `competency_questions` |
### 11.3 자료 검색 및 수집
| 기능 ID | 기능명 | 설명 | 입력 | 출력 |
|---|---|---|---|---|
| ONT-RES-001 | 검색 계획 생성 | 연구 주제별 검색 쿼리와 파라미터 생성 | `research_topic` | 검색 계획 |
| ONT-RES-002 | 검색 실행 | MCP 검색 도구로 검색 수행 | 검색 계획 | 검색 결과 |
| ONT-RES-003 | URL 중복 확인 | URL이 이미 저장되어 있는지 확인 | URL | 문서 ID, 신규/기존 상태 |
| ONT-RES-004 | HTML 본문 추출 | Trafilatura/Playwright로 본문 추출 | URL | 원문, 마크다운 |
| ONT-RES-005 | PDF 텍스트 추출 | PDF를 다운로드하고 텍스트 추출 | URL | 원문, 텍스트 |
| ONT-RES-006 | 문서 요약 | 마크다운을 16k 토큰 이하로 제한 후 요약 | 문서 ID | 요약 |
| ONT-RES-007 | 검색 결과 충분성 평가 | 초기 검색 결과가 연구 질문을 충족하는지 판단 | 검색 결과 | 충분/부족, 보완 검색 |
### 11.4 출처 큐레이션
| 기능 ID | 기능명 | 설명 | 입력 | 출력 |
|---|---|---|---|---|
| ONT-CUR-001 | URL 품질 평가 | 관련성, 권위성, 품질, 신규성 기준 평가 | 검색 결과 | 승인/거부 URL |
| ONT-CUR-002 | 적재 대상 선정 | 승인 URL을 적재 목록에 추가 | 승인 URL | 적재 대기 목록 |
| ONT-CUR-003 | 지식베이스 적재 | LightRAG 또는 내부 그래프 저장소에 문서 적재 | URL/문서 ID | 적재 상태 |
| ONT-CUR-004 | 적재 상태 추적 | URL별 적재 성공/실패 기록 | 적재 작업 ID | 상태 목록 |
### 11.5 온톨로지 추출
| 기능 ID | 기능명 | 설명 | 입력 | 출력 |
|---|---|---|---|---|
| ONT-EXT-001 | 엔티티 타입 사전 관리 | 프로젝트별 엔티티 타입 정의 | 타입 정의 JSON | 타입 사전 |
| ONT-EXT-002 | 관계 타입 사전 관리 | 프로젝트별 관계 타입 정의 | 관계 정의 JSON | 관계 사전 |
| ONT-EXT-003 | 엔티티/관계 추출 | 문서 청크에서 엔티티와 관계 추출 | 문서 청크, 타입 사전 | 엔티티/관계 JSON |
| ONT-EXT-004 | 명칭 정규화 | 약어/별칭을 표준명으로 통합 | 엔티티 후보 | 표준 엔티티 |
| ONT-EXT-005 | 증거 연결 | 엔티티/관계에 원문 근거 연결 | 추출 결과 | evidence 링크 |
| ONT-EXT-006 | 관계 강도 산정 | 관계의 명시성/확실성 점수 산정 | 관계 후보 | `strength` |
### 11.6 품질 감사
| 기능 ID | 기능명 | 설명 | 입력 | 출력 |
|---|---|---|---|---|
| ONT-AUD-001 | 중복 엔티티 탐지 | 이름/별칭/설명 기반 중복 탐지 | 그래프 | 중복 후보 |
| ONT-AUD-002 | 명칭 불일치 탐지 | 동일 개념의 표기 차이 탐지 | 그래프 | 정규화 이슈 |
| ONT-AUD-003 | 관계 충돌 탐지 | 상충 관계나 잘못된 방향 탐지 | 그래프 | 관계 이슈 |
| ONT-AUD-004 | 스키마 위반 탐지 | 허용되지 않은 타입/관계 탐지 | 그래프, 스키마 | 위반 목록 |
| ONT-AUD-005 | 약한 근거 탐지 | evidence가 부족한 엔티티/관계 탐지 | 그래프 | 저신뢰 항목 |
### 11.7 수정 및 승인
| 기능 ID | 기능명 | 설명 | 입력 | 출력 |
|---|---|---|---|---|
| ONT-FIX-001 | 수정 계획 생성 | 감사 이슈를 실행 가능한 수정 계획으로 변환 | 감사 보고서 | 수정 계획 |
| ONT-FIX-002 | 사람 승인 요청 | 삭제/병합/관계 변경 전 승인 요청 | 수정 계획 | 승인/거부 |
| ONT-FIX-003 | 엔티티 수정 | 이름, 타입, 설명 수정 | 승인된 계획 | 수정 결과 |
| ONT-FIX-004 | 관계 수정 | 관계 타입, 방향, 설명, 강도 수정 | 승인된 계획 | 수정 결과 |
| ONT-FIX-005 | 엔티티/관계 삭제 | 승인된 파괴적 변경 실행 | 승인된 계획 | 삭제 결과 |
| ONT-FIX-006 | 수정 이력 저장 | 누가/언제/무엇을 변경했는지 저장 | 수정 결과 | 이력 레코드 |
### 11.8 운영 개선
| 기능 ID | 기능명 | 설명 | 입력 | 출력 |
|---|---|---|---|---|
| ONT-ADV-001 | 실패 패턴 분석 | 수집/적재/추출/감사 실패 로그 분석 | 실행 로그 | 실패 패턴 |
| ONT-ADV-002 | 프롬프트 개선 제안 | 반복 오류를 줄이기 위한 프롬프트 수정안 제시 | 감사/수정 보고서 | 개선안 |
| ONT-ADV-003 | 타입/관계 체계 개선 제안 | 누락/중복 타입 및 관계 개선 | 추출 결과 | 스키마 제안 |
| ONT-ADV-004 | 수집 정책 개선 제안 | 차단 도메인, 신뢰 출처, 우선순위 개선 | 수집 로그 | 정책 제안 |
| ONT-ADV-005 | Top N 개선 리포트 | 가장 영향도 높은 개선안을 정리 | 전체 보고서 | 개선 보고서 |
## 12. 권장 리팩터링 순서
1. Curator/Auditor/Fixer/Advisor 실행 오류를 먼저 수정한다.
2. 보고서 저장 스키마를 모든 에이전트에서 통일한다.
3. 하드코딩 프롬프트를 `prompts/*.txt`로 이동한다.
4. `load_latest_report`를 에이전트 도구로 쓸지, 노드 내부 로직으로 쓸지 분리한다.
5. DB 스키마에 `ontology_project_id`와 실행 ID를 추가한다.
6. 문서 테이블에 `content_hash`, `source_status`, `source_type`, `language`, `license`, `last_checked_at`을 추가한다.
7. LightRAG 프롬프트의 엔티티/관계 타입을 프로젝트별 설정으로 분리한다.
8. Auditor/Fixer 스키마를 명확히 정의하고 승인 UI/API를 설계한다.
9. 수집 실패 도메인 blocklist를 DB화한다.
10. 주요 기능별 테스트를 추가한다.
## 13. 결론
`knowledge_agent-main`은 범용 온톨로지 구축 플랫폼의 초기 골격으로 활용 가치가 높다. 특히 Analyst-Researcher-Curator로 이어지는 “지식 공백 기반 자료 수집 루프”와 `lightrag/prompt.py`의 JSON 기반 엔티티/관계 추출 프롬프트는 거의 그대로 가져와도 된다.
다만 현재 프로젝트는 연구/프로토타입 성격이 강하며, 전체 유지보수 워크플로우를 바로 운영 환경에 넣기에는 Curator 이후 단계의 코드 안정성이 부족하다. 따라서 기본 소스로 채택하되, 먼저 실행 오류와 보고서 스키마를 정리하고, 이후 범용 온톨로지 플랫폼에 맞게 프로젝트 단위 설정, 도메인별 타입 체계, 품질 감사/승인 체계를 확장하는 방식이 적합하다.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,749 @@
# Trafilatura 분석 및 기능 명세
분석 대상: `C:\Users\lasta\MyProject\AI\참고\trafilatura-master`
분석일: 2026-05-13
대상 버전: `trafilatura.__version__ = 2.0.0`
라이선스: Apache-2.0
## 1. 결론 요약
Trafilatura는 웹 문서에서 본문, 댓글, 메타데이터, 링크 후보를 추출하기 위한 Python 라이브러리이자 CLI 도구다. 범용 온톨로지 구축 플랫폼에서는 “웹 원천 데이터 수집 및 정제 계층”의 기본 소스로 거의 그대로 사용하기에 적합하다.
가장 가치가 큰 기능은 다음이다.
- 웹 페이지 다운로드: `fetch_url()`, `fetch_response()`
- HTML 본문 추출: `extract()`, `bare_extraction()`
- 구조 보존 추출: XML/HTML/Markdown/JSON/TEI 출력
- 메타데이터 추출: 제목, 저자, 날짜, canonical URL, 사이트명, 설명, 태그, 라이선스, 대표 이미지
- 링크 발견: RSS/Atom/JSON Feed, sitemap, robots.txt sitemap, focused crawler
- 중복 제거: 본문 세그먼트 LRU 중복 검사, 문서 fingerprint용 SimHash
- 설정 객체: `Extractor`, 결과 객체: `Document`
플랫폼 통합 권장 방식은 `bare_extraction(output_format="python", with_metadata=True)`를 기본으로 삼는 것이다. 이 방식은 문자열 출력으로 손실되기 전의 `Document` 객체, `body` XML tree, `commentsbody`, 정규화 텍스트, 메타데이터를 받을 수 있어 온톨로지 구축 전처리 단계와 연결하기 쉽다.
주의할 점은 전역 상태다. 다운로드 pool, 중복 LRU cache, crawler URL store가 모듈 전역에 존재한다. 단일 작업에서는 편하지만, 멀티 프로젝트/멀티 테넌트 플랫폼에서는 작업 단위 격리, cache reset, 도메인별 crawl 상태 저장을 별도 래퍼에서 관리해야 한다.
## 2. 프로젝트 구조
주요 디렉터리와 파일:
| 경로 | 역할 |
|---|---|
| `trafilatura/__init__.py` | 공개 API re-export |
| `trafilatura/core.py` | 추출 파이프라인 진입점 |
| `trafilatura/main_extractor.py` | Trafilatura 기본 본문/댓글 추출 알고리즘 |
| `trafilatura/htmlprocessing.py` | HTML 정리, 태그 변환, 링크 밀도 제거 |
| `trafilatura/metadata.py` | 메타 태그, JSON-LD, OpenGraph, 날짜/저자/URL 추출 |
| `trafilatura/json_metadata.py` | JSON-LD/schema.org 메타데이터 파싱 |
| `trafilatura/downloads.py` | HTTP 다운로드, Response 객체, 병렬 다운로드 |
| `trafilatura/feeds.py` | RSS/Atom/JSON feed 발견 및 URL 추출 |
| `trafilatura/sitemaps.py` | sitemap/robots.txt 기반 URL 발견 |
| `trafilatura/spider.py` | focused crawler |
| `trafilatura/deduplication.py` | LRU segment dedup, SimHash fingerprint |
| `trafilatura/xml.py` | JSON/CSV/XML/TEI/TXT 변환 |
| `trafilatura/settings.py` | `Extractor`, `Document`, 전역 상수 |
| `trafilatura/settings.cfg` | 사용자 조정 가능한 기본 설정 |
| `docs/` | 사용법/설정/다운로드/크롤링/중복제거 문서 |
| `tests/` | 단위 테스트, 실제 웹 페이지 평가 데이터 |
## 3. 외부 의존성
`pyproject.toml` 기준 필수 의존성:
- `certifi`: TLS 인증서
- `charset_normalizer >= 3.4.0`: 인코딩 탐지
- `courlan >= 1.3.2`: URL 정규화, 필터링, URL store, 링크 추출
- `htmldate >= 1.9.2`: 날짜 추출
- `justext >= 3.0.1`: fallback 본문 추출
- `lxml`: HTML/XML 파싱 및 XPath
- `urllib3 >= 1.26, < 3`: HTTP client
선택 의존성 `trafilatura[all]`:
- `brotli`, `zstandard`: 압축 응답 처리 강화
- `py3langid`: 언어 판별
- `pycurl`: 빠른 HTTP backend
- `urllib3[socks]`: SOCKS proxy
- `htmldate[speed]`: 날짜 추출 속도 개선
## 4. 핵심 데이터 모델
### 4.1 `Extractor`
파일: `trafilatura/settings.py`
추출 옵션을 담는 설정 객체다. 함수 인자가 많기 때문에 플랫폼에서는 개별 인자보다 `Extractor` 객체를 만들어 넘기는 방식을 권장한다.
주요 속성:
| 속성 | 의미 | 기본값 |
|---|---|---|
| `format` | 출력 형식 | `txt` |
| `fast` | fallback 알고리즘 생략 | `False` |
| `focus` | `balanced`, `precision`, `recall` | `balanced` |
| `comments` | 댓글 추출 | `True` |
| `formatting` | 굵게/기울임 등 구조 보존 | `False`, Markdown이면 자동 True |
| `links` | 링크 target 보존 | `False` |
| `images` | 이미지 정보 보존 | `False` |
| `tables` | table 추출 | `True` |
| `dedup` | 중복 세그먼트 제거 | `False` |
| `lang` | 목표 언어 필터 | `None` |
| `url` | 원문 URL | `None` |
| `with_metadata` | 메타데이터 추출/출력 포함 | `False` |
| `only_with_metadata` | 핵심 메타데이터 없으면 폐기 | `False` |
| `tei_validation` | TEI 출력 검증 | `False` |
| `date_params` | `htmldate` 날짜 추출 옵션 | 현재 날짜 max_date |
| `author_blacklist` | 제외할 저자명 집합 | 빈 set |
| `url_blacklist` | 제외할 URL 집합 | 빈 set |
### 4.2 `Document`
파일: `trafilatura/settings.py`
추출 결과와 메타데이터를 담는 객체다.
필드:
| 필드 | 설명 |
|---|---|
| `title` | 제목 |
| `author` | 저자 |
| `url` | canonical URL 또는 입력 URL |
| `hostname` | 호스트명 |
| `description` | 설명/요약 메타 |
| `sitename` | 사이트명/매체명 |
| `date` | 발행일 |
| `categories` | 카테고리 목록 |
| `tags` | 태그 목록 |
| `fingerprint` | SimHash 기반 문서 fingerprint |
| `id` | 호출자가 넘긴 record id |
| `license` | 라이선스 정보 |
| `body` | 본문 XML tree |
| `comments` | 댓글 텍스트 |
| `commentsbody` | 댓글 XML tree |
| `raw_text` | 내부 추출 텍스트 |
| `text` | 최종 출력 문자열 또는 python 모드 텍스트 |
| `language` | 감지 언어 |
| `image` | 대표 이미지 |
| `pagetype` | OpenGraph page type |
| `filedate` | 파일 날짜 |
`Document.as_dict()`로 dict 변환이 가능하다.
## 5. 본문 추출 파이프라인
핵심 진입점:
- `extract(filecontent, ...) -> Optional[str]`
- `extract_with_metadata(filecontent, ...) -> Optional[Document]`
- `bare_extraction(filecontent, ...) -> Optional[Document]`
권장 기본 호출:
```python
from trafilatura import bare_extraction
doc = bare_extraction(
html,
url=url,
output_format="python",
with_metadata=True,
include_comments=False,
include_tables=True,
include_formatting=True,
include_links=True,
deduplicate=True,
)
```
처리 순서:
1. `load_html()`로 문자열/bytes/LXML 입력을 HTML tree로 변환한다.
2. `target_language`가 있고 fast mode이거나 언어 판별 모듈이 없으면 HTML lang 속성을 먼저 검사한다.
3. `with_metadata=True`이면 `extract_metadata()`로 메타데이터를 추출한다.
4. `only_with_metadata=True`이면 `date`, `title`, `url`이 모두 없을 때 문서를 폐기한다.
5. 사용자가 지정한 `prune_xpath`를 tree에서 제거한다.
6. `tree_cleaning()`으로 불필요 태그와 섹션을 제거한다.
7. `convert_tags()`로 HTML 태그를 내부 구조 태그로 변환한다.
8. `include_comments=True`이면 댓글 영역을 먼저 추출하고 본문 tree에서 분리한다.
9. `extract_content()`로 Trafilatura 기본 본문 추출을 수행한다.
10. `fast=False`이면 readability/jusText 계열 fallback과 비교하여 더 나은 결과를 선택한다.
11. 본문 길이가 너무 짧고 precision 모드가 아니면 `baseline()` fallback을 수행한다.
12. `deduplicate=True`이면 LRU cache 기반 중복 본문을 폐기한다.
13. `target_language`가 있으면 최종 텍스트 언어를 검사한다.
14. 요청 형식에 따라 TXT/Markdown/JSON/CSV/HTML/XML/TEI로 변환한다.
## 6. 출력 형식
지원 형식:
| 형식 | 함수 인자 | 용도 |
|---|---|---|
| Python object | `bare_extraction(output_format="python")` | 온톨로지 파이프라인 권장 |
| Plain text | `output_format="txt"` | 단순 텍스트 저장 |
| Markdown | `output_format="markdown"` | 구조 일부 보존, LLM 입력에 유용 |
| JSON | `output_format="json"` | API 저장/교환 |
| CSV | `output_format="csv"` | 배치 처리 결과 |
| HTML | `output_format="html"` | 정제된 HTML preview |
| XML | `output_format="xml"` | 구조 보존 |
| XML-TEI | `output_format="xmltei"` | 인문학/말뭉치 표준 |
온톨로지 구축 플랫폼에서는 다음 전략이 적합하다.
- 원천 보존: raw HTML 별도 저장
- 추출 본문: `Document.text`
- 구조 본문: `Document.body`
- 메타데이터: `Document.as_dict()` 중 primitive 필드
- LLM/IE 입력: Markdown 또는 XML 변환본
- 장기 말뭉치 교환: XML-TEI 선택 가능
## 7. 메타데이터 추출 기능
파일: `trafilatura/metadata.py`, `trafilatura/json_metadata.py`
추출 출처:
- OpenGraph: `og:title`, `og:description`, `og:site_name`, `og:image`, `og:type`, `og:url`
- Twitter cards: `twitter:title`, `twitter:description`, `twitter:image`, `twitter:site`, `twitter:url`
- 표준 meta name: `author`, `description`, `keywords`, `publisher`, `dc.*`, `dcterms.*`, `citation_*`
- JSON-LD/schema.org: `application/ld+json`
- HTML heading: `h1`, `h2`
- canonical/base/alternate link
- `htmldate.find_date()` 기반 날짜 추출
- Creative Commons license URL/text 패턴
기능 명세:
| 기능명 | 입력 | 출력 | 실패 조건 |
|---|---|---|---|
| `extract_metadata` | HTML tree/string, URL, date params | `Document` | HTML 파싱 실패 시 빈/부분 Document |
| `extract_meta_json` | HTML tree, Document | JSON-LD 반영 Document | JSON 파싱 실패 시 fallback parser 사용 |
| `extract_opengraph` | HTML tree | dict | 해당 meta 없으면 None 값 |
| `extract_title` | HTML tree | str 또는 None | 제목 후보 없음 |
| `extract_author` | HTML tree | str 또는 None | 저자 후보 없음 |
| `extract_url` | HTML tree, default URL | str 또는 None | URL 후보 없음/invalid |
| `extract_license` | HTML tree | str 또는 None | license 후보 없음 |
플랫폼 적용:
- `title`, `author`, `date`, `sitename`, `url`, `description`, `tags`, `categories``SourceDocument` 메타로 저장한다.
- `url``date`는 provenance 및 temporal ontology 축의 핵심 속성으로 사용한다.
- `tags/categories`는 초기 후보 개념(seed concept)으로 사용할 수 있으나, 사이트별 노이즈가 많으므로 confidence를 낮게 둔다.
## 8. 다운로드 기능
파일: `trafilatura/downloads.py`
주요 API:
| 기능명 | 설명 |
|---|---|
| `fetch_url(url)` | HTML을 다운로드하고 decode한 문자열 반환 |
| `fetch_response(url, decode=False, with_headers=False)` | `Response` 객체 반환 |
| `buffered_downloads()` | URL buffer 병렬 다운로드 |
| `buffered_response_downloads()` | Response 객체 병렬 다운로드 |
| `is_live_page(url)` | URL 접근 가능성 확인 |
`Response` 필드:
- `data`: bytes
- `headers`: optional dict
- `html`: optional decoded string
- `status`: HTTP status
- `url`: 최종 URL
설정:
| 설정 | 기본값 | 설명 |
|---|---:|---|
| `DOWNLOAD_TIMEOUT` | 30 | 요청 timeout |
| `MAX_FILE_SIZE` | 20000000 | 최대 파일 크기 |
| `MIN_FILE_SIZE` | 10 | 최소 파일 크기 |
| `SLEEP_TIME` | 5.0 | 동일 host 요청 간격 |
| `MAX_REDIRECTS` | 2 | redirect 허용 횟수 |
| `USER_AGENTS` | empty | 사용자 user-agent 후보 |
| `COOKIE` | empty | 요청 cookie |
플랫폼 적용:
- 이미 프로젝트에 크롤러가 있다면 `fetch_url()`을 직접 대체하기보다 HTML 추출 단계에 Trafilatura를 붙이는 것이 안전하다.
- Trafilatura downloader를 쓰는 경우 도메인별 throttling과 robots 정책을 서비스 단에서 명시적으로 기록해야 한다.
- `fetch_response(decode=True, with_headers=True)`는 최종 URL, status, header provenance 저장에 적합하다.
## 9. 링크 발견 기능
### 9.1 Feed 발견
파일: `trafilatura/feeds.py`
주요 API:
```python
from trafilatura.feeds import find_feed_urls
urls = find_feed_urls("https://example.com", target_lang="ko")
```
지원:
- Atom
- RSS/RDF
- JSON Feed
- HTML 내 `<link rel="alternate">`
- HTML 내 feed 후보 `<a href>`
- Google News RSS fallback
- 언어 필터/도메인 유사도 필터
기능 명세:
| 기능명 | 입력 | 출력 | 정책 |
|---|---|---|---|
| `find_feed_urls` | URL, target_lang, external, sleep_time | 정렬/중복 제거 URL 목록 | 기본적으로 유사 도메인만 허용 |
| `determine_feed` | HTML 문자열 | feed URL 목록 | feed MIME/type/URL 패턴 사용 |
| `extract_links` | feed 문자열 | article URL 목록 | feedburner/feedproxy 예외 처리 |
### 9.2 Sitemap 발견
파일: `trafilatura/sitemaps.py`
주요 API:
```python
from trafilatura.sitemaps import sitemap_search
urls = sitemap_search("https://example.com", target_lang="ko")
```
지원:
- `robots.txt`의 Sitemap 항목
- 일반 sitemap guess: `sitemap.xml`, `sitemap.xml.gz`, `sitemap_index.xml`, `sitemap_news.xml`
- XML sitemap
- TXT sitemap
- hreflang 기반 target language
- nested sitemap
- URL filter
- 유사 도메인 필터
기능 명세:
| 기능명 | 입력 | 출력 | 제한 |
|---|---|---|---|
| `sitemap_search` | URL, target_lang, external, sleep_time, max_sitemaps | URL 목록 | 기본 최대 sitemap 10,000개 |
| `find_robots_sitemaps` | base URL | sitemap URL 목록 | robots.txt 10KB 초과 시 폐기 |
| `is_plausible_sitemap` | URL, contents | bool | HTML 응답이면 sitemap 아님 |
### 9.3 Focused crawler
파일: `trafilatura/spider.py`
주요 API:
```python
from trafilatura.spider import focused_crawler
todo, known = focused_crawler(
"https://example.com",
max_seen_urls=10,
max_known_urls=100000,
lang="ko",
)
```
특징:
- 시작 URL 기준 내부 링크 탐색
- robots.txt 파싱 및 `can_fetch("*", link)` 적용
- `Crawl-Delay` 반영
- navigation page 우선 탐색
- `todo`, `known_links`를 외부에서 주입해 단계별 crawl 가능
- 언어 필터 가능
주의:
- `URL_STORE`가 모듈 전역이다. 여러 crawl 작업을 동시에 실행하면 상태 충돌 위험이 있다.
- 플랫폼에서는 Trafilatura crawler를 그대로 병렬 호출하기보다, 작업별 프로세스 격리 또는 `courlan.UrlStore` 래핑이 필요하다.
## 10. 중복 제거와 fingerprint
파일: `trafilatura/deduplication.py`
기능:
- 세그먼트 중복 제거: `duplicate_test(element, options)`
- 문서 fingerprint: `content_fingerprint(content)`
- SimHash 비교: `Simhash.similarity()`
- 도메인 문자열 유사도: `is_similar_domain()`
- token sampling과 BLAKE2b hash
기능 명세:
| 기능명 | 입력 | 출력 | 용도 |
|---|---|---|---|
| `duplicate_test` | LXML element, Extractor/options | bool | 반복 boilerplate 제거 |
| `content_fingerprint` | 문자열 | hex SimHash | 문서 near-duplicate 키 |
| `Simhash.similarity` | 다른 Simhash | 0.0-1.0 | 유사 문서 판정 |
| `generate_bow_hash` | 문자열 | bytes | bag-of-words hash |
설정:
- `MIN_DUPLCHECK_SIZE = 100`
- `MAX_REPETITIONS = 2`
- 전역 LRU cache 크기: `LRU_SIZE = 4096`
플랫폼 적용:
- 추출 중 `deduplicate=True`는 페이지 내부 반복 요소 제거에 유용하다.
- 문서 단위 중복 제거는 `content_fingerprint(title + raw_text)`를 저장하고, 플랫폼 DB에서 유사도/중복 정책을 별도로 운영하는 것이 좋다.
- 전역 `LRU_TEST`는 긴 배치 작업에서 도메인 간 영향을 줄 수 있으므로 작업 단위로 `trafilatura.meta.reset_caches()` 호출을 고려한다.
## 11. HTML 처리와 구조 보존
파일: `trafilatura/htmlprocessing.py`, `trafilatura/main_extractor.py`, `trafilatura/xml.py`
보존 가능한 구조:
- 문단: `p`
- 제목: `head`
- 목록: `list`, `item`
- 인용: `quote`
- 코드: `code`
- 줄바꿈: `lb`
- 삭제/변경: `del`
- 강조/서식: `hi`
- 링크: `ref target="..."`
- 이미지: `graphic`
- 표: `table`, `row`, `cell`
온톨로지 플랫폼 관점에서는 `Document.body` XML tree가 중요하다.
활용 예:
- 제목/소제목을 문서 chunk hierarchy로 사용
- 목록 항목을 독립 주장 후보로 분해
- 표를 entity-attribute 후보로 변환
- 링크를 외부 참조 관계로 저장
- 이미지 alt/title을 보조 설명 텍스트로 저장
- 코드 블록은 일반 자연어 추출 대상에서 제외하거나 별도 타입으로 저장
## 12. 설정 명세
파일: `trafilatura/settings.cfg`
플랫폼 기본 권장값:
| 목적 | 설정/인자 | 권장 |
|---|---|---|
| 고품질 본문 추출 | `fast=False` | 기본 |
| 대량 수집 속도 | `fast=True` | 낮은 priority batch |
| 온톨로지 입력 | `output_format="python"` | 기본 |
| 구조 보존 | `include_formatting=True`, `include_links=True` | 권장 |
| 댓글 제외 | `include_comments=False` | 기본 권장 |
| 표 포함 | `include_tables=True` | 권장 |
| 이미지 후보 | `include_images=True` | 필요 시 |
| 언어 필터 | `target_language="ko"` 등 | 소스 도메인별 설정 |
| URL blacklisting | `url_blacklist` | 플랫폼 정책 DB와 연동 |
| 저자 제외 | `author_blacklist` | “편집부”, “관리자” 등 제거 |
| 날짜 strictness | `date_extraction_params` | max_date 고정 |
`settings.cfg`에서 조정할 값:
| 키 | 의미 |
|---|---|
| `DOWNLOAD_TIMEOUT` | 다운로드 제한 시간 |
| `MAX_FILE_SIZE` | 입력 최대 크기 |
| `MIN_FILE_SIZE` | 입력 최소 크기 |
| `SLEEP_TIME` | 동일 도메인 요청 간격 |
| `MAX_REDIRECTS` | redirect 횟수 |
| `MIN_EXTRACTED_SIZE` | fallback 발동 기준 본문 길이 |
| `MIN_OUTPUT_SIZE` | 최종 본문 최소 길이 |
| `EXTRACTION_TIMEOUT` | CLI 추출 timeout |
| `MIN_DUPLCHECK_SIZE` | 중복 검사 최소 길이 |
| `MAX_REPETITIONS` | 허용 반복 횟수 |
| `EXTENSIVE_DATE_SEARCH` | 날짜 탐색 범위 |
| `EXTERNAL_URLS` | feed/sitemap 외부 URL 허용 |
## 13. 범용 온톨로지 구축 플랫폼 통합 설계
### 13.1 권장 파이프라인
```text
Seed URL
-> Feed/Sitemap/Crawler URL discovery
-> URL normalization/dedup
-> Download raw HTML
-> Trafilatura bare_extraction
-> Document metadata/provenance 저장
-> 구조 유지 chunking
-> 언어/품질/중복 필터
-> 엔티티/관계/속성 후보 추출
-> ontology schema mapping
-> graph/vector/document store 적재
```
### 13.2 Trafilatura 채택 범위
거의 그대로 사용 권장:
- `core.py``extract`, `bare_extraction`, `extract_with_metadata`
- `metadata.py`의 메타데이터 추출
- `downloads.py`의 단일 다운로드 및 Response 모델
- `feeds.py`의 feed discovery
- `sitemaps.py`의 sitemap discovery
- `deduplication.py``content_fingerprint`, `Simhash`
- `xml.py`의 출력 변환
- `settings.py``Extractor`, `Document`
래퍼 필요:
- `spider.py`: 전역 `URL_STORE` 때문에 작업별 격리 필요
- `downloads.py`: 전역 HTTP pool과 user-agent/cookie 정책 관리 필요
- `deduplication.py`: 전역 LRU cache 초기화 정책 필요
- CLI 계층: 플랫폼 내부에서는 직접 CLI보다 Python API 사용 권장
수정 또는 확장 후보:
- 한국어/다국어 품질 점수 산정
- ontology chunk id/provenance 부여
- 표를 relation candidate로 변환하는 후처리
- link target을 source graph edge로 변환
- source별 extraction profile 관리
- 실패 사유와 추출 품질 metrics 기록
### 13.3 플랫폼 내 모듈 제안
| 플랫폼 모듈 | Trafilatura 연결 |
|---|---|
| `SourceDiscoveryService` | `find_feed_urls`, `sitemap_search`, `focused_crawler` |
| `PageFetchService` | `fetch_response` |
| `ContentExtractionService` | `bare_extraction` |
| `MetadataNormalizer` | `Document` 필드 정규화 |
| `DocumentChunker` | `Document.body` XML tree 기반 |
| `QualityScorer` | 본문 길이, 언어, 메타 completeness, 중복 여부 |
| `ProvenanceStore` | URL, hostname, date, fingerprint, raw HTML path |
| `OntologyCandidateBuilder` | title/head/list/table/ref/tag 기반 candidate 생성 |
## 14. 정확한 기능 명세
### F-001 웹 페이지 다운로드
- 입력: URL, SSL 옵션, config/options
- 처리: HTTP GET, redirect 제한, timeout, 크기 제한, charset decode
- 출력: HTML 문자열 또는 `Response`
- 예외/실패: non-200, 크기 미달/초과, SSL/네트워크 오류
- 수용 기준: 성공 시 최종 URL과 status를 기록할 수 있어야 한다.
### F-002 HTML 파싱
- 입력: HTML string/bytes/LXML element
- 처리: 압축 파일 처리, encoding detect, faulty HTML repair, LXML tree 생성
- 출력: `HtmlElement`
- 실패: 빈 입력, 파싱 불가
- 수용 기준: 문자열과 이미 파싱된 LXML tree 모두 동일 추출 파이프라인에 들어갈 수 있어야 한다.
### F-003 본문 추출
- 입력: HTML tree, `Extractor`
- 처리: cleanup, tag conversion, main extractor, fallback 비교, baseline rescue
- 출력: `Document.body`, `Document.text`, `Document.raw_text`
- 실패: 본문 최소 길이 미달, 언어 불일치, 중복 폐기
- 수용 기준: `favor_precision`, `favor_recall`, `fast` 옵션에 따라 결과가 조정되어야 한다.
### F-004 댓글 추출
- 입력: HTML tree, `include_comments`
- 처리: 댓글 XPath 후보 추출 후 본문 tree에서 제거
- 출력: `Document.comments`, `Document.commentsbody`
- 실패: 댓글 길이 미달이면 빈 댓글로 처리
- 수용 기준: 댓글 포함 여부를 소스/도메인별로 설정할 수 있어야 한다.
### F-005 표 추출
- 입력: HTML `<table>`, `include_tables`
- 처리: row/cell 구조 변환, header cell role 지정, colspan span 계산
- 출력: XML tree의 `table/row/cell`
- 실패: table 옵션 off이면 제외
- 수용 기준: ontology relation 후보 생성 단계에서 행/열 구조를 읽을 수 있어야 한다.
### F-006 링크/이미지 보존
- 입력: HTML anchor/img, base URL
- 처리: 상대 URL 절대화, 내부 `ref`/`graphic` 태그 변환
- 출력: XML tree 내 `target`, image attribute
- 실패: 옵션 off이면 텍스트만 남거나 제거
- 수용 기준: source graph edge와 media evidence로 저장 가능해야 한다.
### F-007 메타데이터 추출
- 입력: HTML tree, 입력 URL, date params, blacklist
- 처리: OpenGraph, Twitter, meta, JSON-LD, canonical, heading, htmldate
- 출력: `Document` metadata fields
- 실패: 후보 없음 시 None
- 수용 기준: `only_with_metadata=True`에서 `date/title/url` 필수 조건을 적용해야 한다.
### F-008 언어 필터
- 입력: HTML lang 또는 추출 텍스트, target language
- 처리: HTML lang quick check 또는 `py3langid` 판별
- 출력: pass/fail, `Document.language`
- 실패: target 불일치 시 문서 폐기
- 수용 기준: 언어 판별 패키지가 없을 때는 HTML lang 기반 검사로 degrade해야 한다.
### F-009 Feed URL 발견
- 입력: 홈페이지/feed URL, target_lang, external
- 처리: feed 직접 파싱, HTML feed link discovery, Google News fallback
- 출력: 기사 URL 목록
- 실패: 다운로드 실패, feed 없음
- 수용 기준: 중복 제거와 도메인 유사도 필터가 적용되어야 한다.
### F-010 Sitemap URL 발견
- 입력: 홈페이지/sitemap URL, target_lang, external, max_sitemaps
- 처리: robots.txt sitemap, sitemap guess, nested sitemap, XML/TXT parsing, hreflang
- 출력: 페이지 URL 목록
- 실패: base URL unreachable, invalid sitemap
- 수용 기준: sitemap index가 깊어도 `max_sitemaps` 제한을 지켜야 한다.
### F-011 Focused crawling
- 입력: homepage, max_seen_urls, max_known_urls, todo, known_links, lang
- 처리: robots.txt, crawl delay, navigation URL 우선순위, URL store update
- 출력: 다음 방문 URL 목록, 알려진 URL 목록
- 실패: 시작 URL invalid, frontier 고갈
- 수용 기준: 작업 재개를 위해 `todo`, `known_links`를 저장/재주입할 수 있어야 한다.
### F-012 중복 제거
- 입력: XML element 또는 문서 텍스트
- 처리: LRU exact segment count, SimHash fingerprint
- 출력: duplicate bool 또는 fingerprint
- 실패: 짧은 텍스트는 중복 검사 bypass
- 수용 기준: 문서 fingerprint가 DB unique/near-duplicate 정책과 연결되어야 한다.
### F-013 출력 변환
- 입력: `Document`, `Extractor.format`
- 처리: XML cleanup, JSON/CSV/HTML/TXT/Markdown/XML/TEI 변환
- 출력: 문자열
- 실패: unsupported format이면 AttributeError/ValueError
- 수용 기준: 동일 문서에서 최소 TXT, JSON, XML 출력을 생성할 수 있어야 한다.
### F-014 설정 관리
- 입력: `settings.cfg`, `Extractor`, 함수 인자
- 처리: config parse, 옵션 병합
- 출력: 실행 시 옵션 객체
- 실패: config 파일 없음, 필수 key 없음
- 수용 기준: 플랫폼 source profile에서 추출 설정을 생성할 수 있어야 한다.
### F-015 cache reset
- 입력: 없음
- 처리: module-level cache clear
- 출력: 없음
- 실패: 없음
- 수용 기준: 장시간 batch 또는 tenant 전환 시 cache를 초기화할 수 있어야 한다.
## 15. 품질 및 테스트 자산
테스트 구성:
- `tests/unit_tests.py`: 기본 추출/유틸 단위 테스트
- `tests/metadata_tests.py`: 메타데이터 추출
- `tests/json_metadata_tests.py`: JSON-LD 메타
- `tests/downloads_tests.py`: 다운로드
- `tests/feeds_tests.py`: feed
- `tests/sitemaps_tests.py`: sitemap
- `tests/spider_tests.py`: crawler
- `tests/deduplication_tests.py`: 중복 제거
- `tests/xml_tei_tests.py`: XML/TEI
- `tests/eval/`, `tests/cache/`: 실제 웹 페이지 평가 corpus
플랫폼 통합 테스트로 추가해야 할 것:
- 한국어 뉴스/블로그/쇼핑/위키/공공기관 샘플
- JS-heavy 사이트에서 raw HTML 한계 확인
- HTML table -> relation candidate 변환 테스트
- `bare_extraction` 결과의 provenance field completeness 테스트
- 동일 URL/동일 본문/near duplicate 처리 테스트
- source profile별 precision/recall 옵션 비교 테스트
## 16. 위험 요소와 대응
| 위험 | 설명 | 대응 |
|---|---|---|
| JS 렌더링 미지원 | 정적 HTML 기반 추출 | Playwright/Crawl4AI 등으로 렌더링 후 HTML을 Trafilatura에 입력 |
| 전역 상태 | HTTP pool, URL_STORE, LRU cache | 작업 단위 프로세스 격리 또는 reset |
| 사이트별 메타 노이즈 | tags/category/author가 부정확할 수 있음 | confidence와 source별 rule 적용 |
| 언어 판별 선택 의존성 | `py3langid` 없으면 제한적 | optional dependency 설치 또는 별도 언어 판별기 연결 |
| 표/이미지 실험적 옵션 | 모든 출력 형식에서 완전 보존되지 않음 | `output_format="python"` 또는 XML tree 직접 사용 |
| robots/정책 준수 | downloader 직접 사용 시 정책 책임 필요 | 플랫폼 crawler policy layer에서 관리 |
| 날짜 추출 recall/precision | `EXTENSIVE_DATE_SEARCH`에 따라 오탐 가능 | source별 date extraction profile 운영 |
## 17. 구현 권장 래퍼 인터페이스
```python
from dataclasses import dataclass
from typing import Optional
from trafilatura import bare_extraction
from trafilatura.settings import Extractor
@dataclass
class ExtractedWebDocument:
url: str
title: Optional[str]
author: Optional[str]
date: Optional[str]
sitename: Optional[str]
description: Optional[str]
text: str
body_xml: object
metadata: dict
fingerprint: Optional[str]
def extract_for_ontology(html: str, url: str, lang: Optional[str] = None) -> Optional[ExtractedWebDocument]:
options = Extractor(
output_format="python",
url=url,
with_metadata=True,
comments=False,
tables=True,
formatting=True,
links=True,
images=True,
dedup=True,
lang=lang,
)
doc = bare_extraction(html, options=options)
if not doc or not doc.text:
return None
return ExtractedWebDocument(
url=doc.url or url,
title=doc.title,
author=doc.author,
date=doc.date,
sitename=doc.sitename,
description=doc.description,
text=doc.text,
body_xml=doc.body,
metadata=doc.as_dict(),
fingerprint=doc.fingerprint,
)
```
## 18. 채택 우선순위
1. `bare_extraction()` 기반 ContentExtractionService 구현
2. `Document` metadata를 프로젝트 DB schema에 매핑
3. `Document.body` XML tree 기반 chunker 구현
4. `content_fingerprint()` 기반 중복 문서 정책 추가
5. `sitemap_search()``find_feed_urls()`를 source discovery에 연결
6. 필요한 경우 `focused_crawler()`는 전역 상태 격리 후 채택
7. JS rendering 결과 HTML을 Trafilatura에 넣는 hybrid extractor 구성
## 19. 최종 판단
Trafilatura는 범용 온톨로지 구축 플랫폼에서 “웹 문서를 ontology-ready document로 정제하는 핵심 엔진”으로 채택할 가치가 높다. 본문 추출 알고리즘, 메타데이터 추출, 링크 발견, 중복 제거, 구조 출력이 이미 모듈화되어 있으며 Apache-2.0 라이선스라 기본 소스 활용에도 적합하다.
가장 좋은 통합 방향은 원본 코드를 크게 변형하지 않고, 플랫폼 내부에 얇은 adapter layer를 두는 것이다. Adapter layer는 source profile, 작업 격리, provenance 저장, 품질 점수, 온톨로지 후보 생성만 담당하고 Trafilatura의 본문/메타/URL 발견 로직은 원형에 가깝게 유지하는 편이 안정적이다.