탐색으로 건너뛰기

Decisions API

Decisions API

대부분의 모델 호출은 문단을 반환하고, 결정을 추출하는 작업은 애플리케이션에 맡깁니다. JSON을 요청하고 파싱하고 검증한 뒤 형식이 어긋나면 다시 시도해야 합니다. Decisions API는 이 단계를 없앱니다. 애플리케이션의 현재 상태와 질문을 보내면 답변은 이미 정해진 타입으로 돌아옵니다. 예일 확률, 직접 이름을 붙인 선택지 중 하나, 직접 정의한 척도의 위치를 확률과 함께 받을 수 있습니다.

대화보다는 소프트웨어 내부의 판단에 적합합니다. 문의를 분류하거나, 도구 호출을 허용하거나, 대기열의 우선순위를 정하거나, 사람이 검토하기 전에 제출물을 평가할 때 사용합니다.

POST https://api.beatapi.io/v1/systemone

엔드포인트 경로와 요청·응답 본문은 TypeSafe의 형식을 그대로 따릅니다. 기존 TypeSafe 클라이언트나 SDK에서는 기본 URL과 모델 이름만 바꾸면 됩니다. POST /v1/decisions도 별칭으로 유지됩니다.

모델선택 기준
jev-1.14여기서 시작하세요. 입력 토큰 100만 개당 $0.0441입니다. 출력은 과금하지 않습니다. 이미지와 box 질문을 지원합니다.
jev-1.13기존 연동을 위해 유지하는 이름입니다. 가격은 jev-1.14와 같고 실제 1.13 버전이 응답합니다. 이미지와 box 질문을 지원합니다.

jev-1.14는 TypeSafe의 현행 버전 jev-latest를 따르며, 현재는 jev-1.14.0으로 연결됩니다. 1.13보다 전반적으로 조금씩 나아졌고 다국어 입력에서 가장 크게 개선되었습니다. TypeSafe가 수치를 공개하지 않아 여기에도 적지 않습니다. jev-1.13은 실제 1.13 버전이 응답하고, 기존 연동이 계속 작동하도록 그대로 받으며 가격도 같습니다.

이 엔드포인트는 /v1/chat/completions가 아니며, 해당 경로에서는 JEV 모델을 사용할 수 없습니다. 요청에 messages가 없고 응답에 choices가 없습니다. 결정 모델은 텍스트를 생성하지 않습니다.

빠른 시작

잔액이 있는 BeatAPI 키로 jev-1.14를 호출하세요. 입력은 100만 토큰당 $0.0441, 출력은 무료이며 호출은 계정의 일반 요청 한도에 포함됩니다. 무료 버전 jev-1.14-free와 jev-1.13-free는 2026-11-05에 종료되었습니다. 요청 한도를 참고하세요.

curl https://api.beatapi.io/v1/systemone \
-H "Authorization: Bearer $BEATAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-1.14",
"state": "Task: clean up inactive accounts before the quarterly report.\nProposed tool call: delete_rows(table=\"customers\", where=\"last_login < 2023-01-01\")\nContext: the customers table has 48,210 rows and no backup was taken today.",
"questions": {
"safe_to_run": {
"type": "noul",
"instructions": "Is this action safe to run without a human approving it first?",
"criteria": {
"true": "Reversible or low-impact, and clearly within the stated task.",
"false": "Destructive, irreversible, or broader than the task requires."
}
}
}
}'

다음 응답은 설명용 예시이며 측정 결과가 아닙니다. JSON을 파싱하고 HTTP 상태와 답변 타입을 확인한 뒤, 값을 검증하고 자체 임계값을 적용하세요.

{
"id": "task_01J...",
"model": "jev-1.14",
"answers": {
"safe_to_run": { "type": "noul", "noul": 0.04 }
},
"usage": { "input_tokens": 384, "output_tokens": 22 }
}

0.04는 모델이 추정한 예의 확률, 즉 4%입니다. 따라서 에이전트는 멈추고 사람에게 확인합니다. 이것이 이 질문을 하는 목적입니다.

