AI 에이전트가 계속해서 코드베이스를 재작성하는 이유와 이를 방지하는 방법
요약
AI 에이전트가 새로운 요청을 처리할 때 기존 코드베이스를 과도하게 재작성하는 '프로토콜 문제'를 분석합니다. 에이전트가 변경 요청을 확정된 요구사항으로 오해하여 발생하는 구조적 파괴를 방지하기 위한 전략을 다룹니다.
핵심 포인트
- 에이전트의 과도한 재작성은 모델 결함이 아닌 프로토콜 문제임
- 에이전트는 국지적 코드 청결도를 최적화하려다 전역적 파괴를 초래함
- 새로운 아이디어를 확정된 요구사항이 아닌 가설로 취급해야 함
- 변경 전 실행 가치와 영향도를 판단하는 질문 프로세스가 필요함
AI 에이전트에게 작은 기능을 추가해 달라고 요청합니다. 그러면 에이전트는 언급하지도 않은 파일 세 개를 재작성하고, 추출할 필요가 없는 유틸리티 함수 (utility function)를 추출하며, "미래의 확장성 (future extensibility)"을 위해 추상화 계층 (abstraction layer)을 도입합니다.
익숙한 상황인가요?
이것은 모델의 문제가 아닙니다. 이것은 **프로토콜 문제 (protocol problem)**이며, 특히 아직 아무도 설계하지 않은 간극에서 발생합니다.
아무도 말하지 않는 간극
AI 보조 개발 (AI-assisted development) 생태계는 두 가지 측면에서 매우 뛰어나졌습니다.
새롭게 시작하기. 사양 기반 개발 (Spec-driven development), 제품 요구 사항 문서 (PRDs), 인터뷰 기술 등 — 많은 도구들이 "아이디어가 있다"에서 "계획이 있다"로 넘어가는 것을 도와줍니다.
꾸준하게 실행하기. 점진적 구현 (Incremental implementation), 테스트 주도 개발 (TDD), 얇은 수직 슬라이스 (thin vertical slices) — 무엇을 만들지 알게 되면, 에이전트는 그것을 신중하게 구현할 수 있습니다.
하지만 그 사이에는 실제 프로젝트에서 수십 번씩 발생하는 간극이 존재합니다.
개발이 진행 중입니다. 무언가가 절반쯤 만들어져 있습니다. 그리고 새로운 아이디어가 떠오릅니다.
만든 것을 테스트하다가 다르게 작동해야 한다는 것을 깨달았을 수도 있습니다. 사용자가 방향을 바꾸는 피드백을 주었을 수도 있습니다. 혹은 코드를 보다가 그냥 더 나은 생각이 떠올랐을 수도 있습니다.
이런 일이 발생할 때, 대부분의 에이전트는 다음 두 가지 중 하나를 수행합니다.
- 새로운 아이디어를 수용하기 위해 기반(foundation)을 재작성합니다.
- 명확한 질문을 던진 뒤, 어쨌든 기반을 재작성합니다.
둘 다 당신이 실제로 원하는 방식이 아닙니다.
왜 에이전트는 재작성을 기본값으로 선택하는가
재작성을 기본값으로 선택하는 것은 무작위가 아닙니다. 이는 에이전트가 변경 요청 (change requests)에 대해 추론하는 방식에서 비롯됩니다.
당신이 _"X를 추가하고 싶어"_라고 말하면, 에이전트는 현재의 코드베이스 (codebase)를 평가하고, X가 깔끔하게 들어맞지 않는 지점을 확인한 뒤, 가장 "올바른" 경로를 택합니다. 즉, X가 들어맞을 때까지 구조를 재조정 (restructure)하는 것입니다.
이는 국지적으로는 합리적이지만 전역적으로는 파괴적입니다. 에이전트는 요청이 들어온 순간의 코드 청결도 (code cleanliness)를 최적화합니다. 에이전트는 다음을 알지 못합니다:
- 현재 구조에 의존하고 있는, 절반만 완료된 다른 세 가지 작업이 있다는 사실
- 구조 재편 (restructure)이 이미 잘 작동하던 것들을 다시 테스트하게 만든다는 사실
- 새로운 아이디어가 현실과 부딪혔을 때 살아남지 못할 수도 있으며, 아직 재작성을 정당화할 단계가 아니라는 사실
에이전트는 모든 새로운 아이디어를 확정된 요구사항 (requirement)으로 취급합니다. 하지만 실제 제품 개발 — 특히 아이디어가 그 어느 때보다 빠르게 떠오르는 AI 보조 개발 (AI-assisted development) 환경 — 에서 대부분의 새로운 아이디어는 구축해야 할 요구사항이 아니라 테스트가 필요한 가설 (hypothesis) 입니다.
에이전트가 던져야 할 다섯 가지 질문
개발 도중에 새로운 아이디어가 들어왔을 때, 코드 한 줄을 바꾸기 전에 다음 다섯 가지 사항이 결정되어야 합니다:
1. 이 아이디어가 지금 바로 실행할 가치가 있는가?
새로운 아이디어는 모두 동일하지 않습니다. 어떤 것은 진정한 차단 요소 (blocker, 예: 현재 메인 경로의 버그) 입니다. 어떤 것은 개선 사항 (improvement, 예: 현재 기능이 작동하지만 더 나아질 수 있는 경우) 입니다. 어떤 것은 확장 (extension, 예: 완전히 새로운 기능이나 시나리오) 입니다.
이들은 서로 다른 대응이 필요합니다. 차단 요소는 즉시 처리해야 합니다. 개선 사항은 일괄 처리 (batch) 해야 합니다. 확장은 24시간 동안 보류해야 합니다. 대부분의 새로운 기능에 대한 충동은 사라지거나 더 명확한 무언가로 결정화 (crystallize) 됩니다.
2. 이 변경 사항은 얼마나 파괴적인가?
어떤 변경 사항은 되돌릴 수 있습니다: 새로운 필드 추가, 새로운 경로 (route) 추가, UI 요소 변경 등입니다. 언제든 실행 취소 (undo) 할 수 있습니다.
다른 것들은 일방통행 문 (one-way doors) 입니다: 데이터베이스 스키마 (database schema) 변경, 외부 API 시그니처 (API signature) 수정, 파일 삭제 등입니다. 이러한 작업은 더 면밀한 검토가 필요합니다. 그것이 틀렸기 때문이 아니라, 틀렸을 때의 비용이 높기 때문입니다.
3. 당신이 구축하려는 것을 실제로 사용하는 사람이 있는가?
새로운 모듈, 함수, 또는 API를 만들기 전에, 실제 호출 지점 (call sites) 의 개수를 세어보십시오. 만약 답이 0이라면, 당신은 가상의 미래를 위해 구축하고 있는 것입니다. 만약 답이 1이라면, 추상화 (abstraction) 가 필요하지 않습니다. 만약 답이 3개 이상이라면, 이제 추상화를 고려할 가치가 있습니다.
"사용자가 0명"인 경우가 과잉 엔지니어링 (over-engineering) 이 가장 많이 발생하는 지점입니다. 에이전트는 아무도 실제로 호출하지 않는 범용 시스템을 열정적으로 구축하곤 합니다.
4. 이를 통합하는 가장 파괴적이지 않은 방법은 무엇인가?
통합 모드에는 기존 코드를 얼마나 방해하느냐에 따라 다음과 같은 스펙트럼이 존재합니다:
- 래핑 (Wrap): 기존 코드 주변에 레이어를 추가합니다. 원본은 건드리지 않습니다.
- 확장 (Extend): 새로운 브랜치(branch), 파라미터(parameter), 또는 라우트(route)를 추가합니다. 기존 경로를 변경하지 않습니다.
- 브랜칭 (Branch): 병렬로 구현합니다. 기존 경로를 유지하면서 사용자를 점진적으로 마이그레이션(migrate)합니다.
- 교체 (Replace): 진정으로 다시 작성합니다. 기존 구현이 실제적인 부채(liability)가 될 때만 수행합니다.
대부분의 새로운 아이디어는 래핑(Wrap)이나 확장(Extend)에 해당합니다. 하지만 에이전트는 기본적으로 교체(Replace)를 선택합니다.
5. 동일한 로직이 너무 많은 곳에서 나타나고 있는가?
동일한 패턴이 세 번 이상 나타나면 이는 플래그(flag)를 표시할 가치가 있습니다. 하지만 반드시 즉시 수정해야 할 가치가 있는 것은 아닙니다. 이를 표면화하여 개발자가 결정하게 하세요.
실제 사례에서의 모습
다음은 AI 지원 개발(AI-assisted development)에서 발생하는 실제 패턴입니다.
시나리오: 당신은 데이터 대시보드를 구축하고 있습니다. 사용자 분석 페이지와 콘텐츠 분석 페이지를 완료했습니다. 세션 중간에 당신은 다음과 같이 생각합니다: "실시간 협업(real-time collaboration) 기능을 추가해야겠어."
에이전트의 기본 동작: 실시간 지원을 위한 아키텍처(architecture) 평가를 시작합니다. WebSocket 통합을 제안합니다. 아마도 공유 상태(shared state)를 지원하기 위해 데이터 레이어(data layer)를 리팩터링(refactoring)하기 시작할 수도 있습니다.
실제로 일어나야 하는 일:
- 아이디어를 분류합니다: 버그가 아닌 새로운 시나리오입니다. C-클래스 — 신규 기능(new feature).
- 이를 인박스(inbox)에 기록합니다. 현재 작업을 계속 진행합니다.
- 24시간 후 다시 검토합니다: 실시간 협업이 현재 사용자들이 요청하고 있는 사항인가? 핵심 대시보드가 아직 검증(validated)조차 되지 않은 상태인가?
- 만약 그렇다면 — 그때 제대로 평가하고, 통합 모드를 선택하며, 이를 실제 작업으로 범위를 지정(scope)합니다.
아이디어는 사라지지 않습니다. 잘못된 시점의 충동적인 구현이 아니라, 적절한 시점에 공정한 평가를 받게 됩니다.
또 다른 시나리오: 기존 유틸리티 함수가 약간의 변형을 가진 채 다섯 개의 서로 다른 파일에 나타납니다.
기본적인 에이전트 동작: 조용히 여섯 번째 장소에 복사하거나, 다섯 개 모두를 공통 버전으로 사용하도록 조용히 "리팩터링(refactor)"합니다 (현재 작업 범위를 벗어난 파일들을 건드림).
실제로 일어나야 하는 일:
에이전트가 이를 표시합니다: "[X 로직]이 5번 중복된 것을 발견했습니다. 지금 통합할까요, 아니면 받은 편지함(inbox)에 기록할까요?"
만약 개발자가 "기록해 줘"라고 말하면, 이는 다듬기(polish) 항목으로서 받은 편지함으로 들어갑니다. 현재 작업은 중단 없이 계속됩니다. 통합이 결국 완료될 때는, 무관한 작업의 부작용이 아니라 깔끔하고 전용된 작업으로서 수행됩니다.
build-forward 프로토콜
이 다섯 가지 질문은 제가 만든 build-forward라는 SKILL.md의 핵심입니다. 이는 개발 도중 새로운 아이디어가 나타날 때마다 실행되는 에이전트 지침 세트입니다.
규칙 1 — 먼저 분류하고, 코드를 작성하지 마세요.
모든 새로운 아이디어는 무언가를 작성하기 전에 A/B/C 라벨을 부여받습니다. A (fix, 수정) = 지금 처리. B (polish, 다듬기) = 나중에 일괄 처리. C (extend, 확장) = 24시간 대기 시간(cooldown).
규칙 2 — 파괴성을 평가하세요.
일방통행 문(One-way door, 되돌리기 어려운) 변경은 진행하기 전에 명시적인 영향 매트릭스(impact matrix)가 필요합니다. 양방향 문(Two-way door, 되돌릴 수 있는) 변경은 즉시 진행합니다.
영향 평가 (Impact Assessment):
- 직접적인 변경: [파일 / 인터페이스 이름]
- 하위 영향: [영향을 받는 소비자(consumers)]
...
규칙 3 — 소비자 감사 (Consumer audit).
소비자 0명 → 구축하지 마세요. 소비자 1명 → 인라인(inline)으로 작성하고 추상화하지 마세요. 소비자 3명 이상 → 이제 공유 레이어(shared layer)를 고려하세요.
규칙 4 — 통합 모드를 선택하세요.
Wrap(감싸기) → Extend(확장) → Branch(분기) → Replace(교체) 순으로, 파괴성이 높은 순서대로 나열됩니다. 작동 가능한 가장 낮은 단계의 모드를 선택하세요.
규칙 5 — 중복 경고.
동일한 로직이 3번 이상 나타나면 → 이를 표면화하여, 통합할지 아니면 기록할지 물어보세요.
개발자가 프로토콜을 무시하는 경우를 위한 폴백(fallback)도 있습니다. 에이전트는 논쟁하지 않지만, 영향 매트릭스를 강제로 출력하며 가장 엄격한 평가(Replace 모드)를 기본값으로 설정합니다. 이는 맹목적인 준수가 아닌, 정보에 기반한 결정입니다.
이것이 아닌 것
build-forward는 아이디어를 차단하기 위한 것이 아닙니다. 이는 PRD(제품 요구 사항 문서) 프로세스나 변경 동결(change freeze)이 아닙니다.
이는 아이디어를 적절한 시점과 적절한 경로로 라우팅(routing)하는 것에 관한 문제입니다. 오후 2시에 C-class 충동으로 나타난 아이디어가 다음 계획 세션에서는 유효한 B-class 작업이 될 수도 있습니다. 24시간 규칙은 아이디어를 죽이는 것이 아니라, 검증을 견뎌낼 아이디어를 걸러내는 역할을 합니다.
또한, 에이전트를 더 제한적으로 만드는 것도 아닙니다. build-forward를 실행하는 에이전트는 여전히 당신이 요청한 것을 구현할 것입니다. 다만 먼저 다섯 가지 질문을 던지고, 기존 구조를 파괴하기보다는 보존하는 통합 경로를 선택할 뿐입니다.
시작하기
build-forward는 Claude Code, Cursor, Codex CLI, Gemini CLI 등 SKILL.md 파일을 지원하는 모든 곳에서 작동합니다.
# English version
curl -L https://github.com/dmlin7777777/build-forward/raw/main/SKILL.en.md \
-o .claude/skills/build-forward/SKILL.md
이 스킬은 GitHub의 dmlin7777777/build-forward에서 확인할 수 있으며, 영어와 중국어 버전이 모두 제공됩니다.
더 큰 그림
AI 코딩 어시스턴트(AI coding assistants) 덕분에 코드를 생성하는 것은 매우 쉬워졌습니다. 이제 새로운 병목 구간은 생성이 아니라 **통합(integration)**입니다. AI의 도움을 받는 코드베이스가 마치 항상 처음부터 다시 구축되는 것처럼 느껴지게 만드는 잦은 변동(churn)을 일으키지 않으면서, 어떻게 새로운 아이디어를 기존 구조에 연결할 수 있을까요?
build-forward는 그 질문에 대한 하나의 해답입니다. 다섯 가지 규칙은 복잡하지 않지만, 대부분의 에이전트 워크플로우(agent workflows)가 완전히 방치해 두는 간극, 즉 "방금 무언가 떠올랐다"와 "에이전트가 이미 모든 것을 바꾸고 있다" 사이의 간극을 메워줍니다.
그 간극이야말로 AI 지원 개발에서 낭비되는 대부분의 시간이 발생하는 지점입니다.
여러분의 AI 코딩 워크플로우에서도 이런 문제를 겪은 적이 있나요? 현재는 어떤 방식을 사용하고 계신가요? 댓글로 의견을 들려주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기