AI Agent Fast Learning · 실행 결과 읽기
실패가 몰려 있다는 사실과, 그 몰림이 비교 모형에서 드물다는 판단은 다르다. 성공·실패의 개수를 고정하고 가능한 순서를 모두 비교하면, 관측한 전체 런 수가 얼마나 작은지 계산할 수 있다. 다만 그 계산이 유효하려면 순서를 바꿔도 각 배열이 같은 확률이라는 가정이 필요하다. 작은 p값만으로 장애 원인을 확정할 수는 없다.
“성공 여섯 번 뒤에 실패 여섯 번이 이어졌다. 우연이라고 보기 어려운가?” 앞선 글에서는 실패 묶음을 셌다. 이번에는 그 숫자를 무엇과 비교할지 정한다. 통계 지식 없이도 아래의 924개 배열을 세는 과정을 따라갈 수 있도록, 작은 가상 예제로 범위를 제한했다.

세 배열 모두 성공률은 50%다
S는 검증된 성공, F는 종료 실패다. 한 실행이 끝난 뒤 다음 실행을 시작했고, 열두 실행의 결과를 모두 확인했다고 가정한다. 다음은 실제 서비스 기록이 아니라 설명을 위해 만든 배열이다.
A: SSSSSSFFFFFFB: SSFFSSFFSSFFC: SFSFSFSFSFSF
전체 런(run)은 같은 기호가 연속한 묶음이다. A는 성공 묶음 하나와 실패 묶음 하나여서 2런이다. B는 6런, C는 12런이다. 실패 묶음만 세는 수나 최장 연속 실패 길이와는 다른 통계량이다. 런 수가 작을수록 같은 결과끼리 길게 모여 있는 방향을 나타낸다.
비교 모형: 개수는 고정하고 자리만 바꾼다
성공 여섯 개를 열두 자리 중 어디에 놓을지 고르면 나머지는 실패가 된다. 경우의 수는 12 choose 6 = 924다. 여기서는 이 924개 배열이 모두 같은 확률이라는 귀무 모형을 사용한다. 이는 각 실행이 서로 독립이고 성공 확률이 같다는 모형에서, 성공 개수가 여섯이라는 조건을 붙이면 얻을 수 있다.
검사할 방향은 사전에 “같은 결과가 모여서 전체 런 수가 작아지는가”로 정한다. 그때 단측 p값은 비교 모형에서 관측한 런 수 이하가 나올 확률, 즉 P(R ≤ R_observed)다. 관측 배열 하나만의 확률이나 “우연이 원인일 확률”을 뜻하지 않는다.
A에서 2런 이하인 배열은 SSSSSSFFFFFF와 그 반대 순서뿐이다. 따라서 2/924 = 1/462 ≈ 0.00216이다. 모든 배열을 빠짐없이 세므로 이 예제에서는 정규분포 근사나 무작위 추출 오차가 없다. 하지만 비교 모형 자체가 현실에 맞는지는 별도 문제다.
| 가상 배열 | 전체 런 | 낮은 런 수 방향의 단측 p값 |
|---|---|---|
| A | 2 | 2 / 924 ≈ 0.00216 |
| B | 6 | 362 / 924 ≈ 0.39177 |
| C | 12 | 924 / 924 = 1 |
p값 1인 번갈음도 무작위라는 뜻은 아니다
C는 성공과 실패가 완벽하게 번갈아 나온다. 그런데 위 검사의 p값은 1이다. 이상이 없어서가 아니라, 이 검사가 낮은 런 수 방향만 보고 있기 때문이다. 지나치게 많은 번갈음은 반대 방향의 질문이다. 이번 교육 예제는 양쪽 방향을 합친 검정을 구현하지 않는다.
자료를 본 뒤 낮은 쪽과 높은 쪽 중 더 작은 p값을 골라 그대로 보고하면 처음 정한 검정과 달라진다. 관심 방향과 유의수준은 결과를 보기 전에 정해야 한다. A·B·C는 해석을 설명하기 위한 합성 배열 세 개이며, 이 중 좋은 결과를 골라 실제 AI의 이상을 주장하는 시험이 아니다.
NIST의 런 검정 설명은 이분형 결과의 연속 묶음과 큰 표본에서 쓰는 정규근사를 설명한다. 그 근사 조건은 두 종류의 관측 개수가 각각 10보다 큰 경우다. 이 글의 여섯 개씩인 예제에는 그 근사를 적용하지 않고, 명시한 단측 확률을 직접 센다. NIST 문서의 양측 근사 검정과 아래 구현은 같은 절차가 아니다. 확인일: 2026-10-24.
복사해서 실행하는 작은 정확 계산
아래 코드를 check_runs.py로 저장한 뒤 python check_runs.py로 실행한다. 외부 패키지나 API는 필요 없다. 실행량이 조합 수에 따라 늘어나므로 교육용 함수는 길이를 16 이하로 제한한다. 실제 긴 운영 로그에 이 코드를 그대로 확장하지 않는다.
from itertools import combinations
from fractions import Fraction
from math import comb
def runs(s):
return 1 + sum(a != b for a, b in zip(s, s[1:]))
def exact_lower_tail(s):
if not isinstance(s, str) or not 2 <= len(s) <= 16:
raise ValueError('Use a string of length 2..16')
if set(s) != {'S', 'F'}:
raise ValueError('Both S and F are required; no missing outcomes')
n, successes, observed = len(s), s.count('S'), runs(s)
total, extreme = comb(n, successes), 0
for positions in combinations(range(n), successes):
candidate = ['F'] * n
for i in positions:
candidate[i] = 'S'
extreme += runs(candidate) <= observed
return observed, extreme, total, Fraction(extreme, total)
if __name__ == '__main__':
for s in ['SSSSSSFFFFFF', 'SSFFSSFFSSFF', 'SF' * 6]:
print(s, exact_lower_tail(s))
assert exact_lower_tail('SSSSSSFFFFFF') == (2, 2, 924, Fraction(1, 462))
assert exact_lower_tail('SF' * 6)[3] == 1
assert exact_lower_tail('SSFF') == (2, 2, 6, Fraction(1, 3))
for bad in ['', 'S', 'SSS', 'FFF', 'SF?F', 'S' * 9 + 'F' * 8, None]:
try:
exact_lower_tail(bad)
except ValueError:
pass
else:
raise AssertionError('Invalid input accepted')
print('10 checks passed')
2026-10-24에 Python 3.12.14로 위 합성 코드를 실제 실행했다. 세 배열의 출력과 10개 검사(정상값 3개, 잘못된 입력 7개)가 통과했다. 이것은 산술·입력 처리 시험이며 AI 모델이나 에이전트 SDK를 호출한 시험이 아니다. Python 3.12 문서의 itertools.combinations는 중복 없는 위치 조합을 생성하는 데 사용했다. 문서 확인일: 2026-10-24.
실제 로그에 적용하기 전에 멈춰 볼 네 지점
1. 성공 확률이 구간 내내 같았는가. 앞에는 쉬운 과제, 뒤에는 어려운 과제를 넣었다면 순서를 마음대로 바꿔도 된다는 가정이 성립하지 않을 수 있다. 버전 교체나 시간대별 부하 변화도 먼저 확인한다. 작은 p값이 나온 이유가 실행 간 의존성인지, 과제 구성의 변화인지 이 검사만으로 구분할 수 없다.
2. 같은 단위를 같은 순서로 셌는가. 사용자 요청과 그 요청의 재시도를 섞지 않는다. 동시 실행의 시작 순서와 종료 순서를 바꾸면 배열도 달라진다. 결과를 보기 전에 집계 단위, 순서 기준, 세션 경계를 고정한다. 알 수 없는 결과를 지워 양옆의 실패를 이어 붙이지 않는다. 위 함수는 미확인 기호를 거부한다.
3. 얼마나 많이 찾아보았는가. 하루 전체에서 시작점·길이·모델을 바꿔 가며 가장 작은 p값만 찾으면 이 단일 구간 계산의 의미가 달라진다. 여러 구간을 탐색했다면 탐색 사실과 개수를 남기고, 별도의 확인 자료나 다중 검사 설계가 필요하다. 문제가 생겨 보이는 구간을 찾는 탐색과 사전에 정한 검정은 분리한다.
4. 무엇을 확인했다고 말할 것인가. 작은 값은 정한 비교 모형과 관측 배열이 잘 맞지 않는다는 증거가 될 수 있다. 특정 도구 장애, 모델 결함, 악의적 공격을 확정하지 않는다. 큰 값도 독립성이나 안전성의 증명이 아니다. 원인 확인에는 해당 구간의 비식별 실행 기록과 입력·버전·도구 상태를 대조하는 별도 진단이 필요하다.
평가 기록에는 숫자보다 조건을 먼저 남긴다
복사 양식: 집계 단위 / 관측 구간 / 순서 기준 / S·F 판정 / 미확인 건수 / S·F 개수 / 전체 런 수 / 귀무 모형 / 사전 검사 방향 / p값 / 탐색한 구간 수 / 아직 확인하지 못한 원인. 고객 원문이나 인증값은 넣지 않는다. p값이 작다는 이유만으로 서비스 자동 차단 기준을 새로 만들지 말고, 업무 피해와 오탐 비용을 포함한 별도 운영 기준을 검증한다.
연속 실패를 세는 일은 조사할 모양을 찾는다. 이번 계산은 그 모양을 명시한 비교 모형과 대조한다. 다음 행동은 “원인을 찾았다”는 선언이 아니라, 그 비교 모형을 깨뜨릴 수 있는 입력 구성과 실행 조건부터 확인하는 것이다.
이어 읽기
연속 실패와 실행 순서 읽기: 집계부터 시작하기
무작위 실행 순서와 블록 설계: 비교 조건을 미리 정하기
여러 후보를 찾아본 뒤의 다중 비교 문제