happy_various AI 실전 기록

LLM 중계기 개발기 4부 · 17편 / 전체 33편

2026년 10월 1일 기준

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

성공 응답 속에 숨은 실패 — 합격 봉투 안에 든 불합격 통지 (LLM 중계기 개발기)

합격한 사람에게만 보낸다는 금색 봉투가 도착했다고 해 볼게요. 우편물을 대신 정리해 주는 비서는 봉투 색만 보고 ‘합격’ 서랍에 넣은 뒤, 입학 등록 절차까지 밟아 둡니다. 그런데 며칠 뒤 등록 창구에서 연락이 와요. “제출하신 서류의 형식이 맞지 않습니다.”

서류를 아무리 들여다봐도 이상한 데가 없어요. 한참 뒤에야 봉투를 직접 열어 보니, 안에 든 건 합격증이 아니라 “기한이 지나 처리할 수 없습니다”라는 안내문 한 장이었습니다. 봉투는 ‘합격’이라고 말했지만, 편지는 ‘불합격’이었던 거죠.

제가 만든 LLM 중계기에도 이런 봉투가 두 번 도착했어요. 한 번은 로그인이 만료됐다는 안내, 한 번은 사용 한도를 다 썼다는 안내였는데, 둘 다 ‘정상 답’ 봉투에 담겨 왔습니다.

이 글은 LLM 중계기 개발기의 17편입니다. 지난 16편 「‘다 했어요’라더니 잘린 답」에서는 ‘다 했음’ 도장 아래 숨은 잘림을 다뤘어요. 이번에는 도장 한 칸이 아니라 봉투 전체가 ‘성공’이었는데, 안에 든 편지가 실패 통지였던 이야기입니다.

금색 축하 봉투를 열었다가 커다란 X 표시가 그려진 회색 쪽지를 꺼내 들고 놀란 로봇 (GPT 이미지 생성)

결론 요약

✉️ 1. 증상 — 성공 봉투에 담겨 온 “로그인 만료”

7월 15일 새벽 1시, 중계기를 만든 지 셋째 날의 기록이에요. 맥에서 직접 겪고 남긴 내용입니다.

그날 Claude 명령어 도구의 로그인은 만료돼 있었고, 저절로 다시 이어지지도 못한 상태였어요. 이 상태에서 중계기가 Claude에게 질문을 보냈더니, 돌아온 결과는 이랬습니다.

마지막 줄이 결정적인 단서예요. 질문은 AI에 닿지도 않았어요. 답 칸에 든 문장은 AI가 쓴 답이 아니라, 명령어 도구가 스스로 써 넣은 안내문이었던 거죠. 그런데 겉봉에는 ‘성공’이 찍혀 있었어요.

중계기는 겉봉을 믿었습니다. 이 영어 한 문장을 AI의 답으로 포장해서, 웹에서 “잘 처리됐다”는 뜻의 번호인 200과 함께 쓰는 쪽에 넘겼어요.

받는 쪽은 중계기를 쓰던 도구였어요. 이 도구는 답을 JSON으로 받기로 돼 있었어요. JSON은 프로그램이 읽기 쉽도록 이름표와 값을 짝지어 적는 글 형식이에요. 그런데 영어 문장 하나가 왔으니 읽을 수가 없었죠. 도구는 “AI가 약속한 답 형식을 지키지 않았다”는 오류를 냈어요.

이 오류 메시지만 보면 원인은 ‘AI가 형식을 어겼다’로 보여요. 로그인 만료라는 진짜 원인은 ‘성공’과 ‘형식 오류’, 두 겹 아래에 묻혀 있었어요.

그나마 다행인 건 이 도구가 답의 형식을 검사했다는 점이에요. 덕분에 ‘뭔가 잘못됐다’는 신호만큼은 났어요. 형식을 따지지 않는 프로그램이었다면 “인증 실패…” 문장이 그대로 결과로 저장됐을 수도 있어요.

