기간: 2026年01月14日 ~ 2026年02月11日 10:00
브랜치 관리는 추후에
0. 깃허브 파일을 clone 하기
git clone https://github.com/Choa0Kim/VoiceGuardian_mean-win.git .
1. 매일 아침 Pull 받아서 최신화 하기
git fetch
git pull origin main
2. 마무리 작업
git add .
git commit -m "Commit Message" // gitmoji -c
git push origin main
2. Gitmoji로 Commit Message 남기기
ex) ✨ Feat: LLM에게 프롬프팅 설정 완료
| Icon | Feat | |
|---|---|---|
| ✨ | Feat | 새로운 기능 추가 |
| 🐛 | Fix | 버그/기능에 따른 코드 변경 시 |
| ♻️ | Refactor | 코드의 가독성, 효율성을 위한 코드 변경 시 (기능의 문제 X) |
| 📝 | Docs | 문서 추가/수정/삭제 |
| 🔧 | Chore | 설정 추가/변경 |
| ✅ | Test | 테스트 코드 추가/수정 |
.
├── app.py # Streamlit 웹 UI 진입점
├── requirements.txt # Python 의존성
├── .env.example # 환경변수 템플릿
│
├── src/
│ ├── config.py # 전역 설정 (LLM, RAG, PII, STT/TTS, LangSmith)
│ ├── main.py # CLI 실행 진입점
│ │
│ ├── agents/ # 에이전트 모듈
│ │ ├── master.py # Master Agent — 대화 흐름 총괄, 시나리오 유형 결정, 하위 에이전트 지시
│ │ ├── roleplay_agent.py # Roleplay Agent — 사기범/정상 담당자 역할 대사 생성
│ │ ├── evaluator.py # Evaluator Agent — 사용자 응답 평가 (KcELECTRA / LLM 이중 경로)
│ │ └── guardian.py # Guardian Agent — 위험 경고, 교육 메시지, 정상 시나리오 피드백
│ │
│ ├── evaluator/ # PII 탐지 모델 (KcELECTRA 파인튜닝, CPU 전용)
│ │ └── pii_model.py # beomi/KcELECTRA-base-v2022 기반 이진 분류 (Safe/PII)
│ │
│ ├── graph/ # LangGraph 워크플로우
│ │ ├── state.py # 공유 상태 정의 (VoiceGuardianState)
│ │ └── workflow.py # StateGraph 구성, interrupt 기반 노드/엣지 연결
│ │
│ ├── voice/ # 음성 처리 (STT/TTS)
│ │ ├── stt.py # OpenAI Whisper API 기반 음성→텍스트
│ │ └── tts.py # edge-tts 기반 텍스트→음성
│ │
│ ├── tools/ # 공용 도구 (여러 에이전트가 공유)
│ │ └── voice_phishing_rag.py # ChromaDB 기반 보이스피싱 뉴스 RAG
│ │
│ ├── utils/ # 유틸리티
│ │ ├── llm.py # 에이전트별 ChatAnthropic 싱글톤 관리
│ │ ├── memory.py # 단기 메모리 (10턴) + 장기 메모리 (5턴 주기 요약)
│ │ └── rag.py # RAG 컨텍스트 빌드 공통 래퍼 (search → format 통합)
│ │
│ ├── collect_news/ # 뉴스 수집 파이프라인
│ │ ├── naver_to_BS_article.py # 매일경제 뉴스 크롤링
│ │ └── with_ChromaDB.py # 크롤링 데이터 → ChromaDB 벡터 적재
│ │
│ └── make_test_set/ # 테스트 데이터셋 생성
│ ├── connet_db.py
│ └── make_json.py
│
├── Data/
│ ├── chroma_db/ # ChromaDB 벡터 데이터베이스 (로컬 파일)
│ └── news/ # 수집된 뉴스 JSON
│
└── SQLite3/ # 사용자 더미 데이터 DB
LangGraph 기반 멀티 에이전트 워크플로우로, 4개의 에이전트 + interrupt() 기반 human-in-the-loop 구조입니다.
| 노드 | 역할 | LLM Temperature |
|---|---|---|
| Master | 대화 흐름 총괄, 시나리오 유형 결정(피싱/정상), 하위 에이전트 지시 생성 | 0.3 |
| Roleplay | 사기범 또는 정상 기관 담당자 역할 대사 생성 (뉴스 RAG 참고) | 0.8 |
| Evaluate | 사용자 응답 평가 — KcELECTRA PII 모델 또는 LLM으로 개인정보 노출 / 거절 감지 (피싱 시나리오 전용) | 0.0 |
| Guardian | 위험 경고 + 교육 메시지 / 훈련 종료 피드백 / 정상 시나리오 피드백 | 0.5 |
| human_input | interrupt()로 사용자 입력 대기 (그래프 일시정지) |
— |
워크플로우 흐름 (interrupt 기반):
피싱 시나리오 (~70%):
[START] → master ──┬──→ roleplay → human_input → master (루프)
├──→ evaluate ──┬──→ roleplay (safe)
│ └──→ guardian (danger)
└──→ human_input (주제 선택 대기)
guardian ──┬──→ human_input (위험 경고 후 대화 계속)
└──→ END (세션 종료)
정상 시나리오 (~30%):
[START] → master ──→ roleplay → human_input → master ─┬─→ roleplay (대화 계속)
├─→ guardian → END (자연 종료)
└─→ guardian → END (오인 거절)
interrupt()+Command(resume=...)구조로 전체 세션이 하나의 LangSmith trace로 추적됨InMemorySavercheckpointer를 사용하여 그래프 상태를 유지- 사용자는 시나리오가 피싱인지 정상인지 모르는 상태에서 대응 → 종료 후 Guardian이 유형을 알려주며 피드백
종료 조건:
| 시나리오 유형 | 조건 | Guardian 피드백 |
|---|---|---|
| 피싱 | 사용자가 사기범의 요구를 2회 거절 | 칭찬 + 사기 패턴 분석 + 대응 팁 |
| 피싱 | 최대 20턴 도달 + 거절 부족 | 취약점 강력 경고 + 대처법 안내 |
| 정상 | 업무 대화가 자연스럽게 종료 | 정상 전화였음 안내 + 피싱 구분법 |
| 정상 | 사용자가 정상 전화를 사기로 오인 거절 | 격려 + 정상/피싱 구분법 교육 |
- 전체 훈련 흐름을 관리하는 오케스트레이터
- 사용자 입력으로부터 시나리오 주제를 추출 (LLM 기반 파싱)
- 시나리오 유형 결정: ChromaDB 검색 후 확률적으로 피싱(~70%) / 정상(~30%) 시나리오 배정
- 시나리오 시작 시 RAG에서 뉴스 사례를 검색하여
scenario_context에 저장 - 피싱 시나리오:
current_phase에 따라 다음 노드를 결정하는 라우팅 로직 담당 - 정상 시나리오: LLM structured output으로 대화 자연 종료 여부와 오인 거절(False Positive)을 직접 판단
scenario_type에 따라 다른 시스템 프롬프트로 대사 생성:- 피싱: Master의 지시 + RAG 뉴스 사례를 참고하여 사기범 역할 대사 생성. 사용자 의심/거절 시 더 강압적이거나 회유하는 자연스러운 반응
- 정상: 실제 기관의 정당한 담당자 역할. 개인정보 요구 금지, 정중한 말투, 자연스러운 업무 대화 흐름 유지
- 메모리 관리: 5턴마다 장기 요약 생성, 최근 10턴만 단기 메모리에 유지
- LLM 호출 실패 시 폴백 대사로 시나리오 유지
- 피싱 시나리오에서만 호출 (정상 시나리오는 Master가 직접 판단)
- 이중 평가 경로 (
PII_USE_LOCAL_MODEL환경변수로 제어):true(기본): KcELECTRA 파인튜닝 모델로 PII 탐지 + 정규식 거절 감지 (모델 실패 시 LLM 자동 폴백)false: LLM(Claude)with_structured_output()으로 PII + 거절을 동시에 판별
- 개인정보 노출 감지 (
is_danger): 이름, 생년월일, 계좌번호, CVC, 비밀번호 등 - 완곡한 거절 감지 (
is_refusal): 직접 거절, 회피, 의심 표현, 전화 끊으려는 시도 - LLM도 실패 시 정규식 최종 폴백 처리
state.user_input을 직접 읽어 messages에 아직 추가되지 않은 최신 입력도 평가 가능
- 피싱 시나리오:
- 개인정보 노출 시: 노출된 정보 지적 + 뉴스 사례 인용 + 올바른 대처법 안내
- 거절 2회 달성 시: 칭찬 + 사기 패턴 분석 + 실생활 대응 팁 + 훈련 종료 인사
- 최대 턴(20) 도달 + 거절 부족 시: 구체적 취약점 인용 + 실제 피해 사례 경고 + 단계별 대처법 안내 + 추가 훈련 권장
- 정상 시나리오:
- 자연 종료 시: 정상 전화였음 안내 + 정상/피싱 구분 포인트 교육
- 오인 거절 시: 조심하는 것에 대한 격려 + 정상/피싱 구분법 안내 (개인정보 요구 여부, 긴급감 조성 여부 등)
- 뉴스 기사 링크를
[LINK_N]태그로 1:1 매칭하여 삽입
- beomi/KcELECTRA-base-v2022 파인튜닝 이진 분류 모델 (label 0 = Safe, label 1 = PII)
- CPU 전용 추론, 싱글톤 로딩
- 지원 모델 형식:
- 디렉토리 (
from_pretrained형식):config.json+ model weights + tokenizer .pt파일: state_dict 또는 full model 체크포인트
- 디렉토리 (
- PII 판정은 모델의 softmax 확률 출력이 유일한 기준 (정규식은 유형 라벨링에만 보조 사용)
- STT (
stt.py): OpenAI Whisper API 기반 한국어 음성→텍스트 변환 - TTS (
tts.py): Microsoft Edge Neural TTS (edge-tts) 기반 텍스트→음성 변환- ThreadPoolExecutor 싱글톤으로 리소스 최적화
- 문장 경계 기준 텍스트 절단 (
_truncate_for_tts)으로 생성 속도 개선 - 타임아웃 15초
- Streamlit UI에서 마이크 녹음 → STT → LLM 응답 → TTS 자동 재생 흐름
# 1. 의존성 설치 pip install -r requirements.txt # 2. 환경변수 설정 cp .env.example .env # .env 파일에 ANTHROPIC_API_KEY 입력 # (음성 기능 사용 시) OPENAI_API_KEY 입력
streamlit run app.py
# 대화형 시나리오 선택 python -m src.main # 특정 시나리오로 바로 시작 python -m src.main --topic 검찰사칭 python -m src.main --topic 카드사사칭 python -m src.main --topic 대출사기 # 구조 확인 데모 (API 키 불필요) python -m src.main --demo
.env.example을 복사하여 .env 파일을 생성하고 값을 입력합니다.
| 변수명 | 필수 | 설명 | 기본값 |
|---|---|---|---|
ANTHROPIC_API_KEY |
필수 | Claude API 키 | — |
OPENAI_API_KEY |
음성 기능 시 필수 | OpenAI API 키 (Whisper STT용) | — |
MASTER_MODEL |
선택 | Master Agent LLM 모델 | claude-sonnet-4-20250514 |
ROLEPLAY_MODEL |
선택 | Roleplay Agent LLM 모델 | claude-sonnet-4-20250514 |
EVALUATION_MODEL |
선택 | Evaluator Agent LLM 모델 | claude-sonnet-4-20250514 |
GUARDIAN_MODEL |
선택 | Guardian Agent LLM 모델 | claude-sonnet-4-20250514 |
PII_USE_LOCAL_MODEL |
선택 | PII 탐지 방식 (true=KcELECTRA / false=LLM API) |
true |
PII_MODEL_PATH |
선택 | KcELECTRA 모델 경로 (디렉토리 또는 .pt 파일) | models/pii_detector |
PII_BASE_MODEL |
선택 | .pt 로드 시 베이스 아키텍처 | beomi/KcELECTRA-base-v2022 |
PII_THRESHOLD |
선택 | PII 판정 임계값 (0.0~1.0, 높을수록 보수적) | 0.85 |
TTS_VOICE |
선택 | TTS 음성 (Edge Neural) | ko-KR-InJoonNeural |
TTS_RATE |
선택 | TTS 말하기 속도 | +0% |
CHROMA_DB_PATH |
선택 | ChromaDB 저장 경로 | Data/chroma_db |
CHROMA_COLLECTION |
선택 | ChromaDB 컬렉션 이름 | MK_NEWS_VECTOR |
CHROMA_EMBEDDING_MODEL |
선택 | 임베딩 모델 | all-MiniLM-L6-v2 |
LANGCHAIN_API_KEY |
선택 | LangSmith 추적용 API 키 | — |
LANGCHAIN_TRACING_V2 |
선택 | LangSmith 추적 활성화 | false |
매일경제 뉴스 기반 보이스피싱 사례를 벡터 DB에 저장하고, 에이전트가 대사/교육 생성 시 참고합니다.
# 1. 뉴스 크롤링 (Data/news/에 JSON 저장) python src/collect_news/naver_to_BS_article.py # 2. ChromaDB에 벡터 적재 python src/collect_news/with_ChromaDB.py
- 임베딩 모델:
sentence-transformers/all-MiniLM-L6-v2(ChromaDB 기본) - 유사도: cosine distance
- 싱글톤 캐싱으로 앱 실행 중 임베딩 모델 1회만 로딩
RAG 데이터 흐름:
master.py ─→ utils/rag.py ─→ voice_phishing_rag.py ─→ ChromaDB
↑
roleplay_agent.py ─→ utils/rag.py (캐시 재활용)
↑
guardian.py ─→ voice_phishing_rag.py (직접 호출 — LINK 태그 매칭용 raw results 필요)
- 의견
대화를 하는 과정 + 이상한 링크를 누르거나 이상한 전화번호로 전화하거나 앱설치를 요구하거나
같은 추가적인 상황도 구현할 수 있을까?