"temperature=0이면 결정론적"이라는 착각
프로덕션에 AI를 붙인 팀은 대부분 한 번쯤 이렇게 안심한다. “샘플링 온도를 0으로 고정했으니, 같은 프롬프트엔 같은 답이 나온다.” 그런데 막상 돌려보면 아니다. 같은 문장을 같은 모델에, 같은 파라미터로 1,000번 넣으면 수십 가지 다른 답이 돌아온다.
Thinking Machines Lab이 2025년 9월 공개한 실험이 이걸 정면으로 보여준다. 한 모델에 파인만에 관한 프롬프트를 temperature=0으로 1,000번 생성시켰더니 완성된 답이 80가지로 갈렸다. 가장 많이 나온 답조차 1,000번 중 78번뿐이었다. "결정론적"이라던 설정이 사실상 매번 다른 결과를 뱉고 있었던 셈이다.
흔한 설명은 절반만 맞다
보통은 이렇게 설명한다. “GPU는 부동소수점 연산을 병렬로 하는데, 덧셈 순서가 실행마다 달라져 미세한 오차가 쌓이고, 그게 다른 토큰으로 갈라진다.” 부동소수점이 결합법칙을 안 따른다는 것 — (a+b)+c와 a+(b+c)가 다를 수 있다는 것 — 은 사실이다. 하지만 이건 원인의 절반이다.
진짜 범인은 배치 불변성(batch invariance)의 부재다. 추론 서버는 처리량을 위해 여러 사용자의 요청을 한 배치로 묶어 계산한다. 그런데 정규화·행렬곱·어텐션 같은 리덕션 연산은 배치 크기가 달라지면 내부 누적 순서가 달라진다. 같은 입력이라도 배치 크기 8에서 처리되느냐 32에서 처리되느냐에 따라 결과가 미세하게 어긋난다.
문제는 그 배치 크기를 내가 정하지 못한다는 데 있다. 서버는 그 순간의 트래픽에 맞춰 요청을 묶는다. 내 프롬프트는 똑같아도 나와 같은 배치에 얹히는 남들의 요청은 매번 다르다. 결국 결과는 내 통제 밖의 부하 상태에 따라 흔들린다.
이게 조용히 깨뜨리는 것들
비결정성은 데모에선 안 보인다. 문제는 시스템으로 굳힐 때다.
- 회귀 테스트: 출력이 조금만 달라져도 스냅샷 비교가 깨진다. 그래서 많은 팀이 테스트를 느슨하게 풀고, 결국 진짜 회귀를 놓친다.
- 버그 재현: 고객이 겪은 이상한 출력을 그대로 되살리지 못한다. 같은 입력을 넣어도 다른 답이 나오니까.
- 감사·규제: "이 판단이 왜 이렇게 나왔나"를 되짚어야 하는 도메인에서, 재현되지 않는 시스템은 근거가 되지 못한다.
- 강화학습: 학습에 쓴 추론과 실제 서빙 추론이 미세하게 다르면, on-policy라 믿고 돌린 학습이 실은 off-policy가 된다. 학습이 불안정해지는 숨은 원인이다.
그래서 뭘 해야 하나
두 갈래다.
첫째, 결정성을 기대하지 말고 그 위에서 설계한다. 출력을 글자 단위로 비교하는 대신, 지켜야 할 불변식으로 검증한다. 형식이 맞는지, 필수 필드가 있는지, 값이 범위 안에 드는지. 허용 오차를 코드에 명시적으로 박아 둔다.
둘째, 정말 재현이 필요하면 추론 스택을 통제한다. Thinking Machines Lab은 배치 크기와 무관하게 같은 결과를 내는 커널(정규화·행렬곱·어텐션)을 공개했고, 이걸 쓰면 1,000번 실행이 비트 단위로 똑같아진다. 대가는 처리량 하락이다. LMSYS의 SGLang도 같은 방향으로 결정론적 추론과 재현 가능한 RL 학습을 붙였다.
여기서 하나가 분명해진다. 배치를 통제하려면 추론 인프라를 통제해야 한다. 남의 API 뒤에 있는 모델은 그 순간의 배치를 당신이 정할 수 없다. 재현성이 제품의 요건인 도메인 — 금융·의료·법률 — 에서 전용 추론이나 셀프호스팅을 택하는 진짜 이유가 여기 있다. 결정성은 모델의 성질이 아니라 인프라의 선택이다.