AI 에이전트다른 회사 모델(Codex)로 검토하는 리뷰 에이전트 Critic 도입
· 알고수
- #multi-model
- #codex
- #critic
- #harness
먼저 전제 하나. 12개의 에이전트는 모두 Anthropic의 Claude 모델로 돌아갑니다.
코드 리뷰도 마찬가지였어요. 보안·계약을 보는 에이전트와 기획·결정 기록을 보는 총괄 에이전트가 리뷰를 나눠 맡았지만, 둘 다 같은 Claude 모델 가족이었습니다. 같은 모델은 같은 곳을 놓칩니다. 그 맹점을 서로 잡아 줄 수 없었어요.
그 무렵 OpenAI가 Claude Code 안에서 자사 코딩 모델 Codex를 불러 쓸 수 있는 도구를 공개했습니다. 다른 모델 가족의 눈을 들일 길이 생긴 거예요.
문제
하네스(에이전트들이 일하는 규칙·도구·실행 환경 묶음)가 한 회사의 모델 계열, 즉 한 모델 가족에 묶여 있었고, 코드 리뷰까지 모두 그 가족이 맡아 공통으로 놓치는 맹점을 서로 잡아 줄 수 없었다. 다른 시선이 필요했다.
결정
Codex로 돌아가는 리뷰 에이전트 Critic을 머지 직전 자리에 두었다. 기존 에이전트를 바꾸는 게 아니라 한 자리를 추가하는 방식이다. 동의하는 자리가 아니라 합의를 의심하는 자리다.
결과
18 라운드 교차 리뷰로 심각한 결함(P1) 8건과 개선 권고(P2) 9건을 잡았다. 하지만 절차 위반은 잡지 못했다. 그리고 하네스 자체가 한 모델 가족에 묶여 있다는 더 큰 편향을 발견했다. 다음 목표는 모델을 부품처럼 갈아 끼우는 하네스다.
교체가 아닌 추가를 고른 이유
전면 교체는 고민하지 않았어요.
12개의 에이전트는 이미 자기 역할에 자리 잡고 있었습니다. 각자의 역할 정의, 기준 문서, 서로 연락하는 경로가 안정돼 있었어요. 무너뜨릴 이유가 없었죠. 게다가 한 모델 가족에서 다른 가족으로 통째로 갈아타는 게 정답이라는 보장도 없었습니다. 그건 종속의 대상만 바꾸는 일이니까요.
대신 추가하기로 했습니다. 기존 12개는 그대로 두고, 자리를 하나 새로 만들어 다른 모델 가족을 앉히는 식으로요.
머지 직전이라는 자리
새 자리를 검증 단계에 둔 데에는 이유가 있어요.
코드의 정확성, 보안, 동시성, 되돌릴 수 있는지를 머지 직전에 한 번 더 봐 줄 시선이 필요했습니다. 다른 시선의 가치가 가장 큰 곳도 거기였어요. 같은 모델 가족끼리 서로 리뷰하면 같은 학습 데이터에서 온 같은 맹점을 공유할 수밖에 없거든요. 서로 동의하면 그대로 통과였습니다.
머지 직전에 다른 가족의 시선이 들어오면, 그 합의를 의심하는 자리가 생깁니다. 합의를 깨는 자리. 새 에이전트는 거기에 들어가야 한다고 봤어요.
그래서 이름도 Critic(비평가)으로 정했습니다. 동의하는 쪽이 아니라 의심하는 쪽.
18 라운드와 "다른 시선"
Critic이 본격적으로 일하는 모습을 본 건 135번째 스프린트(짧은 작업 주기)였어요. 알고수는 스프린트를 백 번 넘게 돌렸고, 이 이야기는 그중 130번대 무렵입니다. PR 5건을 차례로 머지하면서 PR마다 Critic을 불렀습니다. 한 번 리뷰받고 고치는 것을 한 라운드로 셌고, 결과는 다음과 같았어요.
3라운드
작업 묶음 A (PR #167)
AI 사용량 한도 검사 시범 구현(aiQuotaCheck PoC)
4라운드
작업 묶음 B (PR #168)
심각 4 / 권고 2
3라운드
정책 동기화 (PR #169)
오류 처리 필터(errorFilter) 정책 맞추기
5라운드
작업 묶음 C (PR #170)
심각 2 / 권고 3
3라운드
작업 묶음 D (PR #171)
심각 1 / 권고 1
모두 18 라운드를 돌며 심각한 결함 8건과 개선 권고 9건을 찾아 고친 뒤 머지했습니다. 위에 건수가 적힌 건 PR 3건뿐이라 그 합(심각 7, 권고 6)과 전체 합계가 다릅니다. 나머지 두 PR(작업 묶음 A, 정책 동기화)의 건수는 따로 나눠 기록해 두지 않았어요.
흥미로웠던 건 결함의 종류였어요. 잡힌 심각한 결함은 대부분, 같은 모델 가족끼리였다면 서로 동의하고 통과시켰을 코드였습니다. 통합에 집중하느라 부수효과를 놓친 모듈. 어림짐작에 기대어 동시 실행 충돌(race) 가능성이 남아 있던 분기. 비즈니스 오류와 인프라 오류를 섞어서 분류하던 필터.
코드는 각각 작동했어요. 다만 제대로 따져 묻는 시선을 받지 않았을 뿐이었습니다. Codex가 그 시선이 들어오는 자리였어요. 같은 학습 분포를 공유하지 않는 모델이 들어오자, 합의가 의심받기 시작했습니다.
이때 처음으로 "모델 다양성"의 가치를 체감했어요. 더 똑똑한 모델이 필요했던 게 아니었습니다. 다르게 배운 모델이 필요했던 거예요.
만능이 아니었던 Critic
기쁨은 짧았어요.
135번째 스프린트를 마치고 기록을 정리하다가 깨달았습니다. Critic이 있었는데도 main 직접 push는 막지 못했다는 것.
바로 앞 스프린트에서, 에이전트가 작업 기록 문서 몇 줄을 고친 뒤, 브랜치도 PR도 없이 main 브랜치에 바로 commit하고 push했습니다. 고친 건 결정 기록(ADR) 텍스트 네 줄이었어요. 상태를 completed로 바꾸고 정리 두세 줄을 더한 정도였죠.
에이전트가 매 세션 자동으로 읽는 규칙 파일 CLAUDE.md에는 굵은 글자로 적혀 있습니다. "에이전트 브랜치 규율: main 직접 push 절대 금지." 이전에 한 번 어긴 뒤 강화했고, 여러 번 강조해 둔 규칙이었어요. 에이전트는 다음 스프린트 기록에 스스로 한 줄을 남겼습니다. "정책 위반 자가 기록".
처음이 아니었습니다. 며칠 전에는 셸 글로빙(와일드카드 패턴) 결과만 보고 어떤 디렉터리가 없다고 결론 냈고, 제가 바로잡았어요. 디렉터리는 실재했습니다. 며칠 뒤 똑같은 패턴으로 같은 실수를 또 했어요.
정해 둔 작업 절차를 무시하는 일이 분명히 늘고 있었습니다. Critic을 들인 뒤에도 같은 모델이 같은 실수를 반복하고 있었어요.
Critic은 코드 변경이 맞는지를 머지 직전에 검증합니다. 절차 위반은 잡지 않아요. 새 브랜치를 만들지 않고 main에 바로 commit하는 건 코드가 틀린 게 아니라 작업 절차를 건너뛴 거예요. PR이 만들어지지 않으니 Critic이 불릴 자리도 없습니다.
코드 검증의 맹점은 줄었지만, 절차 우회는 별개의 문제로 남았어요.
Critic의 자리와 사각지대
하네스에 숨은 편향
여기서 한 걸음 더 거슬러 올라가게 됐어요.
지금 하네스를 보면 디렉터리 이름부터 도구 이름까지 모두 한 모델 가족의 환경에 맞춰져 있었습니다(예: 규칙 파일 CLAUDE.md, 설정 폴더 .claude/). Codex를 한 자리 더 앉혔다고 시스템의 뼈대가 모델 다양성을 갖게 된 건 아니었어요. 검증 단계 한 자리에 다른 모델을 끼웠을 뿐, 뼈대는 여전히 한 모델 가족에 묶여 있었습니다.
이게 진짜 문제였어요.
이번에도 비슷했어요. 기대는 대상이 외부 서비스에서 AI 모델로 바뀌었을 뿐, 패턴은 같았습니다. 시스템이 한 가족에 묶여 있으면, 그 가족이 흔들릴 때 시스템도 흔들립니다.
같은 교훈이 다른 층에서 다시 찾아온 셈이었어요.
모델 종속 없는 하네스로
모델 성능은 시기마다 다릅니다. 지금은 코딩에서 Codex가 앞설 수 있고, 다음 분기엔 Claude가, 그다음엔 Gemini가 앞설 수 있어요. 언제 어느 쪽이 앞설지 미리 알 수 없고, 알 필요도 없습니다.
다만 그때가 오면 바로 갈아 끼울 수 있어야 합니다. 종속에서 벗어난다는 건 그런 뜻이에요.
다음 단계로 그리는 그림은 두 층이에요.
먼저 에이전트마다 모델을 바꾸는 스위치. 12개의 역할 정의는 그대로 두고, 각 자리에 어떤 모델 가족을 앉힐지를 설정으로 고르는 구조입니다. Critic 자리에 지금은 Codex를, 다음 분기엔 다른 모델을 앉힐 수 있게요.
더 멀리는 하네스 자체를 특정 모델과 실행 환경에서 떼어 내는 것. 도구와 환경을 부품처럼 추상화하고, 시스템의 뼈대는 그 위에 얹는 구조입니다. 새 모델이 나오면 기다리지 않고 바로 끼워 넣을 수 있도록.
시작은 작았어요. 한 자리에 다른 가족을 앉혔고, 18 라운드를 검증했고, 심각한 결함 여덟 건을 잡았습니다. 거기서 멈출 생각은 없어요. 백준이 사라졌을 때 배운 교훈을 이번엔 모델 층에서, 더 깊게 적용해 보려 합니다.
종속에서 벗어난 시스템이 더 오래갑니다.