AiHubMix에서 Jev 호출하는 방법: 구조화된 분류 튜토리얼

AIHubMix5분 분량
AiHubMix에서 Jev 호출하는 방법: 구조화된 분류 튜토리얼

요약: jev-1.13 은 텍스트를 생성하지 않습니다. 텍스트와 이름이 지정된 질문 목록을 https://aihubmix.com/v1/systemone으로 POST하면, 질문 이름을 키로 한 타입 있는 답변(카테고리, 점수 또는 확률)을 돌려받습니다. 별도로 파싱할 것이 없습니다. 아래에 동작하는 요청 예시, 전체 응답 형식, 그리고 조용히 정확도를 떨어뜨리는 설계상의 실수 하나를 정리했습니다.

Jev의 용도

단락으로 된 긴 글이 아니라 판단이 필요할 때 사용하세요. 예를 들어 지원 티켓 라우팅, 심각도 점수화, 긴급도 표시, 콘텐츠 게이팅 등이 있습니다. 모델 페이지에도 "텍스트 생성 없음, 파싱할 것 없음"이라고 명시되어 있습니다.

설명, 요약 또는 자유 형식 출력이 필요하다면 대신 일반 채팅 모델을 사용하세요. jev는 이런 출력을 만들 수 없습니다.

시작하기 전에

  • [ ] Python 3 설치 (표준 라이브러리만으로 충분합니다)
  • [ ] AiHubMix 계정과 API 키
  • [ ] 키를 AIHUBMIX_API_KEY로 내보내기, 소스 코드에 하드코딩하지 않기

OpenAI SDK, LangChain, 또는 requests 패키지는 필요하지 않습니다.

1단계 — 엔드포인트 확인하기

POST https://aihubmix.com/v1/systemone
Authorization: Bearer YOUR_KEY
Content-Type: application/json

이것은 모델 전용 경로이며, 아닙니다 /v1/chat/completions. OpenAI 호환 클라이언트로는 호출할 수 없으므로 일반 HTTP를 사용하세요.

2단계 — 질문 유형 선택하기

질문 유형은 세 가지이며, 한 요청에서 자유롭게 섞어 쓸 수 있습니다:

유형용도제공하는 값
choice카테고리 하나 고르기criteria 를 딕셔너리(라벨 → 정의)로 전달
score순서가 있는 척도로 평가하기criteria 를 가장 낮은 값부터 시작하는 리스트로 전달
noul예/아니오 판단instructions 외에는 추가로 필요한 것이 없음

3단계 — 요청 구성하기

state는 판단 대상이 되는 텍스트입니다. questions의 키는 직접 정하는 이름이며, 응답에서도 같은 이름이 사용됩니다.

payload = {
    "model": "jev-1.13",
    "state": "Hi, I have been trying to connect my Stripe account for 3 days "
             "and it keeps failing. I am losing sales. Please help ASAP.",
    "questions": {
        "department": {
            "type": "choice",
            "instructions": "Which team should handle this",
            "criteria": {
                "billing":   "Payment or subscription issues",
                "technical": "Bugs or integration problems",
                "sales":     "Pricing or account questions",
            },
        },
        "frustration": {
            "type": "score",
            "instructions": "How frustrated the customer appears",
            "criteria": [
                "Calm, just stating facts",
                "Frustrated but civil",
                "Very angry, strong language",
            ],
        },
        "is_urgent": {
            "type": "noul",
            "instructions": "The message conveys urgency or time-sensitivity",
        },
    },
}

4단계 — 표준 라이브러리로 전송하기

import json, os, urllib.error, urllib.request