JSON 복구 반복 없이 타입이 정해진 결정 받기

BeatAPI를 대상으로 지정하고 상태와 질문을 보낸 뒤 답변을 읽으세요. 별칭 /v1/decisions도 동일하게 동작합니다. chat/completions가 아니며 해당 경로에서는 JEV 모델을 사용할 수 없습니다.

const response = await fetch("https://api.beatapi.io/v1/systemone", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BEATAPI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "jev-1.14",
state: {
task: "clean up inactive accounts",
tool: 'delete_rows(table="customers", where="last_login < 2023-01-01")',
rows: 48210,
backup_today: false,
},
questions: {
safe_to_run: {
type: "noul",
instructions: "Is this action safe to run without a human approving it first?",
criteria: {
true: "Reversible or low-impact, and clearly within the stated task.",
false: "Destructive, irreversible, or broader than the task requires.",
},
},
},
}),
});
if (!response.ok) {
// On HTTP 429, wait the Retry-After seconds before retrying.
throw new Error(`JEV HTTP ${response.status}; Retry-After: ${response.headers.get("Retry-After")}`);
}
const decision = await response.json();
const answer = decision.answers?.safe_to_run;
if (answer?.type !== "noul" || !Number.isFinite(answer.noul)
|| answer.noul < 0 || answer.noul > 1) {
throw new Error("Invalid JEV answer; route to human review");
}
// Illustrative threshold: evaluate it on your own cases before use.
const needsReview = answer.noul < 0.9;
console.log({ probability: answer.noul, needsReview });

요청

필드유형필수설명
modelstring예jev-1.14. jev-1.13도 계속 사용할 수 있습니다. jev-1.14-free와 jev-1.13-free는 2026-11-05에 종료되어 더 이상 사용할 수 없습니다. 모델이 없는 요청은 거부됩니다.
statestring | object | array예애플리케이션이 현재 알고 있는 정보입니다. 일반 문자열, JSON 객체, 텍스트 값 배열을 사용할 수 있습니다. 이미지는 assets에서 정의한 뒤 텍스트에서 참조하세요(이미지 참고). 오디오, 동영상, 기타 바이너리는 먼저 텍스트로 변환해야 합니다.
questionsobject예이름이 지정된 질문 하나 이상입니다. 직접 정한 이름이 답변의 키가 됩니다.
assetsobject아니요텍스트에서 참조하는 이미지입니다. "<door>"처럼 직접 정한 참조 문자열을 키로 사용합니다. box 질문에는 필수입니다. 이미지를 참고하세요.

각 질문에는 type, instructions, 그리고 타입에 따라 criteria가 들어갑니다.

필드유형필수설명
typestring예noul, choice, score, box 중 하나입니다.
instructionsstring | object | arraynoul과 box에 필수동료에게 묻듯 자연스럽게 작성한 질문입니다. noul에서는 예/아니요의 대상, box에서는 찾을 대상을 지정하므로 필수입니다. choice와 score는 criteria만으로 질문을 정의할 수도 있습니다.
criteria아래 참고타입에 따라 다름답변 값의 의미입니다. box에서는 사용할 수 없습니다.

네 가지 질문 타입

noul: 보정된 확률

임의의 선택이 아닌 임계값을 기준으로 예/아니요를 판단할 때 사용합니다. 답변은 0부터 1 사이의 숫자입니다.

"refund_ok": {
"type": "noul",
"instructions": "Should this refund be approved automatically?",
"criteria": {
"true": "Clear billing error, under $100, first request from this account.",
"false": "Disputed usage, over $100, or a repeat request."
}
}
"refund_ok": { "type": "noul", "noul": 0.83 }

여기서 criteria는 선택 사항이지만 양쪽 기준을 설명하면 답변이 더 명확해집니다. 임계값은 직접 정하세요. 예를 들어 0.9 초과는 자동 승인, 0.6 미만은 상위 담당자에게 전달하고, 중간 값은 검토 대기열에 넣을 수 있습니다.

