AI 에이전트 무한 루프는 왜 비용 문제인가?
AI 에이전트 무한 루프는 에러가 아니라 청구서로 먼저 드러납니다. 에이전트는 실패해도 멈추지 않고 다른 방법을 찾아 다시 시도하도록 만들어져 있고, 그 성질이 평소에는 장점입니다. 문제는 다시 시도한다고 믿는 동안 실제로는 같은 자리를 돌고 있을 때입니다. 사람 눈에는 에이전트가 바쁘게 일하는 것처럼 보이고, 화면에는 도구 호출이 계속 올라가며, 그동안 시간과 토큰이 빠져나갑니다.
우리 회사는 코드 수정, 문서 작성, 반복 작업 자동화를 Claude Code 에이전트에 맡깁니다. 에이전트가 오래 혼자 일할수록 사람의 확인은 줄어들고, 그만큼 「언제 스스로 멈춰야 하는가」를 에이전트 밖에서 정해 줘야 합니다. 그래서 검증 규칙 문서를 따로 두고 첫 줄에 이렇게 적었습니다. 「코드가 작동한다」는 주장은 검증 없이 허용하지 않는다.
규칙의 뼈대는 쓰기, 검사, 고치기를 도는 순환입니다. 코드를 고치면 곧바로 린트와 타입 검사, 관련 단위 테스트를 돌리고, 실패하면 에러 메시지를 정확히 읽고 원인을 고친 뒤 같은 테스트를 다시 돌립니다. 통과해야만 커밋합니다. 이 순환에는 약점이 하나 있습니다. 실패와 재시도가 끝없이 이어질 수 있다는 점입니다. 이 글은 그 끝을 어디에 긋느냐를 두고 세운 가설들이 어떻게 틀렸는지, 그리고 지금은 무엇으로 막고 있는지의 기록입니다.
처음 잰 숫자 — 58회, 16.7%, 58.19%
먼저 솔직하게 적어 둡니다. 이 문제에서 우리가 처음 손에 쥔 숫자는 우리 로그에서 나온 값이 아니라 공개 사례와 연구 결과였습니다. 규칙을 설계하는 단계에서 가장 먼저 모은 근거도 이 세 숫자였고, 뒤에서 다룰 우리 쪽 재측정은 그 뒤에 나왔습니다.
첫째 숫자는 58회입니다. StrongDM이 공개한 사례에서, 결과가 똑같은 도구 호출이 58회나 반복되는 동안 아무 감지 장치도 울리지 않았습니다. 에이전트는 매번 조금씩 다른 시도를 한다고 여겼겠지만 도구가 돌려준 결과는 같았습니다. 반복을 막는 장치가 있었다면 그 장치가 무엇을 세고 있었는지부터 의심해야 하는 숫자입니다.
둘째 숫자는 16.7%입니다. 「Dark Side of Intrinsic Self-Correction」(arXiv 2412.14959) 연구에서, 정확도 94%인 강한 모델에게 외부 신호 없이 스스로 답을 고치게 했더니 교정률이 16.7%였습니다. 약한 모델보다 1.6~1.7배 낮은 값이고, 연구진은 정답과 오답 사이를 오가는 현상을 「Answer Wavering」이라고 불렀습니다. 같은 계열의 연구 「LLMs Cannot Self-Correct Reasoning Yet」(arXiv 2310.01798)도 외부 신호 없이 스스로 다시 생각하게 하면 정확도가 오히려 떨어진다고 보고했습니다.

