AI가 짠 코드, 세 곳에서 동시에 무너진다

AI가 짠 코드, 세 곳에서 동시에 무너진다

테스트·에이전트·Vibe Coding—세 실패 지점이 가리키는 하나의 질문, 'AI 생성 결과물을 얼마나 믿을 수 있는가'

AI 테스트 품질 미러 테스트 에이전트 권한 제어 Vibe Coding Frankenstein 코드 CI 검증 AI 코드 리뷰 프로덕션 배포 위험
광고

초록불이 켜졌다. 그런데 그게 진짜 증거인가?

CI가 통과했다. 에이전트가 배포했다. 코드가 돌아간다. 이 세 문장이 동시에 참일 때, 우리는 보통 안심한다. 그런데 최근 나온 세 개의 실증 사례를 나란히 놓고 보면, 그 안심이 얼마나 얇은 지반 위에 서 있는지가 선명하게 드러난다. 테스트 품질, 에이전트 권한, Vibe Coding의 코드 부채—각각 다른 문제처럼 보이지만, 수렴하는 질문은 하나다. AI가 만든 결과물을 어느 수준까지 신뢰할 수 있는가.

첫 번째 균열: 초록 테스트가 아무것도 증명하지 않을 때

dev.to에 올라온 mirror_audit.py 사례는 불편하게 정직하다. 같은 에이전트가 구현 코드와 테스트를 함께 작성하면, 테스트는 코드를 검증하는 게 아니라 코드를 반영하게 된다. 저자가 직접 측정한 결과, 에이전트가 생성한 테스트 스위트의 50%가 독립적인 신호를 전혀 갖지 않았다. CI는 당연히 초록이었다.

패턴은 세 가지로 반복된다. 구현 공식을 그대로 재계산하는 어서션(f(x) == f(x) 구조), 코드를 한 번 실행해 나온 값을 그냥 고정한 골든 리터럴, 그리고 assert result is not None 수준의 스모크 테스트. 세 가지 모두 틀린 코드가 아니다—그냥 검사가 아닐 뿐이다. 실제로 -50% 할인이 $150 청구서를 만들어도, 미러 테스트는 같은 공식으로 150 == 150을 확인하고 초록불을 켠다. 버그를 축복하는 것이다.

mirror_audit.py의 접근법은 실용적이다. AST를 정적으로 파싱해 네 가지 패턴을 검출하고, 두 개 이상 걸릴 때만 미러 테스트로 분류한다. 실행 없이, API 키 없이, 병합 전에. 이 도구가 증명하는 것은 하나다—테스트 품질은 커버리지가 아니라 독립적 오라클의 존재 여부로 판단해야 한다.

두 번째 균열: "하지 말라고 했잖아"는 가드레일이 아니다

두 번째 사례는 더 아찔하다. 프라이버시 툴 사이트를 운영하던 개발자가 Claude 에이전트에게 하루 세 번 프로덕션 배포를 맡겼다. 에이전트는 잘 동작했다—메타 디스크립션을 고치고, 구조화 데이터를 개선하고, 숨겨진 페이지를 디렉토리에 연결했다.

그런데 어느 날 권한을 확인했더니, 에이전트는 임의 명령 실행, 전체 서비스 삭제, 데이터베이스 파괴적 연산, git 히스토리 강제 덮어쓰기까지 모두 물리적으로 가능한 상태였다. 안전 장치는 프롬프트에 쓴 한 줄—"additive changes only"—뿐이었다.

저자가 직접 꺼낸 교훈이 핵심이다. "Convention is not a guardrail. 'I told it not to' is not the same as 'it cannot.'" LLM은 DROP TABLE이 나쁜 일이라는 직관이 없다. 논리적으로 말이 된다고 판단하면 실행한다. 이후 그가 바꾼 것은 간단하다—배포 외 명령은 물리적으로 차단, 파괴적 DB 명령 하드 덴리스트, 에이전트가 외부에서 읽어온 내용은 무조건 데이터로만 취급. 그리고 에이전트의 다이제스트 대신 외부에서 캡처한 diff와 배포 로그를 진실의 원천으로 삼았다. 에이전트가 스스로 작성한 작업 일지를 신뢰하는 것은, LLM에게 자기 숙제를 채점시키는 것과 같다.

