입금 매칭 라우팅 개선으로 은행 통보 미매칭 70% 복구
목차
파트너 입금 매칭 파이프라인은 SMS/푸시로 들어온 은행 통보를 파싱해 은행별 핸들러로 넘기는 구조다. 채널마다 발신 번호 포맷이 다르고, 은행마다 본문 템플릿이 미묘하게 다르기 때문에 라우팅 레이어가 핵심이다. 이게 제대로 안 되면 파서 단에서 아무리 정교하게 슬롯을 뽑아봤자 엉뚱한 핸들러한테 메시지가 가거나, 아예 폐기된다.
문제는 한 시중은행이 발신 번호 포맷을 조용히 바꾼 시점부터 드러났다. 갑자기 바뀐 게 아니라 슬금슬금 내려가는 그래프였는데, 운영 알람은 "미매칭 누적 N건" 경고만 뱉고 있었다. 처음엔 파서 단 버그인 줄 알고 파싱 로직을 뒤졌다. 한참 삽질하다가 결국 핸들러 선택 단계에서 이미 잘못 분기되고 있다는 걸 발견했음. 라우팅 단 문제였던 거다.
기존 라우팅 룰은 헤더 패턴 한 줄에만 의존하는 구조였다. 발신 번호가 정확히 맞아야 핸들러가 잡히고, 조금이라도 다르면 폐기. 통신사가 표기 방식을 손대거나, 은행 측에서 캠페인 문구를 앞에 끼우거나, 이모지가 들어오면 그대로 빠져나감. 이 구조가 얼마나 취약한 건지 이번에 다시 실감했다.
무엇을 바꿨나
변경은 네 군데에서 동시에 들어갔다.
핸들러 레지스트리부터. 단일 매칭에서 우선순위 + 후보군 다중 매칭으로 바꿨다. 1순위 후보의 confidence가 임계값 아래면 차순위까지 확인하는 방식이다. 후보가 아예 없으면 본문 키워드 스캔으로 넘어감.
파서 유틸은 발신 번호 외에 본문 키워드(은행명, 계좌 마스킹 패턴)를 보조 시그널로 가산하도록 손봤다. 신호 하나에만 의존하는 단점을 줄이려는 의도였는데, 실제로 번호가 바뀌어도 본문 패턴이 살아있으면 라우팅이 붙더라.
추상 핸들러 레벨에서는 매칭 실패 시 즉시 폐기하지 않고 회복 큐에 적재하게 했다. 폐기가 기본 동작이면 알람이 울릴 때 이미 복구 불가 상태가 되는 경우가 많다. 큐에 남겨두면 최소한 재처리 여지가 생긴다.
해당 은행 핸들러는 본문에 끼어드는 광고성 문구와 이모지를 전처리로 제거하고 슬롯을 추출하게 수정했다.
변경 전후 비교를 정리하면,
| 항목 | 이전 | 이후 |
|---|---|---|
| 라우팅 기준 | 발신 번호 1개 | 우선순위 + 본문 키워드 |
| 실패 처리 | 폐기 + 알람 | 회복 큐 → AI 슬롯 추출 |
| 임계값 | 없음 | confidence 0.85 미만 사람 검토 |
| 미매칭 일평균 | ~100건 | ~30건 |
핸들러 선택 흐름을 의사코드로 쓰면 이렇게 된다.
selectHandler(msg):
candidates = registry.matchAll(msg.header)
if candidates.empty:
candidates = scanByBodyKeywords(msg.body)
pick = candidates.sortBy(priority, score).first
if pick is null:
enqueue(recovery, msg)
return
if pick.score < THRESHOLD:
enqueue(human_review, msg)
return
handle(pick, msg)
단일 if-else 분기에서 다단계 낙하산 구조가 됐다. 이전엔 분기가 "맞음 / 폐기" 두 가지였는데, 이제는 "확실히 맞음 / 후보 탐색 / 회복 큐 / 사람 검토"로 늘었다. 코드가 복잡해 보이지만 운영 관점에선 훨씬 낫다. 에러 분기를 안 짜두면 결국 새벽에 깨는 게 나이기 때문에.
AI 복구 단계가 의외로 잘 붙음
룰 레이어가 놓친 통보를 LLM이 받아서 금액, 잔액, 계좌, 시각 슬롯을 추출하게 했다. 미매칭 건 중 70%가 이 단계에서 복구됐음. 예상보다 높은 수치였다.
다만 완전 자동화는 아직 아니다. LLM이 환각으로 엉뚱한 파트너 계좌에 금액을 붙이는 케이스가 한두 건 나왔다. 이게 제일 무서운 케이스다. 자동화가 자신감 있게 틀리는 거. 그래서 confidence 임계값 0.85 미만이면 무조건 사람 큐로 빠진다. AI가 "확신한다"고 해도 기준 이하면 못 넘어가게 막아뒀다.
결국 현재 구조는 이렇다.
- 룰 매칭이 1차 방어. 빠르고 결정론적이다.
- AI 복구가 안전망. 룰이 놓친 걸 잡아주는 역할.
- 사람 검토가 마지막 관문. AI가 자신 없는 건 넘기지 않는다.
단일 룰보다 레이어가 하나 더 끼었지만, 운영 피로는 오히려 줄었다. 회복 큐 도입 이후로 새벽 호출 빈도가 체감상 절반 아래로 내려갔음.
회고
이번에 제일 크게 남은 건 은행 통보 포맷은 "절대 안 바뀜"이 아니라 "조용히 바뀐다"는 거다. 공지 없이 발신 번호 포맷이 바뀌고, 캠페인 시즌엔 본문에 문구가 끼어든다. 모니터링을 단순 카운트가 아니라 매칭률 추세선까지 보게 바꾼 이유다. 숫자가 뜬 시점이 아니라 기울기가 꺾인 시점을 잡아야 한다.
라우팅 레이어 설계에서 배운 점을 정리하면,
- 단일 시그널 의존은 그 시그널이 바뀌는 순간 전체가 깨진다. 보조 시그널을 처음부터 넣어두는 게 낫다.
- confidence 기반 분기를 처음부터 설계하면 나중에 사람 검토 큐나 AI 단계를 끼워 넣기가 훨씬 쉽다. 이진 분기로 시작하면 나중에 뜯어고치기 귀찮아진다.
- 폐기보다 큐. 폐기는 복구 기회를 없애지만, 큐는 재처리 여지를 남긴다. 메시지가 금융 도메인이면 특히 기본 동작을 폐기로 두면 안 된다.
- 룰 + AI 하이브리드는 관리 비용이 생각보다 적다. AI가 잡는 케이스는 대부분 룰이 다루기 애매한 edge case라, 룰셋 복잡도가 크게 올라가지 않는다. 오히려 룰을 단순하게 유지할 수 있게 됐다.
지금 가장 불안한 부분은 AI 복구 단계의 슬롯 추출 정확도 모니터링이 아직 수동이라는 거다. confidence 점수가 높다고 항상 맞는 건 아니기 때문에, 주기적으로 샘플을 뽑아서 실제 매칭 결과와 대조하는 게 필요하다. 이 부분은 다음 스프린트에서 자동화할 생각이다.
댓글 0
첫 댓글 달아줘.