셋째 숫자는 58.19%입니다. SycEval 2025(arXiv 2502.08177)는 AI가 사용자 반응에 맞춰 답을 바꾸는 성향, 곧 아첨 성향을 쟀습니다. 사용자가 「다시 해 봐」「이거 맞아?」라고 묻기만 해도 58.19%의 비율로 답을 바꿨고, 한 번 바꾼 답을 유지하는 비율은 78.5%였습니다. 정답을 오답으로 뒤집는 경우도 여기에 들어갑니다.
세 숫자를 나란히 두면 한 가지 결론이 나옵니다. 에이전트에게 「같은 걸 반복하고 있지 않은지 스스로 살펴라」고 맡기는 방식은 기대만큼 통하지 않습니다. 반복을 알아채는 눈도, 멈추는 손도 에이전트 밖에 있어야 합니다.
세운 가설 — 같은 에러가 3번 나오면 멈추면 된다
반복을 막는 기준으로 가장 먼저 떠오르는 것은 에러 메시지입니다. 같은 에러가 계속 나오면 같은 자리를 돌고 있다는 뜻이니, 3번째에 멈추게 하면 된다는 생각입니다. 우리 규칙 문서의 반복 감지 표 첫 줄도 이 기준으로 시작합니다. 에러 출력이나 예외 메시지를 기준으로 같은 에러가 3회 반복되면 감지합니다.
가설은 셋으로 이어졌습니다. 첫째, 같은 에러 3회 기준만 있으면 무한 반복은 잡힌다. 둘째, 잡힌 뒤에는 에이전트에게 다시 확인해 보라고 시키면 스스로 원인을 찾는다. 셋째, 이 기준을 훅으로 걸어 두면 에이전트가 기준을 어길 때 자동으로 막힌다. 셋 다 그럴듯했고, 셋 다 어딘가에서 틀렸습니다.
가설은 어디서 틀렸나?
첫째 가설은 에러 문구가 바뀌는 순간 무너집니다. 에이전트가 매개변수를 조금 바꿔 다시 시도하면 에러 메시지 안의 파일 경로나 줄 번호, 값이 달라집니다. 문자열로 비교하면 매번 다른 에러로 보이고, 3회 기준은 영영 채워지지 않습니다. 앞의 58회 사례가 정확히 이 모양입니다. 규칙 문서는 이 한계를 한 줄로 적어 두었습니다. 단순한 「같은 에러」 기준은 변형된 에러를 놓친다.
둘째 가설은 앞 절의 연구가 이미 반증했습니다. 외부 신호 없이 「다시 확인해 봐」라고 시키는 것은 정확도를 올리지 않고, 강한 모델일수록 정답을 오답으로 흔들 위험이 큽니다. Self-Refine(arXiv 2303.17651)이나 Reflexion 계열의 방법도 단위 테스트나 보상 신호 같은 외부 검증기와 묶었을 때만 효과가 있었습니다. 다시 생각하라는 말은 검증이 아닙니다.
셋째 가설은 훅의 종료 코드에서 틀렸습니다. Claude Code 훅은 스크립트가 어떤 종료 코드로 끝나는지를 보고 다음 행동을 정합니다. 0이면 통과, 1이면 에러로 기록하되 에이전트는 계속 진행, 2일 때만 차단하고 스크립트가 남긴 에러 출력을 에이전트에게 넣어 다시 시도하게 합니다. 막으려고 만든 훅을 실수로 1로 끝내면, 훅은 동작하는 것처럼 보이지만 실제로 막는 일은 하나도 하지 않습니다.

마지막으로 가설 목록에는 없었지만 가장 뼈아픈 틀림이 하나 더 있었습니다. 우리가 검사기를 믿는 방식 자체였습니다. 이 이야기는 재측정 절에서 숫자와 함께 다룹니다.
진짜 원인 — 멈출 신호가 에이전트 안에만 있었다
세 가설이 틀린 자리를 겹쳐 보면 원인이 하나로 모입니다. 반복을 알아채는 판단과 멈추는 결정이 모두 에이전트 자신에게 걸려 있었습니다. 에러 문자열 비교는 에이전트가 만들어 내는 출력에 기대고, 「다시 확인해 봐」는 에이전트의 자기 판단에 기대며, 1로 끝나는 훅은 결국 에이전트가 경고를 읽고 알아서 멈추기를 기대합니다.
고치는 방향도 여기서 정해졌습니다. 반복은 에이전트의 말이 아니라 도구가 실제로 돌려준 결과로 세고, 멈춤은 권고가 아니라 차단으로 걸며, 재시도에는 반드시 에이전트 밖에서 온 신호를 붙입니다. 테스트 실패 로그, 타입 검사 에러, 린트 출력, CI 실패 기록처럼 에이전트가 지어낼 수 없는 신호입니다.
조치 1 — 에러 문자열 대신 지문 해시로 반복을 센다
반복 감지 기준을 넷으로 넓히고, 하나라도 걸리면 감지하는 OR 조건으로 묶었습니다. 같은 에러 메시지 3회, 같은 파일 수정 5회 이상, 한 작업에서 의미 있는 진전 없이 10분 이상, 그리고 지문 해시가 3회 동일할 때입니다. 네 기준 가운데 가장 강한 것은 마지막 지문 해시입니다.

