2026-07-23 로그
산업안전보건법 RAG 두 가지 — 벡터로, 그리고 위키로
같은 법령 555개 조문, 같은 로컬 LLM으로 RAG를 두 방식으로 구현했다. pgvector 임베딩 검색과, LLM이 만든 위키를 링크 따라 탐색하는 방식.
실험실의 다섯 번째 주제는 온프레미스 RAG다. "폐쇄망 문서 QA"는 로컬 AI의 대표 활용처 — 그 정석 코스를 산업안전보건법령으로 밟되, 같은 코퍼스·같은 로컬 LLM으로 서로 다른 두 방식을 만들어 비교할 수 있게 했다.
코퍼스: 법령 555개 조문
국가법령정보센터(law.go.kr) 공개 API로 현행 산업안전보건법 + 시행령 + 시행규칙 원문 XML을 받아, 조(條) 단위로 파싱했다(항·호·목 계층 보존). 본법 185 + 시행령 124 + 시행규칙 246 = 555개 조문.
방식 1 — 벡터 RAG (데모)
임베딩 모델부터 실측으로 골랐다. 같은 한국어 법령 질의로 두 후보를 비교:
| 모델 | 정답 조문 유사도 | 무관 조문 유사도 | 변별 마진 |
|---|---|---|---|
| bge-m3 | 0.89 | 0.72~0.74 | 0.15 |
| Qwen3-Embedding-4B (4bit) | 0.79 | 0.29~0.40 | 0.38 |
절대 유사도는 bge-m3가 높아 보이지만 무관한 조문에도 0.7을 주는 게 문제 — 정답과 오답을 가르는 폭은 Qwen3-Embedding이 2.5배다. 후자를 채택해 555개 조문을 PostgreSQL+pgvector에 적재했다. 검색 스팟 체크는 5문 5중: "중대재해 → 제54조(0.85)" 처럼 본법·시행령·시행규칙을 넘나들며 정확히 찾는다.
파이프라인: 질문 → 임베딩 → 코사인 top-4 → 검색된 조문만을 근거로 Qwen3-4B가 답변 생성. 시스템 프롬프트로 "발췌 밖 내용 금지, 조문 번호 대괄호 인용, 없으면 모른다고" 를 강제했고, 실제로 답변에 [산업안전보건법 제54조제1항] 같은 인용이 붙는다. 검색+생성 전체 ~6초.
방식 2 — 위키 RAG (데모)
벡터 없이 간다. 사전 단계에서 로컬 LLM이 555개 조문 각각을 위키 페이지로 만든다 — 요약 1~2문장, 태그 3~6개, 그리고 조문 본문의 명시 참조("법 제54조", "영 제29조")를 해석한 페이지 간 [[위키링크]]. 여기서 원칙 하나: 링크는 LLM이 아니라 정규식으로 명시 참조만 추출한다. 소형 모델이 존재하지 않는 조문으로 링크를 지어내는 사고를 구조적으로 차단하기 위해서다. 555페이지 생성에 약 45분.
질문이 오면: ① LLM이 검색어 추출 → ② 파일 검색(제목·태그 가중) → ③ 상위 페이지의 [[관련 조문]] 링크를 한 홉 따라가 문맥 확장 → ④ 답변. 탐색 경로 전체가 UI에 표시되므로, 답이 왜 그렇게 나왔는지 사람이 따라가며 검증할 수 있다.
먼저 드러난 차이 하나
같은 "중대재해" 질문에서 벡터 RAG는 제54조를 0.85로 1위에 올렸지만, 위키 RAG는 LLM이 뽑은 검색어에 노이즈("임직원")가 섞이며 제54조가 2위로 밀렸다. 대신 위키 쪽은 왜 그랬는지가 화면에 그대로 보인다 — 블랙박스 유사도 vs 추적 가능한 탐색. 이 트레이드오프가 이 실험의 핵심 관전 포인트다. 동일 질문 10문 정량 비교는 다음 로그에서.
두 데모 모두 임베딩·검색·생성 전 과정이 Mac mini 안에서 돈다. 외부 API 호출 0.