본문으로 건너뛰기

Platform RAG 대량 수집 운영 가이드

ADR 0021 Platform RAG 의 판례 데이터를 법제처 OPEN API 에서 대량 수집·로컬 검증·Firestore 적재하는 절차. 운영 데이터 꼬임을 방지하기 위해 2 단계 분리 설계를 사용한다.

왜 로컬 스크립트인가

Cloud Function 은 timeout (최대 540초) · 동적 outbound IP · 런타임 파일시스템 read-only 등 제약으로 대량 수집에 부적합:

  • 수천~수만 건 수집은 Cloud Function 한 번으로 불가
  • 실패 시 재시도·진행 상태 저장 복잡
  • 운영 Firestore 에 쓰레기 데이터 직접 흘러갈 위험

로컬 스크립트는 시간 제한 없고, 파일시스템에 원본을 보존하며, 검증을 거친 후에만 Firestore 로 이관하므로 안전.

전체 파이프라인

┌──────────────────────┐
│ 1. 로컬 다운로드 │ scripts/download-law-go-kr-bulk.ts
│ 법제처 API → JSON 파일 │ data/public-rag-raw/by-case/{id}.json
└──────────┬───────────┘

┌──────────────────────┐
│ 2. 로컬 검증 │ scripts/verify-downloaded-data.ts
│ 품질 기준 만족 여부 │ 파싱 성공률 · 필수 필드 · 인코딩
└──────────┬───────────┘
↓ (품질 통과 시)
┌──────────────────────┐
│ 3. Firestore 업로드 │ (후속 PR — 미구현)
│ publicDocumentsRaw + │ scripts/upload-public-raw-to-firestore.ts
│ publicDocuments │
└──────────┬───────────┘
↓ (자동)
┌──────────────────────┐
│ 4. 임베딩 생성 │ Cloud Function onPublicDocumentCreated
│ Vertex AI 768-dim │ publicDocuments.embedding.vector
└──────────────────────┘

로컬 저장 구조

data/public-rag-raw/ (gitignore — 커밋 금지)
├── _catalog.json 카테고리별 판례 id 매핑
├── _progress/ 카테고리별 진행 상태 (재개용)
│ └── debt-query-lending.json
├── _errors/ 실패·이슈 로그
│ ├── parse-failures.jsonl
│ ├── empty-bodies.jsonl
│ └── verify-2026-04-24.jsonl
├── _logs/ 일별 실행 로그
│ └── 2026-04-24.log
└── by-case/ 판례 원본 JSON (판례일련번호 고유 키)
├── 618179.json
├── 618180.json
└── ...

플랫 구조 이유: 동일 판례가 여러 카테고리 (대여금 + 민법 §162 등) 에 매칭되어도 파일은 1건만 저장. _catalog.json 에서 카테고리별 id 목록만 관리.

카테고리 매니페스트

scripts/law-go-kr-categories.ts65 카테고리 정의 (core 다수 + extra). 각 카테고리는 법제처 API 의 query · JO (참조조문) · curt (법원) · org (법원종류) 필터 조합 + domain 분류 메타.

도메인 분류 (Phase C, 2026-05-19 확장)

/library AI 채팅의 system prompt 라우팅·예시 칩 그룹핑에 사용.

domain영역핵심 카테고리
civil-debt민사 채권 회수대여금·구상금·약정금·양수금·임대차보증금·소멸시효
civil-tort불법행위·손배민법 §750·§766
civil-exec집행·보전민사집행법 §229·§231·§276·지급명령
construction건설·도급공사대금·민법 §664·§665
criminal형사 (재산범죄)형법 §355·§356·§357·§359·§347·배임·횡령·임무위배·경업금지·상법 §397·§382조의3
family가사민법 §840·§839조의2·§837·§843·이혼·재산분할
real-estate부동산민법 §186·§187·§245·명의신탁·부동산실명법
inheritance상속민법 §1000·§1009·§1019·§1112·§1115
contract계약민법 §390·§544·§546·§548·§103·§109·§110

