프로젝트3(2026-08-04)
사는 지역의 분리배출 규정과 법령 근거를 함께 답하는 RAG 챗봇입니다. 지자체마다 기준이 다르고 법령은 또 따로 찾아야 해서, 지역을 고르면 그 지역 가이드와 관련 조문을 같이 인용해 답하도록 만들었습니다. 자료에 없으면 지어내지 않고 못 찾았다고 답하는 것을 우선 순위로 뒀습니다.
github.com/SKNETWORKS-FAMILY-AICAMP/SKN32-3rd-3Team · 이 다음 프로젝트에서 Django 로 이식해 ecobotapt.com 으로 배포했습니다(프로젝트4).
개요
기간 : 2026년 7월 22일 ~ 8월 4일 (14일)
인원 : 4명
역할 : 팀장 · 근거 데이터 구축(법령 9건 · 가이드 15건) · 프론트 초안 · 발표
스택 : FastAPI · React + Vite · SQLAlchemy · MySQL · FAISS · OpenAI 임베딩 · Gemini/OpenAI 백엔드 스위치
코퍼스 : 문서 24건 — 지역 6곳(서울 · 천안 · 부산 남구 · 세종 · 인천 미추홀구 · 제주) + 전국 공통

질문 하나에 지역 기준 답변 · 근거 법령 · 출처가 같이 나옵니다 — 위쪽은 의자는 어떻게 버려? 에 천안시 기준과 폐기물관리법 제8조를 붙여 답한 것이고, 아래쪽은 코퍼스에 없는 질문에 관련 정보를 찾을 수 없습니다 로 답하는 장면입니다. 지어내지 않는 것이 이 프로젝트의 첫 번째 목표였고, 그 증거가 같은 화면에 있습니다. (발표 데모 영상에서 딴 화면입니다.)
담당한 것 — 근거 법령/가이드 데이터
원문을 그대로 넣지 않고 검색 단위에 맞춰 다시 만들었고, 문서마다 출처·정제 내용·검증 수치를 이력으로 남겼습니다.
flowchart TD
A["법령 원문 PDF · law.go.kr"] --> B["정제 · 머리말/꼬리말·부칙·시행예정 중복판 제거"]
C["지자체 · 환경부 안내"] --> D["가이드 재작성 · 품목 블록 · 동의어 병기"]
B --> E["청킹 · 법령은 조문 하나가 청크 하나"]
D --> F["청킹 · 가이드는 품목 블록 단위"]
E --> G["임베딩 · 디스크 캐시"]
F --> G
G --> H[("FAISS 인덱스")]
H --> I["검색 · 지역 필터 + 자리 배분<br/>지역 2 · 공통 1 · 법령 2"]
I --> J{"유사도 0.3 이상인 근거가 있나"}
J -->|"아니오"| K["지어내지 않고 못 찾았다고 답함"]
J -->|"예"| L["LLM 답변 · 근거 인용"]법령 9건
부칙 문제 — 부칙에도 제1조가 있어서, 그대로 두면 '
제N조'라는 표현 때문에 하나의 조문이 두 개로 인식되기도 했습니다.시행 예정 중복판을 제거 — 같은 조문이 두 번 있으면 검색이 아직 시행되지 않은 조문을 현행처럼 인용할 수 있습니다.
PDF 줄바꿈을 병합할 때 단어 중간에 남은 공백을 제거(예: 함 으로써 → 함으로써) — 조사나 어미가 끊어져 있으면 임베딩에서 다른 단어로 인식될 수 있습니다.
'별표'로 되어있는 표는 문장으로 바꾸어 임베딩 하였습니다.
가이드 15건
지자체마다 달라지는 값(대형폐기물 수수료, 이불 분류 등)은 값을 직접 넣지 않고 지자체 확인으로 안내하게 썼습니다. 챗봇이 잘못된 금액을 자신 있게 말하는 것보다 낫다고 판단했습니다.
사용자가 실제로 쓰는 표현을 동의어로 병기(계란·달걀), 청크 하나가 그것만 읽어도 말이 되게 자기완결적으로 썼습니다.
지역 선택에 인천 지역을 먼저 넣으려고 하다가, 2026년 7월 행정체제 개편으로 신설 구가 배출 체계를 재정비하는 중이었기 때문에, 개편 영향이 없는 미추홀구를 선택했습니다.
전화번호·서비스 범위처럼 변하는 정보는 문서 머리에 작성 기준일을 박아 뒀습니다.
수집 이력 문서
문서마다 버전·출처·정제 내용·검증 결과를 표로 적은 이력 문서 두 개(_datalaws_수집_정제_이력.md · _dataguide_수집_정제_이력.md)를 함께 관리. 손대는 순간 청크 경계가 달라져서, 무엇을 왜 고쳤는지가 없으면 다음 사람이 같은 판단을 다시 하지 않게 함.
팀이 내린 기술적 의사결정
조문·품목 단위 청킹 — 법령을 글자 수로 자르면 내용이 끊길수 있음. 검색 결과가 곧 인용 단위가 되게 함.
지역 · 공통 · 법령 자리 배분 — 법령은 조문이 많아 청크 비중이 더 높음. 유사도 순으로만 뽑으면 실생활 질문에도 법령만 걸려서 자리를 따로 보장하도록 변경.
안 쓰기로 한 둘 — Cross-Encoder 리랭커는 정답셋으로 재 보니 차이가 없어 복잡도만 늘어나서 사용하지 않았고, BM25 하이브리드는 계란·달걀 같은 동의어를 못 잡아 이 도메인에 맞지 않는다고 봄. (4차에서 형태소 토크나이저를 붙여 다시 실험, 그때는 검색 지표가 올랐습니다.)
성과
30문항 정답셋 통과율 93.3% (28/30) · 평균 정확도 4.56 · 환각률 6.7% · 자료 없음 대응 100%
검색 정확도 81.0% — 프롬프트를 고쳐 통과율을 76% → 80% 로 올렸을 때 이 값은 그대로.(프롬프트는 검색에 관여 하지 않음.)
임계값 0.3 — 0.40 은 무관한 질문을 하나 더 잘 막지만 정상 질문까지 막음. 관련 질문 48건 전부 통과.
프롬프트 개선 이력 65% → 75% → 80% (25문항 기준). 문서를 늘렸다가 오히려 떨어진 구간도 기록에 남김.
의의
위키를 실제로 사용. 팀 회의를 녹음해 개인 위키의 전사 기능으로 녹취록을 만들고, 그 녹취록을 Claude 에 그대로 넘겨 코드 작업에 활용.
GitHub 협업 — 1·2차에서 제대로 못 했던 브랜치·PR 을 이때부터 본격적으로 사용
팀장 역할 — 4차 EcoBot 도 같은 팀으로 이어서 진행.