Rule Engine에서 Claude + RAG 기반 이상거래탐지로 전환한 과정
당근페이 Compliance & Strategy 팀이 룰 엔진(조건·규칙·정책 3단)으로 이상거래를 잡고, 건당 5~20분 걸리던 리뷰의 일관성을 LLM(Claude Sonnet 3.5 via Bedrock) + RAG로 보강
요약
당근페이 FDS가 이상거래 탐지 룰 엔진 위에 LLM 평가와 RAG를 얹어 모니터링 담당자에게 fraud 여부 + reasoning을 제공. RAG는 OpenSearch Serverless 기반, 사기 이력은 건당 별도 JSON 파일로 저장해 청킹이 JSON을 잘라버리는 문제를 회피. Retrieve-and-Generate 대신 Retrieve + Prompt + Converse API 분리 채택.
내용
당근페이 FDS는 중고거래 사기·보이스피싱·스미싱·명의도용 거래를 실시간으로 탐지·차단하는 시스템. 처음에는 룰 엔진으로 규칙을 늘려 가며 대응했지만, 의심 건 1건을 사람이 검토하는 데 5~20분이 걸림. 거래 내역과 관련 중고거래 글을 함께 봐야 하는데, 모니터링 담당자가 시간대 별로 교대하고 다른 업무(전화 응대 등)도 병행해 판단이 흔들리는 환경.
룰 엔진은 새 사기 패턴이 나오면 빠르게 규칙을 추가·수정해 대응할 수 있도록 레고 블록 구조로 짜둠. 이 블록 위에 LLM이 거래 맥락을 읽고 추가 평가를 얹는 흐름이 글의 본 줄거리. 단, 전자금융 환경에서 생성형 AI는 망분리 등 규제를 받기 때문에 혁신금융서비스 지정을 먼저 받아야 했고, 그 조건으로 국내 AWS 리전에서 사용 가능한 Claude Sonnet 3.5 (Bedrock) 채택.
해결 / 접근
룰 엔진 — 조건·규칙·정책 3단 레고
- 조건(Condition): "가입 후 N일 이내", "최근 송금 N건 이상" 같은 임계값 단위 블록
- 규칙(Rule): 조건 조합 (예: 가입 30일 이내 + 송금 30건 이상)
- 정책(Policy): 비슷한 목적의 규칙 묶음. 정책 단위 prompt 지정 + 규칙별 제재 수준·알림 ON/OFF 개별 설정
- 이벤트 두 경로
- 동기 API: 송금 시점 즉시 차단 결정, 매우 낮은 지연
- 비동기 스트림: 즉시 차단 불필요한 케이스, 후처리에서 알림·제재
- 사후 처리: LLM 평가 → 규칙 알림 ON이면 CS팀 알림 → 규칙 제재 수준에 따라 사용자 제재 + 플랫폼 상태 동기화 이벤트
- 도입 효과: 금융기관·수사기관의 사기 정보 요청 건수 감소
Step 01 — Prompt + Converse API
- BigQuery 사기 이력 테이블을 스케줄러가 매일 분류·Redis 캐시 적재
- 위험 평가 후 prompt type별 DataCollector가 필요 데이터 수집 → Prompt builder가 최종 프롬프트 조립 → Bedrock Converse API 호출
- 프롬프트 구조:
<role>,<evaluation_flow>,<current_transaction>,<recent_frauds>,<evaluation_criteria>,<output_format>분리 - 출력은 JSON
{"fraud":"Y or N", "reasoning":"reason1 || reason2 || reason3"}강제 → Slack 알림으로 모니터링 팀 전달 - 학습: 명시적·단계별·구조화된 프롬프트가 결과 안정에 효과
Step 02 — RAG 도입 배경과 인프라
- Prompt Type 2(최근 사기 이력 포함)에서 precision·recall이 점차 하락
- 원인: 최근 사기라도 현재 거래와 무관한 패턴이 섞이면 LLM이 잘못된 매칭 도출
- 해법: 현재 거래와 유사한 사기 이력만 검색해 LLM에 주입 → AWS Bedrock Knowledge Base + OpenSearch Serverless
- Vector field 설정 (정확도 우선)
- dimension: 1024
- space_type: cosinesimil
- ef_construction: 256
- m: 48 (권장보다 높임, 메모리 비용 감수)
- 데이터 소스: S3, 도메인별 분리 (marketplace, atm), 일자별 디렉토리, JSON
Step 02 — 청킹이 JSON을 잘라버린 문제
- 일 약 200건의 신규 사기 이력 임베딩
- 초기: JSONL 1파일에 20건씩, 라인당 1 JSON
- 증상: Retrieve 결과 content가 JSON 중간에서 잘림
- 원인: Bedrock fixed-size chunking이 maxTokens 기준으로 텍스트를 자르므로 JSON 라인 중간에서 분할
- 후보 1: Semantic chunking — breakpointPercentileThreshold·bufferSize·maxTokens 튜닝 필요, 데이터 구조가 다양하면 일관 청킹 어려움
- 선택 — 후보 2: 사기 이력 1건 = 1 JSON 파일
- ChunkingStrategy=NONE으로 파일 = 1 chunk 보장
- FIXED_SIZE라도 파일이 maxTokens 미만이면 단일 chunk
- 검색·분류 가시성도 향상
- 추가 발견: JSON 그대로보다 자연어 텍스트로 임베딩하면 검색 정확도 소폭 상승
Step 03 — Retrieve-and-Generate vs Retrieve + Prompt + Converse API
- Retrieve-and-Generate
- 프롬프트가 길어질수록 응답 에러 빈도 ↑
- 출력 포맷이 불안정
- 인용은 제공되나 검색 결과 제어 어려움
- 어떤 문서가 어떻게 결합돼 생성에 들어갔는지 파악·커스터마이즈 어려움
- 선택 — Retrieve + Converse API 분리
- Retrieve 단계에서 top-N 점수·문서 내용·S3 경로·메타데이터를 직접 확인
- 데이터 결합 방식·프롬프트 삽입 방식을 직접 통제
- 검색 로직·선택 기준·프롬프트 구성 모두 명시적
결과 / 참고
- FDS 룰 엔진 도입 후 금융기관·수사기관의 사기 관련 정보 요청 감소
- LLM 평가 결과(fraud Y/N + reasoning)가 모니터링 팀에 Slack으로 즉시 전달, 판단 일관성 확보
- 혁신금융서비스 지정으로 전자금융 LLM 사용 규제 충족 — 모델 선택은 국내 AWS 리전 가용 모델로 한정
- Next steps
- LLM 호출 전 Guardrails 추가 (개인정보 sanitize 외 안전성 강화)
- True Positive + False Positive 모두 임베딩 → Converse API 프롬프트 자동 생성에 활용
- 작성: peter.kim, 당근페이 Compliance & Strategy 팀 백엔드 엔지니어 (1년 4개월 차)
- 원문: https://medium.com/daangn/the-journey-to-daangn-pays-ai-powered-fds-from-building-a-rule-engine-to-applying-llms-695c58a78622