초기 시드는 core 만 실행 권장 (예상 ~30,000건 · ~390MB · 80분). extra 까지 포함하면 ~36,000건 · ~470MB · 100분.

도메인 단위 수집 (신규)

특정 영역만 우선 채울 때는 단일 카테고리를 순차 실행. 예시 — 형사 영역 배임/횡령 시드:

for cat in criminal-statute-355 criminal-statute-356 criminal-statute-357 \
criminal-statute-359 criminal-query-breach-of-trust \
criminal-query-embezzlement criminal-query-non-compete \
criminal-commercial-397 criminal-commercial-382-3; do
npx tsx scripts/download-law-go-kr-bulk.ts --category=$cat
done

또는 가사·부동산·상속·계약 영역 시드는 같은 패턴 (id prefix family-, realestate-, inheritance-, contract-).

실행 절차

전제

# 환경변수 설정 (shell 세션 내)
export LAW_GO_KR_OC=neohollopro

단계 0 — Dry-run (API 계획만 확인)

실제 대량 수집 전 각 카테고리의 totalCnt · 예상 용량·시간 파악.

npx tsx scripts/download-law-go-kr-bulk.ts --dry-run

단계 1 — Sample (카테고리 1개 · 10건)

가장 먼저 적은 샘플로 API 동작·JSON 포맷·로컬 저장 검증.

npx tsx scripts/download-law-go-kr-bulk.ts \
--category=debt-query-lending \
--limit=10

