Jev로 일본어 메시지 대응 우선순위 분류 시도 보고서
요약
Jev라는 판별 전용 모델을 사용하여 일본어 업무 메시지 360건에 대해 대응 필요 여부를 이진 분류하는 방법을 제시합니다. LLM(Claude Haiku 4.5)으로 처리할 경우 느리고 비싸며, 출력 형식 준수에도 어려움이 있다는 문제점을 지적하며, Jev의 효율성을 강조합니다.
핵심 포인트
- Jev는 일본어 업무 메시지 이진 분류를 $0.02에 빠르게 수행 가능합니다.
- LLM은 처리 시간이 길고(느림), 비용도 많이 발생하여 대량 처리에 비효율적입니다.
- LLM은 프롬프트 지시에도 불구하고 JSON 형식 준수 실패 등 출력 오류가 발생할 수 있습니다.
이 기사에서 알 수 있는 것
- TypeSafe의 판별 전용 모델
Jev에 일본어 업무 메시지(이메일・채팅・예정・과제) 360건을 제공하고, '자신의 대응/확인이 필요한가'라는 이진 분류를 시도한 결과 -
**판단 기준(**criteria`
)
을 작성하면, 반환되는 확률이 '0.4 이하 = false / 0.8 이상 = true / 그 사이 = pending'로 깔끔하게 나뉘었습니다. — 반환되는 확률을 범위(band)로 사용할 때의 함정 — 같은 요청이라도 값이 흔들리며, 경계값을 자체 데이터에 채워 넣으면 오류가 증가합니다. - 비용과 속도 — 메시지 360건 평가가 단 한 번 $0.02이며, 질문 개수를 20개로 늘려도 응답 시간은 거의 변하지 않습니다.
모두 2026년 10월 7일 시점의 모델 jev-1.13.0 기준 결과입니다.
소재: 수신함 우선순위 3 클래스
자신에게 도착한 메시지를 다음 우선순위 정의에 따라 3가지로 분류하게 합니다.
| 클래스 | 정의 |
|---|---|
| P1 | 오늘~다음 영업일 사이에 자신이 움직여야 하는 것 (요청・승인・장애 대응・기한 임박) |
| P2 | 자신의 대응 또는 내용 확인이 필요하지만, 급하지 않은 것 (기한이 더 남았거나, 자신의 업무에 영향을 주는 변경 통지) |
| P3 | 정보 공유만. 읽고 지나가도 좋으며, 대응이나 확인은 불필요함 (회의록・완료 보고・자동 통지・자신과 무관한 공지) |
Jev는 질문 패턴을 다양하게 설정할 수 있으므로(후술), P1~P3의 3클래스 분류뿐만 아니라, 'P3인지 여부'(='자신의 대응이나 내용 확인이 필요한가')라는 2클래스 분류도 시도해봅니다.
이 기사에서 주로 다루는 것은 후자의 이진 판별인 '자신의 대응 또는 내용 확인이 필요한가'이며, true가 P1・P2이고, false가 P3입니다.
배경: 대량의 1차 분류를 LLM으로 처리하는 것이 비효율적
LLM에 위의 분류를 시키면 어느 정도 맞습니다.
실제로 이 기사에서 사용하는 가상 데이터 360건(후술)을 Claude Haiku 4.5에 분류하게 하자, 정답은 317건이었습니다.
하지만 이번과 같은 케이스에서 LLM을 사용하면 정확도와는 별개로 비효율적인 점이 3가지 발견되었습니다.
1. 느림
LLM은 답을 토큰 단위로 생성하기 때문에, 필연적으로 일정 처리 시간이 걸립니다.
| 건당 지연 시간(p50) | |
|---|---|
| Claude Haiku 4.5 (JSON만 출력하게 했을 경우, 출력 24 토큰) | 533 ms |
| ... | |
| (모두 일본에서 측정. Haiku는 Amazon Bedrock의 global 크로스리전 추론을 도쿄 엔드포인트에서 호출하고, temperature 0) |
2. 비쌈
LLM은 입력과 출력 모두에 과금되며, 출력 단가가 입력보다 높게 설정되어 있습니다(Claude Haiku 4.5는 Anthropic의 공식 API 기준 입력 $1 / 출력 $5 per 1M 토큰). 메시지 1,000건 기준으로 추산하면 다음과 같습니다:
| 1,000건당 | |
|---|---|
| Claude Haiku 4.5 (JSON만: 입력 489 + 출력 24 토큰/건) | 약 $0.61 |
| ... | |
| 1건씩 처리할 때는 적은 금액이지만, 수신하는 모든 메시지를 처리한다면 큰돈이 됩니다. |
3. 출력 형식 준수 실패
프롬프트로 'JSON 객체만 출력'이라고 지시했음에도 불구하고, Haiku는 360건 모두에 대해 JSON 뒤에 판별 이유 설명을 추가하여 출력했습니다. 설정한 출력 상한 100 토큰에 도달하면서 360건 모두 중간에 잘렸습니다.
```json
{
여기에 더해, 분류와 함께 '분류의 확신도'를 0~1로 자체 신고하게 해보았을 때, 값은 거의 0.95(197건)와 0.85(85건) 두 가지에 고정되어 있었고, 이는 분류 성공/실패와의 상관관계가 없었습니다. 이 경우 '분류 확신도가 낮은 데이터는 pending으로 처리한다' 같은 안전장치를 구현할 수 없다는 문제가 있습니다.
그래서 문장을 생성하지 않고, 정해진 형태의 답변과 확률만 반환하는 판별 전용 모델인 Jev를 사용해 보았습니다.
## Jev란
TypeSafe AI가 제공하는 **System One 모델**입니다 (LLM처럼 숙고하기보다는 빠른 판단을 수행하는 모델).
기본적인 흐름은 다음과 같습니다:
- '메시지 본문 등의 컨텍스트 (`state`) + 질문 (`questions`)"를 Jev에 주면, - '답변 + 그 확신도나 확률'을 돌려줍니다.
여기서 말하는 질문의 형태는 아래와 같이 준비되어 있습니다:
| 질문 유형 | 답변 유형 | 용도 |
|---|---|---|
`noul` | "예"일 확률: `noul` (0~1) | 이진 분류 |
`choice` | 설정한 선택지: `choice` + 각 선택지에 해당되는 확률: `probabilities` | 다중 클래스 분류 |
`score` | 단계의 기대값・각 단계의 확률: `score` | 순서 척도 추정(예: 긴급도)
요금 및 속도 제한에 대해 공식 문서(Models)에는
- 요금은 입력 100만 토큰당 $0.042이며, 출력은 무료입니다.
- 속도 제한은 초당 10만 토큰・초당 40 요청입니다. 수요에 따라 예고 없이 변경될 수 있습니다.
라고 적혀 있으며, 일본어 성능에 대해서는
- 주요 학습 언어는 영어이며, 정확도 역시 현재는 영어가 가장 좋습니다.
- 중국어・일본어・한국어를 포함하는 다른 언어도 처리할 수 있지만 동등하지 않으므로, 영어 외로 사용할 경우 자신의 데이터로 테스트한 후에 의존해야 합니다.
- 분류에 사용할 때는 확신도에 주의해야 합니다. (2026-10-07 시점)
그래서 실제로 일본어 데이터에서의 성능을 검증해 보기로 했습니다.
## 준비
### API 키
Typesafe AI 콘솔에 로그인한 후, 화면 왼쪽 메뉴 > API Keys에서 발급받을 수 있습니다.
### 최소 호출
표준 라이브러리만으로 작성할 수 있습니다.
import json, urllib.request
def ask(key, state, questions, model="jev-1.13.0"):
req = urllib.request.Request(
...
### State와 Questions
`state`의 작성 방법에 대해 공식 문서(State)에는
Use an object for most requests so each part of the state has a descriptive name and its relationships remain clear.
즉, '대부분의 경우 객체를 사용하고, 각 부분에 설명적인 이름을 붙여 관계를 명확히 하라'고 되어 있어, 이름이 지정된 객체로 작성했습니다. '오늘 중'인지 판단할 수 있도록 기준 시각과 수신 일시도 포함했습니다.
{
"now": "2026-10-07T09:00:00+09:00(수)",
"item": {
...
질문은 1 요청에 6개를 모아서 보냈습니다 (Jev에서는 각 질문이 동시에 평가되므로, 모아도 느려지지 않습니다. 후술).
{
"noul_ja": {
"type": "noul",
...
(그 외 `noul_ja_crit`의 영어 버전과 `choice_ja`의 영어 버전을 넣었습니다.)
위 전자레인지 예제에 대한 응답은, `noul_ja` 0.17 / `noul_ja_crit` 0.14 / `choice_ja` = `P3` / `urgency` 0.04였습니다.
## 실험 설정
- **데이터**: 가상의 업무 메시지 360건 (이메일・채팅・예정・과제 × P1・P2・P3 × 각 30건). 이 중 144건은 판단하기 어려운 경계 사례입니다. - Claude로 1건씩 작성하고, 정답을 숨긴 상태에서 다른 LLM에게도 정답 레이블을 붙여 비교했습니다. 양쪽의 판정이 어긋난 3건은 클래스 정의에 따라 수동으로 레이블링했습니다.
-
**이진 분류로 평가**: Jev의 `noul`
(‘예’일 확률을 반환하는 타입)에 ‘이 항목에 대해 수신자 본인의 대응, 또는 내용 확인이 필요한가?’를 묻습니다. `true`
이 P1・P2(240건), `false`
이 P3(120건)입니다 - 반환된 확률을
**임계값 처리**합니다: -
0.4 이하 → false
- 0.8 이상 → true
- 그 사이 →
**pending**(판단이 어려우므로, 자동 판정하지 않고 보류 처리함)
- 두 가지 관점에서 결과를 확인:
-
**오류**: false 범위에 들어간 P1・P2와, true 범위에 들어간 P3의 비율을 확인했습니다. 여기가 0이 되도록 임계값을 설정할 수 있다면, 오분류를 없애면서 판단이 어려운 데이터를 pending으로 처리할 수 있습니다.
**pending율**: 판단을 보류한 비율입니다. 이 값이 작을수록 보류가 적다는 의미이므로, Jev에 의한 자동 분류의 이점이 큽니다.
-
## 결과1: 판정 기준(criteria)을 작성하면 실용적인 확신도가 출력된다

| 질문 | AUC | 오류(360건 중) | pending율 | 비(非)pending율 (=자동 분류된 비율) |
|---|---|---|---|---|
| 일본어・판정 기준 없음 | 0.987 | 4건 | 79건(21.9%) | 78.1% |
| 일본어・판정 기준 있음 | 0.998 | 0건 | 46건(12.8%) | 87.2% |
| 영어・판정 기준 있음 | 0.998 | 3건 | 28건(7.8%) | 92.2% |
| 일본어・3분류(`1 − P(P3)`) | 0.997 | 7건 | 10건(2.8%) | 97.2% |
| 영어・3분류 | 0.997 | 6건 | 11건(3.1%) | 96.9% |
판정 기준이 없는 경우를 보면, true 범위에 false가, false 범위에 true가 섞여 들어와 있습니다.
반면, `criteria`에 true/false의 판정 기준을 명시함으로써, true 범위 / false 범위에서 오류가 사라진 것을 알 수 있습니다.
요컨대, **판정 기준을 작성한 noul은 “0.4 이하일 경우 false, 0.8 이상일 경우 true, 그 사이는 pending”처럼 깔끔하게 사용할 수 있다**는 것입니다.
참고로, P1 ~ P3의 3클래스 분류(`choice`)도 시도해 봤지만, 값이 원래 양 끝에 치우치기 때문에 pending은 3% 이하로 충분합니다. 다만, 그만큼 오류가 6~7건 발생합니다.
**양 끝 범위만 믿고 자동으로 버리거나 통과시키는** 방식으로 사용하려면, 판정 기준이 있는 `noul`이 가장 직관적이었습니다.
공식 문서(Noul)에는 다음과 같이 나와 있습니다:
When the boundary is subtle, add criteria with true and false descriptions, as the is_repeat_contact question above does. The instruction is enough for most Nouls, so try your questions with and without criteria and keep whichever gives better answers on your documents.
즉, “경계가 미묘할 때는 `criteria`에 true / false 설명을 추가하라. 대부분의 경우 질문문만으로 충분하므로, 유무 모두로 시도하여 문서에서 더 나은 답변을 주는 것을 사용하라”는 의미입니다. 이번에는 true / false 설명이 매우 효과적이었습니다.
## 결과2: 일본어 / 영어 컨텍스트 간 성능 차이는 미미한가?
앞서 언급했듯이, 공식 문서에서는 영어가 최고라고 했기 때문에, 72건의 데이터를 번역한 `state`로도 비교했습니다.
| state | 질문 | AUC | 오류(72건 중) | pending | |
|---|---|---|---|---|
| 일본어(원문) | 일본어・기준 있음 | 0.995 | 0건 | 10건(13.9%) | |
| 일본어(원문) | 영어・기준 있음 | 0.992 | 2건 | 6건(8.3%) | |
| 영어(번역) | 일본어・기준 있음 | 0.986 | 1건 | 8건(11.1%) | |
| 영어(번역) | 영어・기준 있음 | 0.983 | 2건 | 9건(12.5%) |
일본어 그대로 전달하는 것이 더 좋은 결과였습니다. 이번 영어 번역은 LLM에 의한 것이며, 정답 레이블도 일본어 원문을 기준으로 지정했기 때문에, 번역 과정에서 손실된 뉘앙스("급하지는 않지만", "회신 불필요하지만" 등)가 불리하게 작용했을 가능성은 있지만,
적어도 "일본어 데이터는 영어로 번역한 후에 전달해야 한다"고 말할 수는 없었습니다.
다만, 이 부분은 사용 사례(use case)에 따라 다를 것 같습니다.
## 결과 3: 돌아오는 확률의 성질
### 교정 (Calibration)

- ECE(교정 오차)는 `noul`이 0.126, `choice`가 $1 - P(P3)$로 0.040으로, `choice` 쪽이 확률의 의미에 더 가까운 결과였습니다 -
`noul`은 P3 측 값이 0.1~0.5 부근으로 퍼져 있고(최대 0.77), "P = 0.3이면 3할은 대응 필요"라는 해석은 할 수 없습니다. **임계값(Threshold)은 확률의 의미가 아니라, 데이터를 보고 결정**하는 전제하에 사용하는 것이 안전합니다 - 360건・8 빈도의 그림이므로, 형태는 대략적인 경향으로 봐주세요.
### 같은 요청이라도 값이 흔들림
같은 360건의 질문을 2회 보내자, **값의 43%가 미세하게 바뀌었습니다**(차이 평균 0.009, 최대 0.41).
0.4 / 0.8 범위로 보면, **범위가 바뀐 것은 4건**이었습니다. 내역은 pending → false가 2건, false → pending가 1건, pending → true가 1건으로, **false와 true가 직접 바뀌지는 않았습니다**. 2회차에서도 양 끝 범위의 오류는 0건이었습니다. pending 범위가 흔들림을 흡수하는 형태입니다(`choice` 쪽은 답이 3건 바뀝니다).
값은 소수점 둘째 자리까지 반올림되어 돌아오므로, 간격(increment)은 0.01입니다. 경계 바로 근처에 항목들이 모여 있는 배치는 피하고 여유를 두어야 합니다.
### score는 깔끔하게 분리됨

질문 형식으로 `score`도 시험해 보았습니다.
긴급도를 4단계의 `score`로 답변을 받아보니, P1은 평균 2.98(최소 2.56), P2는 1.39, P3는 0.40으로 상당히 깔끔하게 분리되었습니다. P1 감지에는 `score` $\ge$ 2.5와 같은 사용이 가능할 것 같습니다. P2와 P3 사이에는 중첩 부분이 있으므로, 그 부분은 `noul` 쪽이 더 적합합니다.
## 결과 4: 비용과 속도

| 항목 | 실측 |
|---|---|
| 360건 $\times$ 6문항 평가 1회 비용 | 입력 478,111 토큰 $\approx$ $0.020$
|
| 1 요청 지연 시간(일본에서, 6 문항) | p50 185 ms |
| 질문 수 1 $\to$ 20 지연 시간 | 181 ms $\to$ 187 ms (거의 일정) |
| 질문당 입력 토큰 증가량 | 약 24 |
공식 문서(Noul)에서는
Questions are evaluated in parallel, so adding Nouls barely changes the response time.
즉, "질문은 병렬로 평가되므로, noul을 추가해도 응답 시간은 거의 변하지 않는다"고 되어 있으며, 실측도 그와 같았습니다. 분류/긴급도/주제 태그 등을 1 요청으로 한 번에 물어볼 수 있다는 것은 구현상 상당히 편리합니다. 참고로, 질문을 늘려도 핵심 질문의 값은 재전송 시 흔들림과 비슷한 정도(중앙값 0.015)밖에 변하지 않았습니다.
## 비교: OSS의 Laya
Jev와 같은 형식(`noul` / `choice` / `score`)의 판별을 자체 GPU에서 구동할 수 있는 OSS로 **Laya**(Apache-2.0, 인코더 3억 파라미터급)가 있습니다. 동일한 360건으로 비교했습니다.
| 모델 | AUC | 오류(360건 중) | pending |
|---|---|---|---|
| Jev(일본어・판별 기준 있음) | 0.998 | 0 건 | 46 건(12.8%) |
| Laya 제로샷 | 0.682 | 125 건 | 78 건(21.7%) |
| Laya 제로샷 + 동일 판별 기준 | 0.556 | 99 건 | 59 건(16.4%) |
| Laya 파인튜닝(별도 제작한 합성 600건으로 학습, 3 모델 평균) | 0.987 | 15 건 | 16 건(4.4%) |
Laya는 제로샷(zero-shot)으로는 일본어 업무 판별을 거의 할 수 없었고, 같은 판별 기준을 추가해도 개선되지 않았습니다(오히려 하락했습니다). 파인튜닝(fine-tuning)을 하면 AUC가 0.987까지 올라가지만, 여전히 0.4 / 0.8 범위에서는 오류가 15건 남습니다. '양 끝은 신뢰할 수 있다'고 말하기는 어려우므로, pending 범위를 더 넓게 잡거나 임계값을 별도로 재설정해야 합니다. 이는 학습 데이터를 준비했지만 외부로 데이터를 내보낼 수 없는 경우의 대안적 위치입니다.
(규약상 Jev의 출력을 사용하여 유사한 모델을 학습시키는 증류(distillation)는 금지되어 있습니다. 위의 Laya 학습에는 Jev의 출력은 사용되지 않았습니다.)
## 실운영 시 주의할 점
- **데이터 보관 위치**: 공식 문서(Models)에는 'Jev는 고객 요청이나 응답으로 학습되지 않습니다. 데이터 처리 계약(Data Processing Agreement), 개인정보 보호 정책, 그리고 엔터프라이즈 고객을 위한 제로 데이터 보유(ZDR)에 대한 세부 사항을 법률 섹션을 참조하십시오.'라고 명시되어 있습니다.
즉, '고객의 요청이나 응답은 학습에 사용하지 않으며. 데이터를 보관하지 않는 계약(ZDR)은 대규모 고객 대상'이라는 의미입니다. 처리 리전(region)에 대한 언급은 찾을 수 없었습니다. 회사 기밀이나 개인정보를 포함하는 실제 데이터를 전송하려면, 계약과 리전을 먼저 확인해야 합니다. 이번 검증은 모두 가상 데이터로 진행되었습니다.
- **값의 변동성**: 동일한 입력이라도 값이 0.01~0.41 정도로 흔들립니다. 경계 부근의 판별은 안정적이지 않지만, 이번에는 pending 범위가 이를 흡수했습니다(재전송으로 false ⇔ true가 바뀌는 경우는 0건) -
- **범위 설정**: 경계값을 자체 데이터에 맞춰 조정하면 오히려 오류가 늘어납니다(결과 4). pending 범위를 여유 있게 잡는 것이 안전합니다 -
- **외부 의존성**: 가격이나 제공 조건의 변경, 장애 발생 시 처리 방법(판별할 수 없을 때 어느 쪽으로 기울일지)을 미리 결정해 두어야 합니다.
## 요약
- 일본어 업무 메시지 360건을 '자신의 대응/확인이 필요한가'라는 이진 분류로 나눈 결과, 판별 기준이 포함된 `noul`은 **0.4 이하 = false / 0.8 이상 = true / 그 사이 = pending**라는 임계값으로 깔끔하게 처리할 수 있었습니다(true / false 오류율 0%, pending 12.8%) -
효과적이었던 것은 모델의 언어 설정보다, `criteria`에 true/false 경계를 구체적으로 명시한 것이었습니다. 영어 번역은 반드시 이득이 되지 않습니다. 일본어 컨텍스트 그대로 시도할 가치가 있습니다.
- 질문을 늘려도 느려지지 않으므로, 분류/긴급도/태그 지정 등을 한 번에 모아서 물어볼 수 있습니다.
## 참고
### 토론(Discussion)

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn ML의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기