누구나 한 번쯤 이런 루프를 경험해 보셨을 것입니다. 에러 트레이스백(traceback)을 복사해 붙여넣으면 모델은 “수정되었습니다!“라고 답합니다. 하지만 코드를 다시 실행해 보면 똑같은 에러가 발생합니다. 트레이스백을 다시 입력하면 모델은 “아, 원인을 찾았습니다. 수정된 버전입니다”라고 말합니다. 다시 실행해 보면 이제 다른 에러가 발생하거나, 동일한 에러가 다른 형태로 포장되어 나타납니다. 세 번째나 네 번째 반복에 이르면 모델은 완전히 고장 난 동일한 로직의 순서를 자신 있게 바꾸거나, 전체를 try/except 블록으로 감싸버리거나, 실패와는 아무런 관련도 없는 변수명을 바꾸고 있을 뿐입니다.

이는 환각이나 상상이 아닙니다. 여러분의 프롬프트 작성 실력이 부족해서 일어난 일도 아닙니다. 자기회귀(autoregressive) 언어 모델이 설계된 방식에서 비롯된 예측 가능하고 측정 가능한 필연적 결과이며, 동료 평가(peer-reviewed)를 거친 학술 연구를 통해 정량적으로 입증된 사실입니다.

아키텍처의 한계

언어 모델은 여러분의 코드를 직접 실행하지 않습니다. 런타임 상태를 유지하지도 않고, 메모리를 검사하거나 함수 호출 전반에 걸친 변수 값을 추적하지도 못합니다. 모델이 하는 일은 오직 컨텍스트 윈도우에 주어진 정보를 바탕으로 다음에 올 가장 그럴듯한 토큰의 시퀀스를 예측하는 것뿐입니다. 따라서 트레이스백을 보았을 때 모델이 생성하는 것은 텍스트 수준에서 “수정본처럼 보이는 것”이지, 기저에 깔린 논리적 결함을 실제로 “해결하는 것”이 아닙니다.

이로 인해 네 가지 뚜렷한 실패 모드가 발생합니다.

1. 근본 원인 분석보다 패턴 매칭 우선. 모델은 학습 데이터에 나타난 에러 패턴을 인식하고, 구체적인 실패 원인이 전혀 다른 경우에도 해당 패턴에 쓰이던 “일반적인 수정 방식”을 기계적으로 적용합니다. TypeError: undefined is not a function을 만나면 실제 버그가 잘못된 import인지, 레이스 컨디션(race condition)인지, 세 단계 상위 호출부에서 전달된 잘못된 인자인지와 상관없이 판에 박힌 상용구 수정 코드를 내놓습니다.

2. 시스템적 정확성보다 국소적 그럴듯함 우선. 모델은 예외를 유발한 원인 로직이 아니라, 단지 예외가 던져진(throw) 그 한 줄만을 땜질합니다. 대표적인 결과로는 모든 코드를 try/except로 감싸 에러를 침묵시키거나, 실패했던 특정 예제만 통과시키고 다른 모든 케이스를 깨뜨리는 억지 조건을 추가하거나, 에러를 유발하는 코드 라인 자체를 아예 삭제하여 핵심 기능을 망가뜨리는 것 등이 있습니다.

3. 아첨 현상(Sycophancy) — 무조건적인 동조(“Yes-man”) 효과. 인간 피드백 기반 강화 학습(RLHF)은 모델이 유용하고 고분고분하게 응답하도록 훈련합니다. 사용자가 “이 코드에 버그가 있어”라고 말하면, 모델의 최우선 목표는 사용자의 프롬프트를 만족시키는 것이 됩니다. 설령 원래 코드가 맞았거나 모델이 제시한 수정이 새로운 결함을 유발하더라도, 모델은 도움이 되는 척하기 위해 기어이 수정된 코드 블록을 출력합니다. 코드 스멜(code smell) 탐지를 다룬 2025년 실증 연구(arXiv:2607.10411)는 이러한 아첨 편향을 최초로 체계적으로 측정하여, 프롬프트에 담긴 확증 편향과 잘못된 전제가 모델의 예측을 크게 왜곡한다는 사실을 밝혔습니다.

