코딩 에이전트를 사용하며 겪었던 모든 실패는 결국 똑같은 모습으로 끝납니다. 에이전트는 '성공'이라는 요약본을 작성합니다. 즉, 기능은 구현되었고, 테스트를 통과했으며, 브랜치는 준비되었다는 내용입니다. 그러고 나서 제가 그 결과물을 열어보면, 절반가량이 빠져 있는 경우가 많습니다.
흥미로운 점은 모델이 거짓말을 하고 있지 않다는 것입니다. 확인할 방법 자체가 없습니다. 이 모델은 대화의 가장 개연성 높은 다음 내용을 생성했을 뿐이며, '깔끔한 요약과 함께 완료'라는 문구는 극도로 그럴듯한 다음 내용입니다. 루프 과정 중 어느 순간도 증거를 요구한 적이 없었습니다.
그래서 저는 모델을 더 정직하게 만들려고 시도하는 것을 멈추고, 대신 루프의 구조 자체를 바꿨습니다. 제가 현재 운영하는 에이전트 워크포스에서는 어떤 모델도 '완료'라고 말할 수 없습니다. 명령어(command)가 '완료'라고 선언하고, 실제로 종료 코드 0을 반환해야만 합니다.
증거 명령은 작업이 존재하기 전에 작성된다
제가 요청 사항을 입력하면, 가장 먼저 발생하는 것은 작업 자체가 아닙니다. 그것은 계약입니다.
/crew add a pricing page with a monthly / annual toggle
열리는 카드는 여섯 가지 요소를 담고 있습니다:
- goal: 이것이 무엇인지에 대한 저의 설명
- artifact: 변경되는 파일 또는 표면(surface)
- where it lands: 브랜치 이름
- done when: 같은 내용이지만, 일반 언어로 표현
- proof command: 종료 코드가 결정되는 정확한 명령어
- budget: 토큰 제한, 따라서 실행이 무한정 진행되지 않도록 함
순서가 핵심입니다. 증거(proof)는 작업이 아직 존재하지 않을 때 고정됩니다. 이때 저는 정보가 부족하고 솔직하기 때문에 다음과 같이 작성합니다:
npm run test:e2e -- pricing.spec.ts
그리고
- worker가 작업을 수행하고
- proof는 카드가 열렸을 때 작성된 대로 정확히 실행되며, 0이 아닌 종료 코드만이 실패 신호로 간주됩니다.
- coordinator는 카드가 닫히기 전에 증명(proof)을 재실행하므로, 운 좋게 녹색으로 성공한 한 번의 실행만으로는 카드를 닫을 수 없습니다.
- 더 강력한 보장을 요구하는 카드에는 독립적인 검증자(verifier)가 한 번 더 실행됩니다.
The 모델은 코드와 요약문을 작성하고, 판결문(verdict)은 절대 작성하지 않습니다.
카드당 하나의 소유자, 카드당 하나의 작가
두 번째 실패 모드는 드리프트(drift)입니다. 같은 브랜치에 있는 세 명의 에이전트가 각자 로컬적으로 합리적인 행동을 하더라도, 함께 아무것도 생산하지 못하는 경우입니다. 따라서 카드는 한 명의 작가를 갖고, 카드는 하나의 소유자를 가집니다. 이 소유자는 모든 카드 이벤트 발생 시 깨어나 전체 기록을 손에 넣고 정확히 하나의 결정(재시도, 범위 축소, 분할 또는 질문)을 내립니다.
질문 또한 제한적입니다. 어떠한 작업이 시작되기 전에, 채팅은 한 배치에서 최대 다섯 개의 질문이나 아예 질문하지 않습니다. 그 후에는 카드가 끝날 때까지 저는 루프 밖(out of the loop)에 있게 되며, 카드는 제가 요청했던 스레드에서 검증된 결과로 끝나거나, 하나의 구체적인 질문으로 끝납니다. 토큰 예산은 카드당 할당되므로, 예산을 소진하는 실행은 남은 밤을 태우는 대신 멈추고, 연속으로 다섯 번의 도구 호출에 실패한 워커는 스스로 멈춥니다.
외부에서 볼 때의 모습
데모 보드에서 가져온 예시 카드:
16:12:04 /crew add a pricing page with a monthly / annual toggle
16:12:09 contract: artifact app/pricing/page.tsx
proof npm run test:e2e -- pricing.spec.ts
...
마지막 줄이 채팅에 도달하는 것입니다. 느낌의 요약문이 아니라, 통과한 증명(proof)과 시도 횟수가 몇 번이었는지를 보여주는 증거입니다. 만약 증명이 두 번 실패했다면, 저는 대신 두 개의 실패 라인이 첨부된 하나의 질문을 받았을 것입니다.
이 형태가 작동하지 않는 지점
세 가지 정직한 한계가 있습니다. 왜냐하면 승리만을 나열하는 검증에 관한 글은 그 자체로 일종의 허위 정보(bullshit)이기 때문입니다.
- 증명(A proof)은 당신이 의도한 바가 아니라 당신이 쓴 것을 증명합니다.
test:e2e -- pricing.spec.ts는 토글 기능이 아무것도 하지 않더라도 테스트가 잘못된 것을 단언한다면 녹색일 수 있습니다. 핵심 역량은 명령을 잘 작성하는 데 있으며, 이는 인간의 작업입니다.
- '완료(done)'가 판단에 의존하는 업무에는 좋지 않습니다. 명명, 위치 선정, '출시 게시물 작성하기'와 같은 것은 어떤 명령으로도 결정할 수 없습니다. 이 경우 워크포스는 사람에게 의존하게 되는데, 이는 올바른 행동이지만, 이 형태는 검증 가능한 끝이 있는 작업에서만 효과를 발휘합니다.
- 증명은 각각 1분의 비용이 듭니다. 그렇지 않으면 비효율적인 사소한 작업에는 큰 손해입니다. 하지만 달리 말하면, 어차피 밤 11시에 다시 확인할 작업이라면 가장 저렴한 시간 단위가 됩니다.
또한 제가 예상하지 못한 네 번째 점도 있습니다. 증명이 아티팩트(artifact)를 고정하기 때문에, '혹시 이것도 좀...'이라는 요청이 첫 번째 범위 내의 스코프 크립(scope creep)이 아니라 두 번째 카드로 분리됩니다. 성가스럽지만, 올바른 방식입니다.
핵심은 패턴이며, 제 플러그인이 아닙니다
일반화 가능한 규칙은 복잡하지 않습니다:
- 에이전트가 시작하기 전에, '완료'의 실행 가능한 정의를 작성합니다.
- 오직 그 정의만이 루프(loop)를 닫게 합니다.
- 작업한 모델이 아니라 도구(tool)가 그것을 실행하게 합니다.
어떤 에이전트 프레임워크든 이것을 할 수 있습니다. 대부분은 그렇지 못합니다. 왜냐하면 '완료'는 증명하는 것보다 출력하기가 훨씬 쉽기 때문입니다.
저는 이를 Hermes Agent용 플러그인으로 만들었습니다 - Apache-2.0, 자체 호스팅(self-hosted), 사용자의 기기에서 실행되며 텔레메트리(telemetry)가 없습니다 - 그리고 전체 내용은 github.com/macd2/Crew입니다:
hermes plugins install macd2/Crew
python3 ~/.hermes/plugins/crew/install.py --profile NAME
hermes -p NAME plugins doctor crew
설치하기 전에 미리 확인하고 싶다면, 53초 분량의 출시 영상이 있습니다. 하나의 요청을 검증된 결과까지 이끌어가는 과정입니다:
crew.forgecoreai.com은 읽기보다 시청하는 것을 선호할 경우 페이지와 같은 루프를 보여줍니다.
제가 실제로 댓글에서 답변을 받고 싶은 질문은 이것입니다: 당신의 환경에서 'done'이란 무엇을 의미하나요? 그것이 명령어인가요, 아니면 느낌에 가깝나요? 저는 사람들이 진정으로 신뢰하는 사례들을 수집하고 있습니다. pytest를 사용하는 1인 개발자부터 배포 스모크 테스트(deploy smoke test)를 가진 팀, 대시보드에서 숫자를 확인하는 사람까지 말이죠. 당신이 코드로 작성할 수 없는 증명은 위임할 수 없는 작업이며, 흥미로운 이야기는 바로 그 '위임해야 한다고 인정했던' 작업들입니다.
AI 어시스턴트의 도움을 받아 초안 작성 후 제가 편집했습니다.