🔍 2. 원인 — 겉봉만 보고 넘긴 중계기

Claude 명령어 도구는 일을 마치면 마지막에 ‘결과’ 알림을 보내요. 여기에는 답 내용과 함께, 일이 성공했는지 실패했는지를 적는 결과 표시 칸이 있어요. 중계기는 이 칸이 ‘성공’이면 답을 넘기고, 실패면 오류를 돌려주게 만들어져 있었어요. 봉투의 겉면을 보고 서랍을 고르는 비서였던 셈이에요.

그런데 로그인이 만료됐을 때 Claude 쪽 도구는 실패 표시 대신 성공 표시에 안내문을 담아 보냈어요. 그날 직접 확인해 기록에 남긴 동작이에요. 이렇게 오면 겉면만 봐서는 정상 답과 구별할 방법이 없어요. 남은 단서는 편지의 글자뿐이에요.

16편의 잘림과 견주면 차이가 보여요.

실패가 실패로 오면 쓰는 쪽은 그 자리에서 멈추고 원인을 봐요. 실패가 성공으로 오면, 실패는 다음 단계로 흘러가 다른 이름으로 터집니다. 이번에는 그 이름이 ‘형식 오류’였어요.

🔎 3. 해결 — 넘기기 전에 한 번 열어 본다

같은 날 새벽에 나온 판(v0.1.30)에서, 중계기에 우편 검사관을 한 명 세웠어요.

401은 8편에서 본 “누구인지 확인이 안 된다”는 번호예요. 정확히 말하면, 이때 쓰는 쪽이 받은 응답 번호는 ‘중계하던 상대 쪽에서 실패했다’는 뜻의 502였고, 401은 그 안에 ‘원래 원인’을 적는 칸으로 실렸어요. 지금은 안내가 조금 바뀌어서, “Claude 로그인이 필요합니다. [로그인 확인]을 눌러 로그인한 뒤 자동 연결 확인을 기다려 주세요.”라는 문구가 원인과 할 일을 함께 알려 줘요.

큰 돋보기를 들고 뜯어 본 봉투 속 편지를 꼼꼼히 들여다보는 로봇 우편 검사관 (GPT 이미지 생성)

이 검사관을 세울 때 신경 쓴 점이 두 가지 더 있어요.

하나, 두 길 모두에 세운다. 중계기는 Claude를 질문마다 새로 켜서 부르기도 하고, 켜 둔 채 계속 쓰기도 해요(6편에서 다룬 콜택시와 셔틀이에요). 위장된 답은 어느 길로든 올 수 있으니, 검사도 두 길 모두에 넣었어요.

둘, 인증 실패는 다시 시도하지 않는다. 켜 둔 길에서 문제가 생기면 새로 켜는 길로 한 번 더 해 보는 장치가 있었는데, 인증 실패만은 예외로 했어요. 로그인 문제는 길을 바꿔도 똑같이 실패하고, 다시 해 보는 사이 원인만 가려지니까요.

그리고 기록에는, 이 검사가 있는데도 걸리지 않은 일이 두 번 있었다고 적혀 있어요.

① 켜 둔 길에서 검사를 부를 때, 그 자리에 없는 이름(변수)을 넘겼어요. 검사는 시작하자마자 오류로 멈췄고, 주변 장치가 그 오류를 삼켜 버렸어요

② 실패를 붙잡아 새로 켜는 길로 다시 해 보는 장치가 인증 실패까지 삼켰어요. 다시 해 본 결과는 같은 위장 문장이었고, 그게 그대로 넘어갔어요