4. 컨텍스트 오염 (Context rot). 수정 루프가 길어질수록 모델 자신이 내놓은 실패한 시도들이 컨텍스트 윈도우를 가득 채우게 됩니다. 세 번째나 네 번째 턴에 이르면 모델은 사용자의 원래 의도보다는 직전에 자신이 제시했던 잘못된 수정안에 닻을 내리게(anchoring) 됩니다. 이제 모델은 사용자의 코드를 고치는 것이 아니라, 자신이 잘못 고친 코드를 다시 고치려 애쓰는 상태에 빠집니다.

쇠퇴 곡선: 디버깅 능력이 얼마나 빠르게 무너지는가

Scientific Reports (Nature)에 게재된 아드난(Adnan)과 쿤(Kuhn)의 2025년 연구는 이 현상을 정밀하게 수치화했습니다. 연구진은 **디버깅 쇠퇴 지수(Debugging Decay Index, DDI)**를 도입하여, 대부분의 LLM이 불과 23회의 반복 시도 만에 디버깅 능력의 6080%를 상실한다는 점을 예측 가능한 지수 감쇠(exponential decay) 패턴을 통해 입증했습니다.

이는 서서히 일어나는 점진적인 하락이 아니라 절벽에 가깝습니다. 모델의 첫 번째 복구 시도는 꽤 합리적일 수 있습니다. 하지만 두 번째 시도부터는 단순한 추측에 불과해집니다. 세 번째 시도에 이르면 상황을 오히려 적극적으로 악화시킵니다. 실제 근본 원인과는 점점 더 멀어지면서도, 무엇이 문제인지에 대해 겉보기에는 점점 더 그럴듯한 서사를 지어내게 됩니다.

또한 이 연구는 손상된 컨텍스트를 과감히 버리고 원본 코드, 에러 메시지, 그리고 지금까지 시도한 내용을 요약하여 새 대화를 시작하는 **전략적 초기화(strategic fresh start)**를 수행하면, 탐취(exploitation)에서 탐색(exploration)으로 전환되어 디버깅 효과를 다시 회복할 수 있음을 보여주었습니다.

벤치마크가 실제로 보여주는 것

SWE-bench: 골드 스탠다드와 그 안의 균열들

SWE-bench는 널리 쓰이는 12개 Python 저장소에서 추출한 2,294개의 실제 GitHub 이슈를 기반으로 LLM의 실세계 버그 수정 능력을 평가하는 대표적인 벤치마크입니다. 사람이 검증한 500개 하위 집합인 SWE-bench Verified의 현재 최고 점수는 75~95%의 해결률에 육박합니다.

그러나 이 수치는 면밀히 살펴볼 필요가 있습니다. 요크 대학교의 알레이탄(Aleithan) 등의 연구(SWE-Bench+)에 따르면 다음과 같은 사실이 밝혀졌습니다.

  • **전체 이슈의 32.67%**는 이슈 리포트 본문이나 댓글에 해결책이 직접 제공되어 있어, 모델이 스스로 해결책을 도출하지 않고도 정답을 베껴 쓸 수 있었습니다.
  • 31.08%의 이슈는 테스트 케이스가 취약하여 부정확하거나 불완전한 수정을 잡아내지 못했습니다.
  • SWE-Agent + GPT-4의 성능을 분석한 결과, “성공”한 수정 중 63.75%가 의심스러운 수정으로 나타났습니다. 즉, 유출된 솔루션에 의존했거나 결함이 있음에도 취약한 테스트를 통과한 경우였습니다.

이러한 결과는 최고의 벤치마크에서조차 “통과” 판정의 상당 부분이 진정한 문제 해결이 아니라는 점을 시사합니다. 모델이 이슈 설명 속에서 답을 발견했거나, 테스트 스위트가 너무 부실하여 잘못된 수정을 걸러내지 못한 것입니다.

바이트댄스(ByteDance) 연구: 6개의 최고 수준 에이전트, 동일한 한계

멍(Meng) 등(ByteDance, 2024)의 체계적 분석 연구는 SWE-bench Verified에서 최고 성능을 보이는 6개의 LLM 기반 버그 수정 시스템을 조사했습니다.

  • 유사한 기반 모델을 사용함에도 불구하고 시스템 간 성능 편차가 크게 나타났습니다.
  • 파일 수준의 위치 식별보다 **코드 심볼 수준(code symbol level)**의 결함 위치 식별(Fault localization)이 훨씬 더 중요하면서도 훨씬 더 어려웠습니다. 모델은 단순히 올바른 파일을 찾는 것을 넘어 정확한 변수나 함수를 찾아내야 합니다.
  • 버그 재현이 잘못되면 전체 수정 프로세스가 탈선할 수 있습니다. 모델이 실패 모드를 오해하면, 이후의 모든 “수정”은 엉뚱한 문제를 해결하려 들게 됩니다.
  • LLM의 추론 능력뿐 아니라 에이전틱 워크플로우 설계 전반에서 추가적인 최적화가 필수적입니다.

