happy_various AI 실전 기록

LLM 중계기 개발기 5부 · 22편 / 전체 33편

2026년 10월 1일 기준

이 글에는 제휴 링크가 없고 OpenAI·앤트로픽과 아무 관계가 없습니다. 제가 직접 만든 중계기의 개발 기록을 바탕으로 썼습니다. 삽화는 GPT 이미지 생성, 도식은 직접 제작했습니다.

‘준비 중’이 끝나지 않는 화면 — 영원히 ‘조리 중’인 주문 번호판 (LLM 중계기 개발기)

카페에서 음료를 주문하고 진동벨을 받았다고 해 볼게요. 계산대 위 번호판에는 칸이 두 개 있어요. ‘조리 중’과 ‘완료’. 내 번호는 ‘조리 중’ 칸에 떠 있고, 뒤에 주문한 사람들의 번호가 하나둘 ‘완료’로 넘어갑니다. 그런데 내 번호만 움직이지 않아요.

사실 주방에서는 내 음료를 만들다 엎었어요. 그런데 번호판에는 ‘취소’ 칸이 아예 없었습니다. 그래서 내 번호는 ‘조리 중’에 계속 떠 있고, 나는 울리지 않을 진동벨을 쥐고 앉아 있어요.

제가 만든 LLM 중계기에서 꼭 이런 일이 있었어요. AI 연결은 이미 끝났는데, 화면의 준비 표시는 ‘워밍업 중’에서 영영 넘어가지 않았습니다. 그것도 모양을 바꿔 두 번이나요.

이 글은 LLM 중계기 개발기의 22편입니다. 지난 21편 「끄는 것도 기술이다」에서는 꺼졌어야 할 프로그램이 뒤에 남은 이야기를 했어요. 오늘은 끝났어야 할 표시가 끝나지 않은 이야기입니다.

밤의 카페, 번호판의 불 하나만 오래 노랗게 켜져 있고 그 아래에서 로봇 손님이 지친 얼굴로 진동벨을 쥐고 기다린다 (GPT 이미지 생성)

결론 요약

🧾 1. 주문 번호판으로 보는 ‘상태’

번호판의 칸 하나하나를 상태(state)라고 불러요. 주문 하나는 늘 어느 한 칸에 있고, 일이 진행되면 화살표를 따라 다음 칸으로 옮겨 갑니다.

이렇게 칸과 화살표로 그린 그림을 개발자들은 흔히 상태 기계(state machine)라고 불러요. 이름은 거창하지만 결국 ‘어떤 칸이 있고, 어떤 일이 생기면 어느 칸으로 가는지’를 적어 둔 표예요.

이 중에서 ‘완료’와 ‘취소’는 특별한 칸이에요. 여기 닿으면 더는 기다릴 일이 없거든요. 이런 칸을 끝 상태(terminal state)라고 해요. 손님은 번호가 끝 상태에 닿아야 자리에서 일어날 수 있어요. 음료를 받으러 가든, 다시 주문하든요.

그래서 번호판이 믿을 만하려면 한 가지가 꼭 필요해요. ‘조리 중’에서 나가는 화살표가 모든 경우에 있어야 한다는 것. 잘 만든 경우, 엎은 경우, 주방이 아무 대답도 하지 않는 경우까지요. 화살표가 하나라도 빠지면, 그 길로 들어선 주문은 ‘조리 중’에 영원히 갇힙니다.

중계기 화면에도 이런 번호판이 있어요. 6편에서 중계기는 Claude 같은 AI 프로그램을 미리 데워 둔 엔진처럼 켜 두고 쓴다고 했죠. 화면에는 AI마다 준비 표시줄이 있어서, 모델 몇 개가 준비됐는지와 함께 ‘워밍업 중’이나 ‘준비 완료’를 보여 줘요. 화면은 1.5초마다 중계기에 “지금 어때?”를 물어서 이 표시를 바꿉니다.

🔥 2. 첫 번째 — ‘2/3 준비 · 워밍업 중’에서 멈춘 밤

개발 첫날 밤을 넘긴 새벽 1시 8분, v0.1.17의 저장 기록(커밋)에는 이런 증상이 적혀 있어요. Claude는 실제로 연결이 끝났는데, 화면은 ‘2/3 준비 · 워밍업 중’에 영원히 머물렀다. 21편에서 좀비 프로세스를 고친 지 세 시간쯤 뒤의 일이에요.

그때 중계기는 Claude를 연결하면 이렇게 준비했어요. 지금 방식과는 조금 달라요(4절에서 다시 나옵니다).

그런데 데우던 모델 하나의 세션이 오류로 끝나면, 그다음이 문제였어요.