data/public-rag-raw/by-case/*.json 파일 10개를 수동 검토 — 판시사항·판결요지 전문이 포함됐는지, 인코딩이 정상인지 육안 확인.

단계 2 — Category 1개 full

npx tsx scripts/download-law-go-kr-bulk.ts --category=debt-query-lending
  • 해당 카테고리 전부 (예: ~1,000건) 다운로드
  • 5~10분 소요
  • _progress/debt-query-lending.json 에 상태 기록
  • 중단돼도 --resume 으로 재개

단계 3 — Core 카테고리 전체

npx tsx scripts/download-law-go-kr-bulk.ts --core
  • core 카테고리 전부 순차 실행 (Pack 1 민사 채권 + 형사/가사/부동산/상속/계약 확장)
  • 약 60~90분
  • 로그는 data/public-rag-raw/_logs/{date}.log

단계 4 — 검증

npx tsx scripts/verify-downloaded-data.ts

요약 리포트 출력:

[verify] 완료 · 17,845 파일 · 228.4 MB
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
파싱 성공률 : 99.9%
파싱 실패 : 12
사건번호 누락 : 0
선고일자 누락 : 3
법원명 누락 : 8
본문 (판시/요지/내용) 부족: 421
사건번호 중복 : 0
인코딩 의심 : 2
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ 품질 기준 통과 — Firestore 업로드 가능

품질 기준:

  • 파싱 성공률 ≥ 99%
  • 사건번호 누락 0건 · 중복 0건
  • 본문 부족 ≤ 5% (목록 API 만 응답한 케이스)

안전장치 · 재시도 정책

지수 백오프

fetchWithRetry 가 실패 시 자동 재시도:

시도대기
1차즉시
2차1s
3차5s
4차30s

4회 실패 시 해당 항목 skip, 다음 진행. 3연속 인증 에러면 카테고리 중단.

진행 상태 영속화

  • 매 10건마다 _progress/{categoryId}.json 플러시
  • 프로세스 kill 시 최악 10건 재수집
  • --resume 으로 정확한 페이지·인덱스부터 재개

원자 쓰기

모든 파일은 {path}.tmprename(path) 2단계로 원자적. 쓰기 도중 프로세스 종료돼도 부분 파일 남지 않음.

인증 에러 조기 감지

응답 body 에 사용자 정보 검증 · 필수입력요소 문자열 포함 시 파싱 안 함. 카테고리 내 3연속 발생하면 즉시 중단 — OC 키 문제 가능성 경고.

중단·재개 시나리오

상황명령
네트워크 끊김--resume 으로 재시작. _progress 가 중단 지점 복원
인증 에러 후 키 수정같은 명령 재실행. _progress 는 그대로 사용
카테고리 정의 변경해당 _progress/{id}.json 수동 삭제 → 새로 실행
파일시스템만 남고 진행 로그 유실by-case/ 에 파일 있으면 중복 다운로드 skip (by-case 존재 체크)

재해 복구

Firestore 데이터 유실 시

data/public-rag-raw/ 가 있다면 upload-public-raw-to-firestore.ts (후속) 로 재적재. 법제처 재호출 불필요.

로컬 데이터 유실 시

Firestore publicDocumentsRaw 가 있다면 별도 export 스크립트로 로컬 복원 가능. (양방향 동기화 가능)

운영 비용

  • 법제처 API: 무료 (공식)
  • 로컬 스토리지: Pack 1 초기 ~230MB · 전체 확장 시 ~1.3GB
  • 네트워크 (egress): 수십 MB 수준 · 무시
  • 실행 시간: core 18 카테고리 ~45분 (throttle 200ms)

관련 파일

판례 수집

  • 카테고리 정의 — scripts/law-go-kr-categories.ts
  • 다운로드 스크립트 — scripts/download-law-go-kr-bulk.ts
  • 검증 스크립트 — scripts/verify-downloaded-data.ts
  • Firestore 업로드 — scripts/upload-public-raw-to-firestore.ts
  • gitignore — .gitignoredata/public-rag-raw/

법령 수집 (Phase 2)

  • 법령 목록 — scripts/law-go-kr-statute-list.ts
  • 다운로드 스크립트 — scripts/download-law-go-kr-statutes.ts
  • 저장 경로 — data/public-rag-raw/by-statute/
  • 카탈로그 — data/public-rag-raw/_catalog-statutes.json

법령 수집 (Phase 2)

판례 외 법령 조문 도 별도 스크립트로 수집. 민법·상법·민사소송법·민사집행법· 이자제한법·주택임대차보호법 등 민사 채권 회수 실무 필수 법령을 조문 단위로 저장.

특징

  • 법령ID 직접 매핑 — 법제처 search=1 이 부분 매칭이라 부정확 (예: query="상법" → "특별조치법" 먼저 매칭). ID= 파라미터로 직접 조회가 가장 안정.
  • 조문 단위 플랫 저장by-statute/{lawId}-{articleNumber}.json (예: 001706-1.json = 민법 제1조)
  • 카탈로그 _catalog-statutes.json 에 법령 메타 기록

실행

# dry-run — 법령별 조문 개수 확인
LAW_GO_KR_OC=xxx npx tsx scripts/download-law-go-kr-statutes.ts --dry-run

# core 6 법령 (기본)
LAW_GO_KR_OC=xxx npx tsx scripts/download-law-go-kr-statutes.ts

# extra 포함 (+헌법·형법·형사소송법)
LAW_GO_KR_OC=xxx npx tsx scripts/download-law-go-kr-statutes.ts --all

# 단일 법령
LAW_GO_KR_OC=xxx npx tsx scripts/download-law-go-kr-statutes.ts --statute=civil-law

규모 (2026-04-24 실측)

법령조문 수파일 경로 prefix
민법1,337001706-*.json
상법1,308001702-*.json
민사소송법563001700-*.json
민사집행법331009290-*.json
이자제한법8010404-*.json
주택임대차보호법42001248-*.json
Core 6 합계3,589

예상 용량: 20MB (조문당 평균 56KB). 예상 시간: ~5분 (조문 개별 API 불필요, 법령 전체 응답 1회에 모든 조문 포함).

후속 작업

  • ✅ Phase 1 완료: 판례 로컬 다운로드 + Firestore 업로드
  • ✅ Phase 2 완료: 법령 조문 다운로드
  • ⚙️ 다음: 법령 조문 Firestore 업로드 경로 (publicDocuments sourceType="statute")
  • ⚙️ 다음: ops 콘솔 "법령 수집 현황" 대시보드
  • ⚙️ 다음: Cloud Scheduler 증분 수집 (매일 02:00 KST 신규 판례·법령 개정)