검토 방식 상세

모든 단계를 투명하게 공개합니다.
의심해도 좋은 답을 만들기 위해서요.

UrbanLaw가 한 건의 검토를 만들기까지 어떤 데이터를 모으고, 어떻게 정리하고, 어떤 검색·검증 절차를 거치는지 전부 적어두었습니다. 신뢰는 결과만으로 만들 수 없다고 봅니다. 과정을 봐주세요.

01 / DATA

법령 DB는 78,237건 / 514개 법령·조례·고시로 구축됐습니다.

"AI가 제대로 알고 있나?"라는 질문의 시작은 결국 데이터입니다. 우리는 일반적인 LLM의 사전학습 지식을 신뢰하지 않고, 실제 법령 원문을 자체 DB에 적재한 뒤 그 안에서만 인용하도록 설계했습니다.

514
수록 법령·조례·고시
78,237
조문·별표 청크
25,154
판례 청크
2,786
판례 AI 요약

1법령 원문은 어디서 가져오는가

법제처의 공식 OpenAPI(law.go.kr, 정식 발급 인증키 사용)를 통해 원문을 직접 크롤링합니다. 가공·요약된 2차 자료가 아닌 법제처 정본입니다.

법령 본문 / 시행령 / 시행규칙법제처 OpenAPI · 조문 단위 수집 → data/rechunk_crawl_cache/ 저장
지자체 조례 (서울 + 경기 30개 시군 319개 + 하남시 14종 외)법제처 자치법규 API → 시군별 건축·도시계획·경관·주차 조례 자동 매칭
고시·행정규칙 (국토부 고시 12종)법제처 admrul API → 건축물의 에너지절약설계기준, BF 인증심사기준, 범죄예방 건축기준, 녹색건축 인증 기준 등 실무 고시 [위계:4 고시]로 수록
판례·행정심판례·법령해석례법제처 prec/detc/expc API → urbanlaw_precedents 컬렉션 (2024.3 ~ 현재)
지구단위계획·도시계획결정 (서울)UPIS(서울도시공간포털) ArcGIS REST · UPIS gpkg/SHP

2임베딩은 어떻게 만들어지는가

일반 RAG처럼 "원문을 그냥 임베딩"하지 않습니다. 검색 정확도를 위해 임베딩 텍스트를 3중으로 구성합니다.

┌─ 임베딩 입력 텍스트 ─────────────────────────┐
│ [법령명 | 장 | 절 | 조문제목]          ← prefix
│ LLM이 생성한 context_summary            ← 상위법 위임 관계만
│ 조문 원문 그대로                          ← original_text
└──────────────────────────────────────────────┘
모델: OpenAI text-embedding-3-large (3,072차원)
최대 길이: 6,000자 (EMBED_MAX_CHARS)

3맥락 요약(summary)은 환각 없이 만들었나

각 조문에 대해 Gemini Flash로 1~2문장 요약을 생성하지만, 환각을 막기 위해 다음 4개의 절대 규칙을 프롬프트에 박아넣었습니다.

SUMMARY 절대 규칙
  1. 원문에서 알 수 있는 내용은 쓰지 마라.
  2. 원문에 명시적으로 언급된 위임·준용 관계만 써라. 추론하지 마라.
  3. 원문에 상위법 참조가 없으면 "상위법 참조 없음"이라고 써라.
  4. '~를 규정한다' 같은 표현은 절대 쓰지 마라.

검증 결과 (2026-03-17): 무작위 10건 교차검증 → 할루시네이션 0건 확인.

4Parent–Child 청크 구조

5법령은 매주 자동으로 갱신됩니다

법은 계속 바뀝니다. 그래서 DB가 낡지 않도록 매주 일요일 새벽, OS 스케줄러(launchd)가 사람 손 없이 전체 수록 법령을 다시 점검합니다.

주간 갱신 파이프라인
  1. 법제처 API에서 수록 법령 500여 건의 원문을 재수집
  2. 법령일련번호(MST) 비교로 실제 개정된 법령만 선별 (해시만 다른 오탐은 제외)
  3. 변경분만 백업 후 재임베딩·재색인 — 나머지는 건드리지 않음
  4. 구버전은 삭제하지 않고 superseded로 보존 → 시행일·공포일과 함께 버전 이력으로 축적

