전체 구조
아키텍처
┌─────────────────────────────────────────────────┐
│ SvelteKit (프론트엔드) │
│ ┌──────────┐ ┌─────────────────────────────┐ │
│ │ 사이드바 │ │ 대화 영역 │ │
│ │ 대화이력 │ │ [모드 선택: 시민/후보자] │ │
│ │ 폴더/고정 │ │ [보수 에이전트 스트리밍] │ │
│ │ │ │ [관용 에이전트 스트리밍] │ │
│ │ │ │ [합의 결론 + 위험도] │ │
│ └──────────┘ └─────────────────────────────┘ │
│ ↕ SSE (Server-Sent Events) │
└─────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────┐
│ FastAPI (백엔드) │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ 듀얼 에이전트 워크플로우 │ │
│ │ │ │
│ │ 질문 → 쿼리분석 → Hybrid Retrieval │ │
│ │ ↓ │ │
│ │ 관련 조문 + 재귀참조 탐색 │ │
│ │ ↙ ↘ │ │
│ │ 보수 에이전트 관용 에이전트 (병렬) │ │
│ │ ↘ ↙ │ │
│ │ 합의 도출 에이전트 │ │
│ └─────────────────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ ChromaDB │ │ BM25 │ │ SQLite │ │
│ │ (벡터) │ │ (키워드) │ │ (대화이력) │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ │
│ OpenRouter API → Gemini 3.1 Flash Lite │
└─────────────────────────────────────────────────┘
기술 스택
| 계층 |
기술 |
역할 |
| 프론트엔드 |
SvelteKit + TypeScript |
대화 UI, SSE 수신, 상태 관리 |
| 백엔드 |
FastAPI |
REST API, SSE 스트리밍, 정적 파일 서빙 |
| LLM |
OpenRouter (Gemini 3.1 Flash Lite) |
쿼리 분석, 법률 해석, 합의 도출 |
| 벡터 DB |
ChromaDB |
시맨틱 검색 (코사인 유사도) |
| 키워드 검색 |
rank_bm25 |
법률 용어 정확 매칭 |
| 임베딩 |
paraphrase-multilingual-MiniLM-L12-v2 |
한국어 다국어 임베딩 (로컬) |
| DB |
SQLite |
대화, 메시지, 피드백 저장 |
데이터 흐름
- 사용자 → SvelteKit에서 질문 입력
- SvelteKit →
POST /api/chat (SSE 연결)
- FastAPI → 쿼리 분석기로 법률 검색어 변환
- Retriever → BM25 + ChromaDB 검색 → RRF 병합 → 상호참조 확장
- 에이전트 → 보수적/관용적 에이전트 병렬 실행 (asyncio.Queue로 토큰 인터리빙)
- 합의 → 두 의견 종합 → 위험도 판정
- SSE → 토큰 단위로 프론트엔드에 스트리밍
- DB → 응답 완료 후 백그라운드 저장