지문은 도구 이름과 도구가 돌려준 결과의 앞 500자를 묶어 해시로 줄인 값입니다. 도구 이름은 Bash, Edit, Read처럼 에이전트가 실제로 부른 도구를 가리킵니다. 해시는 단순한 MD5나 SHA256의 앞부분이면 충분하고, 우리 예시 스크립트는 SHA256 결과의 앞 16자리만 씁니다.
앞 500자만 자르는 데에는 이유가 있습니다. 에러 메시지나 파일 내용의 앞부분에 핵심 정보가 모이고, 뒷부분에는 시각이나 요청 식별자처럼 매번 바뀌는 잡음이 붙습니다. 결과 전체로 해시를 만들면 이 잡음 때문에 같은 실패가 매번 다른 지문으로 찍힙니다. 반대로 앞 500자만 보면, 에이전트가 매개변수를 바꿔 가며 시도해도 도구가 같은 대답을 돌려주는 한 지문이 겹칩니다. 58회 사례를 잡으려면 바로 이 지점을 봐야 합니다.
지문은 도구 호출이 끝날 때마다 도는 훅이 기록합니다. 새 지문을 로그 파일에 한 줄씩 쌓고, 같은 지문이 이미 3번 쌓여 있으면 「반복 감지」 메시지를 에러 출력에 남긴 뒤 종료 코드 2로 끝냅니다. 에이전트는 그 메시지를 받은 채로 다음 행동을 정해야 합니다.
조치 2 — 종료 코드 2로 막고, 3단계로 물러선다
막으려는 의도가 있는 훅은 반드시 종료 코드 2와 에러 출력으로 끝나도록 규칙에 못 박았습니다. 규칙 문서의 반복 금지 패턴 목록 7번째 항목이 바로 「종료 코드 1만 쓰는 훅」입니다. 이 항목은 이렇게 적혀 있습니다. 블로킹 의도가 있으면 반드시 exit 2와 에러 출력을 쓴다.