세 번째 균열: Vibe Coding이 만드는 Frankenstein 코드베이스

세 번째는 더 느리게 무너진다. Andrej Karpathy가 이름 붙인 Vibe Coding—프롬프트 기반의 직관적 개발—은 속도 면에서 분명히 강력하다. 몇 초 만에 Express 서버를 세우고, SQL 쿼리를 구성하고, API 보일러플레이트를 완성한다.

하지만 dev.to의 분석이 지적하는 사이클은 명확하다. 프롬프트 → 실행 → 에러 복사 붙여넣기 → 재프롬프트. 이 루프는 프로토타입에서는 강력하지만, 아키텍처 없이 쌓이면 Frankenstein 코드가 된다. 한 파일은 함수형, 다른 파일은 OOP. 같은 문제를 해결하는 라이브러리가 세 개. 컨텍스트 윈도우를 초과하는 순간 에이전트는 이미 해결된 버그를 재도입하거나, 존재하지 않는 인터페이스를 발명한다.

결과는 역설적이다. 인간 팀원도 완전히 이해하지 못하고, AI 어시스턴트도 건드리면 세 곳이 동시에 깨지는 코드베이스. 속도가 오히려 유지보수 불가능성을 만든 것이다.

세 개의 실패가 가리키는 하나의 설계 원칙

이 세 사례를 테크 리드 관점에서 정렬하면 패턴이 보인다.

  • 테스트 레이어: AI가 생성한 테스트는 독립적 오라클 존재 여부를 정적으로 검증해야 한다. 커버리지 숫자는 미러 테스트 앞에서 무의미하다.
  • 에이전트 권한 레이어: 프롬프트 인스트럭션은 행동 지침이지 물리적 제약이 아니다. 에이전트가 할 수 없는 것을 시스템 레벨에서 설계해야 한다.
  • 코드 품질 레이어: Vibe Coding의 속도는 아키텍처 의도를 명시적으로 관리할 때만 지속된다. 그렇지 않으면 속도는 부채 속도다.

세 레이어 모두 공통점이 있다. AI 생성물을 신뢰의 대상이 아니라 검증의 대상으로 취급하는 것. 초록불을 보고 안심하는 게 아니라, 그 초록불이 무엇을 실제로 증명하는지를 묻는 것.

내일 팀에 적용할 세 가지 체크

이론이 아니라 내일 당장 써먹을 수 있는 것만 추리면 세 가지다.

  1. AI 생성 테스트에 네거티브 케이스 의무화: PR 리뷰 체크리스트에 "에러 경로와 경계값 테스트 포함 여부"를 추가한다. mirror_audit.py 같은 정적 분석 도구를 CI에 넣는 것도 즉시 실행 가능하다.
  2. 에이전트 권한을 명시적 허용 목록으로 관리: 프롬프트에 쓴 제약은 기록이 아니라 희망 사항이다. 배포 에이전트라면 배포 명령만, 컨텐츠 에이전트라면 컨텐츠 경로만 물리적으로 허용한다.
  3. Vibe Coding 결과물에 아키텍처 리뷰 게이트 추가: 프로토타입이 프로덕션으로 넘어오는 시점에 의존성 지도와 모듈 경계를 명시적으로 리뷰한다. 이 게이트 없이는 Frankenstein 코드가 기술 부채가 아니라 운영 위험이 된다.

AI-First 팀에서 '신뢰'의 의미가 바뀌고 있다

AI 도구에 낙관적인 입장은 여전하다. 하지만 이 세 사례가 동시에 터진 지금, 팀에 전달해야 할 메시지는 분명하다. AI를 신뢰한다는 것은 출력을 그대로 믿는다는 뜻이 아니다. AI가 만든 결과물이 무엇을 실제로 보장하고, 무엇을 보장하지 않는지를 팀이 정확히 아는 것—그게 AI-First 팀의 신뢰 설계다.

초록불이 켜졌다고 끝난 게 아니다. 그 초록불이 무엇을 증명하는지 물어야 한다. 그리고 그 질문을 자동화하는 것이 지금 테크 리드가 해야 할 일이다.

출처

더 많은 AI 트렌드를 Seedora 앱에서 확인하세요