Korean Legal RAG · System Design
Solo Design & Implementation · 2025–2026

한국 법령·판례 데이터로 답변하는
신뢰 가능한 RAG 시스템 설계

국가법령정보 공동활용 API 기반의 법령·행정규칙·판례를 인덱싱하고, hybrid retrieval + multi-chain document review + 안전 배포 파이프라인으로 모델 환각(hallucination)과 도메인 편향을 줄이는 데 집중한 시스템. 백엔드부터 인프라까지 전 영역을 단독으로 설계·구현.

Python · FastAPI SQLite + FTS5 Vector Index (Gemini Embedding) Google Gemini API Cloud Run · Cloud Build · GCS Next.js (Frontend, 별도 배포)
역할 단독 설계·구현 (백엔드, RAG 파이프라인, 인프라, CI/CD) 기간 진행중 도메인 한국 법령·판례 Q&A 및 문서 검토
3 corpora
법령 · 행정규칙 · 판례 통합 인덱싱
Hybrid 3-way
Lexical(FTS5) + Vector + Exact 결합
5-chain parallel
문서 검토 다중 관점 병렬 호출
No-traffic deploy
smoke 검증 후 100% 트래픽 전환
01 · ARCHITECTURE

시스템 한눈에

클라이언트 → API 게이트웨이 → RAG 코어 → 저장소·외부 API. 데이터 수집·인덱싱은 운영 트래픽과 분리된 배치 잡으로 운용해, 학습/임베딩이 응답 지연에 영향을 주지 않게 함.

overview.mmd 도메인: 한국 법령 RAG
다이어그램 렌더 중…
Problem

법령·판례는 도메인 어휘가 무겁고 인용·근거가 핵심이라 범용 LLM만으로는 환각·근거 불일치가 잦음. 동시에 신뢰성을 위해 인용 검증 가능한 컨텍스트가 필요.

Approach

세 단계 분리:

  • Retrieval Core — 의도 분석·키워드 확장·hybrid 검색을 한 서비스에 캡슐화
  • Answering / Review — 검색 결과를 컨텍스트로 받아 구조화 응답
  • Data Pipeline — 수집/임베딩/인덱싱을 운영과 분리된 배치로

Trade-off

서비스 분리로 호출 hop이 늘어나 latency가 약간 증가. 대신 각 단계가 독립 캐시·재시도·관측 가능 — 장애 격리점진 개선이 쉬워짐.

Outcome

검색 품질·답변 품질·배포 안전을 각각 따로 측정·개선할 수 있는 구조. 한 영역의 회귀가 다른 영역으로 번지지 않음.

02 · RETRIEVAL

Hybrid Retrieval — 정확도와 다양성을 동시에

법령 조문 정확도("제N조"는 정규식이 가장 강하다)와 의도 유사도(벡터 검색)를 따로 다루지 않고 하나의 파이프라인에 묶음. 코퍼스 분포 편향 보정까지 마지막 단계로 포함.

retrieval.mmd 3-way Hybrid · Quota-aware
다이어그램 렌더 중…
Problem

(1) 벡터 검색만으로는 "제15조의2" 같은 식별 표현을 못 잡음. (2) lexical-only는 paraphrase에 약함. (3) 인덱스의 대부분이 법령(statute)이라 행정규칙·자율규약이 top-k에서 항상 밀림.

Approach

  • 3-way 동시 검색: exact(정규식) + lexical(FTS5) + vector를 ThreadPool로 병렬 실행
  • 의도 추출 + 키워드 확장을 LLM으로 동시에 돌려 2차 lexical/vector 재검색
  • 결과는 ID 기준 머지, 점수 정렬 후 코퍼스별 minimum quota로 다양성 보정

Trade-off

LLM 호출이 retrieval 안에 들어가 비용·지연 증가. 대신 잘못된 청크가 LLM에 흘러들어가 답을 망치는 비용이 훨씬 크다고 판단 — 검색 단계에서 끊는 게 낫다.

Outcome

소수 코퍼스(행정규칙·자율규약)가 항상 컨텍스트에 포함되어, 다층 규범이 필요한 질문에서 답변 정합성 향상. 식별 표현이 들어간 질문은 exact가 안정적으로 잡아주므로 vector 가중을 무리하게 올리지 않아도 됨.

03 · DOCUMENT REVIEW

Multi-Chain Review — 단일 호출의 한계를 분해

계약서·약관 검토는 단일 프롬프트 한 번으로 처리하면 길이·관점이 한쪽으로 쏠림. 관점을 분해해 병렬 호출하고, 마지막에 병합·정규화하는 방식으로 빠르고 균형 잡힌 결과를 만든다.

review.mmd 5-chain · ThreadPool 병렬
다이어그램 렌더 중…
Problem