def ask(payload):
    req = urllib.request.Request(
        "https://aihubmix.com/v1/systemone",
        data=json.dumps(payload).encode(),
        headers={"Authorization": "Bearer " + os.environ["AIHUBMIX_API_KEY"],
                 "Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=60) as r:
            return json.loads(r.read())
    except urllib.error.HTTPError as e:
        raise SystemExit(f"HTTP {e.code}: {e.read().decode(errors='replace')[:500]}")

요청을 만드는 코드는 함수 안에 두세요. 모듈 최상위에서 요청을 만들고 전송하면, 파일을 import할 때마다 호출이 다시 실행되어 토큰이 소모됩니다.

5단계 — 답변 읽기

각 답변은 해당 항목의 type에 맞는 키 아래에 값을 저장하므로, 접근자 하나로 세 가지 유형을 모두 처리할 수 있습니다:

data = ask(payload)
for name, ans in data["answers"].items():
    kind = ans["type"]
    print(name, kind, ans[kind], ans.get("confidence"))
print("usage:", data.get("usage"))

검증된 출력:

department   choice  billing   0.51
frustration  score   1         1
is_urgent    noul    1         None
usage: {'input_tokens': 424, 'output_tokens': 73}

6단계 — 전체 응답 구조 이해하기

앞의 출력 루프에서는 유용한 필드가 드러나지 않습니다. 다음은 score 답변의 원본 JSON입니다:

{
  "type": "score",
  "score": 1,
  "legend": {"0": "Calm, just stating facts", "1": "Frustrated but civil", "2": "Very angry, strong language"},
  "probabilities": {"0": 0, "1": 1, "2": 0},
  "confidence": 1
}
  • legend는 인덱스를 여러분이 작성한 문구와 연결해 줍니다. 정수 값만으로도 의미가 드러나므로 코드에 별도의 조회 테이블이 필요하지 않습니다.
  • probabilities는 전체 확률 분포를 제공하며, 두 후보의 확률이 거의 같은 경우를 찾아내는 데 유용합니다.
  • noul에는 confidence 필드가 없습니다. 대신 확률 값이 신호 역할을 합니다.

최상위 응답에는 usage, id, provider (TypeSafe), 그리고 실제 처리한 백엔드 버전 typesafe/jev-1.13-20260917도 함께 반환됩니다.

정확도를 떨어뜨리는 실수

위 요청에서 department 는 billing 을 신뢰도 0.51로 반환했습니다. 같은 요청을 반복했을 때는 같은 라벨이 나왔지만 신뢰도는 0.38 이었습니다. 답변은 일관됐지만, 제시된 확신도는 그렇지 않았던 것입니다.

원인은 모델이 아니라 기준(criteria)에 있습니다. billing 은 "결제 또는 구독 문제"이고 technical 은 "버그 또는 연동 문제"입니다. 계속 실패하는 Stripe 연동 은 실제로 두 기준에 모두 해당합니다. 모델은 스키마에 적혀 있던 모호함을 그대로 드러낸 것입니다.

실제 운영 전에 지킬 두 가지 규칙:

  1. choice 기준은 서로 배타적이어야 합니다. 사람이 두 라벨 사이에서 망설인다면, 모델도 망설일 것입니다.
  2. 신뢰도 임계값을 설정하고, 임계값 아래의 결과는 결정으로 받아들이지 말고 사람이 확인하는 대기열로 보내세요. 불확실성을 인정하는 모델이 그것을 숨기는 모델보다 더 가치가 있습니다.

출시 전 체크리스트

  • [ ] 키는 환경 변수나 VCS가 무시하는 600 권한 파일에서 불러오기
  • [ ] choice 기준에 겹치는 부분이 없는지 검토하기
  • [ ] 신뢰도 임계값을 정하고, 그 아래에 대한 대체 경로 마련하기
  • [ ] noul 답변은 별도로 처리하기. 이 답변에는 confidence 가 없습니다.
  • [ ] 사용하지 않는 질문 제거하기 (질문 3개는 입력 토큰 424개, 2개는 355개를 소모합니다)
  • [ ] 2xx가 아닌 응답은 원본 본문과 함께 로그로 남기기

자주 묻는 질문

OpenAI SDK를 사용할 수 있나요? 아니요. /v1/systemone 은 OpenAI 호환 경로가 아닙니다.

jev가 문장이나 요약을 반환할 수 있나요? 아니요. 여러분이 정의한 타입 있는 질문에만 답합니다.

한 요청에 질문을 몇 개까지 넣을 수 있나요? 검증 테스트에서는 2개와 3개를 사용했습니다. 질문마다 입력과 출력 토큰이 추가되므로, 실제로 활용할 질문만 포함하세요.

버전 별칭이 있나요? 모델 페이지에는 jev-1.13 과 함께 jev-latest 별칭이 나와 있습니다. 재현성이 중요하다면 명시적인 버전을 고정해 사용하세요.

비용은 얼마인가요? 모델 페이지에는 입력 토큰 $0.0462 / M , 출력 토큰 $0 / M 이 게시되어 있습니다. 이는 벤더가 제시한 수치이므로, 예산을 세우기 전에 최신 가격을 확인하세요.

컨텍스트 윈도우는 얼마인가요? 모델 페이지의 정보가 일관되지 않습니다. 헤더에는 64K, 제공자 표에는 32K로 적혀 있습니다. 어느 쪽이든 의존하기 전에 여러분의 가장 긴 입력으로 직접 확인하세요.

이 가이드의 범위

위의 모든 내용은 하나의 입력에 대해 실제 호출 3회로 검증했습니다. 지연 시간, 배치 처리, 처리량, 예시와 다른 입력에 대한 동작은 다루지 않습니다. 신뢰도 변동은 재현된 관찰일 뿐 측정된 오류율이 아니므로, 임계값을 정하기 전에 자신의 데이터로 다시 확인하세요.

AiHubMix에서 시작하기

jev-1.13 은 AiHubMix를 통해 이용할 수 있으며, 모델 페이지에는 이 튜토리얼에서 다룬 내용이 모두 나와 있습니다. 즉 /v1/systemone 엔드포인트, criteria 형식이 포함된 세 가지 질문 유형, 전체 응답 필드, 그리고 입력 토큰 $0.0462 / M 과 출력 토큰 $0 / M 의 게시 가격이 포함되어 있습니다. jev-latest 별칭은 최신 릴리스로 연결되므로, 버전이 바뀌어도 항상 최신 상태를 유지합니다.

여기서 시작하세요: https://aihubmix.com/model/jev-latest

다음 단계:

  1. AiHubMix 계정을 만들고 API 키를 발급받기
  2. 3단계의 요청과 4단계의 ask() 함수를 복사하기
  3. state 를 여러분의 대기열에 있는 실제 레코드로 바꾸기
  4. 결과를 지금 해당 레코드를 분류하는 방식과 비교하기

이 가이드가 도움이 되었다면, 구조화된 출력 모델과 분류 파이프라인에 관한 향후 글을 구독해 주세요.

여러 AI 제공업체를 하나의 게이트웨이로. 프로덕션 환경을 위해 설계했습니다.

AIHubMix 웹사이트 방문