결국 화면은 실패한 모델을 ‘아직 데우는 중’으로 읽었습니다. 엎은 음료를 ‘조리 중’으로 보여 준 번호판과 똑같죠. 기록의 표현으로는, 준비된 모델을 세는 장치에 실패라는 끝이 아예 없었어요. 화면이 끝나는 조건은 ‘전부 준비 완료’뿐이었으니, 화면은 1.5초마다 다시 묻기를 끝없이 되풀이했어요.

같은 시기 Codex는 멀쩡해 보였는데, 기록은 그 이유도 적어 두었어요. Codex는 보통 모델이 하나뿐이라 ‘1/1’이었기 때문이라고요. 모델이 하나면 ‘일부만 준비된’ 상황이 생길 틈이 없죠.

⏱️ 3. 첫 수정 — 모든 준비는 ‘준비 완료’ 아니면 ‘실패’로 끝난다

그날 새벽의 수정은 ‘영원히 대기’를 구조적으로 불가능하게 만드는 쪽이었어요.

① 제한 시간을 두르고, 결과는 둘 중 하나 — 모델마다 데우는 일을 제한 시간으로 감쌌어요. 성공하면 ‘준비 완료’, 오류가 나면 ‘실패’, 제한 시간을 넘겨도 ‘실패’예요. 어느 경우든 세는 장치가 한 칸 나아갑니다. 첫 세션을 켜는 데 꽤 오래 걸릴 수 있어서 제한 시간은 넉넉하게 잡았어요(기본 150초) ② 모든 AI가 함께 쓰는 도구로 — 이 규칙을 Claude 전용으로 두지 않고, 어떤 AI 연결 부품이든 가져다 쓸 수 있는 공용 도구로 만들었어요. 이 도구로 데우면 어느 AI든 ‘워밍업 중’에 영원히 머물 수 없어요. Codex도 같은 모양으로 ‘실패’를 보고하게 맞췄고요 ③ 실패는 이유와 함께 — 실패한 모델은 실패 이유를 함께 보고하고, 화면은 그 모델 이름과 이유를 보여 줘요 ④ 화면이 끝나는 조건을 바꿨다 — 예전에는 ‘전부 준비 완료’여야 끝이었어요. 이제는 ‘아직 워밍업 중인 모델이 하나도 없으면’ 끝이에요. 전부 준비됐든, 일부가 실패했든 상관없이요. 끝에 닿으면 화면은 더 묻지 않아요

탄 팬을 든 로봇 요리사가 번호판의 노란 불 하나를 빨간 X 표시로 바꾸고, 기다리던 손님 로봇이 안도하며 일어선다 (GPT 이미지 생성)

그리고 4편부터 이어 온 ‘고장 하나에 검사 하나’ 습관대로 검사를 붙였어요. 기록에는 ‘영구 대기 금지’라는 이름표가 달려 있어요.

이 검사는 처음에 테스트를 돌릴 때마다 맨 먼저 도는 자리에 들어갔고, 지금은 중복을 정리해 전체 테스트 안에서 돌아요.

실제 화면으로도 확인했어요. 일부러 두 모델이 시간 초과가 나게 하자 표시는 ‘준비 완료 1/3 · 일부 실패’로 끝났고 ‘워밍업 중’은 하나도 없었어요. 평소처럼 연결했을 때는 초록색 ’⚡ 준비 완료 (3/3 warm)‘에 도착했고요.

🧊 4. 두 번째 — 아무도 데우지 않는데 ‘워밍업 중’

한 달여 뒤인 8월 19일, v0.1.71의 기록에 거의 같은 증상이 다시 나와요. AI 연결도 성공했고 채팅도 정상인데, 화면이 ’🔥 워밍업 중… (0/3 준비)‘에서 영원히 멈췄다고요. 이번에는 숫자가 0이었어요.

첫 수정이 무너진 걸까요? 아니었어요. ‘워밍업 중인 모델이 하나도 없으면 끝’이라는 화면 규칙은 그대로 맞았어요. 이번에는 보고가 틀렸어요. 아무도 데우지 않는 모델이 스스로 ‘워밍업 중’이라고 말하고 있었거든요.

그 사이 설계가 바뀌어 있었어요. 무거운 앱 껍데기를 걷어내던 8월 초(25편에서 다룹니다)부터 중계기는 6편에서 소개한 지금 방식으로 일해요.

그런데 상태를 보고하는 쪽은 이 변화를 따라오지 못했어요. 기록이 꼽은 원인은 두 가지예요.

