검토 방식 상세

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

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

01 / DATA

법령 DB는 61,732건 / 453개 법령으로 구축됐습니다.

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

453
수록 법령
61,732
조문 청크
25,154
판례 청크
2,786
판례 AI 요약

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

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

법령 본문 / 시행령 / 시행규칙법제처 OpenAPI · 조문 단위 수집 → data/rechunk_crawl_cache/ 저장
지자체 조례 (서울 + 경기 30개 시군 319개 + 하남시 14종 외)법제처 자치법규 API → 시군별 건축·도시계획·경관·주차 조례 자동 매칭
판례·행정심판례·법령해석례법제처 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 청크 구조

02 / LAND DATA

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

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

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

데이터 신뢰도 메모

04 / EXPERT PANEL

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

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

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

1standard 모드 (기본 검토)

  1. 법령 검색 (3-Layer)
  2. 판례·행정심판례·해석례 검색
  3. 1차 답변 생성 (Gemini + Google Search tool)
  4. Pass 2 보충 검색 — 1차 답변에서 부족한 법령 식별 → 추가 검색 → 보강 답변
  5. Recursive Deep-Dive 1회 — 1차 답변에서 후속 쟁점 자동 추출 → 추가 라운드
  6. QA 검증 (Self-Critique)
  7. 교차검증 — 인용한 법령 조문을 다시 검색해 누락 확인
  8. 판례 인용 검증 — 판례번호를 ChromaDB에서 실제 존재 여부 확인

2deep 모드 (심층 검토)

standard 위에 다음을 추가합니다.

소스: core/agents.py · multi_agent_consult() · _recursive_deep_dive() · verify_precedent_citations()

05 / VERIFY

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

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

1QA Self-Critique

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

2법령 교차검증

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

3판례번호 실재 검증

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

왜 이렇게까지 합니까

법규 검토 영역에서 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)

20 / STACK

기술 스택과 의존성

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

백엔드FastAPI + uvicorn (단일 프로세스, 포트 8511)
프론트SPA 1개 (index.html + static/app.js + static/style.css), 6개 탭 동일 페이지
벡터 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
21 / LIMITATIONS

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

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

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

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

단일 획지로 시작 랜딩으로