Skip to content

Commit d50b898

Browse files
authored
Merge pull request #11 from Block-Guard/feat/#10/gpt-prompt-tuning
[Feat] 점수화 로직 추가
2 parents 4040389 + c313c8b commit d50b898

File tree

7 files changed

+579
-58
lines changed

7 files changed

+579
-58
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,4 @@ cython_debug/
204204
# Marimo
205205
marimo/_static/
206206
marimo/_lsp/
207-
__marimo__/
207+
__marimo__/

app/models/fraud_response.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ class FraudResponse(BaseModel):
55
estimatedFraudType: str # 분류된 사기 유형
66
keywords: List[str] = Field(..., min_items=1, max_items=3, description="주요 위험 키워드 (최대 3개)")
77
explanation: str # 해당 유형으로 판단한 이유
8-
score: float = Field(..., ge=0, le=100, description="위험도(0~100)")
8+
score: float = Field(..., ge=0, le=70, description="위험도(0~70)")

app/prompts/data/fraud_examples.py

Lines changed: 398 additions & 19 deletions
Large diffs are not rendered by default.

app/prompts/data/score_rules.txt

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
CAT01 기관 사칭형
2+
A:30:검찰청|경찰서|금융감독원|형사기동대
3+
B:10:사건 송치|수사 협조|조사 회신
4+
C:10:문서번호|공문 발송|사건번호
5+
D:10:주민등록번호|주소|성명
6+
E:10:명의 도용|압수|보안 강화|검찰소환
7+
F:10:bit.ly|han.gl|is.gd|vo.la|me2.do|http|https
8+
9+
CAT02 대출 사기형
10+
A:30:은행|농협|신한저축|금융복지정책
11+
B:15:대출진행|대환대출|생계자금|정부지원상품
12+
C:10:무직자 가능|신용등급 무관|무서류|저금리
13+
D:10:신분증|등본|통장사본|재직증명서
14+
E:10:신청서.zip|앱설치|.apk|hxxp
15+
F:5:상담신청|접수완료|한도조회|대표번호
16+
17+
CAT03 카드사 사칭형
18+
A:30:KB국민카드|현대카드|롯데카드|신한카드|카드
19+
B:15:카드 신청완료|카드 발급완료|개통완료
20+
C:15:본인 신청 아니면 신고|본인 아닐 경우 문의|본인 아님 신고
21+
D:10:개인정보 유출|승인 거절|이상 거래 감지
22+
E:5:상담접수|즉시 문의|콜센터|취소 요청
23+
F:5:Web발신|승인불가|개통내용 아닌 경우
24+
25+
CAT04 돌잔치 초대장형
26+
A:35:돌잔치|첫돌|아들 돌잔치|축하해주세요|많이많이 축하
27+
B:20:모바일 초대장|초대장을 보내드렸습니다|참석하여 주시기 바랍니다
28+
C:5:축복해주세요|모두 축하
29+
D:20:oa.to|vo.to|pa.to|pro.ps|.apk|bit.ly|han.gl|is.gd|http|https
30+
31+
CAT05 모바일 청첩장형
32+
A:35:결혼식|재혼|웨딩홀|결혼합니다|사랑의 결실
33+
B:20:모바일청첩장|청첩장 도착|청접장|Wedding Invitation
34+
C:5:축하해주세요|참석 부탁|인연으로 하나됩니다
35+
D:20:han.gl|bit.ly|c11.kr|na.to|.apk|is.gd|vo.la|me2.do|http|https
36+
37+
CAT06 부고문자형
38+
A:40:별세|소천|사망하셨습니다|부고|訃告
39+
B:10:아버님|어머님|부모님|부친|모친
40+
C:10:삼가 고인의 명복|안타깝게도|불행하게도
41+
D:10:장례식장|빈소|오시는 길
42+
E:10:buly.kr|vo.la|iplogger.com|xgo.kr|gg.gg|bit.ly|han.gl|is.gd|http|https
43+
44+
CAT07 범칙금/과태료 부과형
45+
A:30:도로교통법 위반|정지선 위반|어린이 보호구역
46+
B:15:과태료 부과|벌점 통지서|고지서 발송|가압류|장기연체대상자
47+
C:10:민원24|신고 접수|단속되어|민원내용 확인
48+
D:10:쓰레기 무단투기|음식물분리수거 위반|층간소음행위
49+
E:10:관세청|수입세금|관세징수과|통관번호|세금 미납 안내
50+
F:5:paso.mobilecar.pe.kr|goosmsi.com|homes|mobilecar|bit.ly|han.gl|is.gd|http|https
51+
52+
CAT08 건강보험공단 사칭형
53+
A:35:국민건강보험|건강보험공단|건강지키미
54+
B:10:건강검진 통지서|건강검사 통보문|종합건강검진
55+
C:15:환급금 신청마감|보험료 환급금|건강보험료 미납
56+
D:10:확인바랍니다|조회하기|신청요망
57+
E:10:dokdo.in|nhisis.xyz|cloud|nhis|nhi|bit.ly|han.gl|is.gd|http|https
58+
59+
CAT09 경찰 출석 요구형
60+
A:30:검찰청|경찰서|법원|국정원
61+
B:10:출석요구서|소환장|사건조회번호
62+
C:10:형사소송건|민사소송|재산몰수 통지서
63+
D:10:긴급출석요구|발부되었습니다|즉시 확인
64+
E:10:사건번호|고단
65+
F:10:sc-police.co.kr|xuto.tk|is.gd|bit.ly|han.gl|http|https
66+
67+
CAT10 국세청 사칭형
68+
A:35:국세청|홈택스|국민연금공단|납세자연맹
69+
B:10:종합소득세|연말정산|세금 미납|세금 환급금
70+
C:15:환급 대상자|환급금 수령|금액 확인|환급 내역 조회
71+
D:10:신청하세요|수령 확인|조회 및 납부|통지서 확인
72+
E:10:han.gl|goo.gl|me2.do|hometax.go.kr|bit.ly|is.gd|http|https
73+
74+
CAT11 알바/부업 사기형
75+
A:30:재택근무|단기 알바|쉬운 업무|문자 알바
76+
B:15:시급 3만원|고수익 보장|일 10만 이상|당일 정산
77+
C:10:누구나 가능|자격무관|당일 지급
78+
D:15:오픈채팅|카톡 추가|링크 클릭|접속하세요
79+
E:10:open.kakao.com|bit.ly|t.me|reurl.kr|han.gl|is.gd|http|https
80+
81+
CAT12 정부지원금 위장형
82+
A:30:재난지원금|방역지원금|민생안정지원금
83+
B:10:국세청|고용노동부|중소벤처기업부
84+
C:10:신청마감|신속지급|신청하기 클릭
85+
D:10:신분증 사본|본인 확인|제출서류
86+
E:10:예산소진|원 도착|예산 초과 시 부지급
87+
F:5:bit.ly|han.gl|is.gd|me2.do|vo.la|http|https
88+
G:5:민생 회복|꼭 확인해주세요|확인 안 될 경우 미지급
89+
90+
CAT13 택배 사기형
91+
A:30:택배|쿠팡|택배기사
92+
B:15:주소 오류|주소 불일치|배송지 오류|주소 확인 요망
93+
C:15:배송 지연|배송 실패|미수령 택배|통관번호 오류
94+
D:10:bit.ly|han.gl|is.gd|vo.la|me2.do|http|https
95+
E:10:앱 다운로드|배송조회 바로가기|주소 입력 페이지
96+
97+
CAT14 가상화폐 사기형
98+
A:30:소각 예정|자산 복구|소멸 예정|휴면계정 소각
99+
B:20:해외IP 로그인|로그인 감지|수상한 기기|기기등록 후 사용|본인이 아닐 경우|로그인 알림
100+
C:15:ETH|BTC|이더리움|비트코인|테더|잔여 ETH
101+
D:15:line.me|bit.ly|me2.kr|카톡|상담 바로가기|t.me|http|https
102+
103+
CAT15 주식투자 사기형
104+
A:35:고수익|수익보장|원금보장|손실보상
105+
B:15:에넥스|덕신하우징|2차전지|바이오|유진테크놀로지
106+
C:5:bit.ly|t.me|open-kakao|open.kakao|han.gl|reurl.kr|is.gd|http|https
107+
D:5:쿠폰 증정|단타 무료방|무료혜택|선착순 모집
108+
E:10:단타|매수|매도|수급|테마|상장특별공급|종목추천
109+
F:5:지금 가입|링크 클릭|바로 입장|채팅방 이동|666
110+
G:5:마지막 기회|안정수익|실시간 인증|장마감공개
111+
112+
CAT16 청약 공모주 사기형
113+
A:30:공모주|청약|상장예정|IPO|무료배정
114+
B:15:미래에셋|신한증권|하나증권|증권사|청약담당자
115+
C:15:할인공급가|수익률|급등|이익률
116+
D:10:문자상담|상담전화|빠른회신|순차연락
117+
E:5:할인혜택|무상입고|무료거부|종목확인|IR안내
118+
F:5:두산로보틱스|이노스페이스|APR|에이피알
119+
120+
CAT17 허위결제 사기형
121+
A:35:결제완료|승인요청|인증번호|해외승인|본인아님
122+
B:15:신용카드|휴대폰결제|이니시스|모빌리언스|위메프|아마존
123+
C:15:단축URL|의심URL|IP링크|http|https|hxxp|hxxps|bit.ly|han.gl|is.gd|vo.la|me2.do
124+
D:15:고객센터|소비자보호|문의전화|신고요청
125+
126+
CAT18 가족/지인 사칭형
127+
A:30:가족|친구|지인
128+
B:15:폰고장|액정깨짐|임시폰|문자접속
129+
C:15:급해|갚을게|부탁|수리중|지금바로
130+
D:10:송금|계좌이체|기프트카드|입금요청
131+
E:10:신분증|주민번호|카드사진|인증번호