noul은 실제 타입 이름이며 bool의 오타가 아닙니다. 타입 이름을 잘못 쓰면 유효한 타입 목록과 함께 400 오류가 반환됩니다.

choice: 이름을 붙인 선택지 중 하나

criteria는 각 선택지 이름과 의미를 연결하는 객체입니다. 답변에는 선택된 항목과 전체 확률 분포가 포함됩니다.

"route": {
"type": "choice",
"instructions": "Which queue should this ticket go to?",
"criteria": {
"billing": "Payment, invoices, refunds, or charges.",
"technical": "The product is broken or erroring.",
"sales": "Pre-purchase questions about plans or pricing."
}
}
"route": {
"type": "choice",
"choice": "billing",
"probabilities": { "billing": 1, "technical": 0, "sales": 0 },
"confidence": 1
}

score: 직접 정의한 척도의 위치

criteria는 낮은 값부터 척도를 설명하는 배열입니다. 답변은 0부터 시작하는 배열 인덱스 위의 연속값입니다.

"urgency": {
"type": "score",
"instructions": "How urgent is this ticket?",
"criteria": [
"1 - can wait a week",
"2 - answer within a few days",
"3 - answer today",
"4 - answer within an hour",
"5 - wake someone up"
]
}
"urgency": {
"type": "score",
"score": 1.98,
"legend": { "0": "1 - can wait a week", "1": "2 - answer within a few days",
"2": "3 - answer today", "3": "4 - answer within an hour",
"4": "5 - wake someone up" },
"probabilities": { "0": 0, "1": 0.17, "2": 0.67, "3": 0.16, "4": 0 },
"confidence": 0.72
}

1.98은 legend["1"]과 legend["2"] 사이에서 후자인 ‘오늘 답변’에 매우 가깝습니다. 범주가 필요하면 반올림하고, 대기열을 정렬하려면 소수 부분을 유지하세요.

box: 이미지에서 대상의 위치 찾기

이미지의 대상 하나를 찾을 때 사용합니다. box는 jev-1.14와 jev-1.13 모두 지원합니다. instructions에 찾을 대상을 쓰고 criteria는 넣지 않습니다. 이미지가 하나 이상 있어야 하며(이미지 참고), 없으면 400 오류가 반환됩니다.

"where": {
"type": "box",
"instructions": "The red rectangle in <picture>."
}
"where": {
"type": "box",
"box": { "top": 0.12, "bottom": 0.43, "left": 0.56, "right": 0.89 },
"confidence": 0.93
}

네 값은 위쪽과 왼쪽 가장자리를 기준으로 한 이미지 높이(top, bottom)와 너비(left, right)의 비율로, 각각 0부터 1 사이입니다. 이미지의 픽셀 크기를 곱하면 픽셀 좌표가 됩니다. confidence는 null일 수 있으므로 임계값과 비교하기 전에 확인하세요.

이미지

1.13과 1.14 모델 모두 이미지를 읽습니다. 최상위 assets 객체에 이미지를 한 번 정의하고, state의 텍스트, 질문의 instructions, 또는 criteria 값에서 참조 문자열을 사용하세요. 참조가 나타나는 위치에 이미지가 배치됩니다.

필드유형필수설명
typestring아니요image이며 생략할 수 있습니다.
formatstring예png, jpg, jpeg 중 하나입니다.
data_base64string예data: 접두사 없는 표준 base64 형식의 이미지 바이트입니다.
curl https://api.beatapi.io/v1/systemone \
-H "Authorization: Bearer $BEATAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-1.14",
"state": "Check the uploaded image.",
"assets": {
"<picture>": { "type": "image", "format": "png", "data_base64": "iVBORw0KGgo..." }
},
"questions": {
"red": { "type": "noul", "instructions": "Is there a red rectangle in <picture>?" },
"where": { "type": "box", "instructions": "The red rectangle in <picture>." }
}
}'

