같은 컨텍스트가 작업을 작성하고 승인할 때, '완료된 것처럼 보인다(looks done)'가 기준이 됩니다. 실제 명령을 실행하고 0-100점 점수를 반환하는 별도의 비평가(critic)는 이를 증거로 만들거나 — 또는 무엇이 정확히 빠졌는지 명시합니다.
문제: 빌더가 자신의 숙제를 평가한다
자신의 출력을 검토하는 에이전트는 아무것도 검토하지 않습니다. 단지 이미 가지고 있던 의도를 확인만 할 뿐입니다. 증상은 익숙합니다 — 수렴하지 않는 검토 라운드, '완료되었다'는 반복적인 말, 그리고 신뢰한 사람의 손에서 나중에 발견되는 결함.
해결책은 모델에게 '엄격하게(rigorous)' 되라고 요청하는 것이 아닙니다. 점수를 에이전트 외부로 이동시키는 것입니다: 실제 명령으로 측정하고, 그 점수를 감사하는 별도의 컨텍스트를 사용하는 스크립트가 필요합니다.
하나의 컨텍스트에 절대 병합되어서는 안 되는 네 가지 역할
-
오케스트레이터(Orchestrator): 작업을 실행하는 에이전트입니다. 검사 항목을 선택하고, 라운드를 진행하며, 인프라를 수정하고, 보고서를 소유합니다.
-
빌더(Builder): 아티팩트를 작성한 사람입니다. 패스마다 한 종류의 격차를 수정합니다.
-
비평가(Critic): 사용자가 작성하는 스크립트(loop_runner.py + 사용자 검사 항목)입니다. 모든 명령을 실행하고, 원본 출력을 유지하며, SCORE=와 GAPS=를 출력합니다.
-
검토자(Reviewer): 빌더로부터 어떤 정당화도 받지 않은 신선한 컨텍스트에 있는 다른 에이전트/모델입니다. 루프를 다시 열 수 있습니다.
규칙 제로: 빌더 ≠ 비평가 ≠ 검토자. 만약 하나의 컨텍스트가 이 세 가지 역할을 모두 수행한다면, 그 루프는 연극일 뿐입니다.
단계별 루프
-
코드를 작성하기 전에 검사를 선언하라 (Declare the checks before writing code): 각 검사에 대해 이름(name), 명령어(command), 가중치(weight) 및 '통과(pass)'의 의미를 명시한다. 가중치의 합은 100이다.
{"checks":[{"name":"pytest","cmd":"set -o pipefail; pytest -q","weight":40},
{"name":"no_secret_scan","cmd":"gitleaks detect --no-banner","weight":30}\]}
-
비평가(critic)를 실행하라 (Run the critic): 이는 모든 명령어를 실제로 실행하고, 증거(evidence)를 포착하며, 모델에게 작업이 좋은지 묻지 않고 측정한다.
python scripts/loop_runner.py --config loop.json --round 1
-
점수화, 비교, 결정 (Score, compare, decide): 임계값(threshold) 이상이면 검토자(reviewer)에게 전달하고, 미만이면 가장 큰 격차(gap)를 찾아 수정한 후 다시 실행한다. 라운드 횟수는 제한한다(8회면 충분하다). 만약 수렴하지 않는다면, 코드가 잘못된 것이 아니라 검사 세트 자체가 잘못된 것이다.
-
전달 전 독립적인 검토 (Independent review before delivery): 동일한 결과물(artifact)에 대해 새로운 맥락(context)에서 빌더로부터의 정당화 없이 진행된다. 품질 및 보안 전문가 2~3명이 참여하며, 엄격한 JSON을 반환한다.
-
보안 게이트, 실패 시 차단 (Security gate, fail-closed): diff나 히스토리 내의 비밀 정보, 높은 심각도의 발견 사항(high-severity finding), 인증/경로 탐색/주입 문제 등은 완벽한 테스트가 있더라도 배포를 차단한다. 결론을 내릴 수 없는 답변은 '통과'가 아닌 차단으로 간주된다.
-
점수, 증거 및 검증되지 않은 내용을 포함하는 보고서 (Report with score, evidence and what was not verifiable): 이 보고서는 측정된 내용(raw output 포함)과 확인할 수 없었던 내용을 명시하며, '아마도 괜찮다'와 같은 표현은 없다.
실제 출력 형태는 다음과 같다
빨간색은 실패한 경우(게이트가 차단됨)이고, 초록색은 배포되는 경우이다. 둘 다 시뮬레이션이 아닌 실제 실행 결과이다.
`$ python scripts/loop_runner.py --config loop.json --round 3
SCORE=55
GAPS=[pytest::exit_1, no_secret_scan::missing]
...
녹색 루프가 거짓말하는 네 가지 방법
-
파이프라인(Piping)은 종료 코드를 숨긴다: pytest | tail는 tail의 종료 코드(0)를 반환하므로, 출력에 실패한 테스트가 숨겨진 상태에서 크리틱(critic)이 100점을 부여합니다. 모든 검사 내부에는 반드시 set -o pipefail을 사용하세요.
-
검사 시간보다 짧은 타임아웃은 침묵의 제로: 크리틱 자체가 자신의 타임아웃으로 인해 종료되고, 오케스트레이터(orchestrator)는 빈 갭 리스트와 함께 점수 0을 읽어 아무것도 수정할 것이 없어 반복하게 됩니다. 타임아웃 시간을 실제 지속 시간보다 길게 설정하고 항상 크리틱의 원본 로그를 보관하세요.
-
단축되는 '성공' 판정: 200을 응답하는 서버가 잘못된 서버일 수 있습니다. 포트 충돌이 발생하면 검사가 다른 앱을 테스트하게 되고, 잘못된 이유로 실패합니다. 단순히 도달 가능성(reachability)만 확인하지 말고 식별자(identity)(제목, 버전, 알려진 페이로드 등)를 단언하세요.
-
녹색으로 만들기 위해 재생성되는 오래된 기준선: 시각적 기준선(visual baseline)을 '통과'시키기 위해 재생성하는 것은 테스트가 포착하기 위해 존재하는 회귀(regression)를 지워버립니다. 기준선은 명시적인 결정에 의해, 그리고 그 역사가 기록된 곳에서만 변경되어야 하며, 검사를 침묵시키기 위해서는 절대 안 됩니다.
매일 달라지는 것들
핵심은 점수가 아닙니다. 대화입니다. '끝났나요?'라는 질문이 빌더(builder)의 의견을 넘어 명령 출력과 함께 SCORE=100 또는 이름 및 가중치와 함께 갭 리스트가 첨부되는 것이 되어야 합니다. 검증할 수 없는 것이 있다면, 거짓된 녹색 신호로 바뀌는 대신 기록되어야 합니다.
이러한 패턴은 어떤 결과물(deliverable)에도 적용됩니다: 코드, 파이프라인, 데이터 마이그레이션, 누군가 결정하는 데 사용할 문서 등입니다.
지금 시작하기
이 기능을 수행하는 기술은 AI Test Loop라는 이름으로 배포됩니다. 이 패키지에는 loop_runner.py, 점수 산정 기준표(scoring rubric), 리뷰어 프롬프트, 보안 검사 등이 포함되어 있습니다. 저장소는 오픈 소스(MIT)이며, 스토어 버전에는 즉시 사용할 수 있는 가드(guards)가 추가됩니다.
AI Test Loop 기술 보기
무료 버전 받기
프로젝트에 설치하는 것이 더 나을까요? 첫 번째 사이클을 함께 실행하며 R$ 1.500부터 가이드 설정하기를 이용하세요.
← all skills