app/prompts/fraud_example.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
class FraudExample(BaseModel):
55
type_name: str
6-
message_content: str
6+
message_content: List[str]
77
keywords: List[str]
8-
additional_description: str
9-
image_content: str
8+
additional_description: List[str]

app/prompts/fraud_prompts.py

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,58 @@
11
from typing import List, Dict
2+
from pathlib import Path
23
from app.prompts.fraud_example import FraudExample
34
from app.prompts.data.fraud_examples import FRAUD_EXAMPLES
45

6+
SYSTEM_PROMPT = """
7+
너는 보이스피싱 사기 탐지 전문가다.
8+
다음 규칙표를 사용해 입력 텍스트를 분석하고,
9+
1) 사기 유형(카테고리) 선택
10+
2) 핵심 키워드(최소1~최대3) 추출
11+
3) 점수는 최소 0점에서 최대 70점
12+
13+
[점수 규칙]
14+
- 규칙표는 "카테고리ID 카테고리명" 한 줄 + 그 아래 여러 룰 라인으로 구성된다.
15+
- 룰 라인 형식: "룰ID:배점:키워드1|키워드2|...".
16+
- 텍스트에 해당 룰의 키워드 중 1개라도 의미/표현상 매칭되면 그 룰의 배점을 가산(룰별 최대 1회).
17+
- 유저가 입력한 'keywords'에서 점수 계산을 하고, 'additionalDescription'과 'imageContent'를 참고하여 점수 계산.
18+
- 키워드는 의미가 같으면 띄어쓰기/대소문자/오타 등과 동의어 허용.
19+
- 동일 카테고리에서 여러 룰이 적중할 수 있으며, 합산 후 카테고리 점수는 70을 초과하지 않는다(상한 70점).
20+
- 최종적으로 가장 점수가 높은 카테고리를 estimatedFraudType으로 선택.
21+
- 동점이면 적중 룰 개수가 더 많은 카테고리를 선택. 그래도 동률이면 의미상 더 근접한 쪽.
22+
- 링크/단축URL은 http/https, bit.ly/han.gl/is.gd/vo.la/me2.do 등도 매칭으로 본다(표기 변형 허용).
23+
24+
출력은 반드시 valid JSON 객체로만 응답. 오직 JSON만 출력.
25+
코드블록(```), 주석, 추가 텍스트, 설명 모두 금지.
26+
'estimatedFraudType' 에는 오로지 카테고리명만 넣을 것.
27+
아래는 응답 예시.
28+
{
29+
"estimatedFraudType": "<카테고리명>",
30+
"keywords": ["<키워드1>", "<키워드2>", "<키워드3>"],
31+
"explanation": "<왜 이 유형이고 어떤 이유로 판단하였는지 간결히 설명>",
32+
"score": <0~70의 실수값>
33+
}
34+
35+
""".strip()
36+
37+
38+
def _load_rules() -> str:
39+
rules_path = Path(__file__).parent / "data" / "score_rules.txt"
40+
return rules_path.read_text(encoding="utf-8")
41+
542
def get_fraud_detection_prompt(
643
message_content: str,
744
additional_description: str,
845
keywords: List[str],
946
image_content: str,
1047
examples: List[FraudExample] = FRAUD_EXAMPLES
1148
) -> List[Dict[str, str]]:
12-
13-
system = {
14-
"role": "system",
15-
"content": (
16-
"당신은 사기 탐지 어시스턴트입니다. "
17-
"입력된 텍스트를 반드시 미리 정의된 사기 유형 중 하나로 분류하고, "
18-
"최소 1개에서 최대 3개의 주요 위험 키워드를 추출하며, 그 이유를 설명하고, "
19-
"위험 점수(0–100%)를 제공해야 합니다.\n"
20-
"출력은 반드시 valid JSON 객체로만 응답하세요. 아래는 응답 예시입니다:\n"
21-
"{\n"
22-
" \"estimatedFraudType\": \"복권 사기\",\n"
23-
" \"keywords\": [\"키워드1\", \"키워드2\"],\n"
24-
" \"explanation\": \"...\",\n"
25-
" \"score\": 92.4\n"
26-
"}\n"
27-
)
28-
}
49+
rules_text = _load_rules()
50+
example_text = "".join(build_example_lines(examples))
2951