덕분에 검색 결과의 조문에는 [시행 YYYY.MM.DD · 공포 YYYY.MM.DD] 버전 배지가 붙고, 어떤 버전 기준의 답인지 확인할 수 있습니다. 축적된 버전 이력은 「법규 변경 이력」 탭에서 조문 단위 비교까지 열람 가능합니다.

02 / LAND DATA

토지정보는 정부 공식 API에서 실시간으로 가져옵니다.

검토 대상지의 토지정보·규제·건축물대장은 우리가 미리 저장해둔 데이터가 아니라, 검토할 때마다 정부 OpenAPI를 호출해 그 시점의 최신 정보를 받아옵니다.

주소 → PNU 변환 VWorld 주소검색 (api.vworld.kr/req/search) — 도로명·지번 모두 지원
공시지가 / 토지특성 VWorld getLandCharacteristics · getLandUseAttr — 연도별 공시지가 시계열 포함
토지이용규제 (용도지역·지구·구역) VWorld 토지이용규제 API → 용도지역, 지구단위계획구역, 개발제한구역, 학교환경위생정화구역 등 직접 추출
건축물대장 국가건축물대장 OpenAPI (BLD_API_KEY) — 표제부·총괄표제부·층별 정보 (PNU 11번째 자리로 대지/산 자동 분기)
지구단위계획 상세 (서울) 서울시 공식 프록시(urban.seoul.go.kr/proxy) 경유 UPIS ArcGIS WFS · 도면번호·결정고시·특별계획구역까지 추출 (용도지역 폴리곤은 UPIS 저장 GeoJSON 1순위 → WFS fallback)
지구단위계획 (경기 외) UPIS gpkg + VWorld WFS lt_c_upisuq161 fallback (gpkg 미수록 지역용)

데이터 신뢰도 메모

04 / EXPERT PANEL

한 건당 최대 7명의 AI 전문가가 합의에 도달합니다.

단일 LLM 응답을 그대로 신뢰하지 않습니다. 역할이 다른 전문가 페르소나가 각자의 관점에서 따져보고, 반박 전문가가 반대 입장을 일부러 만들어 부딪치게 합니다.

법령적용 범위·위계
도시계획지구단위·용도지역
건축대지·일조·이격
조경면적·식재 기준
판례유사 사건·해석례
반박(devil)일부러 반대해석
판정(judge)종합 의견 합의

1기본 검토 (standard) — 공통 골격

  1. 법령 검색 (3-Layer)
  2. 판례·행정심판례·해석례 검색
  3. 전문가 분석 — 필지 조회: 5명 병렬(법령·도시계획·건축·조경·판례) / 일반 질문: 1차 답변 생성(Gemini + Google Search tool)
  4. Pass 2 보충 검색 — 답변에서 부족한 법령 식별 → 추가 검색 → 보강 답변
  5. 종합 판정(judge) — 전문가 의견을 하나의 결론으로 종합 (필지 조회)
  6. QA 검증 (Self-Critique)
  7. 교차검증 — 인용한 법령 조문을 다시 검색해 누락 확인
  8. 판례 인용 검증 — 판례번호를 ChromaDB에서 실제 존재 여부 확인

2심층 검토 (deep) — 기본 위에 추가

※ 이전의 고정 재귀 딥다이브(1~2회 반복 재작성)는 제거했습니다. 필지 분석은 이미 5전문가 + 쟁점토론 + 반박 + Pass2 스택으로 대체되어, 추가 반복은 중복·drift 위험이 있기 때문입니다. 일반 질문은 필요할 때만 조건부 심화가 붙습니다.

3기존 건물 실증 판정 규칙

"이미 준공된 건물이 서 있다"는 사실은 그 규모·용도가 한 번 인허가를 통과했다는 실증입니다. 판정이 근거 없이 보수적으로 흐르지 않도록, 건축물대장의 실현 데이터를 판정 규칙에 직접 반영합니다.

소스: core/agents.py · answer_parcel_analysis() · answer_general_question() · verify_precedent_citations() · core/agent_prompts.py

05 / VERIFY

최종 답변은 3중 검증을 통과해야 출력됩니다.

"법령 인용한 척"하는 LLM의 흔한 패턴을 막기 위해, 모델이 만든 답변에서 인용된 조문/판례를 거꾸로 우리 DB에 다시 조회합니다.

1QA Self-Critique

같은 모델에게 "이 답변에 누락이나 오류가 있다면?"이라고 다시 묻고, 빠진 쟁점이 있으면 보강 답변을 생성합니다.