둘 다 ‘검사는 있는데 걸리지 않는’ 상태예요. 코드의 오타 같은 실수를 미리 잡아 주는 맞춤법 검사기(린터)도 없던 때라, 검사 코드의 모양을 직접 확인하는 시험을 만들었어요. 켜 둔 길이 올바른 이름으로 검사를 부르는지, 인증 실패를 바로 알리는 줄이 ‘다시 해 보기’보다 앞에 있는지를 봐요. 함께 넣은 시험은 모두 다섯 개예요. 그날 받은 문장은 반드시 오류가 돼야 하고, 다른 인증 실패 문구 세 개도 잡혀야 하고, 정상적인 짧은 답은 그대로 통과해야 한다는 시험이 나머지 셋이에요.

💳 4. 두 달 뒤 — 이번엔 “사용 한도를 다 썼습니다”

9월 15일, 같은 모양의 봉투가 또 왔어요.

그날 오전 중계기에는 사용 한도 갈래가 새로 생겼어요. 계정의 사용 한도를 다 쓴 상태를 ‘연결 실패’로 뭉뚱그려 알리는 바람에, 사람이 연결 확인 버튼만 되풀이해 누르게 되는 일이 있었거든요. 한도 소진은 연결 고장이 아니라 계정의 상태예요. 그래서 연결과 모델 목록은 그대로 두고, 호출에는 429와 ‘사용 한도 소진’(insufficient_quota)이라는 이름표, 그리고 12편에서 본 대로 10분이라는 긴 ‘다시 올 시간’을 붙여 돌려주게 했어요.

그 수정이 실제 설치본에서 제대로 도는지 점검하던 첫 라운드에서 일이 생겼어요. 계정의 사용 한도가 다 찬 상태에서 Claude에게 질문을 보냈더니, 이번에도 결과 표시는 성공이었어요. 답 칸에는 “사용 한도에 도달했다”는 영어 안내 한 줄이 들어 있었고, 실제 AI 호출 시간도 쓴 토큰도 0이었어요. 7월과 똑같은 위장이죠.

7월의 검사관은 이 편지를 알아보지 못했어요. 검사관이 찾던 건 로그인 문구뿐이었으니까요. 중계기는 이 문장을 다시 성공으로 흘려보냈어요. 그대로 두면 쓰는 도구는 7월처럼 이 문장을 답으로 받게 돼요.

같은 날 낮 12시 54분에 고쳤고, 그날 나온 v0.1.96 판에 실렸어요.

이번에 붙인 시험은 네 개예요. 그날 받은 문장을 429로 바꾸는지, 600자가 넘는 긴 정상 답은 한도 낱말이 섞여 있어도 통과하는지, 연결 확인에서는 경고만 붙이고 세션을 살려 두는지, 그리고 한도 문구를 제대로 분류하는지를 봐요.

전에는 '성공 200' 봉투 속 로그인 만료·한도 소진 안내가 답처럼 넘어가 쓰는 도구가 엉뚱한 형식 오류를 냈고, 후에는 중계기 검사관이 열어 보고 로그인 필요(인증 실패 401 갈래)와 429 사용 한도 소진으로 바꿔 돌려준다 (직접 제작)

🧱 5. 글자로 판단하는 검사의 약점, 그리고 울타리

솔직히 말하면 이 검사는 튼튼한 방법이 아니에요. 결과 표시처럼 정해진 칸 대신 글자를 읽고 판단하니까요. 약점은 두 가지예요.

그래서 검사가 함부로 끼어들지 못하게 울타리를 쳤어요.

① Claude에게만 — 이 위장을 실제로 본 건 Claude뿐이에요. 검사는 Claude 연결 부품 안에만 있고, 다른 AI의 답은 건드리지 않아요

② 성공 표시가 붙은 최종 답에만 — 실패 표시로 온 결과는 원래대로 실패로 처리해요. 검사관은 ‘성공’인데 수상한 경우만 봐요

③ 한도 문구는 짧은 답에만 — 위장 안내는 한 줄짜리예요. 그래서 600자를 넘는 답은 한도 낱말이 들어 있어도 그대로 통과시켜요

④ 실제로 받은 문장으로 시험 — 7월과 9월에 받은 문장을 글자 그대로 시험에 넣어 뒀어요. 나중에 목록을 손보다 이 문장을 놓치면 시험이 실패해요. 반대로 정상 답이 통과하는지도 함께 시험해요