DebugBench: 인간 개발자와 비교한 통과율

ACL 2024 Findings에 실린 DebugBench는 세분화된 버그 분류 체계를 바탕으로 C++, Java, Python에 걸쳐 LLM 디버깅 능력을 평가했습니다.

  • 오픈소스 모델들의 통과율은 43.9%에서 66.6% 사이에 머물렀습니다.
  • 상용 클로즈드소스 모델들 역시 인간 프로그래머보다 열등한 디버깅 성능을 보였습니다.
  • 런타임 피드백(코드를 직접 실행하고 에러를 다시 주입하는 방식)은 분명한 영향을 미쳤으나 일관되지는 않았습니다. 특정 버그 카테고리에서는 도움이 되었지만 다른 카테고리에서는 오히려 해가 되기도 했습니다.
  • 디버깅 난이도는 버그의 유형에 따라 극적으로 달라졌습니다. 구문 오류(Syntax error)는 사소한 수준이었으나, 상태 관련 버그(stateful bug)나 오프바이원(off-by-one) 경계값 오류는 훨씬 더 해결하기 어려웠습니다.

Olausson 연구: 자체 복구는 만병통치약이 아니다

올라우스손(Olausson) 등(MIT/Microsoft Research, ICLR 2024)의 기념비적 논문 *“Is Self-Repair a Silver Bullet for Code Generation?”*은 LLM의 자체 복구(Self-repair) 능력에 대한 결정적인 분석을 제시합니다.

  • 복구를 수행하는 데 드는 토큰 비용을 감안하면, 성능 향상은 미미하거나 데이터셋마다 편차가 심하며, 때로는 전혀 개선되지 않는 경우도 있었습니다.
  • 자체 복구는 모델이 자신의 코드에 피드백을 제공할 수 있는 능력에 의해 병목이 발생합니다. 모델은 특정한 사고 경로를 거쳐 버그를 생성합니다. 따라서 이를 고치라고 요구받아도 동일한 사고의 틀에 갇히게 됩니다. 한 발짝 물러서서 문제를 처음부터 다시 추론하지 못하는 것입니다.
  • 모델 자체적으로는 복구하지 못하는 상황에서도, 더 강력한 상위 모델을 피드백 제공자로 활용하면 성능 향상을 이끌어낼 수 있었습니다.
  • 인간의 피드백을 제공하는 것은 심지어 GPT-4에서도 복구 성공률을 비약적으로 높였습니다. 이는 모델이 자체적인 분석만으로 파악할 수 있는 것보다 코드 수정에 대해 더 많은 잠재 지식을 지니고 있음을 뜻합니다.

모델이 잘 고치는 버그와 그렇지 못한 버그

이는 단순히 된다, 안 된다의 이분법적인 문제가 아닙니다. 모델의 디버깅 역량은 실패 유형에 따라 극명하게 갈립니다.

실제로 효과가 있는 영역:

카테고리 잘 작동하는 이유
구문 오류 (Syntax errors) 에러 메시지가 문제 지점을 직접적으로 명시함
타입 불일치 (Type mismatches) 학습 데이터에 흔히 존재하는 일반적인 패턴임
명백한 API 오용 “인자 개수 불일치” 등 모호하지 않은 에러
트레이스백이 근본 원인을 직접 드러내는 에러 모델이 올바른 수정안으로 패턴 매칭을 수행할 수 있음

일관되게 실패하는 영역:

카테고리 실패하는 이유
상태 관련 버그 (Stateful bugs) 실행 흐름 전반에 걸친 값의 변화를 추적해야 함
오프바이원(Off-by-one) 경계 조건 로직 경계 조건에 대한 정밀한 논리적 추론이 필요함
레이스 컨디션 (Race conditions) 동시 실행 환경에 대한 시간적(temporal) 추론이 필요함
다중 함수 간 값 추적 여러 파일에 걸친 전역적인 맥락 이해가 요구됨
모델이 방금 직접 생성한 코드의 버그 동일한 사고의 틀과 맹점에 갇히게 됨
알고리즘 효율성 문제 근본적인 재설계 없이 피상적인 코드 변경에 그침

