100건을 평가해 실패가 한 번도 없었다면 관측 실패율은 0/100=0%다. 그러나 앞으로 들어올 요청의 실패확률까지 0이라고 확인한 것은 아니다. 독립적인 요청마다 같은 실패확률을 갖는다는 이항 가정 아래에서는, 실패 0건일 때 그 확률의 단측 95% 신뢰상한이 약 2.95%다.
이 글의 10건·100건·1,000건은 설명용 합성 표본 크기다. 실제 AI 서비스나 모델을 시험하지 않았다. 계산은 미리 정한 실패 기준으로 고정된 표본 수를 평가해 모두 성공한 상황만 다룬다. 두 모델의 우열 검정, 변경의 인과 효과, 미래 무실패 보증은 계산하지 않는다.
실패 0건이 나올 확률에서 상한을 구한다
요청별 실패 여부가 서로 독립이고, 모든 요청의 실패확률이 같은 p라고 하자. 표본 수를 n으로 고정하면 실패 건수 X는 이항분포를 따른다. 이때 실패가 한 번도 없을 확률은 P(X=0 | p)=(1-p)^n이다.
NIST의 비율 신뢰구간 안내는 적은 실패 건수에서 이항분포에 기반한 정확 구간을 설명한다. 거기 제시된 양측 구간의 상단 꼬리 확률은 α/2다. 여기서는 단측 95%를 구하므로 한쪽에 α=0.05를 두고, 실패 0건의 확률식을 직접 풀면 다음과 같다.
(1-p_upper)^n=0.05p_upper=1-0.05^(1/n) (n은 1 이상의 정수)
n=100을 대입하면 상한은 약 0.029513, 백분율로 약 2.9513%다. 실제 실패확률이 이 상한일 때 100건에서 실패 0건을 볼 확률이 5%라는 계산이다. 상한보다 큰 실패확률에서는 실패 0건을 볼 확률이 더 작다. 이는 참 실패확률이 2.95%라고 추정했다는 뜻도 아니다.
표본 수가 달라도 관측값은 모두 0%다
| 고정 표본 수 n | 관측 실패율 | 정확 상한 | 3/n 근사 |
|---|---|---|---|
| 10 | 0/10 = 0% | 약 25.8866% | 30% |
| 100 | 0/100 = 0% | 약 2.9513% | 3% |
| 1,000 | 0/1,000 = 0% | 약 0.2991% | 0.3% |
‘실패 없음’이라는 관측은 같아도 표본 수가 다르면 남은 불확실성이 다르다. 10건에서 실패를 못 본 결과를 1,000건에서 못 본 결과와 같은 검증 강도로 읽으면 안 된다. n=0일 때는 관측 비율도 이 식도 정의되지 않으며 평가하지 않은 상태다.
3/n은 같은 조건에서 쓰는 근사다
상한식을 1-exp(log(0.05)/n)으로 쓰면, n이 충분히 커서 지수가 0에 가까울 때 1-exp(-a/n)≈a/n을 적용할 수 있다. 여기서 a=-log(0.05)≈2.9957이므로 약 3/n이다. 위 확률식에서 도출한 근사이며 실패가 관측된 경우나 다른 신뢰수준의 만능 공식이 아니다.
n=10에서는 정확 상한 약 25.89%와 근사 30%의 차이가 눈에 띈다. 아주 작은 n에서 3/n이 1을 넘으면 유효한 확률 상한으로 그대로 보고할 수도 없다. 이 상황은 계산이 쉬우므로 보고할 때는 정확식을 쓰고, 3/n은 크기를 가늠하는 데 사용하면 된다. 단측 95% 상한과 양측 95% 구간의 상단도 서로 같지 않다.
본문 코드로 상한과 0건 확률을 검산한다
다음 JavaScript를 Windows의 Node.js v24.15.0에서 본문 HTML의 코드 텍스트를 추출·entity 해제해 실행했다. Math.expm1(x)는 exp(x)-1을 계산하므로 1에서 매우 가까운 수를 빼는 손실을 줄인다. 출력의 upperPct와 ruleOfThreePct는 백분율 단위다.
function zeroFailureUpper95(n) {
if (!Number.isSafeInteger(n) || n < 0) {
throw new Error("n must be a nonnegative safe integer");
}
if (n === 0) return null;
return -Math.expm1(Math.log(0.05) / n);
}
const round4 = x => Number(x.toFixed(4));
for (const n of [0, 10, 100, 1000]) {
const upper = zeroFailureUpper95(n);
console.log(JSON.stringify({
n,
observedPct: n === 0 ? null : 0,
upperPct: upper === null ? null : round4(100 * upper),
ruleOfThreePct: n === 0 ? null : round4(300 / n),
zeroProbabilityAtUpper: upper === null ? null
: round4(Math.exp(n * Math.log1p(-upper)))
}));
}
{"n":0,"observedPct":null,"upperPct":null,"ruleOfThreePct":null,"zeroProbabilityAtUpper":null}
{"n":10,"observedPct":0,"upperPct":25.8866,"ruleOfThreePct":30,"zeroProbabilityAtUpper":0.05}
{"n":100,"observedPct":0,"upperPct":2.9513,"ruleOfThreePct":3,"zeroProbabilityAtUpper":0.05}
{"n":1000,"observedPct":0,"upperPct":0.2991,"ruleOfThreePct":0.3,"zeroProbabilityAtUpper":0.05}
‘95% 확률로 참값이 이 아래’라는 뜻은 아니다
NIST의 신뢰수준 해석 설명처럼, 빈도주의 신뢰수준은 같은 가정 아래에서 표본추출과 구간 계산을 반복할 때 그 절차가 참값을 덮는 비율에 관한 말이다. 이 글에서 참값은 실패확률이다. 일반적인 정확 이항 단측 신뢰구간 절차의 포함률은 적어도 95%가 되도록 구성된다. 실패 0건인 표본만 골라 반복했을 때의 조건부 포함률을 말하는 것은 아니다.
이번에 얻은 상한 하나에 대해 ‘고정된 참 실패확률이 95% 확률로 이 아래에 있다’는 사후확률로 읽지 않는다. 또 ‘다음 100건은 95% 확률로 모두 성공한다’는 예측도 아니다. 표본 수·실패 건수·단측 여부·신뢰수준·가정을 함께 적어야 숫자의 의미가 남는다.
같은 문서를 반복한 횟수를 새 요청 수로 세지 않는다
같은 문서의 페이지나 같은 입력의 반복 실행은 결과가 상관될 수 있다. 100개 행이 있다고 해서 독립적인 새 입력 100건과 같다고 볼 수 없다. 반복과 그룹 의존이 있으면 위 단순 이항 상한을 그대로 적용할 근거부터 확인해야 한다. 목표 모집단을 대표하지 않는 쉬운 예제만 모았다면, 그 표본의 무실패를 실제 트래픽의 실패확률 상한으로 확대할 수도 없다.
실패 기준·프롬프트·모델·입력 구성이 바뀌면 같은 p라는 가정도 다시 검토한다. 실패할 때마다 기준을 고치고 성공이 나올 때까지 시험한 뒤 마지막 성공 묶음만 보고하거나, 결과를 보며 임의 시점에 멈춘 경우에는 고정 표본 수 설계의 이 계산을 그대로 정당화할 수 없다. 평가 계획과 제외한 결과도 남겨야 한다.
보고 문장은 ‘미리 정한 기준으로 독립·동일 실패확률을 가정한 합성 예: n=100, 실패 0건, 관측 0%, 정확 이항 단측 95% 상한 약 2.95%’처럼 쓸 수 있다. 실제 운영 보고에는 합성이 아닌 실제 표본의 기간·선정 방식·실패 정의와 가정의 한계를 기입한다.
성공률의 %p와 상대 변화 계산은 관측 비율의 산술을 다룬다. 이 글은 그다음 질문인 ‘실패 0건에서도 어느 정도 불확실성이 남는가’를 한 가지 이항 상황에서 계산했다. 평가 묶음 구성은 프롬프트 회귀 평가의 대표 입력·중요 예외 구분과 함께 확인한다.
자주 묻는 질문
실패가 한 건이면 3/n에 1/n을 더하면 되나요?
그렇게 계산하지 않는다. 이 글의 식은 실패 0건에 한정된다. 실패가 관측됐다면 해당 건수와 표본 수에 맞는 이항 신뢰구간 방법을 선택한다.
상한 2.95%면 그 정도 실패는 허용해도 되나요?
통계 상한은 업무상 허용 위험을 정하지 않는다. 한 번의 실패가 미치는 영향과 복구 가능성, 평가 범위를 별도로 판단해야 한다.
양측 95% 구간도 같은 숫자인가요?
아니다. 같은 이항 꼬리 역산 방식의 양측 95% 구간 상단은 0.05 대신 0.025를 넣는다. 단측·양측을 생략한 채 숫자만 비교하면 안 된다.