빈틈이 없는 건 아니에요. 2026년 10월 1일 코드 기준으로 두 가지가 남아 있어요.

글자로 판단하는 검사는 어디까지나 울타리예요. Claude 쪽 도구가 실패를 실패 표시로 보내 준다면 필요 없는 장치죠. 그때까지는 울타리를 좁게, 시험은 촘촘하게 두는 쪽을 택했어요.

🏷️ 6. 남긴 규칙 — 실패는 실패로, 제 이름으로

두 번의 위장에서 남긴 규칙을 정리하면 이래요.

하나, 겉봉만 믿지 않는다. 결과 표시가 ‘성공’이어도, 알려진 실패 안내문이면 답이 아니라 실패로 다뤄요.

둘, 실패에는 제 이름을 붙인다. 로그인 만료는 ‘로그인 필요’, 한도 소진은 ‘사용 한도 소진’이에요. 이름이 맞아야 할 일도 맞아요. 로그인 문제는 사람이 다시 로그인해야 풀리고, 한도 문제는 한도가 갱신돼야 풀려요. 둘 다 같은 요청을 곧바로 다시 보내서는 풀리지 않아요.

셋, 쓰는 쪽이 이미 아는 말로 돌려준다. 한도 소진에 붙이는 429와 insufficient_quota는 코드 메모에 적힌 대로 OpenAI와 같은 약속이에요. OpenAI 형식을 아는 프로그램이면 따로 배울 것 없이 알아들어요. 연결 안내서에 있던 규칙, “429가 오면 다시 올 시간만큼 기다린 뒤 재시도하고, 기다리는 중이라고 화면에 표시하라”도 그대로 들어맞고요. 다시 올 시간을 10분으로 길게 주는 건, 쓰는 쪽이 1초 간격으로 닫힌 창구를 두드리지 않게 하려는 거예요.

넷, 검사가 실제로 걸리는지도 검사한다. 3절의 두 번처럼, 검사는 있는데 걸리지 않는 상태가 가장 위험해요. 겉으로는 지켜지는 것처럼 보이니까요. 그래서 검사 코드가 제자리에서 제대로 불리는지까지 시험으로 확인해요.

편지에 주황 경고 도장을 힘차게 찍는 로봇 우체국 직원, 옆 편지에는 보라 자물쇠 도장이 찍혀 있다 (GPT 이미지 생성)

정리

① Claude가 로그인 만료와 사용 한도 소진을 ‘성공’ 결과에 담아 보냈고, 중계기가 이를 답으로 넘기는 바람에 쓰는 도구는 엉뚱한 ‘형식 오류’를 냈어요. 실패가 성공으로 오면, 다음 단계에서 다른 이름으로 터져요 ② 중계기는 Claude의 성공 답을 넘기기 전에 열어 보고, 알려진 실패 문구면 로그인 만료는 인증 실패(401) 갈래의 오류로, 한도 소진은 429와 “10분 뒤 다시”로 바꿔 돌려줘요. 두 경우 모두 같은 요청을 곧바로 다시 보내지 않아요 ③ 글자로 판단하는 검사는 깨지기 쉬워서, Claude의 성공 답에만, 한도 문구는 600자 이하에만 적용하고, 실제로 받은 문장으로 시험해요

다음 18편은 “에러 메시지를 자르지 마라”입니다. 이번 편이 실패를 성공 봉투에 담아 보낸 이야기였다면, 다음은 실패 안내가 제대로 오긴 했는데 중계기가 그 일부만 남기고 잘라 버리는 바람에, 진짜 원인이 세 번이나 사라진 이야기예요.


2026년 10월 1일 기준입니다. 제가 만든 중계기의 개발 기록을 바탕으로 썼고, 특정 기업·서비스의 공식 입장이 아닙니다.