마이그레이션, Validator, Orchestrator, Harness

큰 작업을 AI와 함께 작게 쪼개며 배운 것

Table of Contents

최근 회사 프로젝트에서 큰 마이그레이션 작업을 진행하고 있다. 실제로 아직도 계속 진행 중이고, 작업을 진행하면서 방법 자체도 계속 바꿔보고 있다. 처음에는 AI에게 큰 작업을 맡기고 검증만 잘하면 어떻게든 될 줄 알았다. 그런데 실제로 해보니 그렇게 단순하지 않았다.

이전에 랜딩 이관 작업에서도 비슷한 실패를 겪었다. 당시에는 커다란 plan 을 만들고, 그 plan 을 바탕으로 한 번에 진행하려 했다. 하지만 결과적으로 실패했다. plan 자체가 너무 커지면 내가 그 plan 을 제대로 핸들링하기 어렵고, AI가 한 번에 처리하기에도 범위가 넓어졌다. 겉으로는 그럴듯한 계획이 있어도, 실제 진행 과정에서는 어디서부터 잘못되고 있는지 추적하기가 어려웠다.

이번 마이그레이션에서도 처음에는 비슷하게 접근했다. deterministic validator 를 잘 만들면 괜찮지 않을까 생각했다. 마이그레이션 이후 결과가 올바른지 검증하는 함수를 만들고, 그 검증을 통과할 때까지 AI가 수정하게 만들면 되지 않을까 싶었다. 얼핏 보면 그럴듯하다. 실제로 검증 가능한 부분에서는 꽤 강력한 접근이다. 문제는 마이그레이션 범위가 커지면 validator 자체가 명확하지 않아진다는 점이었다.

여기서 말하는 validator 는 커다란 마이그레이션 자체를 한 번에 검증하려는 시도에 가깝다. 마이그레이션 이후 전체 결과가 기존과 동일한지, 기능이 깨지지 않았는지, 의도하지 않은 변화가 없는지 검증하려 했다.

validator 는 애매한 것을 명확하게 만들기 위한 도구다. 예를 들어 번역 작업이라면 원문이 누락되지 않았는지, 마크다운 구조가 유지되었는지, 코드 블록이 깨지지 않았는지 같은 것들은 어느 정도 검증할 수 있다. 빌드나 린트처럼 정적인 검증 도구도 있다. 특정 파일이 깨졌는지, 타입이 맞는지, 테스트가 통과하는지도 확인할 수 있다.

그런데 큰 마이그레이션에서는 이걸로 충분하지 않았다. 검증 함수가 존재해도, 그 함수가 실제로 무엇을 보장해야 하는지가 계속 흔들렸다. "기능적으로 동일하다"는 말은 쉽지만, 무엇을 동일하다고 볼 것인지 정하기 어렵다. 화면이 같아야 하는지, API 호출 흐름이 같아야 하는지, 내부 구조도 비슷해야 하는지, 아니면 사용자 관점의 결과만 같으면 되는지 계속 판단이 필요했다.

결국 validator 를 만들면서도 다른 문제가 계속 튀어나왔다. 어떤 부분은 결정적으로 검증 가능하지만, 어떤 부분은 여전히 AI scoring 이나 리뷰에 의존해야 했다. 또 검증 대상이 너무 크면, validator 가 실패했을 때 무엇을 고쳐야 하는지도 다시 애매해진다.

한동안은 Opus 와 GPT 사이에서 계속 ping-pong 을 했다. 대략 30번 가까이 review 와 수정이 오갔던 것 같다. 이쯤 되면 validator 가 있는 게 중요한 게 아니라, validator 로 닫을 수 있는 범위가 어디까지인지 정하는 게 더 중요하다는 생각이 들었다. 검증이 작업을 끝내주는 것이 아니라, 작업을 끝낼 수 있을 만큼 충분히 작게 쪼개져 있어야 검증도 의미가 있었다.

다음에는 내가 직접 orchestrator 가 되어보기로 했다. 작업을 분류하고, 잘게 나누고, 어떤 순서로 진행할지 정하고, 각 작업을 AI에게 넘겼다. 이 방식은 직관적이다. 내가 전체 맥락을 알고 있으니 위험한 부분을 직접 통제할 수 있고, 필요하면 중간에 방향을 바꿀 수 있다.

