설정하고 배포하기: 내가 잠든 사이 AI 에이전트가 Java 서비스를 구축하게 만드는 방법
요약
AI 에이전트가 자율적으로 고품질의 Java 서비스를 구축하게 만드는 워크플로를 소개합니다. 모호한 프롬프트 대신 테스트 가능한 요구사항, 비판 에이전트, 자동화된 실행 환경이라는 세 가지 '게이트'를 통해 에이전트의 결과물을 검증하는 것이 핵심입니다.
핵심 포인트
- 테스트 가능한 구체적인 요구사항 작성이 필수적임
- 구축 에이전트와 별개인 비판(Critique) 에이전트 활용
- 모든 요구사항이 통과될 때까지 작업을 강제하는 게이트 시스템 구축
- 권한 승인 팝업을 끄고 중단 없는 실행 환경 조성
저는 무언가를 쉽게 만들어준다고 약속하는 모든 것을 의심할 만큼 이 일을 오랫동안 해왔습니다. 그래서 솔직하게 말씀드리고 싶습니다. 몇 주 동안 작동하는 것을 지켜본 후에도, 다음에 이어질 내용은 여전히 저에게 조금 비현실적으로 느껴집니다.
요약하자면 이렇습니다. 현재의 에이전트(Agents)들은 5시간 동안 연속으로 실행되며 당신이 요구하는 거의 모든 것을 진정으로 견딜 만한 품질로 구축할 수 있습니다. 하지만 함정이 있으며, 이것이 이 포스트의 핵심입니다. 에이전트들은 당신이 요구사항(Requirements)을 신중하게 작성하고, 결과가 당신에게 돌아오기 전에 엄격한 게이트(Gates)를 통해 작업을 강제할 때만 그렇게 작동합니다. 그 과정을 건너뛰면, 5시간 동안 자신감 넘치고 그럴싸한 쓰레기(Garbage)를 얻게 될 뿐입니다. 제대로 수행한다면 한계치는 모델이 아니라 당신이 얼마나 명확하게 생각할 수 있느냐에 의해 결정됩니다.
이것을 제대로 해야 하는 이유
유능한 에이전트에게 느슨한 프롬프트(Prompt)와 몇 시간을 주면, 엄청난 양의 결과물을 만들어낼 것입니다. 문제는 그 산더미 같은 결과물이 표류한다는 점입니다. 작은 가정들이 쌓이고, 결과물은 당신이 실제로 원했던 것에서 벗어나며, 3시간째가 되면 당신이 요청하지도 않은 것을 다듬고 있을 것입니다.
게이트(Gates)가 이를 해결합니다. 구체적으로 세 가지 게이트가 있으며, 이들은 함께 작동합니다.
첫째, 실제로 테스트 가능한 요구사항입니다. 느낌(Vibes)이나 "잘 만들어줘" 같은 모호함이 없어야 합니다. 둘째, 별도의 비판 에이전트(Critique agent)입니다. 이 에이전트의 유일한 임무는 해당 요구사항에 따라 작업을 검토하고, 모든 요구사항이 충족될 때까지 통과를 거부하는 것입니다. 셋째, 이 모든 과정이 방해받지 않고 실행될 수 있는 공간입니다. 아무도 에이전트를 감시(Babysit)할 필요가 없도록 권한 팝업(Permission pop-ups)을 꺼두어야 합니다.
이 중 어느 것도 단독으로는 영리하지 않습니다. 하지만 이들이 함께할 때 데모(Demo)와 실제로 신뢰할 수 있는 워크플로(Workflow) 사이의 차이를 만들어냅니다.
내가 어기지 않는 규칙들
저는 다섯 가지 원칙으로 요약했습니다. 이 중 하나라도 건너뛰면 매번 후회했기 때문에 절대 생략하지 않습니다:
- 에이전트가 시작하기 전에 요구사항(requirements)을 작성하세요. 작업이 너무 당연해 보일 때라도 예외는 없습니다.
- 모든 요구사항을 제안이 아닌 게이트(gate)로 취급하세요.
- 다른 에이전트가 결과물을 심사하게 하세요. 구축을 담당한 에이전트에게는 투표권을 주지 않습니다.
- 모든 항목을 통과(pass)할 것을 요구하세요. 대부분이 아니라, "대체로 완료됨"이 아니라, 전부 다여야 합니다.
- 권한 승인 프롬프트(permission prompts)를 끄고 항상 실행(always-on) 상태로 돌리세요.
견고한 요구사항 작성하기
요구사항 목록은 계약서이며, 솔직히 말해서 이제 진짜 작업은 여기서 이루어집니다. 목록이 모호하면 결과물도 모호해지며, 에이전트는 그 빈틈을 추측으로 기쁘게 채워버릴 것입니다.
제가 목표로 하는 것은 제가 자리에 없어도 기계가 채점할 수 있는 요구사항입니다. 각 요구사항은 동작(behaviour), 파일, 인터페이스, 제한 사항(limit)과 같이 구체적인 무언가를 명시합니다. 각 항목은 논쟁의 여지 없이 통과(pass) 또는 실패(fail)로 표시될 수 있습니다. 이 항목들 사이에는 엣지 케이스(edge cases), 성능(performance), 보안(security), 문서(docs)와 같은 지루한 부분들도 포함됩니다. 왜냐하면 그렇지 않으면 바로 이런 부분들이 조용히 누락되기 때문입니다.
간단한 전후 비교를 해보겠습니다. 여기 당신을 곤경에 빠뜨릴 버전이 있습니다:
"API는 빠르고 안전해야 합니다."
그리고 실제로 당신을 보호해 줄 버전은 다음과 같습니다:
"모든 엔드포인트(endpoints)는 100개의 동시 요청(concurrent requests) 상황에서 p95 기준 200ms 이내에 응답해야 합니다. 모든 입력값은 서버 측에서 검증(validated)되어야 합니다. 로그에 비밀 정보(secrets)가 포함되어서는 안 됩니다.
/health를 제외한 모든 경로에는 인증(Auth)이 필요합니다."
의도는 같지만, 결과는 판이하게 다릅니다. 이 목록을 날카롭게 다듬는 데 쓰는 시간은 장기적으로 그 몇 배의 가치를 돌려주므로, 저는 더 이상 이 과정을 서두르지 않습니다.
비판 게이트 (The critique gate)
아무도 강제하지 않는 요구사항 목록은 그저 바람(wish)일 뿐입니다. 강제성은 별도의 비판 에이전트(critique agent)가 담당하며, 이를 분리하는 것이 핵심 비결입니다. 구축 담당자가 스스로의 숙제를 채점하게 해서는 안 됩니다.
루프는 간단합니다. 빌더(builder)가 작업물을 생성합니다. 비판 에이전트(critique agent)는 그 작업물과 전체 요구사항 목록을 전달받아, 항목별로 하나씩 검토하며 통과(pass) 또는 실패(fail)를 표시합니다. 실패한 모든 항목은 구체적인 결함(gap)이 지적된 상태로 다시 되돌아가며, 이 과정이 반복됩니다. 모든 요구사항이 깨끗하게 통과되어야만 작업물이 제 책상에 도착합니다.
비판 에이전트에게 제가 고집하는 몇 가지 사항이 있습니다. 샘플링이 아니라 모든 것을 검사해야 한다는 점입니다.
티켓이 하나 들어옵니다: 결제된 트랜잭션(settled transactions)을 원장 항목(ledger entries)과 대조하여 불일치 사항을 표시하는 PaymentReconciliation 서비스를 추가하라는 내용입니다. 몇 년 전이었다면 이 작업은 2~3일이 걸렸을 것입니다. Mithun은 IDE를 열지 않습니다. 대신 requirements.md를 열고 계약(contract)을 작성합니다:
# 요구사항: PaymentReconciliation 서비스
## 기능적 요구사항 (Functional)
...
단 15줄입니다. 이것이 실제 업무이며, 나머지는 그가 더 이상 할 필요가 없는 타이핑 작업일 뿐입니다.
오전 9:10 - 실행하고 떠나기
그는 빌더 에이전트(builder agent)를 팀의 상시 가동 환경(always-on environment)에서 실행하며, 리포지토리(repo)와 요구사항 파일을 지정합니다. 그의 프롬프트에서 가장 중요한 마지막 줄은 다음과 같습니다:
"모든 작업은
requirements.md에 있는 모든 요구사항에 대해 별도의 비판 에이전트(critique agents)에 의해 검증되어야 합니다. 비판 에이전트가 요구사항의 100%를 통과했음을 확인하기 전까지는 중단하지 마십시오.mvn verify결과는 반드시 성공(green)이어야 합니다."
그러고 나서 그는 노트북을 닫고 스탠드업 미팅(standup)에 참석하러 갑니다. 그를 뒤쫓는 팝업창은 없습니다.
오전 9:15 ~ 오전 11:30 - 그가 없는 동안 진행되는 과정
그가 회의에 참석하는 동안, 모든 과정은 스스로 진행됩니다. 빌더는 서비스, JPA 엔티티(entity), 컨트롤러(controller), 매칭 로직(matching logic)의 스캐폴딩(scaffold)을 수행합니다. 또한 까다로운 테스트들을 포함하여 JUnit 테스트를 작성합니다. 예를 들어 제로 델타(zero-delta) 매칭, 대응 항목 누락, 센트(cent) 경계에서의 반올림 문제 등이 포함됩니다.
그다음 비판 에이전트가 변경 사항(diff)을 가져와 검토를 시작합니다. 두 가지 항목에서 실패가 발생합니다. 벤치마크가 없어 지연 시간(latency) 요구사항이 실제로 증명되지 않았다는 점과, 패키지 레이아웃(package layout)에 대해 Checkstyle이 만족하지 않는다는 점입니다. 두 사항 모두 반려됩니다. 빌더는 1만 개의 레코드가 포함된 피스처(fixture)를 대상으로 타이밍 테스트를 추가하고, 두 클래스를 적절한 위치로 이동시킵니다. 비판 에이전트가 다시 실행되고, 이번에는 깨끗하게 통과됩니다. 15개 중 15개 모두 통과, 빌드 성공(green), OpenAPI 재생성, README 업데이트까지 완료됩니다. 아무도 이 과정에 손을 대지 않았습니다.
오전 11:35 - 프로세스가 아닌 결과물을 검토하다
Mithun은 완료된 브랜치와 자신을 기다리고 있는 보고서를 확인하며 돌아옵니다.
POST /reconciliation/run 구현됨 ......... 통과 (PASS)
불일치 규칙 (delta > 0.00 | 누락) ....... 통과 (PASS)
ReconciliationReport 저장됨 ............... 통과 (PASS)
...
그는 여전히 매칭 로직(matching logic)과 엣지 케이스 테스트(edge-case tests)를 읽습니다. 버그를 잡기 위해서가 아니라 — 게이트(gate)가 이미 그 역할을 수행했으므로 — 그 _접근 방식(approach)_이 팀이 조정(reconciliation)에 대해 생각하는 방식과 일치하는지 확인하기 위해서입니다. 일치합니다. 그는 자신이 다르게 선택했을 법한 명명 규칙(naming choice)에 대해 메모를 하나 남긴 뒤, 다음번에는 코멘트가 아닌 게이트(gate)로 작동할 수 있도록 해당 선호도를 팀의 요구사항 템플릿(requirements template)에 추가합니다.
오후 2:00 - 두 개를 병렬로 추가하기
이 부분이 그의 하루를 재편성한 지점입니다. 코드를 직접 작성하는 것이 아니기 때문에, 이제 그의 병목 현상(bottleneck)은 단지 자신이 원하는 바를 명확하게 생각하는 것뿐입니다. 그래서 그는 오후 시간을 할애하여 두 개의 요구사항 목록을 더 작성합니다. 하나는 결제 이벤트(settlement events)를 위한 Kafka 컨슈머(Kafka consumer)이고, 다른 하나는 원장 읽기(ledger reads)를 위한 캐싱 레이어(caching layer)입니다. 그리고 저녁까지 실행되도록 두 가지 모두를 시작합니다.
오후 6:30 - 설정하고 배포하기
그는 로그아웃합니다. 비판 루프(critique loops)는 밤새 돌아갑니다. 아침이 되면 사람이 읽을 수 있도록 준비된 각각의 깔끔한 보고서를 담은 두 개의 브랜치(branches)가 더 생겨 있을 것입니다. 그의 업무는 조용히 코드를 작성하는 것에서 계약(contracts)을 작성하는 것으로 바뀌었으며, 이를 통해 해제되는 처리량(throughput)은 솔직히 제가 여전히 이해하기 어려울 정도로 엄청납니다.
제가 실제로 이 과정을 실행하는 단계별 방법
이 워크플로우(workflow)를 복제하고 싶다면, 그 형태는 다음과 같습니다:
- 작업 범위를 정하고, 모든 항목이 테스트 가능한 요구사항 목록을 작성합니다.
- 프롬프트(prompt)에 엄격한 규칙을 넣습니다: 별도의 비판 에이전트(critique agents)가 모든 작업을 검사하며, 결과가 돌아오기 전에 100% 통과해야 합니다.
- 권한 게이트(permission gates)는 끄고 가드레일(guardrails)은 켠 상태로, 항상 켜져 있는 환경(always-on environment)을 준비합니다.
- 작업 내용과 전체 목록을 가지고 빌더(builder)를 실행합니다.
- 비판 루프(critique loop)가 돌아가게 둡니다. 항목별로 통과/실패를 판정하며, 실패 시 빌더로 다시 되돌아갑니다.
- 모든 항목이 완전히 통과되었을 때만 결과물을 수락합니다.
- 프로세스가 아닌 결과물을 검토하고, 배운 점이 있다면 무엇이든 템플릿에 다시 반영합니다.
이 방식이 잘못되는 경우들
제가 목격한 거의 모든 실패는 다음 중 하나로 거슬러 올라갑니다:
검증할 기준이 전혀 없는 "잘 만들어줘"와 같은 모호한 요구사항 (Vague requirements). 빌더(Builder)가 자신의 작업물을 스스로 승인해버려 검증 게이트가 통째로 무너지는 자기 검토 (Self-review). "대부분 완료됨"이라는 말로 드리프트(Drift)를 조용히 다시 허용하는 부분적 통과 (Partial passes). 남겨진 권한 승인 프롬프트 때문에 정작 목표했던 능력을 상실하게 만드는 베이비시팅 (Babysitting). 그리고 2시간 만에 절전 모드로 들어간 머신 때문에 5시간짜리 작업이 중단되는 저사양 환경 (Under-powered environment).
요구사항을 정확히 설정하고, 비평가(Critic)를 정직하고 독립적으로 유지하며, 실제로 실행할 수 있는 환경을 제공하는 것 — 이것이 전투의 대부분입니다. 나머지는 노트북을 덮을 수 있을 만큼 게이트(Gates)를 신뢰하는 법을 배우는 과정입니다.
간단한 면책 조항을 덧붙입니다. 결과는 상황에 따라 다를 수 있습니다. 위의 모든 내용은 특정 코드베이스와 특정 작업에서 저에게 효과가 있었던 방식을 반영한 것이며, 그 어떤 것도 보장되지는 않습니다. 모델의 동작, 작업의 복잡성, 그리고 기존의 테스트 및 검토 인프라가 모두 결과에 영향을 미칩니다. 이를 레시피가 아닌 시작점으로 취급하십시오. 에이전트를 격리된 브랜치와 샌드박스(Sandboxed) 환경에서 실행하고, 자격 증명(Credentials)의 범위를 제한하며 지출 한도를 설정하십시오. 또한, 무엇인가가 프로덕션(Production)에 배포되기 전에 반드시 사람이 결과물을 검토해야 합니다. 주의 깊게 살펴봐야 할 한 가지는 토큰(Token) 사용량입니다. 빌더와 비평가 루프(Builder-plus-critique loops)가 포함된 수 시간 단위의 실행은 토큰을 빠르게 소모하며, 실패하고 재시도되는 요구사항이 발생할 때마다 작업에 대한 추가 패스(Pass)가 추가됩니다. 비용은 빠르고 예측 불가능하게 상승할 수 있습니다. 엄격한 예산 한도를 설정하고, 장시간 실행 중에는 소비량을 모니터링하며, 에이전트를 큰 작업에 풀어놓기 전에 작은 작업을 통해 비용을 산출해 보십시오. 게이트는 위험을 줄여줄 뿐, 제거해주지는 않습니다. 판단력을 발휘하고, 리스크가 낮은 작업부터 작게 시작하며, 본인의 컨텍스트에 대한 확신이 생길 때만 규모를 키우십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기