코드 생성을 넘어선 AI 코딩 에이전트 테스트: 실무 벤치마크
요약
단순한 코드 생성을 넘어 기존 프로젝트의 상태를 유지하며 리팩터링과 마이그레이션을 수행하는 AI 코딩 에이전트의 실무 능력을 테스트한 사례 연구입니다. Greenfield 구축과 기존 애플리케이션의 인증 및 DB 마이그레이션 과정을 통해 에이전트의 복구 및 유지보수 역량을 분석했습니다.
핵심 포인트
- 단순 코드 생성을 넘어 상태(stateful)를 가진 프로젝트 관리 능력의 중요성 강조
- 인증 리팩터링 및 DB 마이그레이션 등 복잡한 유지보수 태스크 수행 결과 기록
- 테스트 통과 및 빌드, 린트 등 실무 워크플로우 검증 과정 포함
- 단일 사례 연구로서의 한계와 재현성 측면의 주의사항 명시
1. 서론
대부분의 공개적인 AI 코딩 에이전트 시연은 빈 디렉토리에서 시작하여 눈에 보이는 기능이 작동할 때 종료됩니다. 이는 유용하지만, 소프트웨어 엔지니어링의 첫 번째이자 가장 쉬운 부분인 생성 (generation)만을 측정합니다. 실제 프로젝트는 상태를 가집니다 (stateful). 기존의 동작, 유지되어야 하는 데이터, 보안 경계, 부분적으로 완료된 작업, 그리고 설득력 있는 데모로 대체될 수 없는 검증 단계들을 포함합니다.
이 벤치마크는 이러한 더 어려운 문제에 대한 작고 실질적인 기록으로서 설계되었습니다. 이는 동일한 풀스택 태스크 매니저 (task-manager) 프로젝트에 대한 두 번의 Codex 실행을 기록합니다. 1단계 (Phase 1)는 그린필드 (greenfield) 구축이었습니다. 2단계 (Phase 2)는 인증 (authentication) 및 데이터베이스 마이그레이션 (database-migration) 리팩터링 (refactor)을 위해 기존 애플리케이션으로 돌아갔습니다. 두 번째 실행에는 사용자가 시작한 긴 중단 과정도 포함되어, 복구 (recovery) 과정이 관찰된 워크플로우 (workflow)의 일부가 되었습니다.
제한적인 결과는 고무적입니다. 초기 애플리케이션은 약 34분 만에 완료된 것으로 기록되었으며, 이후의 리팩터링은 사용자 주도 일시 중지를 제외하고 약 42분의 활성 실행 시간이 소요되었습니다. 2단계 (Phase 2) 실행에서는 16개의 백엔드 테스트 (backend tests), 1개의 레거시 마이그레이션 테스트 (legacy-migration test), 25개의 프론트엔드 테스트 (frontend tests)가 통과되었으며, 린트 (lint), 타입 (type), 빌드 (build), 의존성 (dependency), 그리고 브라우저 수락 (browser-acceptance) 체크도 함께 수행되었습니다.
이 수치에는 한계가 있습니다. 이것은 단일 환경의 사례 연구 (case study)이며, 공식적인 벤치마크가 아니며, 제공자 간의 통제된 비교가 아니며, 운영 환경에서의 보증도 아닙니다. 현재의 문서 세트는 전체 소스 트리 (source tree), 정확한 프롬프트 (prompts), 원시 터미널 출력 (raw terminal output), 마이그레이션 아티팩트 (migration artifact), 데이터베이스 픽스처 (database fixture), 또는 브라우저 트레이스 (browser trace)를 유지하고 있지 않습니다. 따라서 결과는 독립적으로 재현된 증거라기보다는 제공된 실행 기록으로서 제시됩니다.
2. 단순한 코드 생성 테스트가 불충분한 이유
"task app을 만들어줘"와 같은 프롬프트는 주로 합성 (synthesis) 능력을 테스트합니다. 에이전트는 기술 스택을 선택하고, 파일을 생성하며, 컴포넌트를 연결하고, 작동하는 경로를 만들어냅니다. 이는 속도와 기본적인 도구 사용 능력을 보여줄 수는 있지만, 제약 조건들이 충돌할 때 에이전트가 어떻게 행동하는지에 대해서는 거의 알려주지 않습니다.
유지보수 작업은 그러한 충돌을 야기합니다. 인증 리팩토링 (authentication refactor)은 데이터 모델, API 계약 (API contracts), 프론트엔드 상태 (frontend state), 라우팅 (routing), 테스트 픽스처 (test fixtures), 그리고 마이그레이션 동작을 동시에 변경합니다. owner_id 컬럼이 존재한다고 해서 사용자 소유권 (user ownership) 기능이 완성된 것은 아닙니다. 모든 읽기 및 쓰기 경로에서 경계 (boundary)를 강제해야 합니다. 새로운 데이터베이스가 잘 작동한다고 해서 마이그레이션 (migration)이 완료된 것도 아닙니다. 업그레이드 후에도 레거시 행 (legacy rows)들이 여전히 유효해야 합니다. 컴파일이 되는 프론트엔드라 할지라도 CORS, 토큰 저장 (token storage), 라우팅, 또는 일치하지 않는 응답 형태 (response shape) 때문에 실패할 수 있습니다.
따라서 중요한 단위는 생성된 코드가 아닙니다. 그것은 상태가 있는 시스템 (stateful system)에 대한 검증된 변경입니다.
유용한 에이전트 평가는 최소한 다섯 가지 질문을 던져야 합니다:
- 요청된 동작이 작동했는가?
- 기존 동작이 온전하게 유지되었는가?
- 기존 데이터가 보존되었는가?
- 보안 경계가 UI에 의해 암시되는 것이 아니라 서버에서 강제되었는가?
- 워크플로우가 중단되거나 도구 실패 후에도 상태를 조용히 잃어버리지 않고 복구될 수 있는가?
이러한 질문들은 벤치마크에 테스트, 빌드, 마이그레이션 확인, 그리고 브라우저 수락 테스트 (browser acceptance)를 포함하도록 강제합니다. 또한 실패 증거를 가치 있게 만듭니다. 마이그레이션 버그를 드러내는 느린 실행이, 마이그레이션을 전혀 테스트하지 않는 빠른 실행보다 더 많은 정보를 제공합니다.
3. Phase 1: 처음부터 구축하기
Phase 1은 그린필드 프로젝트 (greenfield project)에서 시작되었습니다. 기록된 스택은 프론트엔드의 React 및 TypeScript, 백엔드의 FastAPI, 그리고 지속성을 위한 SQLite였습니다. 요청된 제품은 생성, 읽기, 수정, 삭제 (CRUD) 흐름과 반응형 인터페이스를 갖춘 작업 관리자 (task manager)였습니다.
해당 실행은 엔드 투 엔드 (end to end)로 약 34분 만에 완료된 것으로 기록되었습니다. 완료 기록에는 애플리케이션 구현, 자동화된 테스트 (automated tests), 프로덕션 빌드 (production build), 보안 점검, 그리고 CRUD 워크플로우에 대한 브라우저 수락 (browser acceptance)이 포함됩니다. HTTP 429 오류가 한 차례 발생했습니다. 워크플로우는 약 2~3분 동안 대기하며 에이전트 및 스킬 호출을 줄인 후, 완료를 향해 계속 진행되었습니다.
1단계 (Phase 1)는 에이전트가 적당한 규모의 풀스택 애플리케이션 (full-stack application)의 여러 계층을 빠르게 조정할 수 있음을 입증했습니다. 더 중요한 점은, 나중에 변경할 수 있는 프로젝트 상태를 구축했다는 것입니다. 이를 통해 익숙한 그린필드 (greenfield) 데모를 넘어 실제 유지보수 문제를 테스트하는 것이 가능해졌습니다.
증거의 경계는 유의미합니다. 정확한 테스트 횟수, 의존성 버전 (dependency versions), 총 요청 수, 총 토큰 수 및 원시 출력 (raw output)은 이 단계에 대해 보존되지 않았습니다. 34분이라는 수치는 이 기록된 실행을 설명하는 것이지, 다른 애플리케이션이나 환경에 대한 예상 성능을 의미하는 것이 아닙니다.
4. 2단계 (Phase 2): 인증 및 데이터베이스 마이그레이션 리팩터링 (Refactor)
2단계는 기존의 작업 관리자 (task manager)를 다시 구축하는 대신 기존 상태로 돌아갔습니다. 요청된 범위에는 JWT 인증 (JWT authentication), Argon2 비밀번호 해싱 (password hashing), 백엔드에서 강제되는 작업 소유권 (task ownership), 태그 (tags), 보관 및 복구 동작, 그리고 기존 SQLite 데이터베이스를 위한 Alembic 관리 스키마 진화 (schema evolution)를 포함한 회원가입 및 로그인 기능이 추가되었습니다.
이는 엔지니어링 문제를 변화시켰습니다. 인증 (Authentication)은 프론트엔드, 백엔드, 그리고 지속성 (persistence) 경계를 가로질렀습니다. 사용자별 격리 (Per-user isolation)를 위해서는 모든 관련 서버 경로에서 권한 부여 (authorization) 확인이 필요했습니다. 기존의 작업 행 (task rows)들은 사용자 생성 이전에 존재했으므로, 마이그레이션에는 레거시 소유권에 대한 명시적인 전략이 필요했습니다. 제공된 실행 기록에 따르면, 해당 행들은 데이터베이스를 삭제하거나 재생성하는 대신 플레이스홀더 사용자 (placeholder-user) 방식을 통해 보존되었습니다.
리팩터링(refactor)에는 약 42분의 실제 실행 시간(active execution)이 소요되었습니다. 실제 경과 시간(wall-clock span)은 약 11시간 49분이었는데, 이는 사용자가 작업을 장시간 중단했기 때문입니다. 이처럼 긴 경과 시간을 에이전트의 연속적인 작업으로 설명해서는 안 됩니다.
보고된 보안 기준선(security baseline)에는 JWT 인증, Argon2 비밀번호 해싱(password hashing), 서버 측 owner_id 격리(isolation), 그리고 CORS 허용 목록(allowlist)이 포함되었습니다. 수락 기록(acceptance record)에 따르면 한 사용자가 다른 사용자의 작업을 읽거나 수정 또는 삭제할 수 없었습니다. 이는 의미 있는 경계 검사(boundary check)이지만, 완전한 보안 평가라고 할 수는 없습니다. localStorage 내의 토큰 저장, 보고되지 않은 회원가입 및 로그인 속도 제한(rate limiting) 누락, 명시되지 않은 JWT 로테이션(rotation) 및 취소(revocation) 동작, 그리고 SQLite 동시성 제한(concurrency limits)은 문서화된 위험 요소로 남아 있습니다.
5. 중단 복구 (Interruption Recovery)
2단계에서의 중단은 사용자에 의해 시작되었습니다. 이는 모델 충돌(model crash), 서비스 중단(service outage), 또는 속도 제한(rate limit)으로 기록되지 않았습니다. 작업이 재개되었을 때, 에이전트는 기존 프로젝트 상태에서 계속 진행하여 남은 범위를 복구하고 구현 및 검증을 완료했습니다. 기록에 따르면 전체 재시작, 파괴적인 프로젝트 교체, 데이터베이스 재생성 또는 기존 데이터 손실은 발생하지 않았습니다.
중단 복구는 신뢰성(reliability)의 일부이기 때문에 이 점은 유용합니다. 장시간 실행되는 에이전트 작업은 중단되지 않는 채팅 기록(chat transcript)에 의존해서는 안 됩니다. 지속 가능한 상태(durable state)는 리포지토리(repository)에 속해야 합니다: 변경된 파일, 마이그레이션 수정 사항(migration revisions), 테스트 명령, 수락 기준(acceptance criteria), 그리고 남은 작업에 대한 명시적인 노트 등이 이에 해당합니다. 복구 프로세스는 추가 변경을 수행하기 전에 현재 상태를 재확립해야 하며, 이전 결과가 여전히 유효하다고 가정하는 대신 관련 게이트(gates)를 다시 실행해야 합니다.
이 벤치마크가 특정 내부 메모리 메커니즘을 증명하는 것은 아닙니다. 타임스탬프가 찍힌 복구 기록(recovery transcript)과 체크포인트 매니페스트(checkpoint manifest)는 유지되지 않았습니다. 이 벤치마크가 기록하는 것은 운영자에게 중요한 외부 동작입니다: 즉, 프로젝트 상태가 유지되었고, 에이전트가 요청된 변경 사항을 재개했으며, 검증 시퀀스(validation sequence)가 완료되었다는 점입니다.
6. 테스트 결과
Phase 2에서 제공된 실행 기록 보고서에는 다음과 같은 결과가 보고되었습니다:
| 검증 게이트 | 보고된 결과 |
|---|---|
| 백엔드 테스트 | 16개 통과 |
| ... |
자동화 스위트 전체적으로 총 42개의 테스트가 통과한 것으로 보고되었습니다: 백엔드 16개, 마이그레이션 1개, 프론트엔드 25개입니다. 이 총합은 우연히 분 단위의 근사 활성 실행 시간과 동일한 숫자입니다. 두 측정값은 관련이 없습니다.
마이그레이션 테스트는 특히 중요합니다. 왜냐하면 새로운 데이터베이스를 초기화하는 것보다 레거시(legacy) 데이터베이스를 업그레이드하는, 가장 위험도가 높은 전환을 목표로 하기 때문입니다. 브라우저 체크가 중요한 이유는 또 다릅니다. 인증(Authentication), CORS, 토큰 처리(token handling), 라우트 보호(route protection), API 연결(API wiring), 그리고 렌더링은 통합된 애플리케이션에서만 만납니다. 단위 테스트(Unit tests)와 성공적인 빌드만으로는 이 전체 경계(boundary)를 모두 커버할 수 없습니다.
현재 작업 공간에는 원시 명령어 출력(Raw command output), 커버리지(coverage), 건너뛴 테스트 개수(skipped-test counts), 테스트 이름, 브라우저 추적 기록(browser traces), 그리고 마이그레이션 리비전은 포함되어 있지 않습니다. 따라서 이 표는 독립적으로 감사 가능한 CI 증거가 아니라 실행에 대한 구조화된 보고서로 읽어야 합니다.
7. 작동한 부분
첫째, 벤치마크를 그린필드(greenfield) 단계와 리팩토링(refactor) 단계로 분리함으로써 서로 다른 역량을 노출했습니다. Phase 1은 조정된 생성(coordinated generation)을 측정했고, Phase 2는 제약 조건 하의 변경 사항을 측정했습니다. 이 두 가지 관점을 결합하는 것이 처음부터 새로운 애플리케이션을 반복하는 것보다 더 많은 정보를 제공했습니다.
둘째, 명시적인 검증 게이트는 '완료(done)'의 정의를 작동하는 화면보다 넓게 유지했습니다. 백엔드 테스트, 프론트엔드 테스트, 마이그레이션 테스트, 정적 체크(static checks), 의존성 체크(dependency checks), 프로덕션 빌드(production build), 그리고 브라우저 승인(browser acceptance) 각각이 서로 다른 실패 표면(failure surface)을 다루었습니다.
셋째, 지속적인 프로젝트 상태가 복구성을 지원했습니다. 긴 일시 중단 시간에도 처음부터 다시 시작할 필요가 없었습니다. 이는 저장소(repositories), 피처(fixtures), 체크리스트, 그리고 반복 가능한 명령어들이 단순히 관리적 오버헤드가 아니라 에이전트 하네스(agent harness)의 일부임을 시사합니다.
넷째, 마이그레이션 범위로 인해 데이터 보존(data preservation)이 벤치마크에 강제되었습니다. 이는 빈 데이터베이스에 새로운 스키마(schema)를 생성하는 것보다 실제 유지보수를 더 잘 나타내는 대리 지표(proxy)가 됩니다. 또한 플레이스홀더 사용자(placeholder-user) 전략을 통해 기존 행(rows)을 조용히 삭제하는 대신 호환성 결정 사항을 명시적으로 드러낼 수 있었습니다.
마지막으로, 이번 실행은 테스트 통과를 프로덕션 준비 완료(production readiness)의 증거로 취급하기보다 오히려 리스크를 드러내는 역할을 했습니다. 로컬 토큰 저장, 보고된 인증 속도 제한(auth rate limiting)의 부재, 불완전한 JWT 생명주기(lifecycle) 증거, SQLite 쓰기 동시성(write-concurrency) 제한, 그리고 누락된 로우 아티팩트(raw artifacts) 등이 기록에 여전히 남아 있습니다.
8. 실패한 요소
가장 큰 실패는 증거 보존(evidence retention)이었습니다. 현재 리포지토리(repository)에는 전체 애플리케이션 소스, 정확한 프롬프트(prompts), 로우 테스트 로그(raw test logs), 의존성 락파일(dependency lockfiles), 마이그레이션 파일(migration file), 데이터베이스 스냅샷(database snapshots), 브라우저 트레이스(browser trace) 또는 기계 판독 가능한 타이밍(machine-readable timing) 정보가 포함되어 있지 않습니다. 이로 인해 독립적인 재실행이 불가능하며, 모든 결과가 제공된 기록에 의존하게 됩니다.
또한 벤치마크에는 반복된 시행(repeated trials)과 실패한 실행 기록이 부족합니다. 두 번의 성공적인 단계만으로는 신뢰도(reliability rate)를 확립할 수 없습니다. 다른 에이전트, 다른 모델, 또는 인간의 구현 방식과 비교할 수 있는 통제된 베이스라인(baseline)도 없습니다. 운영체제 빌드(operating-system build), 런타임 버전(runtime versions), 브라우저 버전(browser version), 하드웨어와 같은 환경 세부 정보도 불완전합니다.
단계 1(Phase 1)의 429 이벤트는 실제 상황에서 복구되었으나, 응답 헤더(response headers), 재시도 메타데이터(retry metadata), 타임스탬프(timestamps), 그리고 요청 트레이스(request trace)는 보존되지 않았습니다. 따라서 이는 일반적인 속도 제한(rate-limit) 주장이 아닌, 좁은 범위의 운영적 교훈만을 뒷받침합니다.
단계 2(Phase 2)의 보안 점검은 유용했으나 불완전했습니다. 통과된 npm audit은 그 시점의 락파일(lockfile)과 어드바이저리 데이터베이스(advisory database)에 의존합니다. pip check는 설치된 의존성 호환성을 검증할 뿐, 취약점(vulnerabilities)을 검증하는 것이 아닙니다. 침투 테스트(penetration test), 부하 테스트(load test), 롤백 기록(rollback transcript), 또는 철저한 권한 부여 매트릭스(authorization matrix)도 보존되지 않았습니다.
9. 현재의 한계
이는 단일 환경 및 소규모 애플리케이션을 대상으로 합니다. 이것은 공식적인 벤치마크(benchmark)가 아니며, OpenAI, Anthropic 또는 독립적인 표준 기구(standards body)에 의해 실행되거나 보증되지 않았습니다. 또한 실제 운영 환경에서의 성능을 보장하지 않습니다.
시간 측정은 대략적입니다. 활성 시간(Active time)과 실제 경과 시간(wall-clock time)은 다르며, 특히 페이즈 2(Phase 2)에서 그러합니다. 테스트 결과는 현재 문서 작업 공간에 원시 로그(raw logs) 없이 보고된 결과물입니다. 모델 라우팅 식별(Model routing identity), 요청 횟수, 토큰 사용량 및 비용은 독립적으로 검증되지 않았습니다.
본 벤치마크는 전형적인 지연 시간(latency), 가동 시간(uptime), 재현성(repeatability), 제공업체의 우월성, 개인정보 보호 보장 또는 더 큰 코드베이스에서의 성능을 확립할 수 없습니다. 또한 모든 레거시 데이터베이스 형태에 대한 무손실 마이그레이션(lossless migration)이나 권한 부여(authorization), XSS, 인증 남용(authentication-abuse) 및 동시성 오류(concurrency failures)에 대한 완전한 저항성을 증명할 수 없습니다.
10. 향후 벤치마크 계획
다음으로 유용한 실험은 더 큰 마케팅적 주장(marketing claim)이 아니라 반복(repetition)입니다. 더 강력한 프로토콜은 하나의 시작 커밋(starting commit), 하나의 정확한 프롬프트 세트(prompt set), 하나의 환경 매니페스트(environment manifest), 그리고 하나의 해시된 레거시 데이터베이스 픽스처(hashed legacy-database fixture)를 고정하는 것입니다. 동일한 리팩터링(refactor)을 최소 3회 실행해야 하며, 성공, 불완전, 실패한 결과가 모두 유지되어야 합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기