「北広島市」が広島県ではない判定:文字列一致から新しい AI モデル Jev に置き換えた記録
요약
본 글은 웹사이트에 수집된 사이버 보안 기사의 도도부현 분류 시스템을 개선한 사례를 다룹니다. 개발자는 일반적인 LLM 대신 TypeSafe AI의 'System One' 모델인 Jev를 도입하여, 정형화된 데이터 형태로 정확하게 지역 정보를 판별하는 방법을 제시했습니다.
핵심 포인트
- Jev는 선택지 기반으로 답변이 정형화되어 프로그램 연동에 용이합니다.
- 기존 문자열 일치 방식의 한계를 극복하고 높은 정확도를 달성했습니다.
- 조직명이나 간접적인 정보만으로도 본사 소재지를 추정하는 것이 가능해졌습니다.
개인적으로 사이버 보안 관련 뉴스 사이트에서 기사를 모으는 웹사이트를 제작하고 있는데, 여기에 Jev를 도입해 본 기록입니다.
간단하게 만든 서비스에 대한 설명입니다.
- 사이버 보안 정보 수집용 웹 애플리케이션
- 매일 3시간마다 각 사이트에서 신규 기사를 가져와 DB에 저장합니다.
- 개요와 원본 기사 링크를 대시보드에 표시합니다.
- 개요를 통해 어떤 현에서 사고가 발생했는지 라벨링하고, 일본 지도 위에 히트맵으로 표시합니다.
- 이 히트맵은 시각적으로 흥미로울 것 같다는 이유로 만든 기능이며, 도도부현별 발생 건수의 정확한 경향을 나타내는 것은 아닙니다.
도도부현 분류는 기존에는 문자열 일치(string matching) 방식으로 처리했지만, Jev를 사용해 보기로 했습니다. 현재 방식에 대한 불만이라기보다는 Jev를 서비스에 사용해 보고 싶다는 동기가 더 컸습니다.
Jev는 TypeSafe AI가 제공하는 'System One'이라는 AI 모델 중 하나입니다. 일반적인 LLM(Large Language Model)처럼 문장을 생성하는 것이 아니라, 개발자가 준비한 선택지 중에서 답을 골라 확률과 함께 반환해 줍니다.
- 질문의 유형(Primitive)은 3가지가 있습니다: Choice (선택지 중 1개 선택), Noul (예/아니오), Score (단계 평가)
- 답변이 정형화된 데이터 형태로 돌아오기 때문에 프로그램에서 바로 사용할 수 있습니다.
- 공식 문서: https://docs.typesafe.ai/
이번에는 47도도부현과 '해당 없음' 중 하나를 선택하게 하고 싶었기 때문에 Choice를 사용했습니다.
- 도입을 결정하기 전에 다음과 같은 간단한 스크립트로 테스트했습니다.
from typesafe_sdk import Choice, TypeSafeClient
import argparse
def build_parser():
...
--message
인수에 판별하고 싶은 메시지를 넣어 실행하면 결과 도도부현이 출력됩니다.
- 제작 과정에서 다음 기사의 내용이 큰 도움이 되었습니다.
- 기사에 따르면 모든 패턴을 포괄할 수 없을 때는 탈출구(escape route)를 만드는 것이 좋다고 했기 때문에 47개 도도부현 + '해당 없음'의 선택지를 마련했습니다.
단순한 문자열 일치 방식으로는 '도쿄도' 안에 있는 '교토'와도 일치해 버립니다 (이전 방식에서는 정규 표현식(regex)으로 개별적으로 대처했었습니다). Jev를 사용하면 이러한 개별적인 조치 없이 정확하게 판별할 수 있었습니다.
$ python jev-test.py --message
(1달러를 150엔으로 환산하면 약 0.004엔입니다。)
테스트에서 충분한 효과를 체감했기 때문에 실제로 서비스에서 집계된 기사 데이터(200건)를 사용하여 Jev와 기존 방식(문자열 일치)을 비교했습니다.
- 대상: 최근 200건의 기사 (취약점 정보 데이터베이스인 JVN의 기사는 도도부현과 거의 관련이 없으므로 제외)
- 프롬프트: 사전 검증에서 발견된 인명 오판(테스트 패턴 4)에 대응하기 위해 '지명과 같은 문자를 포함하는 인명은 판단 자료로 삼지 않는다'는 내용을 추가했습니다.
- 정확성 여부는 차이가 나는 기사를 한 건씩 눈으로 확인하여 판단했습니다.
| 판정 | 건수 |
|---|---|
| 양쪽 모두 '해당 없음' | 163 |
| ... |
차이점은 전 건에 걸쳐 Jev가 옳거나 타당했고, 기존 방식이 우세했던 경우는 0건이었습니다.
- Jev만 (9건): 기존 방식의 누락을 발견했습니다.
- 사전에 없는 지명/표기: 탓츠카 시립 병원 → 효고현, 코프 야마구치 → 야마구치현, JA 엔슈 무사키 → 시즈오카현
- 조직명으로부터 본사 소재지를 추정: 게이오 전철・게이오 플라자 호텔 → 도쿄도, 니치대 → 도쿄도, 간사이 가쿠인 대학교 → 효고현, 세이부 전철 → 사이타마현 (피해는 예약 사이트였지만, 본사 소재지로는 정확하므로 타당하다고 판단)
- 기존만 (1건): 기존 방식으로 '리코 블랙람스 도쿄'의 팀명에 부분 일치한 오판입니다. Jev의 '해당 없음'이 옳습니다.
- 기존이 복수(1건): 이는 기존 방식으로 '야마구치 도쿄 이과대'를 '도쿄', '야마구치' 양쪽에 분류했던 예시입니다. Jev는 야마구치현만으로 정확하게 분류했습니다.
- Jev의 Choice 프리미티브에서는 단일 선택만 가능하지만, 정말로 여러 현에 걸쳐 있는 기사는 200건 중 0건이므로 실용상 문제가 없어 보였습니다 (공식 문서에서는 복수 적용되는 경우 레이블별로 Noul을 사용하는 방법을 소개하고 있습니다).
기사 중에 지명이 없더라도 **피해 조직의 본사 소재지로부터 추정하는 것은 인정한다**는 방침으로 Jev로 전환을 결정했습니다.
이상, 이번에는 도입을 결정한 단계까지입니다.
주의할 점으로, 문자열 일치와 달리 Jev의 결과는 프롬프트 작성 방식이나 기사의 작성 방식에 따라 달라집니다. 실제로 인명 오판을 바로잡으려고 프롬프트를 조정했더니, 이번에는 다른 케이스에서 오판이 나오기도 했습니다.
그래서 더 고안하여 도입했지만 그것은 별도 기사로 쓰겠습니다.
여기까지 읽어주셔서 감사합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기