Constraint Decay: 백엔드 코드 생성에서 LLM 에이전트의 취약성
요약
LLM 에이전트가 복잡한 백엔드 코드 생성 시 명시적인 아키텍처 규칙과 제약 조건을 준수하지 못하는 '제약 붕괴(Constraint Decay)' 현상을 분석합니다. 코드베이스가 커질수록 자연어 지시사항의 모호함이 증가하며, 프로덕션 수준의 신뢰성을 확보하기 위한 기술적 한계를 다룹니다.
핵심 포인트
- 복잡한 규칙이 추가될수록 LLM의 제약 준수 능력이 저하됨
- 코드베이스가 문맥 창을 초과하면 apply_patch 방식이 중요해짐
- 기능 요구사항과 비기능 요구사항의 동시 최적화가 어려움
- LLM 생성 코드는 재조합에 가까우며 새로운 창조에는 한계가 있음
LLM 코드 생성에 완전히 회의적이었는데 이제는 내가 업무에서 쓰는 코드의 80% 이상이 생성 코드가 됨
다만 한계도 꽤 분명해졌고, 일부 프로젝트에서 드러나기 시작했으며 이 글이 내 의심을 확인해 주는 듯함
복잡한 작업일수록 Markdown 명세, 규칙, 스킬에 제약, 스타일 가이드, 경계 조건, 오류 처리, 최적화 지침을 계속 추가하게 됨
어느 순간 프로그래밍 언어의 더 형식적이고 결정적인 세계에 있던 복잡성을 자연어의 비형식적이고 비결정적인 세계로 옮기는 것처럼 보임
작성 속도 향상은 엄청나고 비즈니스는 당연히 이를 생산성 향상으로 보지만, 그 대가가 분명한데 많은 사람이 무시하는 듯함
모두가 말하지 않는 문제가 바로 이것임. 코드베이스가 LLM이 생성한 지시와 가이드라인과 요청이 담긴 Markdown 파일로 커지고 있고, 그게 계속 쌓이고 있음
아무도 100% 검토하지 않고, 검토하더라도 매우 주관적임
“RESTful 접근을 따르라”, “우리는 REST를 쓰고 GraphQL은 쓰지 않는다”, “엔드포인트의 90%는 리소스 지향이지만 일부는 RPC처럼 보이니 무시하라” 사이의 차이가 뭔지 애매함
전부 꽤 어리석어 보임
매번 실행할 때마다 의미가 다른 코드를 생성하는 컴파일러를 쓰는 것과 비슷함
사실상 정의되지 않은 동작으로 가득하지만 대부분 “동작하는 것처럼 보이는” 프로그램을 컴파일하는 셈임
비즈니스가 이것을 생산성 향상으로 본다는 건 결국 다시 초당 코드 줄 수로 “생산성”을 재는 시대로 돌아가는 느낌임
아주 크고 복잡한 코드베이스에서도 크게 고생하진 않고 있음. 원시 소스 기준 50MB 초과 규모에서도 강한 정적 타입 덕을 많이 보는 듯하지만, 그게 전부는 아니라고 봄
코드베이스가 문맥 창의 처음 20% 안에 들어가 한 번의 추론으로 완전히 반복 가능한 수준을 벗어나면, 실행 하네스와 코드 패치 기법이 훨씬 중요해짐
OAI가 모델에 다듬어 온 apply_patch 방식이 초대형 코드베이스에는 가장 나은 접근으로 보임
줄 범위나 단순 찾기-바꾸기에 기반한 방식은 가장자리에서 무너지고, cshtml 파일 같은 까다로운 경우를 다루려면 여러 공간 앵커가 필요함
prepare/commit 동작은 많은 큰 파일에 걸친 모호한 문맥을 반복하며 앵커를 정제하는 데 이상적임
생성 코드의 80%가 LLM에서 나온다면 이미 있는 것을 재조합하는 것에 가깝고, 결국 슬롭임
LLM은 새로운 것을 만들어낼 수 없음
“체계적 연구는 LLM 기반 코딩 에이전트에서 제약 붕괴 현상을 드러낸다. 현재 모델은 제약 없는 생성에는 뛰어나지만, 명시적 아키텍처 규칙을 따라야 하면 성능이 떨어진다. 최종 사용자에게 이 이분법은 에이전트가 빠른 시제품 제작에는 신뢰할 만하지만, 프로덕션급 백엔드 개발에는 여전히 신뢰하기 어렵다는 뜻이다.”
이 연구의 큰 약점은 비용 문제로 최전선 모델을 충분히 테스트하지 않았다는 점이라 구체적인 성능 수치는 조심해서 봐야 함
그래도 동작과 아키텍처가 모두 맞아야 할 때 모델 성능이 떨어진다는 결론은 흥미롭고 계속 지켜볼 만함
“서로 다른 두 목표를 동시에 최적화할 수 없다”는 문제의 하류 현상으로 보임
기능 요구사항만 있다면 일종의 프로그램 합성을 하는 셈이고, 강화학습이 이를 매우 강하게 최적화할 수 있음
기능 요구사항과 비기능 요구사항이 섞이면 사실상 불완전한 명세를 모델에 주는 것이고, 모델은 빈칸을 채우기 위해 사용자의 의도를 어느 정도 추측해야 함
원하는 코드 스타일 예시를 프롬프트에 넣는 것이 대단히 강력한 이유도 여기에 있음
AI 보조로 작성한 책에서도 비슷한 현상을 봄. 초반에는 괜찮지만 몇 장이 지나면 각 장의 시작이 이전 장의 끝을 반복하고, LLM 특유의 흔적이 더 자주 나타남
참고할 내용이 많아질수록 앞에서 나온 것을 반복하는 데 더 의존함
저자들이 뒤쪽 장으로 갈수록 주의를 덜 기울이고 편집에 노력을 덜 들이는 것도 가능함
Amazon에 물량은 엄청나지만, LLM은 아직 글을 잘 쓰는 단계가 아님
Opus와 여러 차례 상호작용하며 계획을 세울 때 비슷한 현상을 겪음
호환되지 않는 해법을 내놓아 추가 문맥과 요구사항을 넣어 주면, 원래 아키텍처에 고정되는 경향이 있고 적응을 어려워함
때로는 원래 계획을 위한 변경을 몰래 끼워 넣으려 하기도 함
프롬프트가 “정렬”이나 “가드레일”을 강제하려 할 때 보이는 문제와 같을 수 있음. 성능이 떨어짐
가능한 해답 공간의 큰 덩어리가 도달 불가능해지는 듯함
예를 들어 1년 전쯤 이미지 생성기에 가드레일을 적용하면 모든 사람이 비슷하게 보이기 시작했고, 이야기 생성기는 몇 가지 표준 이름만 쓰기 시작했음
최전선 모델에서도 아직 이런 일이 일어나는지 궁금함
이 연구에서 쓴 가장 강한 최전선 모델인 GPT 5.2도 에이전트식 프로그래밍에는 겨우 쓸 만한 수준이라고 봄
이런 모델의 약점 분석에는 크게 관심이 없음. 경험상 모델이 강해지고 추론 노력을 높이면 많은 약점이 완전히 사라짐
특히 원하는 행동을 명확히 말해 주면 더 그렇고, 수락 기준이 늘어나면 실패율이 올라가는 건 놀랍지 않음
상황은 더 나쁨. 에이전트는 “구조적 제약” 아래에서 더 어려움을 겪을 뿐 아니라, 그 구조적 제약 자체가 바뀌어야 할 때는 더 형편없음
시스템이나 컴포넌트를 설계할 때 우리는 불변식이 되는 아이디어를 세움
어떤 불변식은 큰 아키텍처처럼 크고, 어떤 것은 자료구조 선택처럼 작음
그런데 결국 그 불변식과 충돌하는 기능을 추가하고 싶어지는 순간이 옴
그때 보통 선택지는 세 가지임: 기능을 추가하지 않거나, 불변식 위에 우아하지 않거나 비효율적으로 기능을 얹거나, 돌아가서 불변식을 바꾸는 것임
대개 이 중 하나만 맞고, 적어도 하나는 아주 크게 틀려 나쁜 결과를 낳음
에이전트는 제약을 따를 수 있을 때조차 제약을 바꿔야 하는 시점을 알아차리는 데 매우 서툼
에이전트식 코딩에 대한 기대는 매우 제한적이지만, 어느 정도 써 본 경험은 있고 이 말과 완전히 일치함
이것은 패턴 인식과 추론 사이의 경계 중 하나이며, 사고 과정이라는 마케팅 주장과 달리 LLM은 조금도 추론하지 않음
추론하는 것처럼 보이게 하려는 모든 시도는 하네스가 번개를 병에 가두려는 재귀적 격리 노력에 가깝다고 봄
여러 분야의 문서 편집 작업을 LLM에 위임한 최근 논문이 떠오름 https://arxiv.org/abs/2604.15597
그 논문에서는 대부분의 LLM이 오류를 누적하고 문서를 망가뜨리지 않고 긴 지평의 작업을 수행할 수 있는 유일한 분야가 프로그래밍이라고 봤음
이번 논문은 아직 초록만 읽었지만, 프로그래밍을 더 정밀하게 들여다보고 비슷한 현상을 보여준 듯함
다만 긴 지평의 작업이라기보다 더 큰 구조적 제약 묶음에 대한 “긴 스타일 지평”에 가까워 보임
관련 토론: https://news.ycombinator.com/item?id=48073246
쉽게 검증할 수 없는 일에는 LLM이 능숙하지 않음
매우 흥미로운 논문이고 전적으로 동의하지만, 새로운 이야기는 아니라고 봄
어떤 에이전트식 코딩 솔루션을 프로젝트에 떨어뜨리고 작업 목록을 던지면 프로젝트의 사전 정의된 제약을 마법처럼 따를 거라는 초기 기대부터 조금 빗나가 있음
어떤 에이전트식 코딩 스택도 기본 상태로 이걸 할 수 있다고 믿지 않음
에이전트가 문맥, 제약, 목표를 안정적으로 이해하려면 여전히 적절한 메커니즘이 필요하고, 주요 AI 연구소들이 도구·스킬·프로세스를 계속 업데이트하는 걸 보면 아직 진행 중인 영역임
이 추가 계층은 순수 모델과 토큰 소비보다 훨씬 더 수익성 있을 수도 있음
현재 테스트된 것 같은 개방형 모델도 제대로 구동하면 원하는 제약을 따르는 프로덕션 코드를 이미 만들 수 있다고 봄
최근 몇 달 동안 여러분의 프로덕션 코드는 어땠는지 궁금함
긴 지평의 에이전트식 코딩을 꽤 실험해 왔고 https://medium.com/@vishvananda/i-spent-2-billion-tokens-wri..., 특정 아키텍처 패턴을 강제하면 에이전트 성능이 나빠지는 것도 봄
제약을 나중에 추가하는 것보다 진행 중에 함께 넣으면 조금 나아짐
내가 석회화라고 부르는 부작용이 있는데, 코드베이스에 어떤 패턴이 나타나기 시작하면 에이전트가 그 패턴을 따라가다가 문맥을 지배하고 자기강화됨
기존 코드베이스에서는 코드 품질에 따라 강점이 될 수도 약점이 될 수도 있음
처음부터 아키텍처 지침을 포함한 새 코드베이스 실행들이 마무리되면 더 많은 통찰이 생길 듯함
나도 이것을 봤음. 에이전트와 모델에는 고유한 스타일이 있고, 대체로 지나치게 장황함으로 요약됨
또한 모델은 구현을 “계획”할 여지가 있을 때는 모듈화를 어느 정도 잘하지만, 나중에 추상화가 도움이 되겠다고 스스로 판단하는 경우는 드묾
새 코드베이스에서 여러 번 반복한 뒤나 레거시 코드베이스에 투입됐을 때 특히 그렇고, 종종 거대 파일로 이어짐
사용자가 이를 짚어 주면 모델은 제대로 비판하는데, 애초에 자신이 쓴 코드일 때는 꽤 우스움
“채팅이 길어질수록 가드레일이 흐려지는 것 같다”의 또 다른 버전처럼 들림
문맥 창을 전부 쓸 수 없는 이유는 끝부분에서 출력이 제약이나 가드레일을 지키지 않기 때문임
그런데 프로덕션급 코드를 안정적으로 만들려면 모델이 넓은 인식을 가져야 하고, 이는 문맥 창을 금방 채움
“이 6개 디렉터리의 모든 것을 염두에 두고 이 변경을 하라”고 말하는 것과 비슷한데, 모든 것을 염두에 두는 것만으로 이미 문맥 창이 차서 제약을 따르는 능력을 잃게 됨
새로운 문제는 아님. 우리가 모듈식 코드와 엄격한 인터페이스를 쓰기 시작한 이유가 바로 이것임
더 강한 가드레일을 주면 되지 않을까? Sonarcube 같은 것들 말임
다만 그러면 실패 양상이 린터를 만족시키는 데 집중하다가 요구사항을 점점 잊어버리는 쪽이 될 듯함
시도/실패 반복도 문맥에는 전혀 좋지 않을 것임
연구에서 Python과 JS처럼 동적 타입 언어를 썼음
내 경험상 정적 타입 코드베이스는 사람에게도 유지보수가 더 쉬우니 에이전트에게도 그럴 수 있음
Go 코드에서 Codex나 Claude Code를 쓸 때 에이전트가 변경하고, 빌드를 실행해 오류를 찾고, 다시 고치는 일을 셀 수 없이 봤음
하네스 규칙에 타입을 추가하고 매 변경 후 ty를 실행하게 하면 됨
요즘 모델은 Python 타입을 꽤 잘 다룸
사람들이 Python을 기본적으로 동적 타입 언어라고 여기는 게 이상함
Python에서는 몇 년 전부터 강한 정적 타입이 선택지였고, 그냥 기본값이어야 함
“8개 웹 프레임워크에 걸친 작업”이라고 하는데, LLM이 기존 프레임워크로 작업하는 것보다 순수 HTML+CSS+JS를 더 잘 만든다는 경험이 있는지 궁금함
웹 프레임워크는 gpt-5.4 이후로 “곤란한 처지”가 된 것 같음. 이제 React 같은 것을 쓰는 건 상상하기 어려움
최근 본 가장 놀라운 조합은 Razor Pages에 JavaScript로 점진적 향상을 얹는 방식임
이 구성에서는 최신 모델이 어떤 일이 서버 쪽(cshtml)에서 일어나야 하는지, 클라이언트 쪽(js)에서 일어나야 하는지를 꽤 잘 판단함
코드베이스의 몇 부분을 관용적인 형태로 먼저 다듬고, 그 파일들을 예시 파일로 @로 지정하는 데 시간을 쓰길 추천함
Markdown으로 조종하려는 것보다 훨씬 잘 작동함
FastAPI 같은 경우에는 꽤 괜찮지만 JavaScript가 최악으로 보임
지침과 예시를 줘도 지정한 API를 쓰기보다 쓸데없는 코드를 잔뜩 인라인하려는 경향이 있음
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기