장문 문서에 대한 단일 프롬프트 검토는 (1) 컨텍스트 토큰 한계로 누락이 생기고, (2) "리스크/목적/제도" 중 한 관점만 부각되며, (3) 사용자가 기다리는 동안 응답 지연이 길어짐.

Approach

  • 스캔 → 관점 분해: 조항 파싱 후, 제도 / 목적 / 위험 / 판단 4관점을 병렬로 호출
  • 관점별 RAG: 각 관점의 lookup 쿼리로 별도 청크 보강 (한 컨텍스트에 다 못 담는 문제 해결)
  • 통합 호출 안전망: 병렬 결과 누락 시 종합 호출이 fallback
  • 출력 스키마 정규화: 관찰 / 미흡 / 외부고려 / 판단 4섹션으로 통일

Trade-off

LLM 호출 수가 늘어 비용 증가. 다만 병렬 실행으로 wall-clock은 단일 호출과 비슷하게 유지. 병합 단계 복잡도가 증가하지만, 그 대가로 결과가 사용자 검토 가능한 형태로 일관됨.

Outcome

검토 누락이 줄어들고, 각 관점이 항상 보장됨. 추가로 다중 파일 검토는 별도 오케스트레이터로 분기해 확장.

04 · SAFE ROLLOUT

데이터·인덱스 변경을 안전하게 배포하기

RAG 시스템에서 가장 위험한 변경은 인덱스 갱신. 임베딩 모델·청킹 정책·코퍼스 추가가 동시에 일어나면 한 번의 잘못된 배포가 답변 품질을 크게 떨어뜨림. 그래서 롤백 가능한 단계 배포를 인프라 수준에서 강제.

rollout.mmd No-traffic deploy · Smoke gate
다이어그램 렌더 중…
Problem

(1) 인덱스 빌드 실패가 운영 트래픽을 멈추면 안 됨. (2) 임베딩이 일부 깨졌어도 200이 떨어지면 알아채기 어려움. (3) 환경변수 변경이 트래픽에 잘못 반영되는 흔한 함정.

Approach

  • 운영 ↔ 빌드 분리: 수집/임베딩은 Cloud Run Job, 운영은 Cloud Run Service
  • DB 백업 → ingest → 새 이미지 → no-traffic 배포 순으로 실패 시 즉시 롤백 가능
  • Smoke gate: 새 리비전이 실제 답변 3건을 통과해야 100% 트래픽 전환
  • 스냅샷 백업 자동화: 매 배포 시 직전 DB를 별도 버킷에 보존

Trade-off

배포 단계가 길어져 turnaround가 늘어남. 대신 잘못된 인덱스가 사용자에게 노출되는 사고가 구조적으로 차단됨 — RAG에서는 이 쪽이 비교 불가하게 중요.

Outcome

인덱스를 자주, 부담 없이 갱신할 수 있게 됨. 새로운 코퍼스 추가나 청킹 정책 실험이 운영 리스크 없이 가능.

05 · WHAT I LEARNED

이 시스템을 만들며 배운 것

RAG는 "검색 + LLM"이라는 단순한 슬로건과 달리, 운영 가능한 검색 품질을 만드는 게 본질이라는 걸 체감. 도메인 특성과 인프라 제약 사이에서 트레이드오프를 결정하는 일이 많았다.

검색은 다층화한다

한 가지 검색 방식이 모든 질문 타입을 잘 풀어주지 않는다. 식별 표현·자연어·도메인 어휘는 서로 다른 검색기를 요구한다. 하나의 검색 서비스에 묶되 내부에서 분기하는 게 운영하기 좋다.

편향은 점수 정렬 다음에 잡는다

코퍼스 분포가 비대칭이면 score-only top-k가 항상 다수 코퍼스를 뽑는다. "코퍼스별 최소 보장" 같은 단순한 후처리가 가장 효과적이었다.

긴 호출은 분해해서 병렬화한다

단일 호출의 한계를 피하려면 관점을 분해하고, 마지막에 병합 + 안전망 통합 호출을 둔다. wall-clock은 비슷하면서도 누락이 크게 줄어든다.

RAG 배포는 DB 배포에 가깝다

코드만 바꾸는 게 아니라 인덱스가 바뀐다. 백업·검증·트래픽 분리가 없으면 한 번의 실수가 답변 품질 회귀로 이어진다. CI/CD를 RAG에 맞게 다시 설계할 필요가 있었다.

관찰 가능성이 결국 품질을 만든다

인용이 실제 청크에 존재하는지, top-k 분포가 어떤지, 어떤 질문에서 fallback이 발동하는지 —지표를 코드에 박아두는 것이 막연한 "프롬프트 튜닝"보다 빨랐다.

스키마 정규화가 UX의 절반

LLM 출력은 매번 미묘하게 다른 모양으로 나온다. 응답 후처리에서 강한 스키마와 폴백을 두는 게, 프롬프트만 다듬는 것보다 안정적인 클라이언트 경험을 만든다.