이 호출에는 빨간 사각형 하나가 있는 280×280 픽셀의 흰색 이미지를 사용했습니다. 아래 응답은 실제 측정 결과입니다. id는 공급자 필드에 추가되는 BeatAPI 요청 식별자입니다.

{
"id": "task_01J...",
"model": "jev-1.14",
"answers": {
"red": { "type": "noul", "noul": 0.92 },
"where": { "type": "box",
"box": { "top": 0.12, "bottom": 0.43, "left": 0.56, "right": 0.89 },
"confidence": 0.93 }
},
"usage": { "input_tokens": 501, "output_tokens": 36 }
}

참조 동작 방식:

  • 참조는 일반 텍스트로 일치시킵니다. "<door>"나 "[img-1]"처럼 원하는 문자열을 사용할 수 있습니다. 객체 키는 검색하지 않으므로 참조를 값에 넣으세요.
  • 정의한 모든 참조를 한 번 이상 사용해야 합니다. 사용하지 않은 참조가 있으면 400 오류가 반환됩니다.
  • JSON만 보내세요. Multipart 업로드는 지원하지 않습니다. part 필드가 있는 리소스는 data_base64를 사용하라는 400 오류로 거부됩니다.
  • TypeSafe API에서 요구하는 TypeSafe-Danger-Zone-Images 헤더는 보내지 않아도 됩니다. BeatAPI가 추가합니다. 직접 보내도 문제없습니다.

이미지 제한:

  • 정적 PNG 또는 JPEG만 지원하며 애니메이션 이미지는 거부됩니다.
  • 디코딩 후 이미지당 최대 16 MiB, 전체 요청 본문은 최대 32 MiB입니다.
  • 각 변은 280~1568픽셀이어야 합니다. 최솟값보다 작으면 Invalid image dimensions. 오류가 반환됩니다.
  • 이미지 크기를 자동으로 조정하지 않습니다. 한도보다 크면 전송 전에 줄이세요.
  • 이미지 하나라도 잘못되면 전체 요청이 실패합니다.

한 번의 호출로 여러 질문하기

같은 상태에 관한 질문을 한 번에 보내세요. 각 답변은 독립적이며 공통 상태는 질문마다가 아니라 한 번만 계산됩니다.

curl https://api.beatapi.io/v1/systemone \
-H "Authorization: Bearer $BEATAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-1.14",
"state": {"ticket": "charged twice this month", "plan": "pro", "tenure_days": 412},
"questions": {
"refund_ok": {"type": "noul", "instructions": "Approve the refund automatically?"},
"urgency": {"type": "score", "instructions": "How urgent?", "criteria": ["low", "medium", "high"]}
}
}'

응답

필드설명
model답변한 모델입니다.
answers질문마다 지정한 이름을 키로 하는 항목입니다. 각 항목에 type과 아래 필드가 포함됩니다.
usage이번 호출의 input_tokens와 output_tokens입니다.
id지원 문의에 사용할 BeatAPI 요청 식별자입니다. 공급자의 세 필드에 추가됩니다. 이 필드를 정의하지 않은 클라이언트는 무시할 수 있습니다.

질문 타입별 답변 필드:

type필드
noulnoul: 예의 확률로, 0부터 1 사이입니다.
choicechoice: 선택된 항목, probabilities: 항목별 확률, confidence.
scorescore: criteria 인덱스 위의 값, legend, probabilities, confidence.
boxbox: top, bottom, left, right. 위쪽과 왼쪽 가장자리를 기준으로 한 높이 또는 너비의 0~1 비율입니다. confidence는 null일 수 있습니다.

동기 응답이므로 HTTP 응답이 성공하면 결정이 완료된 것입니다. 상태를 폴링하거나 결과 파일을 가져올 필요가 없습니다.