아이오와 주립대학교의 2026년 6월 연구(Zhang & Kothari)는 이 마지막 항목을 생생하게 입증했습니다. DeepSeek-R1은 10번의 반복에 걸쳐 성능 버그 수정을 시도했습니다. 매 반복마다 코드를 피상적으로만 변경했습니다. 테스트 케이스 커버리지는 10번의 시도 내내 99.56%에 머물렀습니다. 모델은 알고리즘 자체를 바꿔야 한다는 점을 전혀 깨닫지 못한 채, 동일한 O(n²) 접근 방식의 코드 배치만 끊임없이 바꾸었습니다.

프로덕션 환경에서의 실제 대가

이는 단지 벤치마크 상의 문제에 그치지 않습니다. 널리 쓰이는 AI 인프라의 심각한 버그들이 LLM 기반 시스템에 의해 수개월 동안 감지되지 않은 채 방치되기도 했습니다.

  • 높은 동시성을 요구하는 서빙 환경에서 프롬프트 토큰이 누락되는 사일런트 실패(silent failure).
  • 프로덕션 추론 엔진에서의 중복 응답 발생률.
  • 특정 하드웨어 구성이나 부하 패턴에서만 발생하는 버그.

LLM 추론 엔진의 버그를 다룬 2025년 연구는 6가지 증상 유형과 28가지 근본 원인을 분류하며, 현재의 LLM이 스스로 진단할 수 없는 복잡성의 깊이를 여실히 보여주었습니다. 이러한 버그들을 발견하고 수정한 것은 자신이 망가뜨린 인프라를 바탕으로 동작해야 할 모델들이 아니라, 인간 엔지니어들이었습니다.

Google Research에 따르면 기본 설정(out-of-the-box)의 자동 프로그램 복구 시스템이 **실제 산업 환경 버그에 대해 거둔 성공률은 고작 11%**에 불과했습니다. 생성된 패치의 대부분은 문제를 해결하지 못했거나 새로운 결함을 유발했습니다. 모델이 감당하기에 너무 복잡한 버그를 사전에 걸러내고 패치가 실제로 문제를 해결하는지 검증하는 2단계 필터링을 도입한 뒤에야 성공률이 53%로 올랐습니다. 이는 여전히 동전 던지기 수준의 확률입니다.

실제로 작동하는 7가지 탈출구

문제는 명확합니다. 해결책 또한 구체적입니다.

1. 단언(Assertion) 대신 실행(Execution)을 강제하십시오

“수정했습니다”라는 말을 그대로 받아들이지 마십시오. 모델이 직접 증명하도록 강제하십시오.

“수정했다고 말로만 하지 마십시오. 코드를 직접 실행하고 터미널 출력을 그대로 붙여넣으십시오.”

에이전틱 워크플로우(Claude Code, Cursor, Aider, Codex)에서는 모델이 테스트를 직접 실행하고 실제 출력을 확인합니다. 이것이 가장 강력한 지렛대입니다. 실행 루프가 모델의 자체 역량보다 훨씬 더 중요합니다.

2. 코드를 수정하기 전에 먼저 진단하게 하십시오

두 가지 역할을 분리하십시오. 코드 한 줄을 수정하기 전에 모델이 에러를 먼저 분석하도록 강제하십시오.

“먼저 근본 원인을 두 문장으로 설명하십시오. 아직 코드는 수정하지 마십시오. 에러가 터진 지점이 아니라, 잘못된 값이 처음 시작된 지점이 어디입니까?”

만약 진단이 틀렸다면 그것부터 먼저 바로잡은 뒤 코드를 수정하게 하십시오. 토큰 예측의 관성을 끊어주면, 모델이 겉보기만 그럴듯하고 잘못된 땜질식 패치로 곧장 빠져드는 것을 막을 수 있습니다.

3. 문제의 범위를 축소하십시오

한 번에 하나의 버그만 다루십시오. 최소 재현 코드(Minimal repro)를 만드십시오. 300줄짜리 코드를 붙여넣고 “이거 고쳐줘”라고 하는 대신, 문제를 재현하는 20줄의 코드와 실패하는 단 하나의 어설션(assertion)만 제공하십시오. 컨텍스트가 작을수록 모델이 피상적인 패턴 매칭으로 잘못된 수정을 내놓을 가능성이 줄어듭니다.

4. 수정 범위를 엄격히 제한하십시오