하지만 생각보다 많이 힘들었다. 계속 plan 을 읽고, approve 하고, 결과를 리뷰하고, 다시 나누고, 다시 시키는 과정이 반복된다. 하나하나 보면 어려운 일은 아닌데, 이걸 오래 하다 보면 집중력이 빠르게 떨어진다. 특히 위험한 순간은 내가 plan 을 제대로 이해하지 못했는데도 무의식적으로 approve 하고 있을 때였다.

또 다른 위험 신호는 review ping-pong 이 반복될 때다. 내가 문제를 정확히 설명하지 못하고 있고, AI도 무엇을 고쳐야 하는지 명확히 잡지 못한 채 계속 수정한다. 그러면 겉으로는 작업이 진행되는 것처럼 보이지만, 실제로는 같은 주변을 맴돌고 있다. 이 상태에서는 내가 orchestrator 라기보다 그냥 approve 버튼 누르는 사람이 되어버린다.

결국 이 방식도 한계가 있었다. 물론 작은 작업에서는 괜찮다. 오히려 가장 빠를 때도 많다. 하지만 큰 마이그레이션처럼 수십 개의 판단이 계속 필요한 작업에서는 내가 병목이 된다. AI에게 일을 맡겼는데, 정작 내가 계속 컨텍스트 스위칭을 하며 작업 큐를 관리해야 한다면 자동화라고 부르기 어렵다.

그래서 지금은 Ouroboros 라는 harness 를 사용해보고 있다. 앞에서 말한 validator 방식과 harness 방식은 비슷해 보일 수 있지만, 실제로는 검증의 단위가 다르다.

처음 시도한 validator 는 커다란 마이그레이션 전체를 한 번에 검증하려 했다. 반면 harness 에서의 validator, 혹은 QA 는 각 기능을 분리하고, 그 기능에 대해 작은 test 를 만들며 진행하려는 쪽에 가깝다. e2e 테스트든 unit 테스트든, 핵심은 전체 마이그레이션을 하나의 거대한 검증 대상으로 보지 않고 기능 단위로 작게 닫는 것이다.

지금은 대략 이런 흐름으로 진행하고 있다.

interview(ooo)
-> seed(ooo)
-> qa(ooo)
-> strategic-compaction(evething-claude-code) & compaction(cc)
-> run/ralph(ooo)
-> strategic-compaction(evething-claude-code) & compaction(cc)
-> evaluate(ooo)
-> simplify(cc)
-> review(evething-claude-code)/ultrareview(cc)

interview 단계에서는 작업을 먼저 명확하게 만든다. seed 단계에서는 작업 단위와 진행 방향을 만든다. qa 에서는 무엇을 검증해야 하는지 먼저 잡는다. 이후 strategic-compaction 과 compaction 을 통해 컨텍스트를 정리하고, run/ralph 에서 실제 작업을 굴린다. 다시 compaction 을 거친 뒤 evaluate 로 결과를 보고, simplify 와 review 또는 비용이 허락한다면 ultrareview 로 불필요한 복잡도를 줄이고 마지막 리뷰를 거친다.

좋은 점은 작업을 잘게 나누는 흐름이 어느 정도 정해져 있다는 것이다. 내가 매번 처음부터 "이걸 어떻게 쪼개야 하지"를 고민하지 않아도 된다. predefined agents 기반으로 subsession 을 만들고, 각 세션이 자기 역할을 맡아 진행한다. 컨텍스트도 분리되기 때문에 토큰 효율 면에서도 장점이 있어 보인다.

특히 큰 작업을 다룰 때는 이 점이 꽤 중요하다. 하나의 거대한 세션에서 모든 것을 이해하고 모든 것을 고치게 만들면, 컨텍스트가 쉽게 비대해진다. 그리고 어느 순간부터는 모델이 무엇을 보고 판단하는지 나도 잘 알 수 없게 된다. 반대로 harness 를 이용하면 적어도 작업 단위와 역할이 나뉘어 있고, 각 결과를 다시 확인할 수 있다.

다만 아직 마냥 좋다고 말하기는 어렵다. 일단 너무 느리다. 속도도 중요한데, harness 를 쓰면 중간 단계가 늘어나는 만큼 체감 속도가 확 떨어진다. 그리고 토큰을 적게 쓸 것 같지만 은근히 많이 쓴다. 최근 2주 정도 마이그레이션을 진행하면서 토큰 사용량이 기하급수적으로 늘었다. 이전에는 두 달 동안 50억 개가 넘는 토큰을 사용한 것도 놀랐는데, 이번에는 짧은 기간에 그에 못지않은 속도로 토큰이 쌓였다. Codex 7d limit 이 찰 줄은 정말 몰랐다.