30-
example_lines = build_example_lines(examples)
31-
assistant_content = "".join(example_lines)
32-
assistant_content += (
33-
"이제 아래 입력을 같은 형식으로 분류하세요:\n"
34-
)
3552

36-
assistant = {
37-
"role": "assistant",
38-
"content": assistant_content
53+
system = {
54+
"role": "system",
55+
"content": f"{SYSTEM_PROMPT}\n\n[규칙표]\n{rules_text}\n\n[예시]\n{example_text}"
3956
}
4057

4158
user = {
@@ -48,7 +65,8 @@ def get_fraud_detection_prompt(
4865
)
4966
}
5067

51-
return [system, assistant, user]
68+
return [system, user]
69+
5270

5371
def build_example_lines(examples):
5472
example_lines = ["사기 유형 및 예시:\n"]
@@ -57,11 +75,5 @@ def build_example_lines(examples):
5775
example_lines.append(f" messageContent: '{ex.message_content}'\n")
5876
example_lines.append(f" additionalDescription: '{ex.additional_description}'\n")
5977
example_lines.append(f" keywords: '{ex.keywords}'\n")
60-
example_lines.append(f" imageContent: '{ex.image_content}'\n")
61-
example_lines.append(" 출력 JSON 예시:\n")
62-
example_lines.append(
63-
f" {{\"estimatedFraudType\": \"{ex.type_name}\", "
64-
f"\"keywords\": [...], \"explanation\": \"...\", \"score\": ...}}\n\n"
65-
)
6678

67-
return example_lines
79+
return example_lines

app/services/gpt_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ async def call_gpt(request: FraudRequest):
2222
response = client.responses.create(
2323
model="gpt-4o-mini",
2424
input = messages,
25-
temperature = 0.5, # 생성된 텍스트의 무작위성을 결정
25+
temperature = 0.1, # 생성된 텍스트의 무작위성을 결정
2626
max_output_tokens = 200
2727
)
2828
logger.info(f"GPT API 호출 성공: {response}")

0 commit comments

Comments
 (0)