2법령 교차검증

답변에서 인용한 법령·조문을 추출 → DB에서 다시 검색 → 누락된 조문이 있으면 자동 보강합니다.

3판례번호 실재 검증

verify_precedent_citations()가 답변 텍스트에서 사건번호 패턴(예: 2018두12345)을 추출 → ChromaDB urbanlaw_precedents 컬렉션에서 실제 존재 여부 조회.

+실증 모순 가드 (deterministic)

LLM을 거치지 않는 코드 레벨 가드도 하나 더 있습니다. 판정이 "불가"인데 그 필지에 준공된 건물이 등재돼 있으면, 결과 화면에 ⚠️ 경고 배너를 띄워 "판정 근거에 규제 강화 이력이 인용됐는지 확인"을 권장합니다. 판정을 코드가 뒤집지는 않되, 실증과의 모순을 사용자에게 그대로 보여줍니다.

왜 이렇게까지 합니까

법규 검토 영역에서 LLM이 가장 자주 틀리는 패턴이 조문 번호 환각판례 인용 환각입니다. 그래서 우리는 두 가지를 정한 뒤 출시했습니다 — (1) DB에 없는 법령은 인용하지 않는다, (2) 검증 결과는 답변 안에 그대로 노출한다. 깔끔한 답변보다 거짓을 줄인 답변이 우선이라고 봅니다.

10 / SINGLE PARCEL

단일 획지 검토는 "주소 한 줄"로 시작합니다.

가장 많이 쓰이는 검토 유형입니다. 주소 하나만으로 토지정보부터 법령·판례까지 한 번에 검토합니다.

처리 흐름

  1. 주소 입력 → POST /api/search-address (VWorld 주소검색)
  2. 후보 주소 선택 → POST /api/land-info (PNU 확정 + 데이터 수집)
    • VWorld getLandCharacteristics / getLandUseAttr → 공시지가·토지특성
    • VWorld 토지이용규제 → 용도지역·지구·구역 추출
    • 국가건축물대장 API → 표제부·총괄표제부
    • 서울이면 UPIS ArcGIS → 지구단위계획·도면번호
    • 비서울이면 SHP/VWorld WFS fallback
  3. 지도·기본정보·지구단위계획·건축물 정보 렌더
  4. POST /api/analyze SSE 스트림 → 위 03·04·05 섹션의 검색·전문가 패널·검증 절차 그대로 수행
  5. 최종 보고서 + 후속 채팅(/api/chat/stream) + 재분석(/api/reanalyze) + 내보내기(/api/export/docx) 가능

소스: routes/land.py, routes/analyze.py

11 / BLOCK

블록 단위 분석은 GIS 집계 + 단일 분석을 합칩니다.

한 필지가 아니라 여러 필지를 한꺼번에 봐야 하는 사업형 검토용입니다.

처리 흐름

  1. 주소 검색 → 블록 후보 로딩 (POST /api/block-parcels)
  2. 지도에 parcel GeoJSON 표시 → 사용자가 다중 선택
  3. 필요 시 POST /api/multi-parcel-zoning · POST /api/block-zoning 호출
    • 서울: UPIS ArcGIS proxy로 지구단위계획·용적률·건폐율 overlay 계산
    • 비서울: VWorld WFS로 PNU·필지경계 조회
  4. 선택 필지 속성을 합쳐 블록용 landInfo 재구성 (대지면적 합산, 평균 용적률 등)
  5. 이후 단일 분석과 동일한 POST /api/analyze 또는 /api/block-analyze 사용

소스: routes/block.py (707 LOC)

12 / GENERAL Q&A

일반 법령 질의는 우리 DB 안에서만 답합니다.

"역세권 청년주택의 인센티브 한도?"처럼 토지 맥락이 없는 제도 자체에 대한 질문 모드입니다.

특이점

버그 히스토리 (정직한 고지)

2026-04-17 이전까지 후속 채팅(/api/chat/stream)에서 법령 검색 결과가 항상 0건으로 반환되는 버그가 있었습니다. search_laws() 반환 타입을 dict로 잘못 가정한 코드가 try/except로 숨겨져 있던 것이 원인이었고, 발견 즉시 수정·배포했습니다. 이후로 후속 질문도 정상 인용됩니다.

소스: routes/analyze.py · core/search.py

13 / GUIDELINE PDF

지침서 PDF는 텍스트 추출 + 세션화로 분석합니다.