이 과정에서 모델과 도구의 역할도 조금 다르게 보이기 시작했다. 긴 실행 작업은 Codex 쪽이 더 잘 맞는 것 같다. 30분, 1시간, 2시간짜리 작업도 중간에 멈추지 않고 끝까지 진행하는 편이라 긴 작업을 맡기기 좋았다.

반면 Claude 는 planning 이나 review 에 더 적합하다는 느낌이 있다. 큰 방향을 잡거나, 설계를 비판적으로 검토하거나, 리뷰 코멘트를 만드는 데는 여전히 강점이 있다. 다만 긴 작업을 처음부터 끝까지 맡기면 중간에 멈추거나 컨텍스트 한계가 더 크게 느껴질 때가 있었다.

물론 이건 절대적인 구분은 아니다. 작업 종류와 프롬프트, 당시 모델 상태에 따라 달라질 수 있다. 그래도 지금 감각으로는 planning/review 는 Claude, 긴 실행이나 검증 루프는 Codex 쪽이 더 맞아 보인다. 중요한 건 하나의 도구가 모든 것을 해결해주길 기대하기보다, 어디에 어떤 도구를 붙일지 나누는 일인 것 같다.

현재까지의 결론은 단순하다. 큰 작업을 한 번에 하지 말자.

대신 작게 이관해야 한다. 단순히 작은 파일부터 옮긴다는 뜻은 아니다. 중복된 부분을 먼저 분리하고, 어떤 순서로 이관해야 안전한지 전략을 세워야 한다. 각 단계는 가능한 한 명확하게 끝나는 조건을 가져야 한다. 이 단계에서 무엇이 바뀌고, 무엇이 바뀌면 안 되고, 무엇을 검증하면 되는지가 작아야 한다.

validator 도 마찬가지다. validator 가 있으면 큰 작업을 안전하게 할 수 있는 것이 아니라, 작업이 충분히 작고 명확할 때 validator 가 힘을 발휘한다. 애매한 요구사항을 그대로 둔 채 검증 함수만 붙이면, 결국 검증 함수 자체도 애매해진다.

요즘 가장 중요하게 느끼는 것도 이 지점이다. 명확하지 않은 것을 얼마나 명확한 부분으로 끌고 올 수 있는가. AI를 잘 쓰는 것은 결국 프롬프트를 멋지게 쓰는 문제가 아니라, 모호한 작업을 검증 가능한 단위로 바꾸는 문제에 가깝다. 적어도 지금 내가 겪는 마이그레이션에서는 그렇다.

다음에는 두 가지를 병렬로 해보려 한다. 하나는 내가 orchestrator 가 되는 방식이다. 작은 단위에서는 여전히 이 방식이 빠르고 통제감이 있다. 다른 하나는 harness 를 사용하는 방식이다. 느리지만, 잘 굴러가기만 하면 내가 계속 붙잡고 있지 않아도 된다는 장점이 있다.

또 Ouroboros 를 다른 사람들은 어떻게 쓰는지도 찾아볼 생각이다. 예전에 어떤 해커톤에서 1등을 했다는 사람이 harness 에 대해 이야기하는 것을 잠깐 들었다. 요지는 지금 내가 하던 방식은 Cursor tab 의 더 진화된 버전에 가깝고, 진짜로 중요한 것은 노트북을 닫아도 작업이 계속 굴러가게 만드는 것이라는 말이었다. 그게 안 되면 결국 수동이라는 이야기였다.

아직은 잘 모르겠다. 다만 방향은 조금 보인다. 큰 작업을 한 번에 잘하는 AI를 찾는 것이 아니라, 큰 작업이 작게 흘러가도록 만드는 시스템을 만들어야 한다. 사람이 모든 것을 들고 있는 orchestrator 가 아니라, 작업을 명확히 쪼개고, 실행하고, 검증하고, 다시 이어갈 수 있는 harness 가 필요하다.

이번 마이그레이션은 아직 끝나지 않았다. 하지만 적어도 무엇이 잘 안 되는지는 조금 더 선명해졌다. 한 번에 옮기지 않기. 검증 가능한 단위로 만들기. 내가 이해하지 못한 plan 은 approve 하지 않기. review ping-pong 이 길어지면 작업을 더 작게 쪼개기.

당분간은 이 원칙으로 계속 밀어볼 생각이다.