LLM은 전체 파일을 통째로 다시 작성하는 것을 좋아합니다. 이는 새로운 버그를 유발합니다. 다음과 같이 지시하십시오.

“42~55행만 수정하십시오. 전체 파일이 아닌 diff 형식으로 반환하십시오. 함수 시그니처는 변경하지 마십시오.”

5. 자체 복구(Self-repair) 루프를 끊으십시오

수정이 두 번 연속 실패하면 즉시 리셋하십시오. 디버깅 쇠퇴 지수(DDI) 연구에 따르면 전략적 초기화가 효과를 회복시키는 것으로 나타났습니다. 다음과 같이 새 대화를 시작하십시오.

“여기에 원래의 명세와 최소 재현 코드, 그리고 에러 메시지가 있습니다. 이전의 모든 시도는 잊으십시오.”

혹은 두 번째 모델 인스턴스를 비평가(critic)로 활용하십시오.

“여기에 코드와 에러가 있습니다. 이 수정안이 올바른가요? 올바르지 않다면 그 이유는 무엇입니까?”

6. 검증된 골드 스탠다드 프롬프트를 사용하십시오

다음과 같은 프롬프트 구조는 단순한 “이 버그 고쳐줘”보다 훨씬 일관되게 우수한 결과를 냅니다.

실패한 테스트와 트레이스백이 여기 있습니다. 근본 원인을 한 단락으로 설명하십시오. 그런 다음 증상이 아닌 근본 원인을 해결하는 가장 작은 단위의 패치를 제안하십시오. 변경된 라인에 대해서만 수정 전과 수정 후를 보여주십시오.

7. 실행 피드백을 제공하는 에이전틱 워크플로우로 전환하십시오

채팅 기반 코딩에서 에이전틱 코딩 환경(Cursor, Windsurf, Aider, Claude Code, Codex)으로 업계가 전환된 이유는 정확히 이 문제 때문입니다. LLM이 터미널에 직접 연결되면 다음과 같은 일이 일어납니다.

  • 수정 코드를 작성하고, 코드를 실행하며, 에러를 확인하고, 반복 개선합니다.
  • 테스트 루프를 포함하는 반복적 에이전틱 워크플로우는 수정 성공률을 약 50%에서 80% 이상으로 끌어올립니다.
  • 모델은 겉보기만 그럴듯한 텍스트를 지어내는 대신 런타임의 냉정한 현실과 마주할 수밖에 없습니다.

올라우스손의 연구 역시 반대 방향에서 동일한 효과를 보여주었습니다. 더 강력한 모델이든, 코드 실행이든, 사람이든 간에 피드백의 품질이 향상되었을 때 자체 복구 능력이 극적으로 개선되었습니다.

핵심 결론

모델이 버그를 고치는 척 연기하는 것은 아닙니다. 주어진 제한된 정보 속에서 내놓을 수 있는 가장 그럴듯한 출력을 생성하고 있을 뿐이며, 그 출력이 실제로 작동하는지 검증할 자체적인 수단이 없을 뿐입니다. 실행과 테스트를 통한 피드백 루프가 없다면 모델은 버그가 실제로 고쳐졌는지를 신뢰성 있게 알 방법이 없습니다.

채팅 기반 디버깅에서 에이전틱 코딩 환경으로의 전환은 엔지니어링 커뮤니티가 바로 이 결함을 직시했기 때문에 일어난 변화입니다. 해결책은 실행 루프에 있습니다. 더 좋은 모델이나 더 정교한 프롬프트가 아니라, 모델로 하여금 런타임 현실을 직시하게 만드는 근본적인 아키텍처의 전환이 유일한 해법입니다.

LLM을 훌륭한 페어 프로그래머이자 코드 리뷰어로 대하되, 도구와 연결되지 않은 상태에서는 평균 이하의 디버거로 취급하십시오. “코드를 실행할 수 있는 시니어 엔지니어”라는 환상보다는 “코드를 실행해 볼 수 없는 주니어 개발자”라는 멘탈 모델이 현실에 훨씬 가깝습니다.

실제로는 아무것도 고치지 못하면서 세 번 연속 “수정되었습니다!“를 외치는 모델의 루프는 스스로 사라지지 않습니다. 오직 실행 증거가 뒷받침되지 않는 어떠한 수정안도 받아들이지 않음으로써만, 여러분은 그 루프를 깨뜨릴 수 있습니다.

관련 기사