← Back to sungyongcho.com

PetV3 에이전트 공장 4: 자율 실행에 예산과 체크포인트 넣기

#petv3#orchestration#codex#claude

PetV3 자동화 시스템 시리즈 4/4

자동화에 “계속 진행하라”는 명령만 주면 두 가지 문제가 생긴다. 할 일이 남아 있다는 이유로 비싼 모델을 계속 호출할 수 있고, 컨텍스트가 끝난 뒤 다음 대화가 오래된 보고를 현재 사실로 믿을 수 있다.

PetV3의 마지막 관제층은 이 두 문제를 사용량 governor와 append-only checkpoint로 다룬다.

모델 강도와 제품 성능을 분리했다

대시보드의 small부터 max는 펫의 CPU/RSS 예산이 아니다. 어떤 모델과 몇 개의 워커를 어떤 검증 강도로 배분할지 정하는 관제 정책이다.

아래 수치는 제공자의 공식 한도나 현재 계정 한도가 아니다. 2026-09-01 당시 ChatGPT Pro 20x를 기준으로 PetV3가 정한 내부 정책 스냅숏이다.

모드 당시 UTC 일일 정책 상한 파생 5시간 값
small 1%p 0.208333%p
med 2%p 0.416667%p
high 3%p 0.625000%p
xhigh 4%p 0.833333%p
max 5%p 1.041667%p

5시간 값은 관측된 제공자 한도가 아니라 일일 정책값 × 5/24로 계산한 값이다. 관제자가 사용량 값을 넣었을 때 라우터와 pause 상태가 전환되는 동작은 코드와 시험으로 검증했다. 메시지 수는 같은 요청이라도 모델, 컨텍스트, reasoning, tool 사용에 따라 비용이 달라 하드 게이트로 쓰지 않는다.

Luna/Haiku는 작고 결정적인 작업, Terra/Sonnet은 중간 판단, Sol/Opus는 상태기계·보안·충돌 중재 같은 고위험 검토에 제한한다. max의 숫자는 목표 동시성도 아니다. 닫힌 비충돌 작업, 사용량, 로컬 자원 상한 중 가장 작은 값만 실행한다.

알 수 없으면 0이 아니다

Codex와 Claude의 실제 구독 게이지를 저장소가 직접 읽는 안정적인 API는 없다. 관제자가 /status 또는 /usage에서 확인한 값을 파동 전후 라우터에 넣어야 한다. 따라서 여기서 자동 정지는 백그라운드 감지기가 사용량을 스스로 읽는다는 뜻이 아니라, 제공된 값이 정책 상한에 닿았을 때 라우터가 pause 상태를 쓰도록 설계됐다는 뜻이다.

설계상 값이 unknown이면 0%로 바꾸지 않고 small 첫 파동 하나만 허용한다. 계속 알 수 없으면 다음 파동을 만들지 않는다. stop_on_cap=true가 기본이고, 사람의 정지는 manual, 예산 정지는 usage_cap으로 분리한다.

실제 기록에서는 사용자가 제공한 근사 게이지를 검토한 뒤 관제자가 revision 43에 usage_cap pause를 명시적으로 기록했다. 당시 정확한 일일 baseline 시각과 5시간 창의 시작·현재 값은 없었다. 이후 Claude 대화는 이미 설정된 pause를 확인하고 그대로 따랐다. 이 사례가 보여주는 것은 pause 집행과 인계 연속성이지, 어느 제공자가 사용량을 무인 감지해 스스로 정지했다는 사실은 아니다.

자율성은 멈추지 않는 성질이 아니다. 멈춰야 할 조건을 미리 코드로 정해두는 성질이다.

변경이 없으면 모델에게 아무것도 보내지 않는다

대시보드 제어의 원문은 비추적 control.ini에 있다. 관제자는 파동 전후와 커밋·착지 전에 revision 이후 delta를 poll한다.

scripts/dash-control.sh poll --since 42

revision이 같으면 출력은 0바이트다. 변경이 있을 때만 작은 JSON snapshot을 모델 컨텍스트에 넣는다. 렌더링 비용을 낮추는 것과 모델 토큰을 낮추는 것을 같은 문제로 취급하지 않고, 각각 다른 경계에서 줄였다.

여섯 번마다 리팩터링 필요성만 감사한다

지속 실행은 코드가 계속 커지는 압력도 만든다. 그래서 여섯 번 착지하면 diff-only 감사가 열린다.

감사 워커는 원본 소스를 읽지 않고 마지막 기준 이후 diff 묶음만 읽어 none, inspect, refactor 중 하나를 반환한다. 일곱 번째 착지는 감사가 기록되기 전까지 거부된다. inspectrefactor일 때만 관제자가 정의와 호출부를 좁게 확인한다.

중요한 점은 감사가 리팩터링을 자동 생성하지 않는다는 것이다. 필요성 판정과 새 작업 승인을 분리한다.

대화를 넘길 때는 요약 하나로 끝내지 않는다

일시정지 체크포인트는 같은 id의 두 파일이다.

YYYY-MM-DDTHHMMSSZ-slug.worklog.md
YYYY-MM-DDTHHMMSSZ-slug.resume.md

worklog에는 사용자에게 보인 결과, 실행 명령과 정확한 결과, 결정과 승인을 적는다. resume에는 검증 전 snapshot, 다음 순서, 사용량 원장, 중지 조건을 적는다. 둘은 append-only이며 최신 파일을 이름순으로 찾는다.

게시할 때 현재 main을 수정하지 않는다. 원격 handoff/petv3 끝을 detached worktree로 열고 두 파일만 명시적으로 stage해 force 없이 push한다. 미작성 표식이나 API key처럼 보이는 문자열이 있으면 게시를 거부한다.

새 Codex 또는 Claude 대화는 다음 순서로 재개한다.

AGENTS.md
→ model-routing.md
→ checkpoint worklog
→ checkpoint resume
→ backlog.md
→ 현재 Git/control 상태 재측정

체크포인트의 HEAD와 dirty state는 과거 관측이다. 현재 저장소에서 다시 확인하기 전에는 사실로 사용하지 않는다.

마지막 결론

PetV3에서 자동화는 하나의 거대한 agent loop가 아니다. 작은 계약들의 조합이다.

  • worktree는 변경을 격리한다.
  • ledger는 겹침을 보이게 한다.
  • land gate는 검증한 snapshot만 main에 올린다.
  • TUI는 근거와 제어를 한 화면에 모은다.
  • usage governor는 다음 파동을 열지 결정한다.
  • checkpoint는 Codex와 Claude 사이에서 사실과 다음 행동을 분리해 넘긴다.

이 구조를 만들며 가장 크게 바뀐 생각은 이것이다.

좋은 자동화는 더 오래 달리는 시스템이 아니라, 언제 달리고 언제 멈추며 무엇을 사실로 믿을지 설명할 수 있는 시스템이다.

처음부터 읽기: PetV3 에이전트 공장 1: 자동화보다 먼저 실패를 설계에 넣었다