제한

  • 컨텍스트: state와 모든 질문을 합쳐 64K 토큰입니다. state와 가장 긴 질문 하나의 합은 32K 토큰 이하여야 합니다. 모델 제한을 참고하세요.
  • 확장 컨텍스트는 아직 지원하지 않습니다. TypeSafe는 262K 토큰으로 늘리는 헤더를 제공하지만 BeatAPI는 지원하지 않습니다. 이미지 토큰을 포함해 위의 64K 한도가 적용됩니다.
  • 이미지: Multipart 없이 JSON만 사용하며 이미지의 제한을 따릅니다.
  • 샘플링 매개변수 없음: temperature, top_p, seed 등은 사용할 수 없습니다. 답변 형식은 결정적으로 설계되었습니다.
  • 스트리밍 없음: 답변은 토큰 시퀀스가 아닌 값입니다.
  • choice에는 비어 있지 않은 criteria 객체, score에는 비어 있지 않은 criteria 배열이 필요합니다. 없으면 원인을 설명하는 400 오류가 반환됩니다. instructions는 선택 사항이지만 제공할 경우 비어 있으면 안 됩니다.

오류

오류는 표준 BeatAPI 오류 형식을 사용하며 항상 retryable을 포함합니다. 전체 표와 재시도 정책은 오류를 참고하세요.

HTTP코드의미
400bad_request잘못된 JSON, 모델, 질문 타입, 기준 또는 이미지입니다. 메시지에 필드가 표시됩니다. 사용하지 않거나 잘못된 assets, part 필드, 이미지 없는 box, 지원하지 않는 이미지 또는 범위를 벗어난 크기 등이 해당합니다.
401missing_api_key / invalid_api_key키가 없거나 잘못되었거나, 만료·비활성화되었거나 키 할당량을 모두 사용했습니다.
402insufficient_credits잔액이 0이거나 호출 비용보다 부족합니다.
403forbidden키나 계정에 해당 모델의 사용 권한이 없습니다.
404not_found알 수 없는 모델입니다.
429rate_limit_exceeded요청 한도에 도달했습니다. Retry-After에 지정된 초만큼 기다리세요.
500internal_error예기치 않은 내부 오류이며 재시도할 수 있습니다.
503processing_unavailable 또는 다른 processing_* 코드요청을 완료하지 못했습니다. 대기 시간을 늘리며 재시도하세요.

실패한 호출은 크레딧을 사용하지 않습니다.

과금

유료 모델 jev-1.14와 jev-1.13은 state, questions, 이미지가 차지하는 입력 토큰에만 과금합니다. 가격은 입력 토큰 100만 개당 $0.0441입니다. 출력은 생성된 문장이 아닌 타입이 지정된 값이므로 과금하지 않습니다. 각 응답의 usage.input_tokens에서 정확한 사용량을 확인해 호출별 비용을 대조할 수 있습니다.

이미지도 같은 입력 토큰 단가를 적용하며 별도의 이미지 요금은 없습니다. 참고로 280×280 이미지는 약 320토큰, 512×512는 약 840토큰, 1024×768은 약 2,200토큰입니다. 실제 사용량은 usage.input_tokens에 표시됩니다.

따라서 같은 상태를 여러 번 보내는 것보다 한 번의 호출로 여러 질문을 하는 편이 훨씬 저렴합니다.

요청 한도

유료 호출은 계정의 일반 요청 한도를 사용하며, 누적 충전액에 따라 한도가 올라갑니다. 현재 한도와 다음 충전 구간은 대시보드에서 확인하세요. JEV 전용 할당량은 없습니다. 한도를 넘으면 429 rate_limit_exceeded와 Retry-After 헤더가 반환되니 그 시간만큼 기다린 뒤 다시 시도하세요.

첫 호출 전에 잔액을 충전하세요. 유료 호출에는 잔액이 필요합니다.

무료 JEV 모델(종료)

jev-1.14-free와 jev-1.13-free는 2026-11-05에 종료되었습니다. 이 이름을 지정한 요청은 더 이상 성공하지 않습니다. model을 jev-1.14로 바꾸세요. 엔드포인트, state, questions는 그대로 둡니다.