설계공모 지침서, 사업 설명서 PDF를 올리면 핵심 조건·법적 한도·인센티브·리스크를 자동으로 정리합니다.

처리 흐름

  1. PDF 업로드 → POST /api/competition/analyze
  2. PyMuPDF로 페이지별 텍스트 추출
  3. Gemini로 핵심 정보 JSON 추출 (대상지·면적·용도·인센티브 등)
  4. 주소 추출되면 → get_land_info로 대상지 토지정보까지 보강
  5. search_laws_for_guideline()로 관련 법령 대량 검색
  6. search_legal_limits()로 지침서 수치 vs 법적 한도 비교 (예: 지침서 "용적률 600%" vs 법령 한도)
  7. search_incentives()로 적용 가능한 인센티브 후보 수집
  8. generate_risk_flags()로 누락·재확인 필요 항목 생성
  9. 세션 ID 발급 → 이후 POST /api/competition/chat으로 같은 지침서에 대해 후속 질의

소스: routes/competition.py (1,205 LOC)

14 / SCALE & INCENTIVES

규모 검토는 법적 한도와 시뮬레이션을 정량적으로 부딪쳐봅니다.

지침서/대지 조건을 바탕으로 건폐율·용적률·높이·인센티브·최대 규모를 계산합니다. UI는 별도 탭이지만, 백엔드는 지침서 분석(competition)의 구조화 데이터를 재활용합니다.

핵심 endpoint

소스: routes/competition.py · scale 관련 로직

15 / DEV REVIEW

대규모 개발 검토는 지도 라쏘 + 공간 분석으로 시작합니다.

필지 단위가 아닌 구역 단위 가능성 검토용. 정비사업·재개발·도시재생을 염두에 둔 모드입니다.

처리 흐름

  1. 지도에서 라쏘 폴리곤 선택 → POST /api/devreview/analyze
  2. 입력 폴리곤 면적 계산
  3. VWorld 규제 레이어 병렬 조회 — 용도지역·지구단위계획·개발제한구역 등
  4. 용도지역별 면적 비중 + 가중평균 개략 FAR(용적률) 계산
  5. SHP/UPIS 기반 정비사업·지구단위계획 현황 수집
  6. 요약된 land context를 다시 routes.analyze.api_analyze()에 넘겨 AI 종합 분석 수행 (검색·전문가 패널·검증 모두 동일)

소스: routes/devreview.py (275 LOC)

16 / CHANGELOG

법규 변경 이력은 조문 단위 diff까지 보여줍니다.

매주 자동 갱신(01-5)에서 축적된 버전 이력을 그대로 열람하는 탭입니다. "법이 언제, 왜, 어느 조문이 어떻게 바뀌었나"를 타임라인으로 봅니다.

제공 기능

정직한 한계

소스: core/law_changelog.py · /changelog

20 / STACK

기술 스택과 의존성

"내부적으로 뭐 쓰는지" 묻는 분들을 위해 그대로 적습니다. 숨길 이유가 없습니다.

백엔드FastAPI + gunicorn (UvicornWorker × 2, 포트 8511, timeout 300s)
프론트SPA 1개 (index.html + static/js 모듈 + static/styles), 탭 동일 페이지 + 법규 변경 이력 탭
벡터 DBChromaDB 1.5.5 (PersistentClient, 단일 프로세스 전용)
임베딩 모델OpenAI text-embedding-3-large (3,072차원)
LLMGoogle Gemini (Vertex AI) — Flash / Pro 모델 혼용, Google Search tool 활성화
BM25BM25Okapi (한국어 토크나이징, 약 2~3분 빌드)
Rerankercross-encoder/ms-marco-MiniLM-L-6-v2 (numpy 1.26.4 고정)
외부 APIVWorld · 법제처 · 국가건축물대장 · UPIS ArcGIS(서울시 프록시 경유)
스케줄러macOS launchd — 매주 일요일 법령 자동 갱신 (에이전트·수동 개입 없음)
21 / LIMITATIONS

정직하게 적은 한계입니다.

잘 되는 것만 적으면 신뢰가 안 쌓인다고 봐서, 우리가 알고 있는 한계도 같이 적습니다.

읽으셨다면, 한 번 검토해보세요.

설명을 신뢰하기보다, 직접 결과를 확인하시는 게 가장 빠릅니다. 단일 획지 검토는 약 30~60초면 끝납니다.

단일 획지로 시작 랜딩으로