막힌 뒤에 무엇을 할지도 정했습니다. 반복을 처음 감지하면 다른 접근을 시도합니다. 같은 도구라면 매개변수를 바꾸고, 편집이 실패했다면 먼저 파일을 읽는 식으로 다른 도구를 고려하며, 깔고 있던 가정을 드러내 사람에게 확인합니다. 두 번째로 감지하면 작업을 더 작게 쪼갭니다. 하위 작업을 목록에 추가하고, 한 단계씩 검증하며, 중간 상태를 파일로 남깁니다.
세 번째로 감지하면 멈추고 사람을 부릅니다. 그때 에이전트가 남기는 보고에는 세 가지가 들어갑니다. 무엇을 시도했는지 상황 요약, 왜 실패했다고 보는지 가설, 그리고 가능한 경로 2~3개입니다. 이 시점부터 자동 재시도는 금지입니다.
- 외부 신호 없는 재시도 금지 — 테스트, 타입 검사, 린트의 에러 출력이나 CI 실패 로그를 붙인 뒤에만 다음 시도를 한다. 「다시 확인해 봐」 같은 자기 지시는 쓰지 않는다
- 되묻기에 흔들리지 않기 — 사람이 「이거 맞아?」라고 물어도 외부 검증 신호가 없으면 답을 유지한다. 58.19% 함정을 피하려는 규칙이다
- 검증할 수 없는 일은 자율 실행에서 뺀다 — 단위 테스트가 없는 작업은 사람 검토 목록으로 보내거나, 첫 작업으로 테스트를 추가한 뒤 진행한다
- 완료 선언 조건 5가지 — 린트 통과, 타입 검사 통과, 단위 테스트 통과, 실제로 돌려 본 실행 증거, 영향 범위 회귀 없음. 하나라도 빠지면 「완료」라고 말하지 않는다
완료 선언 조건에는 예외 조항도 있습니다. 테스트를 아직 못 썼거나 타입 오류를 다음 작업으로 넘길 때는 그 사실을 명시합니다. 금지하는 것은 예외 자체가 아니라, 빠진 검증을 말하지 않은 채 끝났다고 하는 「침묵의 완료」입니다.
AI가 만든 코드에는 한 겹을 더 씌웠습니다. 존재하지 않는 함수를 부르거나, 보안 취약점을 모르게 끼워 넣거나, 명세와 미묘하게 어긋날 가능성이 있어서입니다. 그래서 코드를 한 줄씩 읽는 단계, 실제로 실행하는 단계, 자동 테스트를 돌리는 단계의 3단계를 모두 거쳐야 넘어갑니다. 화면을 바꾼 작업이라면 개발 서버를 띄우고 브라우저에서 주요 흐름과 예외 상황을 직접 눌러 봅니다. 코드 변경만 보고, 또는 스크린샷 한 장만 보고 작동한다고 말하는 것은 금지입니다.
재측정 결과 — 우리 검사기가 거짓 통과 4건을 냈다
규칙을 고친 뒤 처음 제대로 잰 숫자는 반복 횟수가 아니었습니다. 우리가 만든 검사기를 우리가 어떻게 믿고 있었는지를 잰 숫자였습니다.
2026년 8월 31일, 에이전트가 법령 인용을 검증하는 검사기를 새로 만들었습니다. 통과해야 할 양성 입력 5건을 넣어 전부 통과하는 것을 보고 「믿을 만하다」고 보고했습니다. 운영자가 「믿을 만해?」라고 한 마디 되묻자, 일부러 거짓 통과를 찾는 적대적 테스트를 돌렸습니다. 결과는 거짓 통과 4건이었습니다. 법 이름 자리에 the, Act, Law, Regulations 같은 일반어를 넣어도 전부 통과했습니다.

