-
Notifications
You must be signed in to change notification settings - Fork 0
[Feat] 점수화 로직 추가 #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat] 점수화 로직 추가 #11
Conversation
Walkthrough프롬프트 시스템이 파일 기반 규칙과 예시 데이터를 사용하는 구조로 재구성되었고, 예시 데이터 스키마가 리스트 기반으로 변경되었습니다. 위험도 점수 상한이 70으로 조정되었고, 점수 규칙 데이터가 추가되었습니다. GPT 호출의 temperature가 0.1로 낮춰졌습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PromptBuilder as fraud_prompts.get_fraud_detection_prompt
participant RulesFile as score_rules.txt
participant GPTService
participant LLM
User->>PromptBuilder: 입력(텍스트/키워드/이미지메타)
PromptBuilder->>RulesFile: _load_rules()로 규칙 로드
PromptBuilder-->>User: [system, user] 프롬프트 반환(예시 포함)
User->>GPTService: 프롬프트 전송 (temperature=0.1)
GPTService->>LLM: 모델 요청
LLM-->>GPTService: 응답(점수/판정 등)
GPTService-->>User: 응답 반환
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Out-of-scope changes
Possibly related PRs
Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🔭 Outside diff range comments (2)
app/services/gpt_service.py (1)
13-27: async 함수 내 동기 API 호출로 인한 이벤트 루프 블로킹 위험
client.responses.create(...)는 동기 호출입니다. 현재async def call_gpt에서 직접 호출하면 이벤트 루프를 블로킹할 수 있습니다. 스레드 오프로딩 또는 동기 함수화가 필요합니다.다음과 같이 오프로딩을 권장합니다(해당 범위 내 diff):
@@ - try: - response = client.responses.create( + try: + import asyncio + response = await asyncio.to_thread( + client.responses.create, model="gpt-4o-mini", - input = messages, - temperature = 0.1, # 생성된 텍스트의 무작위성을 결정 - max_output_tokens = 200 - ) + input=messages, + temperature=0.1, # 생성된 텍스트의 무작위성을 결정 + max_output_tokens=200 + )또는 단순히
def call_gpt(...)로 동기 함수로 선언을 바꾸는 것도 방법입니다.app/prompts/fraud_prompts.py (1)
71-79: FraudExample가 List[str]로 바뀌었는데 문자열로 그대로 출력 — 예시 포맷 깨짐
ex.message_content/ex.additional_description가 리스트인데 리스트의 str 표현으로 들어갑니다. 모델이 예시를 제대로 학습/참조하지 못할 수 있습니다. 항목별로 줄바꿈/인덱스로 풀어써 주세요.수정 diff:
-def build_example_lines(examples): - example_lines = ["사기 유형 및 예시:\n"] - for idx, ex in enumerate(examples, start=1): - example_lines.append(f"{idx}. {ex.type_name}:\n") - example_lines.append(f" messageContent: '{ex.message_content}'\n") - example_lines.append(f" additionalDescription: '{ex.additional_description}'\n") - example_lines.append(f" keywords: '{ex.keywords}'\n") - - return example_lines +def build_example_lines(examples: List[FraudExample]) -> List[str]: + example_lines = ["사기 유형 및 예시:\n"] + for idx, ex in enumerate(examples, start=1): + example_lines.append(f"{idx}. {ex.type_name}:\n") + # message_content + if ex.message_content: + for j, msg in enumerate(ex.message_content, start=1): + example_lines.append(f" messageContent[{j}]: '{msg}'\n") + else: + example_lines.append(" messageContent: ''\n") + # additional_description + if ex.additional_description: + for j, desc in enumerate(ex.additional_description, start=1): + example_lines.append(f" additionalDescription[{j}]: '{desc}'\n") + else: + example_lines.append(" additionalDescription: ''\n") + # keywords + example_lines.append( + f" keywords: {', '.join(ex.keywords) if ex.keywords else 'None'}\n" + ) + return example_lines
🧹 Nitpick comments (5)
app/prompts/fraud_example.py (1)
6-8: 리스트 필드에 최소 아이템 수 등 제약 추가 제안실제 예시는 최소 1개 이상의 메시지/설명을 전제로 합니다. 모델 레벨에서 제약을 추가하면 데이터 품질을 보장할 수 있습니다.
적용 예시(diff는 해당 범위 내):
-from pydantic import BaseModel +from pydantic import BaseModel, Field ... - message_content: List[str] + message_content: List[str] = Field(..., min_items=1, description="메시지 블록들") ... - additional_description: List[str] + additional_description: List[str] = Field(..., min_items=1, description="설명 블록들")app/prompts/data/score_rules.txt (1)
131-131: 파일 끝 개행 추가 제안(선택)일부 도구에서 마지막 개행 누락을 경고합니다. 유지보수성을 위해 개행 추가를 권장드립니다.
app/services/gpt_service.py (1)
28-28: 응답 전체 로그는 PII/비용 측면에서 과도함 — 최소화 권장성공 로그에 전체
response객체를 남기면 사용자 입력/출력이 포함되어 PII 유출 및 로그 비용 증가 우려가 있습니다. ID/메타만 남기세요.적용 예시(diff):
- logger.info(f"GPT API 호출 성공: {response}") + try: + logger.info(f"GPT API 호출 성공: id={getattr(response, 'id', None)}, model=gpt-4o-mini") + except Exception: + logger.info("GPT API 호출 성공") # 안전한 폴백app/prompts/fraud_prompts.py (2)
53-56: 시스템 프롬프트에 규칙+모든 예시를 전부 포함 — 토큰/비용 폭증 우려규칙표 자체가 길고 예시도 다수입니다. 호출당 시스템 프롬프트가 과도해 지연/비용 증가가 큽니다. 예시 수를 축소하거나 카테고리별 대표 1~2건만 샘플링하는 옵션을 고려하세요. 규칙표도 필요한 섹션만 선택적으로 포함하거나 캐시/버전 관리를 통해 동일 프롬프트 재사용을 권장합니다.
61-65: 유저 입력을 평문으로 직렬화 — JSON 직렬화로 파싱 안정성 향상 권장따옴표/개행/특수문자 때문에 모델 파싱 혼선이 생길 수 있습니다. JSON으로 전달하면 일관성이 좋아집니다. 시스템 프롬프트에도 “다음 JSON 입력을 분석하라”로 맞춰주세요.
해당 범위 내 수정(diff) 및 import 추가:
+import json @@ - "content": ( - f"messageContent: '{message_content}'\n" - f"additionalDescription: '{additional_description}'\n" - f"keywords: {', '.join(keywords) if keywords else 'None'}\n" - f"imageContent: '{image_content}'" - ) + "content": json.dumps({ + "messageContent": message_content or "", + "additionalDescription": additional_description or "", + "keywords": keywords or [], + "imageContent": image_content or "" + }, ensure_ascii=False)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
.gitignore(1 hunks)app/models/fraud_response.py(1 hunks)app/prompts/data/fraud_examples.py(1 hunks)app/prompts/data/score_rules.txt(1 hunks)app/prompts/fraud_example.py(1 hunks)app/prompts/fraud_prompts.py(3 hunks)app/services/gpt_service.py(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
app/prompts/fraud_example.py (1)
app/models/fraud_request.py (1)
FraudRequest(5-9)
app/prompts/fraud_prompts.py (1)
app/prompts/fraud_example.py (1)
FraudExample(4-8)
app/prompts/data/fraud_examples.py (2)
app/prompts/fraud_example.py (1)
FraudExample(4-8)app/models/fraud_request.py (1)
FraudRequest(5-9)
🔇 Additional comments (6)
.gitignore (1)
205-207: Marimo 산출물 디렉터리 ignore 추가 LGTMmarimo/ 추가로 불필요한 산출물이 커밋되지 않도록 방지합니다.
app/models/fraud_response.py (2)
8-8: 점수 상한(0~70)으로의 조정 일관성 확보프롬프트 내 지시(최대 70점)와 모델 검증 범위가 일치합니다. 좋은 정합성 개선입니다.
8-8: 점수 범위(0~70) 변경에 따른 다운스트림 영향 점검 권고ripgrep 스크립트로 “0
100” 가정 패턴은 검색되지 않았으나, 클라이언트/UI·문서·통계 집계·알람 임계치 등에서 여전히 0100을 기준으로 동작하는 부분이 남아있을 수 있습니다. 수동으로 아래 항목을 반드시 검토해주세요.
- UI에서 퍼센트 계산 로직이 0~70 범위에 맞게 조정되었는지
- 게이지/바 컴포넌트의 최대값(MAX) 설정
- API 응답 스펙 및 사용자 가이드(README.md, 위키 등) 내 예시
- 통계 집계 파이프라인 및 알람 임계치 설정 (기존 100단위 트리거 여부)
app/prompts/fraud_example.py (1)
6-8: 예시 스키마를 다중 블록(List[str])로 전환한 점 좋습니다데이터셋과 프롬프트 빌더 변경 사항과 정합성 있습니다.
app/prompts/data/score_rules.txt (1)
1-131: 규칙 데이터 리소스 추가 LGTM카테고리/룰/가중치 포맷이 명확하며, 프롬프트 로딩 로직과 일치합니다.
app/services/gpt_service.py (1)
25-25: 온도(temperature) 0.1로 낮춘 변경 LGTM결정론적 출력을 강화하는 합리적 조정입니다.
| FRAUD_EXAMPLES: List[FraudExample] = [ | ||
| FraudExample( | ||
| type_name="피싱", | ||
| message_content="귀하의 계정이 잠길 수 있습니다. 비밀번호를 확인하려면 여기를 클릭하세요.", | ||
| additional_description="늦은 밤, 낯선 번호로 온 SMS를 우연히 열어보았습니다.", | ||
| keywords=["계정 잠금", "비밀번호 확인", "SMS 링크"], | ||
| image_content="은행알림 Bot: 당신의 계좌가 비정상적으로 활동되어 잠길 예정입니다. https://bit.ly/secure-link" | ||
| type_name="기관 사칭형", | ||
| message_content=[ | ||
| "[Web발신]\n[서울강북경찰서] 귀하의 사건\n[송치번호 : 2021-439857]호를\n서울북부지방검찰청으로 인계하였습니다.\n담당 검사가 지정되기까지 1~3일 소요될 수 있습니다.", | ||
| "서울중앙지방검찰청 민원실\n수신인:\n문서번호: 중앙-2023-XXXX\n귀하 명의의 계좌가 명의도용으로 사용되어\n금융감독원으로부터 신고 접수되었습니다.\n관련 서류는 등기 발송하였으나 반송되어 본 고지로 대체하며 신속히 연락 주시기 바랍니다.\n연락처: 010-XXXX-XXXX", | ||
| "[Web발신]\n[금융감독원] 고객님 명의 계좌에서\n수상한 거래 및 불법 송금 시도가 감지되었습니다.\n긴급 보안조치 및 신분 확인 바랍니다.\n확인링크: bit.ly/xxxx" | ||
| ], | ||
| additional_description=[ | ||
| "검찰로 사건이 송치되었다며 담당 검사 지정까지 대기하라는 문자 수신. 실제 경찰서 발신 여부 확인 필요해 의심됨.", | ||
| "명의도용 신고가 접수되었으며 문서번호와 연락처가 포함됨. 해당 번호가 기관과 다르고 신속 연락을 요구해 사기 가능성 높음.", | ||
| "수상한 거래 발생 안내와 함께 링크로 신분 확인을 유도. 링크가 수상하고 발신자 정보가 불분명해 의심됨." | ||
| ], | ||
| keywords=[ | ||
| "전화", | ||
| "수사기관", | ||
| "공공기관", | ||
| "개인정보", | ||
| "송금 요청", | ||
| "링크 클릭 요청", | ||
| "수상한 링크 포함", | ||
| "실제 기관/지인 연락처와 달랐다", | ||
| "무리한 정보 요청이 있었다", | ||
| "링크나 파일이 수상해 보였다", | ||
| "긴급하게 행동을 요구했다" | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="투자 사기", | ||
| message_content="2주 만에 30% 수익 보장! 지금 투자하세요.", | ||
| additional_description="점심시간 카페에서 친구가 공유한 링크를 클릭했습니다.", | ||
| keywords=["30% 수익", "지금 투자", "보장된 수익"], | ||
| image_content="InvestPro: 한정 시간 30% 수익, 투자하기 ▶ http://invest.example.com" | ||
| type_name="대출 사기형", | ||
| message_content=[ | ||
| "[Web발신]\nKB국민은행 고객님께 안내드립니다.\n정부지원 서민금융상품 신청 대상자로 선정되셨습니다.\n\n【상품 특징】\n최대 1,500만원, 금리 2.3%~5.2%\n무직자 가능, 신용등급 무관, 무서류 진행, 중도상환 수수료 없음\n대환대출, 생활안정자금 지원 가능\n\n【신청 방법】\n상담원 연결 후 1번 누르시면 접수 완료!\n대표번호 02-1577-XXXX\n※ 접수자 많을 시 상담 지연될 수 있습니다.", | ||
| "[Web발신]\n안녕하세요, 현대캐피탈 박대리입니다.\n대출 진행을 위해 아래 서류 제출 바랍니다.\n\n신분증 사본\n등본, 초본\n재직증명서, 통장사본\n거래내역서 (주거래은행 3개월)\n※ 카카오톡으로 사진 전송 가능\n※ 아래 링크 통해 앱 설치 후 신청서 작성 부탁드립니다.\nhxxp://xxxxx.bank.top/신청앱.apk", | ||
| "고객님 대출 승인 완료되었습니다.\n대출금 수령을 위해 아래 파일을 다운로드 후 설치해주세요.\n압축 해제 시 상담신청 앱 실행됩니다.\n\nKB국민은행.zip (용량 7.9MB)\n※ 신청서 삭제 시 대출 자동취소될 수 있으니 반드시 유지 바랍니다.\n문의사항은 바로 메시지 주세요.\n당일 수령 가능하며 전자서명 완료 후 입금됩니다." | ||
| ], | ||
| keywords=[ | ||
| "전화", | ||
| "금융기관", | ||
| "송금 요청", | ||
| "개인정보 입력", | ||
| "링크 클릭 요청", | ||
| "앱 설치 / 파일 다운로드 유도", | ||
| "신분증", | ||
| "대출 이력", | ||
| "주민등록번호", | ||
| "무리한 정보 요청이 있었다", | ||
| "링크나 파일이 수상해 보였다", | ||
| "긴급하게 행동을 요구했다" | ||
| ], | ||
| additional_description=[ | ||
| "정부지원 대출 대상자로 선정되었다며 상담을 유도하는 문자 수신. 국민은행을 사칭하고 상담번호가 수상해 의심됨.", | ||
| "대출 진행을 위해 신분증 등 서류를 요구하고 apk 파일 설치를 유도하는 메시지. 링크가 수상하여 사기 의심됨.", | ||
| "대출 승인을 사칭하여 zip 파일 설치를 유도. 설치하지 않으면 대출이 취소된다고 하여 위기감을 조성함." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="복권 사기", | ||
| message_content="축하합니다! 당신은 1,000,000달러에 당첨되었습니다. 수수료를 지불하면 수령 가능합니다.", | ||
| additional_description="출근길 지하철에서 받은 이메일에 포함된 링크를 클릭했습니다.", | ||
| keywords=["당첨", "수수료", "이메일 링크"], | ||
| image_content="LotteryKingdom: Congratulations! You've won $1,000,000. Click here https://lotto.fake/claim" | ||
| type_name="카드사 사칭형", | ||
| message_content=[ | ||
| "[Web발신] KB국민카드 승인불가\n본인 미신청 시 02-XXX-XXXX로 문의 바랍니다.", | ||
| "[Web발신] 신한카드 개통완료.\n개통내용이 본인과 다를 경우 즉시 상담접수 바랍니다.", | ||
| "[Web발신] 현대카드에서 이상 거래가 감지되었습니다.\n본인 아닌 경우 1644-XXXX로 취소 요청 바랍니다." | ||
| ], | ||
| keywords=[ | ||
| "전화", | ||
| "금융기관", | ||
| "개인정보 입력", | ||
| "보안카드 번호", | ||
| "신분증", | ||
| "실제 기관/지인 연락처와 달랐다", | ||
| "무리한 정보 요청이 있었다", | ||
| "긴급하게 행동을 요구했다" | ||
| ], | ||
| additional_description=[ | ||
| "KB국민카드 승인불가 문자 수신. 본인이 신청하지 않았으면 전화하라는 내용으로 긴급히 대응을 유도함.", | ||
| "신한카드 개통완료라는 문자 수신. 본인과 다를 경우 상담 요청을 유도하여 개인정보 입력을 유도할 우려가 있었음.", | ||
| "현대카드 이상 거래 감지 문자 수신. 본인이 아닐 경우 즉시 취소 요청하라는 문구로 위기감을 조성하여 행동을 유도함." | ||
| ] | ||
| ), | ||
| # … (총 60~70개 항목) | ||
| ] | ||
| FraudExample( | ||
| type_name = "돌잔치 초대장형", | ||
| message_content = [ | ||
| "[Web발신] 저희 아들 첫돌 잔치에 초대합니다 모바일 초대장 oa.to/invite123", | ||
| "[Web발신] 축하해주세요~ 우리 아이 돌잔치 초대장이 도착했어요 vo.to/happybaby", | ||
| "아들 돌잔치 초대장 보내드렸습니다. 시간 되시면 꼭 참석해주세요! http://baby.partyapp.apk" | ||
| ], | ||
| keywords = [ | ||
| "문자", | ||
| "가족 / 친구 / 지인", | ||
| "링크 클릭 요청", | ||
| "링크나 파일이 수상해 보였다", | ||
| "실제 기관/지인 연락처와 달랐다" | ||
| ], | ||
| additional_description = [ | ||
| "지인인 척 하며 아들 돌잔치 초대 문자를 보냈고, 생소한 링크 클릭을 유도. 돌잔치 초대장이 문자로 오는 게 이상해서 의심", | ||
| "축하해 달라는 내용과 함께 링크로 접속을 유도하는 메시지를 받음. 돌잔치라는 표현이 감성적으로 다가왔지만 링크 주소가 수상", | ||
| "시간 되면 참석해 달라며 파일이 포함된 초대장을 보냄" | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="모바일 청첩장형", | ||
| message_content=[ | ||
| "[Web발신] 안녕하세요~ 저 결혼합니다\n사랑의 결실을 맺게 되어 모바일 청첩장 보내드립니다 han.gl/wedding2025", | ||
| "[Web발신] 청첩장이 도착했습니다.\nWedding Invitation c11.kr/loveyou\n참석해주시면 큰 기쁨이 될 거예요!", | ||
| "재혼을 결심하고 소중한 분들께 모바일 청접장을 보내드립니다\n청첩장 확인 http://mywedding.invite.apk" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "가족 / 친구 / 지인", | ||
| "링크 클릭 요청", | ||
| "링크나 파일이 수상해 보였다", | ||
| "실제 기관/지인 연락처와 달랐다" | ||
| ], | ||
| additional_description=[ | ||
| "지인처럼 결혼 소식을 전하며 모바일 청첩장을 보냈고, 단축 링크 클릭을 유도. 결혼 소식이 갑작스럽고 링크가 수상해 의심되었습니다.", | ||
| "Wedding Invitation이라는 제목으로 링크가 포함된 청첩장을 받았습니다. 정식 청첩장이 아닌 문자로 온 점이 이상해서 사기로 의심했습니다.", | ||
| "재혼 안내와 함께 .apk 파일이 포함된 청첩장 링크를 받았고, 설치를 유도하는 방식이라 매우 의심스러웠습니다." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="부고문자형", | ||
| message_content=[ | ||
| "[Web발신] 안타깝게도 부친께서 별세하셨습니다.\n부고 및 장례식장 안내 buly.kr/funeral123", | ||
| "[Web발신] 삼가 고인의 명복을 빕니다.\n○○○님 모친상 부고 안내드립니다. 빈소 위치 확인 gg.gg/빈소위치", | ||
| "[訃告] ○○○님의 아버님께서 소천하셨습니다.\n조문 오시는 길 iplogger.com/funeral" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "가족 / 친구 / 지인", | ||
| "링크 클릭 요청", | ||
| "링크나 파일이 수상해 보였다", | ||
| "실제 기관/지인 연락처와 달랐다" | ||
| ], | ||
| additional_description=[ | ||
| "부친 별세 소식과 함께 장례식장 안내라는 명목으로 링크 클릭을 유도하였고, 링크 도메인이 낯설어 의심되었습니다.", | ||
| "모친상 부고 문자를 받았는데, 단축 링크가 포함되어 있었고 감성적 표현으로 클릭을 유도하여 사기 가능성이 있다고 판단했습니다.", | ||
| "訃告라는 제목과 함께 조문 안내 링크가 왔지만 전혀 모르는 사람 이름과 수상한 링크 주소로 사기로 강하게 의심되었습니다." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="범칙금/과태료 부과형", | ||
| message_content=[ | ||
| "[Web발신] [도로교통공단] 정지선 위반으로 과태료가 부과되었습니다.\n자세한 고지서 확인 paso.mobilecar.pe.kr/warning", | ||
| "[Web발신] 민원24에서 쓰레기 무단투기에 대한 민원이 접수되었습니다.\n내용 확인 homes-go.com/violation", | ||
| "[Web발신] [관세청] 귀하의 통관번호에 수입세금 미납이 있어 고지서를 발송하였습니다.\n goosmsi.com/tax" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "공공기관", | ||
| "링크 클릭 요청", | ||
| "개인정보 입력", | ||
| "수상한 링크 포함", | ||
| "링크나 파일이 수상해 보였다" | ||
| ], | ||
| additional_description=[ | ||
| "도로교통법 위반으로 과태료가 부과되었다며 고지서 확인을 유도하는 문자 수신. 발신기관 명칭은 있었지만 링크 주소가 낯설어 의심됨.", | ||
| "쓰레기 무단투기 민원 접수 안내와 함께 내용을 확인하라는 문자. 공식 사이트가 아닌 생소한 링크를 보내 사기로 의심됨.", | ||
| "관세청을 사칭하여 세금 미납 고지서를 링크로 확인하라는 문자 수신. 관세청 링크가 아니었고 사기 가능성이 높아보였음." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="건강보험공단 사칭형", | ||
| message_content=[ | ||
| "[Web발신] [국민건강보험공단] 종합건강검진 통지서가 발송되었습니다.\n dokdo.in/healthcheck", | ||
| "[Web발신] [건강지키미] 건강보험료 환급금 신청이 마감됩니다. 신청 요망 nhisis.xyz/refund", | ||
| "[Web발신] 보험료 미납으로 인해 건강검진 통보문이 반송되었습니다.\n확인바랍니다 cloud-check.kr/notice" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "건강보험공단 / 의료기관", | ||
| "링크 클릭 요청", | ||
| "수상한 링크 포함", | ||
| "긴급하게 행동을 요구했다", | ||
| "링크나 파일이 수상해 보였다" | ||
| ], | ||
| additional_description=[ | ||
| "건강검진 통지서를 확인하라는 문자였고, 공단을 사칭하며 수상한 링크로 접속을 유도해 의심.", | ||
| "보험료 환급 신청 마감이라며 긴급하게 신청을 유도하고 이상한 링크를 보냄", | ||
| "보험료 미납으로 건강검진 통보문이 반송됐다며 확인을 요청하고 의심스러운 링크를 제공해 사기 같았음" | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="검찰 출석 요구형", | ||
| message_content=[ | ||
| "[Web발신] [검찰청] 형사소송건과 관련하여 긴급출석요구가 발부되었습니다.\n사건번호: 13-093157 sc-police.co.kr/confirm", | ||
| "[Web발신] ○○○님께 형사소송 관련 출석요구서가 발송되었습니다. 즉시 확인 바랍니다.\n xuto.tk/doc", | ||
| "[Web발신] [법원] 귀하의 사건번호 경기13고단758에 대한 민사소송이 접수되었습니다.\n확인 is.gd/lawsuit" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "수사기관", | ||
| "출석 / 소환 요구", | ||
| "개인정보 입력", | ||
| "링크 클릭 요청", | ||
| "링크나 파일이 수상해 보였다", | ||
| "긴급하게 행동을 요구했다", | ||
| "긴급성이나 위기감을 느끼게 하는 표현이 있었다" | ||
| ], | ||
| additional_description=[ | ||
| "검찰청에서 형사소송건 출석요구서를 발부했다며 사건번호와 수상한 링크를 보내와 사기 의심이 들었음.", | ||
| "형사소송 관련 문서를 확인하라며 링크를 통해 즉시 확인을 요구하여 긴급하고 위협적인 분위기였음.", | ||
| "법원에서 민사소송 접수 안내와 함께 링크를 보내왔고, 사건번호까지 있어 실제처럼 보였지만 의심스러웠음." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="국세청 사칭형", | ||
| message_content=[ | ||
| "[Web발신] [국세청] 종합소득세 환급 대상자입니다. 환급금 수령을 위해 신청하세요 han.gl/refund123", | ||
| "[Web발신] 홈택스 연말정산 환급금 내역 조회가 가능합니다. 확인 me2.do/taxcheck", | ||
| "[국민연금공단] 세금 미납 내역이 확인되어 납부 통지서가 발급되었습니다.\n goo.gl/notify123" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "공공기관", | ||
| "금융기관", | ||
| "지원금 / 환급금 수령 유도", | ||
| "링크 클릭 요청", | ||
| "링크나 파일이 수상해 보였다", | ||
| "실제 기관/지인 연락처와 달랐다" | ||
| ], | ||
| additional_description=[ | ||
| "국세청을 사칭하여 환급 대상임을 강조하고 링크를 클릭해 신청하라고 하여 사기 의심이 들었음.", | ||
| "홈택스 연말정산 환급금 조회가 가능하다며 링크를 보내왔고, 환급 유도 방식이 수상했음.", | ||
| "국민연금공단 명의로 세금 미납 통지서를 보냈고 링크를 통해 확인을 요구해 사기 가능성이 높다고 판단됨." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="알바/부업 사기형", | ||
| message_content=[ | ||
| "[Web발신] 안녕하세요! 당사 유통사에서 상품 검수 및 단순 작업을 도와주실 분을 모집합니다. 하루 20분 작업, 일당 최대 14만원 지급. 카카오톡 open.kakao.com/abcd 로 문의주세요.", | ||
| "[광고] 온라인 부업 모집! 나이/경력 무관, 하루 30분 휴대폰으로 간단한 수익 가능. 급여 당일 정산. 관심 있으시면 http://bit.ly/jobapply 로 접속하세요.", | ||
| "[Web발신] [TE MTV VIP] 채용 공고 – 재택근무 알바 모집 중! 20~50세 대상, 카카오톡 아이디 통해 1:1 채용 상담 진행 중. 지금 바로 문의 주세요!" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "송금 요청", | ||
| "앱 설치 / 파일 다운로드 유도", | ||
| "링크 클릭 요청", | ||
| "개인정보 입력", | ||
| "신분증", | ||
| "휴대폰 인증번호", | ||
| "긴급하게 행동을 요구했다", | ||
| "링크나 파일이 수상해 보였다" | ||
| ], | ||
| additional_description=[ | ||
| "open.kakao 링크를 포함하여 단순 재택근무를 빙자하고 높은 급여를 약속하며 개인정보 유도.", | ||
| "초단기 고수익 부업을 미끼로 링크 클릭을 유도하고, 당일 정산이라는 문구로 사용자의 판단을 흐리는 사례.", | ||
| "카카오톡 ID 또는 상담 링크를 통해 접촉을 유도하며, 연령 조건을 제시해 신뢰감을 조성하는 형태의 스미싱 메시지." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="정부지원금 위장형", | ||
| message_content=[ | ||
| "[Web발신] [고용노동부] 민생안정지원금 330,000원 지급 대상자입니다. 예산 소진 전 신청하세요 han.gl/abcd", | ||
| "[Web발신] [중소벤처기업부] 방역지원금 신청마감 임박! 신청자에 한해 신속지급됩니다 bit.ly/abcd", | ||
| "[국세청] 재난지원금 관련 신분증 사본 제출이 누락되었습니다. 제출하지 않으면 미지급 처리 is.gd/abcd" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "공공기관", | ||
| "지원금 / 환급금 수령 유도", | ||
| "개인정보 입력", | ||
| "링크 클릭 요청", | ||
| "신분증", | ||
| "주민등록번호", | ||
| "링크나 파일이 수상해 보였다", | ||
| "긴급하게 행동을 요구했다" | ||
| ], | ||
| additional_description=[ | ||
| "고용노동부를 사칭해 민생안정지원금 33만원 수령 대상자라고 하며, 예산 소진 전 신청을 유도한 메시지.", | ||
| "방역지원금 신청 마감이 임박했다며 긴급하게 링크 클릭을 유도하는 메시지.", | ||
| "국세청을 사칭하여 신분증 사본 제출을 요구하며 미제출 시 미지급 처리된다는 위협성 문구를 포함한 사기형 메시지." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="택배 사기형", | ||
| message_content=[ | ||
| "[Web발신] [CJ대한통운] 배송지 오류로 인해 상품이 반송되었습니다. 주소 확인 bit.ly/배송확인", | ||
| "[Web발신] 택배 배송이 지연되고 있습니다. 주소를 다시 입력해 주세요 han.gl/재확인", | ||
| "[CJ택배] 고객님의 택배가 도착하지 못했습니다. 정확한 배송을 위해 앱 다운로드 바랍니다 http://xgo.kr/tpapp.apk" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "택배기사", | ||
| "링크 클릭", | ||
| "앱 설치 / 파일 다운로드 유도", | ||
| "링크나 파일이 수상해 보였다", | ||
| "실제 기관/지인 연락처와 달랐다" | ||
| ], | ||
| additional_description=[ | ||
| "CJ대한통운을 사칭하여 주소 오류로 인한 반송을 알리며 링크 클릭을 유도하는 사례.", | ||
| "배송 지연을 명목으로 주소 재입력을 유도하며 단축 URL로 링크를 유도하는 사기형 메시지.", | ||
| "앱 설치를 유도하는 악성 APK 다운로드 유도형 스미싱 메시지." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="가상화폐 사기형", | ||
| message_content=[ | ||
| "[Web발신] [Upbit] 귀하의 계정에서 해외IP 로그인이 감지되었습니다. 본인이 아닐 경우 즉시 확인 bit.ly/secure-eth", | ||
| "[Web발신] [Binance] 잔여 ETH 소각 예정입니다. 소각 전 자산 복구를 원하시면 상담 요청 line.me/xyz123", | ||
| "[알림] 비트코인 휴면계정 자산 소멸 예정입니다. 로그인 후 기기 등록 후 이용 가능 me2.kr/login-warning" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "암호화폐 거래소", | ||
| "링크 클릭 요청", | ||
| "앱 설치 / 파일 다운로드 유도", | ||
| "개인정보 입력", | ||
| "신분증", | ||
| "긴급하게 행동을 요구했다", | ||
| "링크나 파일이 수상해 보였다", | ||
| ], | ||
| additional_description=[ | ||
| "업비트를 사칭하여 해외 로그인 감지라는 명목으로 긴급하게 링크 클릭을 유도하는 메시지.", | ||
| "바이낸스를 사칭해 ETH 소각 예정이라며 자산 복구를 미끼로 라인 상담 링크를 유도하는 사례.", | ||
| "비트코인 자산 소멸 예정이라는 경고와 함께 me2.kr 링크 클릭 및 기기 등록을 유도하는 메시지." | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="주식투자 사기형", | ||
| message_content=[ | ||
| "[Web발신] 이번주 급등주 5개 공개! 가입 후 종목 수령하세요\n에넥스, 덕신하우징 등 급등 예상 종목\n수익률 최대 150% 보장, 손실 발생 시 전액 보상!\nhttps://bit.ly/vvipstock", | ||
| "[Web발신] (광고) 2차전지 유망주 유진테크놀로지 특별공급 안내\nNH증권 주관, 상장 전 선착순 신청\n공모가 14,000원 공급가 6,000원\n수익 극대화 기회! 지금 신청하세요\nhttps://bit.ly/yujinipo", | ||
| "[Web발신] 전문가 추천 종목 단타방 오픈!\n매일 수익 인증, 무료혜택 제공\n가입 후 '666' 입력 시 입장\n단기 수익률 30% 목표\nhttps://t.me/stockvip" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "투자회사 / 증권사", | ||
| "링크 클릭 요청", | ||
| "개인정보 입력", | ||
| "지원금 / 환급금 수령 유도", | ||
| "신분증", | ||
| "긴급하게 행동을 요구했다", | ||
| "링크나 파일이 수상해 보였다", | ||
| ], | ||
| additional_description=[ | ||
| "에넥스 등 실제 종목명을 활용하여 고수익 보장과 손실 보상을 미끼로 단축 URL을 통해 가입을 유도하는 메시지", | ||
| "2차전지 유망주를 빙자해 할인 공급과 수익 극대화를 강조하며 선착순 신청을 유도하는 사기 사례", | ||
| "전문가 단타방 입장을 유도하며 무료 혜택, 수익 인증 등을 통해 사용자의 심리를 자극하고 링크 클릭을 유도하는 메시지" | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="청약 공모주 사기형", | ||
| message_content=[ | ||
| "[Web발신]\n(광고) IPO 공모 청약 신청\n24년 첫 코스피 상장 APR에이피알(KOSPI)\n상장일정: 2024년 2월 26일\n주관사: 신한투자증권\n공모가: 250,000원 공급가: 70,000원\n청약 담당자: 010-8014-XXXX\n빠른회신 부탁드립니다.", | ||
| "[Web발신]\n축하드립니다. 공모주 청약 당첨 안내\n두산로보틱스 10주 무상배정\n상장일: 2023년 10월 2일\n주관사: 미래에셋증권, 한국투자증권\n공모가: 25,000원 ~ 28,000원\n당첨자에 한해 순차적으로 안내 전화 드리겠습니다.", | ||
| "[Web발신]\n청약 가능한 공모주 안내\n이노스페이스 (발사체 제작, 우주항공)\n일반 공모가: 36,400~43,300원\n사전신청 시 할인 공급가 적용\n청약 일정: 6월 20~21일\n신청링크: hxxps://poo-ipo.net" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "투자회사 / 증권사", | ||
| "링크 클릭 요청", | ||
| "링크나 파일이 수상해 보였다", | ||
| "긴급하게 행동을 요구했다" | ||
| ], | ||
| additional_description=[ | ||
| "실제 증권사를 언급하며 낮은 공급가로 공모주 청약을 유도", | ||
| "공모주 당첨을 위장해 무상배정과 안내 전화를 강조하여 응답을 유도", | ||
| "실제 기업명을 사용하고, 사전 신청을 통해 할인된 공급가로 청약할 수 있다는 내용으로 유인" | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="허위결제 사기형", | ||
| message_content=[ | ||
| "[Web발신] 아마존 해외결제 354,000원 승인완료. 본인 아닌 경우 즉시 신고 1544-XXXX", | ||
| "[Web발신] 해외 승인 결제 요청: $299.99 / 본인 아닐 경우 http://checkpay.co.kr/verify", | ||
| "[소비자보호원] 본인 아닌 카드 결제건이 발생했습니다. 취소를 원하시면 즉시 확인 http://card-cancel.com" | ||
| ], | ||
| keywords=[ | ||
| "문자", | ||
| "금융기관", | ||
| "링크 클릭 요청", | ||
| "긴급하게 행동을 요구했다" | ||
| ], | ||
| additional_description=[ | ||
| "해외 결제가 본인도 모르게 진행된 것처럼 꾸며져 즉시 신고를 유도", | ||
| "해외 결제건 승인 요청으로 가장해 링크 클릭을 유도", | ||
| "소비자보호 기관을 사칭하여 카드결제를 취소하라며 링크 클릭을 유도" | ||
| ] | ||
| ), | ||
| FraudExample( | ||
| type_name="가족/지인 사칭형", | ||
| message_content=[ | ||
| "엄마 나 폰 액정 깨져서 수리 맡기고 급하게 문자나라로 문자하는 거야\n지금 급한 부탁 있어서 그래 문자 확인하면 답장 줘\n무슨 일이야?\n지금 기프트카드 필요한데 엄마가 먼저 20만원권 3장만 구매해줘", | ||
| "아빠 폰 고장나서 임시로 문자하는 거야 급하게 부탁이 있어서\n보험 신청하려는데 내 폰 인증이 안돼서 아빠 명의로 진행해도 돼?\n민증이랑 카드 앞뒤 사진 보내줘\n알았어 보내줄게\n그리고 계좌번호랑 비번 4자리 필요해", | ||
| "이모 부탁 하나만 드려도 될까요?\n공인인증서 오류로 이체가 안돼서요\n이모가 대신 송금해주실 수 있나요?\n내가 오늘 중으로 바로 갚을게요\n얼마 보내야 해?\n95만원이에요\n계좌번호 알려줘" | ||
| ], | ||
| keywords=[ | ||
| "메신저", | ||
| "가족 / 친구 / 지인", | ||
| "송금 요청", | ||
| "기프트카드 구매 요청", | ||
| "개인정보 입력", | ||
| "신분증", | ||
| "주민등록번호", | ||
| "긴급하게 행동을 요구했다", | ||
| "무리한 정보 요청이 있었다", | ||
| "실제 기관/지인 연락처와 달랐다" | ||
| ], | ||
| additional_description=[ | ||
| "메신저 문자앱을 통해 접근하고 급하게 기프트카드를 사달라고 요청함", | ||
| "폰 고장 핑계로 메신저 접근, 가족 명의 정보 요구 및 보험 명목 사기", | ||
| "공인인증서 오류 핑계로 이체 요청, 계좌 정보 요구 및 긴급한 어투" | ||
| ] | ||
| ) | ||
| ] No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
예시 데이터 확장/정합성 훌륭 — 규칙표 카테고리명과의 일치 여부만 검증 권고
타입 전환(List[str])과 카테고리 확장이 잘 반영되었습니다. 다만 score_rules.txt의 카테고리명과 type_name이 1:1 매칭되는지 자동 검증을 추가하면 안정적입니다.
다음 스크립트는 규칙표의 카테고리명과 예시의 type_name 집합 차이를 출력합니다(없어야 정상):
예상 결과: 두 줄 모두 빈 리스트.
🏁 Script executed:
#!/bin/bash
python - <<'PY'
import re, pathlib, json
rules_path = pathlib.Path("app/prompts/data/score_rules.txt")
ex_path = pathlib.Path("app/prompts/data/fraud_examples.py")
# Extract category names from rules (after CATxx )
rule_names = []
for line in rules_path.read_text(encoding="utf-8").splitlines():
m = re.match(r'^\s*CAT\d+\s+(.+?)\s*$', line)
if m:
rule_names.append(m.group(1).strip())
# Extract type_name strings from FRAUD_EXAMPLES
text = ex_path.read_text(encoding="utf-8")
type_names = re.findall(r'type_name\s*=\s*"([^"]+)"', text)
rs, es = set(rule_names), set(type_names)
print("Rules only (missing in examples):", sorted(rs - es))
print("Examples only (missing in rules):", sorted(es - rs))
PYLength of output: 84
카테고리명 일치 검증 완료 & CI 자동화 제안
제안한 Python 스크립트를 실행한 결과,
app/prompts/data/score_rules.txt의 CATxx 명칭과
app/prompts/data/fraud_examples.py의 type_name이 1:1로 완벽히 일치합니다.
향후 예시나 규칙표가 변경될 때마다 자동으로 매칭 여부를 검사할 수 있도록
해당 스크립트를 CI 워크플로우에 통합하세요.
- 검증 대상 파일
- app/prompts/data/score_rules.txt
- app/prompts/data/fraud_examples.py
- 검증 스크립트
import re, pathlib # …위 review_comment에 제안된 스크립트…
- CI 워크플로우 예시
- 파일: .github/workflows/verify_category_match.yml
- 실행 시점: PR 열림/업데이트 시
🤖 Prompt for AI Agents
In app/prompts/data/fraud_examples.py around lines 4 to 407, the reviewer
verified that type_name values match CATxx entries in
app/prompts/data/score_rules.txt and requests CI automation; add a verification
script (e.g., scripts/verify_category_match.py) that reads both files, extracts
CAT identifiers and type_name values, compares them 1:1 and exits non-zero on
mismatch, then add a GitHub Actions workflow
(.github/workflows/verify_category_match.yml) triggered on pull_request
(opened/synchronize) that runs the script with the repository Python
environment; ensure the script is executable in CI, document the workflow in
CONTRIBUTING or the repo README, and return clear non-zero exit codes so PRs
with mismatches fail the check.
| def _load_rules() -> str: | ||
| rules_path = Path(__file__).parent / "data" / "score_rules.txt" | ||
| return rules_path.read_text(encoding="utf-8") | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
규칙 파일 매 요청 디스크 로드 — 캐싱 및 예외 처리 추가 권장
현재 매 호출마다 파일 I/O가 발생합니다. LRU 캐싱과 파일 없을 때의 명확한 예외로 신뢰성을 높이세요.
해당 범위 내 수정(diff) 및 추가 import:
+from functools import lru_cache
@@
-def _load_rules() -> str:
- rules_path = Path(__file__).parent / "data" / "score_rules.txt"
- return rules_path.read_text(encoding="utf-8")
+@lru_cache(maxsize=1)
+def _load_rules() -> str:
+ rules_path = Path(__file__).parent / "data" / "score_rules.txt"
+ try:
+ return rules_path.read_text(encoding="utf-8")
+ except FileNotFoundError as e:
+ raise RuntimeError(f"규칙 파일을 찾을 수 없습니다: {rules_path}") from e📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def _load_rules() -> str: | |
| rules_path = Path(__file__).parent / "data" / "score_rules.txt" | |
| return rules_path.read_text(encoding="utf-8") | |
| from functools import lru_cache | |
| @lru_cache(maxsize=1) | |
| def _load_rules() -> str: | |
| rules_path = Path(__file__).parent / "data" / "score_rules.txt" | |
| try: | |
| return rules_path.read_text(encoding="utf-8") | |
| except FileNotFoundError as e: | |
| raise RuntimeError(f"규칙 파일을 찾을 수 없습니다: {rules_path}") from e |
🤖 Prompt for AI Agents
In app/prompts/fraud_prompts.py around lines 38 to 41, the _load_rules function
currently performs disk I/O on every call and lacks clear error handling; add an
LRU cache to avoid repeated reads (e.g., import functools and decorate with
@lru_cache(maxsize=1)) and wrap the file read in a try/except that catches
FileNotFoundError (or OSError) and raises a clear exception including the
rules_path string so callers get a meaningful error; ensure you keep utf-8
encoding and add the required import(s) at the top of the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
app/prompts/data/score_rules.txt (3)
131-131: 파일 말미 개행 추가 권장파일 끝에 개행이 없어 도구/플랫폼에 따라 경고가 발생할 수 있습니다. 의미 변화 없이 개행을 추가해 주세요.
- E:10:신분증|주민번호|카드사진|인증번호 + E:10:신분증|주민번호|카드사진|인증번호 +
45-50: 카테고리 간 키워드 교차 혼입 가능성 점검CAT07(범칙금/과태료) 내 E 항목에 ‘관세청/수입세금/통관번호’ 등 세금/통관관련 키워드가 포함되어 있어 CAT10(국세청) 또는 택배 통관 유형과의 경계가 모호해질 수 있습니다. 스코어링이 “카테고리 합산”인지 “최대치 선택”인지에 따라 분류 정확도가 변할 수 있으니, 교차 혼입으로 인한 과대 점수/오분류 가능성을 검토해 주세요.
필요 시, 공통 키워드(세금/통관)를 별도의 “공통 의심 신호” 섹션으로 분리하고 가중치를 낮춰 “보조 신호”로만 작동하게 조정하는 것을 제안드립니다.
1-131: 규칙 데이터 변경에 대한 파싱/스코어링 회귀 테스트 필요본 파일이 프롬프트 시스템에 직접 주입되므로, 파싱/스코어 합산/상한(캡) 적용이 의도대로 동작하는지 회귀 테스트를 권장합니다. 특히:
- 미지정 라벨(G 등) 처리
- 범용 링크 토큰 제거/하향 후 임계치 도달 여부 변화
- 카테고리 헤더 스킵/트리밍
테스트 케이스/픽스처 준비를 원하시면 알려주세요. 예시 문구에 대한 기대 스코어표 생성과 함께 테스트 스캐폴딩을 도와드릴 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/prompts/data/score_rules.txt(1 hunks)
🔇 Additional comments (3)
app/prompts/data/score_rules.txt (3)
33-33: 의도된 철자/표현인지 확인 필요: ‘청접장’, ‘원 도착’, ‘open-kakao’
- 라인 33의 ‘청접장’은 ‘청첩장’의 흔한 오탈자일 수 있으나, 실제 피싱에서 자주 쓰이는 변형 표현이라면 유지가 타당합니다.
- 라인 86의 ‘원 도착’은 금액 알림 패턴(예: “100,000원 도착”)을 겨냥한 표현으로 보입니다. 의도된 패턴이라면 OK입니다.
- 라인 106의 ‘open-kakao’는 ‘open.kakao’/‘open.kakao.com’의 변형 표현으로 보입니다. 실제 사례 수집에 근거한 것인지 확인 부탁드립니다.
의도된 커버리지라면 주석으로 남기거나, 파서/문서에 “변형 스펠링도 포함” 명시를 권장합니다.
Also applies to: 86-86, 106-106
88-88: 파서 호환성 이슈 없음 — G 레이블 허용앱 코드를 살펴본 결과,
app/prompts/fraud_prompts.py의_load_rules()함수는score_rules.txt를 단순히 텍스트로 읽어서 LLM에게 전달할 뿐, A–F만 허용하도록 제한하는 로컬 파싱 로직이 없습니다. 따라서 G 라벨(라인 88, 110)의 존재로 인해 룰이 무시되거나 에러를 일으킬 우려가 없으며, 별도의 수정이 필요하지 않습니다.
1-1: 제안 사항 불필요: _load_rules는 단순 파일 읽기만 수행합니다이 프로젝트에서는
score_rules.txt를 프로그래밍적으로 파싱하지 않고,_load_rules()가 파일 전체 텍스트를 읽어 LLM에 원문 그대로 전달합니다. 따라서 “CATxx …” 헤더를 건너뛰거나 트리밍하는 로더 로직이 존재하지 않으며, 별도의 헤더 주석화 등 제안된 수정은 적용 대상이 아닙니다.Likely an incorrect or invalid review comment.
| C:10:문서번호|공문 발송|사건번호 | ||
| D:10:주민등록번호|주소|성명 | ||
| E:10:명의 도용|압수|보안 강화|검찰소환 | ||
| F:10:bit.ly|han.gl|is.gd|vo.la|me2.do|http|https |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
http/https 범용 토큰은 과도한 오탐 위험 — 일반 링크 토큰 제거/가중치 하향 권고
여러 규칙에서 http|https 같은 범용 토큰이 포함되어 있습니다(예: 라인 7, 29, 123). 이는 거의 모든 정상 메시지에도 존재하는 신호라 오탐을 크게 높입니다. 단축 URL/의심 도메인만 유지하고, 일반 프로토콜 토큰은 제거하거나 가중치를 크게 낮추는 것을 권장합니다.
예시로 아래와 같이 최소 수정안을 제안드립니다(패턴 유지, 오탐 감소 목표).
- F:10:bit.ly|han.gl|is.gd|vo.la|me2.do|http|https
+ F:10:bit.ly|han.gl|is.gd|vo.la|me2.do
- D:20:han.gl|bit.ly|c11.kr|na.to|.apk|is.gd|vo.la|me2.do|http|https
+ D:20:han.gl|bit.ly|c11.kr|na.to|.apk|is.gd|vo.la|me2.do
- C:15:단축URL|의심URL|IP링크|http|https|hxxp|hxxps|bit.ly|han.gl|is.gd|vo.la|me2.do
+ C:15:단축URL|의심URL|IP링크|hxxp|hxxps|bit.ly|han.gl|is.gd|vo.la|me2.do추가로, 일반 링크 토큰을 반드시 유지해야 한다면 가중치를 1~2로 낮춰 다른 강한 신호와의 동시 출현에서만 임계치를 넘기도록 구성하는 것을 추천합니다.
Also applies to: 29-29, 123-123
🤖 Prompt for AI Agents
In app/prompts/data/score_rules.txt around line 7, the rule includes generic
tokens "http|https" which produce high false positives; remove the generic
protocol tokens from this rule (retain only shortener/ suspicious domains like
bit.ly|han.gl|is.gd|vo.la|me2.do) or, if protocol tokens must remain, lower
their scoring weight to 1–2 so they only contribute when combined with stronger
signals; apply the same change to the other rules referenced (lines 29 and 123)
to reduce over-detection.
| A:30:재택근무|단기 알바|쉬운 업무|문자 알바 | ||
| B:15:시급 3만원|고수익 보장|일 10만 이상|당일 정산 | ||
| C:10:누구나 가능|자격무관|당일 지급 | ||
| D:15:오픈채팅|카톡 추가|링크 클릭|접속하세요 | ||
| E:10:open.kakao.com|bit.ly|t.me|reurl.kr|han.gl|is.gd|http|https | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
오퍼 유도형(알바/투자) 규칙의 강한 미끼 단어 가중치 재점검
- CAT11(B: “시급 3만원/고수익 보장/당일 정산”)과 CAT15(A/D/F/G: “고수익/원금보장/선착순/링크 클릭/지금 가입/마지막 기회/실시간 인증” 등)은 정상 마케팅 문구와도 일부 겹칩니다.
- 일반 링크 토큰과 결합 시 오탐 증가가 우려됩니다.
권장:
- 강한 상업/미끼 신호 단어의 가중치를 소폭 하향하고,
- 단축 URL/오픈채팅/메신저 초대 링크와의 동시 출현 시 추가 가중(AND 조건 가중)을 적용.
현재 데이터 파일만으로는 AND 로직을 표현하기 어렵다면, 프롬프트/파서 레벨에서 “동시 매칭 보너스”를 구현하는 방향을 검토해 주세요.
Also applies to: 103-111
🤖 Prompt for AI Agents
In app/prompts/data/score_rules.txt around lines 75-80 (also apply same change
to lines 103-111), the weight for strong bait/commercial tokens is too high and
is causing false positives when combined with generic marketing text and links;
reduce the numeric weights for those categories slightly (e.g., lower B/C/D/E
group weights by ~20-30% or adjust the specific category labels referenced in
the file) and introduce an AND-condition bonus when short
URLs/openchat/messenger-invite tokens co-occur with bait tokens: implement a
small additional positive score in the scoring logic (not the static token list)
when both a bait category token and a short-URL/openchat token are matched
together; if the flat data file cannot represent AND logic, implement the
simultaneous-match bonus at the prompt/parser layer that consumes this file so
co-occurrence yields extra weight while individual token weights remain reduced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/prompts/data/fraud_examples.py (2)
82-82: 일관성 있는 할당 연산자 사용 권장Line 82에서
type_name = "돌잔치 초대장형"처럼=주변에 공백을 사용했으나, 다른 모든 예시에서는type_name="기관 사칭형"처럼 공백 없이 사용하고 있습니다.일관성을 위해 다음과 같이 수정하는 것을 권장합니다:
- type_name = "돌잔치 초대장형", + type_name="돌잔치 초대장형",
83-87: 할당 연산자 일관성 문제Line 83-87에서도 동일한 공백 사용 패턴이 발견됩니다.
- message_content = [ + message_content=[- keywords = [ + keywords=[- additional_description = [ + additional_description=[
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/prompts/data/fraud_examples.py(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/prompts/data/fraud_examples.py (4)
app/prompts/fraud_example.py (1)
FraudExample(4-8)app/prompts/fraud_prompts.py (2)
build_example_lines(53-67)get_fraud_detection_prompt(5-51)app/models/fraud_request.py (1)
FraudRequest(5-9)app/models/fraud_response.py (1)
FraudResponse(4-8)
🔇 Additional comments (4)
app/prompts/data/fraud_examples.py (4)
2-2: Import 경로 수정 완료이전에 지적된 순환 참조 문제가 해결되었습니다.
FraudExample을 올바른 모듈에서 가져오고 있습니다.
4-407: 예시 데이터 구조 개선 및 확장 완료데이터 모델이
List[str]기반으로 성공적으로 전환되었고, 18개 카테고리로 확장되어 다양한 사기 유형을 포괄하고 있습니다. 각 예시마다 3개의 메시지 블록과 상세한 설명, 키워드가 체계적으로 구성되어 있어 GPT 프롬프트 튜닝에 효과적입니다.특히 다음 개선사항들이 인상적입니다:
- 실제 사기 패턴을 반영한 현실적인 메시지 내용
- 카테고리별 특징적인 키워드 분류
- 사용자 심리를 고려한 상황별 설명
230-250: 알바/부업 사기형 예시의 현실성 검증Line 231에서 "하루 20분 작업, 일당 최대 14만원"이라는 조건이 제시되어 있습니다. 이는 시간당 42만원에 해당하는 비현실적인 수준으로, 실제 사기 사례보다 과장되어 있어 보입니다.
실제 알바/부업 사기 사례의 급여 제안 수준을 확인하여 더 현실적인 범위로 조정하는 것을 권장합니다. 예를 들어:
- "[Web발신] 안녕하세요! 당사 유통사에서 상품 검수 및 단순 작업을 도와주실 분을 모집합니다. 하루 20분 작업, 일당 최대 14만원 지급. 카카오톡 open.kakao.com/abcd 로 문의주세요.", + "[Web발신] 안녕하세요! 당사 유통사에서 상품 검수 및 단순 작업을 도와주실 분을 모집합니다. 하루 2-3시간 작업, 일당 5-8만원 지급. 카카오톡 open.kakao.com/abcd 로 문의주세요.",
4-407: 카테고리 매핑 일관성 확인 완료
score_rules.txt와fraud_examples.py모두 18개 카테고리가 일치하며, 누락 혹은 추가 항목이 없습니다.
이제 해당 부분은 문제없이 유지하셔도 됩니다.
| "[Web발신]\n(광고) IPO 공모 청약 신청\n24년 첫 코스피 상장 APR에이피알(KOSPI)\n상장일정: 2024년 2월 26일\n주관사: 신한투자증권\n공모가: 250,000원 공급가: 70,000원\n청약 담당자: 010-8014-XXXX\n빠른회신 부탁드립니다.", | ||
| "[Web발신]\n축하드립니다. 공모주 청약 당첨 안내\n두산로보틱스 10주 무상배정\n상장일: 2023년 10월 2일\n주관사: 미래에셋증권, 한국투자증권\n공모가: 25,000원 ~ 28,000원\n당첨자에 한해 순차적으로 안내 전화 드리겠습니다.", | ||
| "[Web발신]\n청약 가능한 공모주 안내\n이노스페이스 (발사체 제작, 우주항공)\n일반 공모가: 36,400~43,300원\n사전신청 시 할인 공급가 적용\n청약 일정: 6월 20~21일\n신청링크: hxxps://poo-ipo.net" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
공모주 사기 예시의 정확성 검증 필요
Line 346-348에서 "APR에이피알(KOSPI)" 및 "두산로보틱스" 등 실제 기업명과 구체적인 상장 일정이 언급되어 있습니다. 이러한 실제 기업 정보를 사용하는 것이 적절한지 검토가 필요합니다.
다음 사항들을 확인해보세요:
- 실제 기업명 사용에 대한 법적 검토 필요성
- 가상의 기업명으로 대체 가능성
- 상장 일정 등 구체적인 정보의 정확성
🏁 Script executed:
#!/bin/bash
# 공모주 관련 실제 기업명 사용 현황 확인
echo "실제 기업명이 포함된 라인들:"
rg -n "(APR에이피알|두산로보틱스|이노스페이스)" app/prompts/data/fraud_examples.pyLength of output: 594
공모주 사기 예시의 실제 기업명 교체 및 일정 확인 필요
실제 기업명("APR에이피알", "두산로보틱스", "이노스페이스")과 구체적 상장 일정·공모가 정보는 법적·윤리적 이슈를 야기할 수 있으므로, 모두 가상의 명칭 및 임의 생성한 스케줄로 대체해야 합니다.
• 수정 대상
- 파일: app/prompts/data/fraud_examples.py
- 라인: 346–348
• 권장 조치
- 실제 기업명을 “회사A”, “회사B”, “회사C” 등의 가명으로 교체
- 상장 일정, 공모가, 주관사 등 수치는 랜덤 혹은 샘플용으로 재생성
- 변경 후 예시가 사기 시나리오 학습용임을 명확히 주석으로 표기
예시 diff:
- "[Web발신]\n(광고) IPO 공모 청약 신청\n24년 첫 코스피 상장 APR에이피알(KOSPI)\n상장일정: 2024년 2월 26일\n…"
+ "[Web발신]\n(광고) IPO 공모 청약 신청\n24년 첫 코스피 상장 회사A(KOSPI)\n상장일정: 2024년 3월 15일\n…"Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In app/prompts/data/fraud_examples.py around lines 346–348, the examples contain
real company names and specific listing details; replace the real names
("APR에이피알", "두산로보틱스", "이노스페이스") with neutral placeholders like "회사A", "회사B",
"회사C", scramble or randomize dates/prices/underwriters to non-identifying sample
values, sanitize phone numbers and URLs (keep hxxps:// form), and add a clear
comment above the examples stating these entries are fictional test/simulation
data for fraud-detection training only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수고하셨습니다! 다음에 리펙토링할때 enum 으로 사기 유형 정의해도 좋을 것 같네용
저도 할 때 예시 데이터 txt 파일로 할걸 그랫네여 ~ㅠㅠ 훨씬 깔끔하네여 ~ㅠㅠ 이 부분도 리펙할때 고려해보면 좋을 것 같습니다!!
💻 Related Issue
🚀 Work Description
사기 유형명 통일 후, 점수화 로직 추가하였습니다. gpt 내부에 점수 환산 기준 넣어서 판단하도록 했는데 조금 더 손 봐야할 것 같습니다.
🙇🏻♀️ To Reviewer
➕ Next
Summary by CodeRabbit
New Features
Refactor
Chores