개요
TypeSafe AI의 의사결정 모델 'Jev'를 사용해 보았습니다.
LLM의 출력 정확도를 높이는 방법을 공부하던 중, 최근 화제가 되고 있는 Jev가 궁금해서 시작하게 되었습니다. 주제는 '식당 매출이 하락한 원인을 특정하는 것'으로 정하고, Jev에게 단계적으로 질문을 던진 후 로컬 LLM(llama3:8b)과 비교해 보았습니다.
결론부터 말씀드리자면, Jev의 강점은 정확도 자체보다는 확신도를 그대로 활용할 수 있다는 점이었습니다. 또한, 정확도를 좌우한 것은 모델 자체보다 입력 설계였으며, 이는 Jev에 국한되지 않고 LLM 프롬프트 개선에도 적용 가능한 내용이었습니다.
Jev란?
TypeSafe AI가 2026년 9월 15일에 공개한 'System One' 모델입니다. 문장을 생성하는 것이 아니라, 앱의 상태(텍스트 또는 JSON)와 타입 지정된 질문을 전달하면, 정해진 선택지 중 하나의 답변과 확률을 반환합니다.
질문의 유형은 세 가지가 있습니다.
- Choice: 선택지 중 하나를 고릅니다.
choice, probabilities, confidence가 반환됩니다.
- Score: 단계별 평가로 점수를 매깁니다.
score, probabilities, confidence가 반환됩니다.
- Noul: 어떤 문장이 참일 확률을 0에서 1 사이의 값으로 반환합니다.
답변은 정의된 선택지 중에서만 나오기 때문에 존재하지 않는 답변을 만들 위험이 없습니다. 다만, 잘못된 선택지를 고를 수는 있습니다. 비용은 입력 100만 토큰당 $0.042이며, 출력은 무료입니다 (Jev 1.13 기준). 가중치는 공개되지 않았으며 API를 통해서만 사용할 수 있습니다. 공식에 따르면, 문장을 생성하는 LLM보다 수십~수백 배 빠르고 저렴하다고 합니다.
준비
console.typesafe.ai에서 계정을 만들었습니다. 등록 시 $5 크레딧이 제공된다는 글을 봤지만, 제가 등록했을 때는 없었고 최소 $5의 충전이 필요했습니다. 구매한 크레딧은 12개월 내에 만료됩니다.
처음에는 콘솔 플레이그라운드에서 사용해 보고, 이후에는 Python SDK로 실험했습니다.
uv add typesafe-sdk python-dotenv
API 키는 .env 파일에 TYPESAFE_API_KEY로 두면 SDK가 읽어줍니다.
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
CAUSES = {
"service": "대기 시간이나 접객 서비스 악화로 단골 고객이 떠나고 있다",
...
단계적으로 시도하기
1차: 답변이 명확한 데이터
대기 시간이 9분에서 24분으로 늘어나고, 재방문율과 후기 평가도 떨어진 가게입니다.
{
"store_name": "역전점",
"customers": 2100,
...
주요 원인(Choice), 개선의 긴급도(Score, 3단계), '대기 시간이 너무 길어 손님이 불만족스러워하고 있다'(Noul) 세 가지를 질문했습니다.
결과는 service를 확신도 0.99로 선택했고, 긴급도는 1.99, Noul은 0.87이었습니다. 입력 650 토큰에 비용은 약 $0.00003입니다.
Score의 1.99는 각 단계(0~2)의 확률로 가중치를 준 평균값인 것 같습니다. 정수가 아닌 연속 값으로 반환되기 때문에, 코드에서는 임계치로 판별하면 될 것 같습니다.
2차: 원인이 혼재된 데이터
비가 오는 날이 늘어난 달에 메뉴 변경까지 겹친 가게입니다. 고객 수는 12% 줄고, 객단가도 8% 하락하여 매출은 19% 감소했습니다. 매출 하락의 영향은 비와 메뉴 양쪽에 있습니다.
처음에는 비 오는 날짜만 전월 값 없이 넣고 질문했습니다 (JSON은 발췌).
{
"customers": 2290,
"customers_prev_month": 2600,
...
결과는 weather가 0.65, menu가 0.29였고, 확신도는 0.53이었습니다. 전월 값이 없어도 Jev는 '한 달에 13일의 비는 많다'는 것을 파악하는 것 같았습니다.
다음으로 `
다만, 여기서 문제가 발생했습니다. 고객 단가 8% 감소라는 또 다른 원인이 거의 0%로 보여서 사라졌습니다. Choice는 '주요 원인을 하나 선택'하는 질문이므로, 두 번째 원인은 확률을 빼앗기게 됩니다. 원인이 여러 개일 수 있는 상황에서 Choice만 보는 것은 위험하다는 것이 이번 배움이었습니다.
3번째: 원인별로 Noul에게 물어보기
공식 문서에는 '여러 요소가 얽힌 판단은, 요소를 나누어 질문하고 코드로 조합한다'고 나와 있습니다. 그래서 원인별로 Noul을 만들었습니다. 처음에는 질문문에 데이터 관찰 내용을 섞어서 작성했습니다.
"cause_menu": Noul(instructions="`avg_spend`가 `avg_spend_prev_month`보다 낮아져서, 메뉴 변경으로 고객 단가가 떨어지고 있다")
결과는 날씨가 0.69, 메뉴가 0.41, 경쟁사가 0.38, 접객이 0.08이었습니다. Choice에서는 0.01이었던 메뉴가 0.41까지 떠올랐습니다.
4번째: 계산을 코드로 옮기고 판단만 듣기
변화율(customers_change_pct: -12, avg_spend_change_pct: -8 등)을 계산하여 입력에 넣고, 질문에서는 관찰 내용을 제외하고 '매출 하락의 큰 요인은 메뉴 변경으로 고객 단가가 낮아진 것이다'처럼 판단만 물었습니다.
결과는 날씨가 0.64, 경쟁사가 0.23, 메뉴가 0.19, 접객이 0.13입니다. 메뉴가 0.41에서 0.19로 떨어져 버렸습니다.
'큰 요인'이라는 표현이 너무 엄격했던 걸까 싶어 '요인 중 하나'로 바꿔봤지만, 0.25까지밖에 오르지 않았습니다.
원인은 입력에 있었습니다. 데이터에는 '고객 단가가 낮아졌다'는 것만 있을 뿐, '이번 달 메뉴를 변경했다'는 사실이 어디에도 없습니다. 고객 단가 하락만으로는 메뉴 변경 때문이라고 단정할 수 없는 것입니다. 그래서 `
두 모델 모두 어려움을 겪은 곳은 경쟁점 때문인 가게였습니다. Jev는 5건 중 3건, llama3:8b는 1건도 맞히지 못했습니다. 데이터에 '근처에 경쟁점이 생겼다'라는 사실이 없기 때문에 신규 고객 감소에서 추측할 수밖에 없다고 생각합니다. 네 번째 메뉴 변경과 같은 구도라 원인의 전제가 데이터에 없으면 판단이 흔들립니다.
그 외에 파악한 점은 다음과 같습니다.
- llama3:8b는 20건 중 5건에서 3번의 답변이 달랐습니다.
- Jev 역시 답변은 매번 같았지만, 확신도는 약간씩 흔들립니다(예: 0.80, 0.76, 0.75). 기준치에 아슬아슬한 판정은 실행할 때마다 분류되는 곳이 달라집니다.
- 응답 시간은 Jev가 약 0.15초, llama3:8b가 약 4.4초로, 약 30배의 차이가 있었습니다.
소감
Jev와 LLM 중 어느 것이 더 똑똑한지보다 역할 분담에 대한 이야기라고 느꼈습니다. 1건의 분석을 사람이 읽기만 한다면 LLM으로도 충분하며, 개선책 제안문까지 작성할 수 있다는 점이 편리합니다. 대량의 데이터를 매일 판정하거나 결과를 코드로 자동 처리하는 상황에서는 속도와 확신도의 사용 용이성이 효과적입니다.
솔직히 말하자면, 이번 더미 데이터는 '신규 고객만 크게 줄었다면 경쟁점을 의심한다' 같은 규칙으로도 풀릴 수 있을 것 같습니다. 모델이 정말 유용하게 쓰이는 것은 후기 글처럼 규칙화하기 어려운 입력을 다룰 때라고 생각합니다. 공식에서 제시하는 속도나 비용 배율 역시 벤더(vendor) 자체의 수치이므로, 자신의 작업에 대입해 비교해보는 것이 가장 확실합니다.
실험을 통해 익힌 것은 Jev 사용법보다 프롬프트와 Eval의 기본이었습니다.
- 비교 기준(전월 값)은 입력 데이터에 포함한다.
- 원인의 전제가 되는 사실(메뉴를 변경했다 등)도 데이터로 제시한다.
- 원인이 여러 개일 수 있다면, Choice에서 하나만 선택하게 할 뿐만 아니라 요인별로 질문한다.
- 한 번에 바꾸는 것은 한 곳만 한다.
다음에는 더미 데이터에 '근처에 경쟁점이 생겼다'라는 항목을 추가하여, 경쟁점의 정답률이 어떻게 변하는지 시험해 보겠습니다.
Discussion