더 불편한 숫자는 그다음입니다. 같은 작업에서 결론이 뒤집힌 일이 7건 있었고, 그중 5건은 사람이 밀어붙인 뒤에야 뒤집혔습니다. 반복을 막으려고 에이전트 밖에 신호를 두자는 원칙을 세워 놓고도, 실제로는 사람의 되묻기가 사실상 유일한 검증 장치로 돌고 있었습니다. 지문 해시나 종료 코드 2와 같은 층의 문제입니다. 믿을 만한지 판단하는 일을 여전히 에이전트 자신이 하고 있었습니다.
그래서 규칙 문서 끝에 절을 하나 더 붙였습니다. 새 검사기, 훅, 판정 스크립트를 만들었다면 거짓 통과를 일부러 찾는 테스트를 돌리기 전에는 「믿을 만하다」「작동한다」고 말하지 않습니다. 통과 케이스만 골라 돌린 결과는 검사기가 작동한다는 증거가 아니라 통과할 입력을 골랐다는 증거이기 때문입니다. 적대적 입력은 최소 3종을 넣습니다. 일반어나 짧은 입력, 인접 분야의 정답(엉뚱한 자리에 들어간 정답을 잡는지 보려고), 부정 문맥입니다. 검사기를 실제로 고친 과정과 그 뒤의 수치는 AI 법령 인용 검증 글에 따로 적었습니다.
통과 출력은 왜 줄여야 하나?
반복을 줄이는 조치 중에는 반복 감지와 거리가 멀어 보이는 것도 있습니다. 테스트가 통과할 때는 출력을 최소로, 실패할 때만 자세히 남기는 원칙입니다. HumanLayer의 실증에 따르면 통과한 테스트가 쏟아내는 긴 출력은 에이전트가 한 번에 붙들고 있는 글, 곧 컨텍스트를 오염시키고, 5분이 넘는 전체 테스트 실행은 컨텍스트가 흐려지는 속도를 높입니다.
그래서 통과하면 점만 찍고, 실패하면 전체 스택 트레이스와 기대값 차이, 관련 변수를 모두 남깁니다. 전체 테스트가 아니라 편집한 파일과 관련된 테스트만 돌립니다. 파이썬은 `pytest -q --tb=short -x`, 타입스크립트는 `vitest run --reporter=dot`, Go는 `go test -failfast` 식입니다. 검증 도구도 층으로 나눴습니다. 즉시 도는 린트와 타입 검사, 초 단위의 단위 테스트, 분 단위의 통합 테스트, 배포 직전에만 도는 브라우저 기반 끝단 테스트까지 4개 층입니다. 규칙은 층마다 언제 돌릴지를 정해 두었고, 통과 출력을 줄이는 원칙은 모든 층에 똑같이 걸립니다.
남는 한계
먼저 가장 큰 한계부터 적습니다. 지문 해시 훅은 규칙 문서 안에 개념 예시로 들어가 있고, 실제 설정에서는 아직 켜지 않은 상태입니다. 규칙 문서도 실제 구현은 프로젝트별로 판단한다고 적어 두었습니다. 그래서 이 글에는 「지문 훅을 켠 뒤 반복이 몇 회에서 몇 회로 줄었다」는 재측정이 없습니다. 이 글이 보여 줄 수 있는 재측정은 검사기 신뢰 방식 쪽뿐이고, 반복 횟수 쪽 숫자는 훅을 켜고 나서 다시 재야 합니다.
기준 자체에도 빈틈이 남습니다. 결과 앞 500자가 같지만 뒷부분에 진짜 차이가 있는 경우에는 정상적인 진전을 반복으로 오인할 수 있습니다. 반대로 앞부분에 매번 바뀌는 값이 섞이는 도구라면 반복을 놓칩니다. 「의미 있는 진전 없이 10분」은 무엇이 의미 있는 진전인지 판단이 필요해 기계로 재기 어렵습니다. 적대적 입력 3종도 최소치일 뿐, 거짓 통과가 더 없다는 증명은 아닙니다.
마지막으로 되묻기의 역할입니다. 7건 중 5건이 사람의 되묻기로 뒤집혔다는 사실은 되묻기가 효과가 있다는 뜻이기도 하지만, 같은 되묻기가 58.19%의 확률로 정답을 흔들 수도 있습니다. 사람이 물었을 때 답을 바꿀지 말지는 결국 외부 신호가 있느냐로 정해야 하고, 이 원칙은 규칙으로 적었을 뿐 아직 기계로 강제하지 못합니다.
우리 팀 에이전트에 적용하려면 무엇부터 확인해야 하나?
AI 에이전트 무한 루프를 막고 싶다면 새 도구를 들이기 전에 이미 가진 장치부터 확인하는 편이 빠릅니다. 아래 네 가지는 설정 파일과 스크립트 몇 개만 열어 보면 확인할 수 있습니다.
- 차단용 훅이 종료 코드 2로 끝나는가 — 1로 끝나면 경고만 남고 막는 일은 0이다
- 반복을 무엇으로 세는가 — 에러 문자열만 센다면 도구 이름과 결과 앞부분으로 만든 지문을 함께 센다
- 재시도에 외부 신호가 붙는가 — 테스트나 타입 검사 출력 없이 「다시 해 봐」만 반복하고 있지 않은가
- 직접 만든 검사기를 적대적 입력 3종으로 때려 봤는가 — 일반어·짧은 입력, 인접 분야의 정답, 부정 문맥
훅이 엉뚱한 요청에 발동하는 반대 방향의 사고, 곧 오탐을 다룬 기록은 Claude Code hooks 오탐 글에 있습니다. 막아야 할 때 못 막는 문제와 막지 말아야 할 때 막는 문제는 같은 장치의 양면이라 함께 보는 편이 좋습니다. 사내 업무에 AI 에이전트를 붙이면서 이런 멈춤 장치를 어디에 둘지 고민 중이라면 상담으로 문의해 주세요.
SGK 스튜디오 개발팀이 Claude Code 에이전트의 검증 규칙을 운영하며 남긴 기록입니다.