검사 하나도 틀린 정답을 지키고 있었어요. Claude 연결 부품의 검사가 ‘연결 직후 다른 모델은 워밍업 중’을 정답으로 적어 두고 있었거든요. 뒤에서 데우던 시절의 정답이 그대로 남아 있었던 거예요.

번호판으로 치면 이래요. 주방 불은 꺼져 있고 요리사는 쉬러 갔는데, 번호판에는 ‘조리 중’이 켜져 있는 거예요. 아무도 만들고 있지 않은 주문인데요. 정직한 표시는 ‘주문하시면 그때 만들어요’예요.

이번 수정의 원칙은 기록에 한 줄로 적혀 있어요. warming은 실제 진행 중일 때만.

화면 표시도 언제나 끝나게 바꿨어요.

릴리스 노트는 이 수정이 표시의 약속만 고친 것이라고 적었어요. 요청을 어디로 보내는지, 언제 데우는지는 하나도 바뀌지 않았어요. 바뀐 건 화면이 하는 말뿐이에요. 앞의 틀린 정답은 ‘준비 전’으로 고쳤고, 한 번도 데운 적 없는 모델과 5분 정리 뒤의 모델이 ‘준비 전’인지, 살아 있는 세션이 있는 모델이 ‘준비 완료’인지, Codex 앱 서버가 내려가 있을 때 ‘준비 전’인지 확인하는 검사도 더했어요.

전에는 '실패'로 가는 화살표와 '준비 전' 칸이 없어 표시가 '워밍업 중'에 갇혔고, 후에는 어느 길로 가도 끝 상태에 닿는다 (직접 제작)

🔁 5. 같은 병의 세 번째 얼굴 — ‘적용 중’에서 멈춘 업데이트

끝나지 않는 표시는 워밍업에만 생기지 않았어요. 9월 29일 v0.1.108의 기록은 자동 업데이트 이야기예요. 새 버전을 찾고 내려받기까지 했는데, 설치가 진행되지 않고 ‘적용 중’에서 멈췄어요.

중계기의 업데이트는 이렇게 적용돼요.

그날은 같은 문 번호에 이미 다른 중계기 서버가 떠 있었어요. 개발하면서 직접 띄워 둔 서버였어요. 릴리스 노트는 지난 실행에서 남은 서버도 같은 일을 일으킬 수 있다고 적었어요(21편의 좀비가 떠오르죠). 설치된 트레이는 자기 서버를 새로 띄우지 않고 이미 떠 있던 그 서버에 조용히 붙었어요. 설정 화면도 업데이트 버튼도 그 서버의 것이 됐고, 신호는 나갔지만 그 줄을 읽을 트레이가 없었어요. 그래서 ‘적용 중’은 끝나지 않았습니다. 화면에 보이던 버전도 설치본이 아니라 그 서버의 버전이었고요.

이번 해결은 조금 달랐어요. 끝을 만들어 주는 대신, 끝낼 주체가 없는 일은 시작하지 않게 했어요.

업데이트에서 겪은 다른 일들은 다음 편들에서 이어 갈게요.

📋 6. 남긴 규칙 — 모든 상태에는 끝이 있다

세 번의 일에서 남은 규칙을 번호판의 말로 정리하면 이래요.

로봇 검사원이 선반 위 신호등을 하나씩 확인한다. 불은 모두 초록이나 빨강으로 또렷하게 켜져 있다 (GPT 이미지 생성)

정리

① 화면의 ‘워밍업 중’은 번호판의 ‘조리 중’과 같아요. 여기서 나가는 화살표가 하나라도 빠지면 표시는 영원히 끝나지 않아요 ② 첫 번째는 실패한 준비가 갈 칸이 없었고(2/3 준비), 두 번째는 아무도 데우지 않는 모델이 ‘워밍업 중’이라고 보고했어요(0/3 준비). 실패와 시간 초과를 끝 상태로 만들고, 진행 중인 일이 없으면 ‘준비 전’이라고 말하게 고쳤어요 ③ 같은 병이 업데이트 ‘적용 중’에서도 나타나서, 끝낼 주체가 없는 일은 시작하기 전에 이유와 함께 거절하게 했어요

다음 23편은 「자동 업데이트가 계속 되돌아간 이유」예요. 이번 편과 반대로, ‘실패’라는 끝을 너무 일찍 정해 버려서 새 버전이 자꾸 옛 버전으로 되돌아가던 이야기를 할게요.


2026년 10월 1일 기준입니다. 제가 만든 중계기의 개발 기록(저장 기록의 시각과 메모, 릴리스 노트)을 바탕으로 썼고, 특정 기업·서비스의 공식 입장이 아닙니다.