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.ts 에 65 카테고리 정의 (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}.tmp → rename(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 —
.gitignore→data/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,337 | 001706-*.json |
| 상법 | 1,308 | 001702-*.json |
| 민사소송법 | 563 | 001700-*.json |
| 민사집행법 | 331 | 009290-*.json |
| 이자제한법 | 8 | 010404-*.json |
| 주택임대차보호법 | 42 | 001248-*.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 신규 판례·법령 개정)