89 lines
4.5 KiB
Markdown
89 lines
4.5 KiB
Markdown
|
|
# 크롤링 처리 흐름 및 DB 미적재 이슈 리포트
|
||
|
|
|
||
|
|
작성일: 2026-05-11
|
||
|
|
대상 프로젝트: C:\Users\lasta\MyProject\AI
|
||
|
|
테스트 사이트: https://the912.co.kr/
|
||
|
|
|
||
|
|
## 1) 결론 요약
|
||
|
|
- 현재 구조는 `연결 테스트`와 `실제 크롤링/추출/저장`이 분리되어 있다.
|
||
|
|
- 연결 테스트(`GET /v1/models`)는 모델 목록 확인만 하므로 DB에 아무것도 저장되지 않는다.
|
||
|
|
- 사이트 크롤링 시에도 모든 페이지를 저장하지 않는다. 기본적으로 `product/brand/review` 타입만 추출/저장 대상이다.
|
||
|
|
- `listing`으로 분류된 페이지는 `discovered`로 끝나며 엔티티/클레임이 저장되지 않는다.
|
||
|
|
- LM Studio 응답 지연/타임아웃, 무효 JSON 응답, 중복 해시(upsert) 조건 때문에 “동작은 하는데 DB가 거의 안 쌓여 보이는” 현상이 발생한다.
|
||
|
|
|
||
|
|
## 2) 처음 연결 시 처리 주체
|
||
|
|
### 2-1. UI
|
||
|
|
- 프론트에서 Analyzer 테스트 버튼 실행 시 `/extractors/models` 호출.
|
||
|
|
- 파일: `crawler_platform/app/web/static/app.js`
|
||
|
|
|
||
|
|
### 2-2. API
|
||
|
|
- 백엔드는 provider별 모델 목록만 조회해서 반환.
|
||
|
|
- LM Studio는 OpenAI 호환 엔드포인트의 `/v1/models`만 호출됨.
|
||
|
|
- 파일: `crawler_platform/app/api/routes.py`
|
||
|
|
|
||
|
|
### 2-3. DB
|
||
|
|
- 이 단계는 크롤링/추출/저장이 아니므로 DB 적재 없음.
|
||
|
|
|
||
|
|
## 3) 실제 처리(크롤링) 흐름
|
||
|
|
### 3-1. 요청 진입
|
||
|
|
- `/crawl-site` 요청으로 `SiteCrawler` 인스턴스 생성 후 동기 처리.
|
||
|
|
- 파일: `crawler_platform/app/api/routes.py`
|
||
|
|
|
||
|
|
### 3-2. 페이지 처리 파이프라인
|
||
|
|
- queue 기반으로 URL 순회
|
||
|
|
- robots 검사
|
||
|
|
- fetch(requests/playwright)
|
||
|
|
- parse(clean_html)
|
||
|
|
- classify_page(product/review/brand/listing)
|
||
|
|
- 파일: `crawler_platform/app/core/crawler/site_crawler.py`
|
||
|
|
|
||
|
|
### 3-3. 추출기 선택 주체
|
||
|
|
- provider가 `lm_studio/openai/ollama`면 `LLMJsonExtractor` 사용
|
||
|
|
- 그 외 domain 기반 rule-based 사용
|
||
|
|
- 파일: `crawler_platform/app/core/extractor/factory.py`
|
||
|
|
|
||
|
|
### 3-4. 저장 주체
|
||
|
|
- `KnowledgeRepository.save_extraction_bundle()`에서 entities/claims/evidence/extraction_logs 저장
|
||
|
|
- page/entity/claim은 upsert/dedupe 규칙이 있어 신규 건수가 작을 수 있음
|
||
|
|
- 파일: `crawler_platform/app/core/database/repository.py`
|
||
|
|
|
||
|
|
## 4) “DB가 안 쌓이는 것처럼 보이는” 주요 원인
|
||
|
|
1. 분석 대상 제한
|
||
|
|
- 기본 분석 대상이 `product/brand/review`로 고정되어 있음.
|
||
|
|
- listing/네비게이션/정책 페이지는 저장 대상에서 제외됨.
|
||
|
|
|
||
|
|
2. 타임아웃/클라이언트 disconnect
|
||
|
|
- 로그에 `read timeout=300` 및 `Client disconnected` 패턴 확인.
|
||
|
|
- 모델 생성이 느리면 API 클라이언트가 먼저 끊기고, 해당 건은 실패/부분 처리될 수 있음.
|
||
|
|
|
||
|
|
3. AI 응답 품질 문제
|
||
|
|
- 일부 응답은 JSON 파손/무효 엔티티/무효 클레임으로 실질 저장 0건 발생.
|
||
|
|
|
||
|
|
4. 중복 제거 정책
|
||
|
|
- 동일 canonical entity, 동일 claim_hash는 업데이트로 처리되어 "신규 카운트"가 늘지 않음.
|
||
|
|
|
||
|
|
## 5) 적용된 안정화(현재 코드 기준)
|
||
|
|
`crawler_platform/app/core/extractor/ai_provider.py`에 다음이 반영됨:
|
||
|
|
- LM Studio 기본 타임아웃을 300s -> 120s로 조정
|
||
|
|
- 2단계 추출 시도(primary -> compact_retry)
|
||
|
|
- AI 결과 무효/오류 시 rule-based fallback 수행
|
||
|
|
- fallback 결과도 provider=`lm_studio`로 extraction_log에 남겨 추적 가능
|
||
|
|
- 프롬프트 노이즈 감소 및 입력 길이/출력 토큰 제한
|
||
|
|
|
||
|
|
## 6) 2건 timeout + 1건 no-usable 오류의 해석
|
||
|
|
- `read timeout=300`: 모델 응답이 늦어 클라이언트가 먼저 끊긴 건
|
||
|
|
- `AI returned no usable entities or claims`: 모델이 응답은 했지만 저장 가능한 구조를 만들지 못한 건
|
||
|
|
- 현재 구조에서는 fallback으로 정상 저장 가능하도록 보완되어야 하며, 해당 보완이 반영되어 있음
|
||
|
|
|
||
|
|
## 7) 운영 체크포인트
|
||
|
|
1. 처리량 확인은 `visited_count`가 아니라 `analyzed_count` 기준으로 본다.
|
||
|
|
2. 저장 확인은 entities/claims 증가 + extraction_logs(raw_output.extraction_mode)로 함께 본다.
|
||
|
|
3. listing 비중이 높은 사이트는 page_type 분류 규칙 또는 analyze_page_types 정책 재조정이 필요하다.
|
||
|
|
4. 동시 실행 테스트 시 SQLite lock 가능성이 있어 순차 테스트를 권장한다.
|
||
|
|
|
||
|
|
## 8) 다음 개선 권장
|
||
|
|
- 분류 규칙(classify_page) 한국어 토큰 정비(깨진 인코딩 토큰 정리 포함)
|
||
|
|
- 페이지 유형별 프롬프트 분기(상품/브랜드/리뷰)
|
||
|
|
- crawl_jobs 대시보드에 `failed/discovered/completed` 원인별 집계 표시
|
||
|
|
- timeout, fallback, no-usable 건수의 일별 지표화
|