3개 AI Family가 내 블로그를 검수한다: 멀티 모델 리뷰 파이프라인 구축기
목차
Google(Gemini) + Anthropic(Claude) + OpenAI(GPT-5.1) — 3개 모델 family의 6개 에이전트가 블로그 초안을 병렬 검수한다.
Devil’s Advocate가 논증 허점을 찌르고, Synthesis가 충돌을 중재하고, PR로 사람이 최종 승인한다.

개인 블로그를 운영하면서 가장 부담스러운 단계는 발행 후 검수였다. AI가 변환한 초안을 직접 읽으면서 라인 단위로 수정하는 작업이 매번 반복됐다. 글 하나에 30분에서 1시간이 들었다.
기존에는 단일 AI에게 “검토해줘”라고 맡겼다. 하지만 하나의 모델은 자기 편향 안에서 판단한다. 실제로 Claude에게 “전반적으로 검토해줘”라고 맡긴 글이 구조 9점, 가독성 8점을 받고 발행됐는데, 발행 후 코드 예시가 실행 불가능하다는 피드백을 받았다. 반대로 GPT에게 맡긴 글은 코드는 완벽했지만, “왜 이 접근을 했는가”라는 서사가 빠져 있었다. 하나의 관점만으로는 품질을 담보할 수 없었다.
여러 AI 모델이 서로 다른 관점에서 검수하면 이 부담을 줄일 수 있지 않을까. 영감은 유튜브에서 본 dmsdc-ai/aigentry-deliberation 프로젝트였다. 7개 AI CLI를 공통 메시지 버스로 연결해 구조화된 라운드 토론으로 합의에 도달하는 시스템이다. 하지만 블로그 리뷰에 이 정도 인프라는 과했다. 각자 독립적으로 평가한 뒤 중재자가 통합하는 구조가 더 통제 가능하고 실용적이었다.
도구는 이미 손에 있었다. gemini -p, claude -p, opencode run — 세 CLI의 non-interactive 모드를 Bash에서 &로 병렬 호출하고 wait로 대기하면 됐다.
Gemini CLI는 Google이 공식 제공하는 터미널 AI 도구다. OAuth 로그인으로 Google AI Pro 구독을 직접 활용한다.
npm install -g @google/gemini-cli로 설치한다. OpenCode CLI는 75개 이상의 LLM 공급자를 지원하는 오픈소스 터미널 AI 도구로, GitHub Copilot 인증을 통해 GPT-5.1 등 OpenAI 모델을 호출할 수 있다.brew install opencode로 설치한다.
입력 품질: 검수 이전의 문제
아무리 정교한 검수 파이프라인을 만들어도, 초안 자체의 품질이 낮으면 2라운드를 돌려도 한계가 있다. Garbage In, Garbage Out이다.
블로그 전체(24개 글)에 대한 외부 감사를 받았을 때 핵심 진단은 “좋은 아키텍처 블로그인데 읽히는 블로그는 아니다”였다. 기술 깊이 8.5/10, 독자 친화성 3/10. 이 피드백을 글쓰기 변환 규칙에 반영했다.
- 도입부 4단계 필수: 어떤 문제가 있었는가 → 기존에 어떻게 해결했는가 → 왜 부족했는가 → 이 글의 접근. 독자가 “왜 읽어야 하는지”에 공감한 상태로 본문에 진입해야 한다
- 적용 범위와 한계 필수: “언제 이 접근이 적합하고, 언제 쓰면 안 되는가”를 명시한다. 장점만 나열하면 독자가 잘못된 결정을 내릴 수 있다. 이 규칙은 B-3(Devil’s Advocate)의 존재 이유와도 맞닿아 있다
- SEO: H2에 핵심 키워드, 기존 글 간 내부 링크, 주장에 출처 링크
입력 품질을 끌어올리고 나서야, 검수 시스템이 의미 있는 피드백을 내놓기 시작했다.
6개 Critic 설계: 3 Family 체제
단순히 “검토해줘”가 아니라 역할을 명확히 분리해야 다양한 관점의 피드백이 나온다.
| Critic | 모델 | Family | 페르소나 | 평가 항목 |
|---|---|---|---|---|
| A-1 | Gemini Pro | 이 주제를 처음 접하는 시니어 개발자 | 가독성, 흐름, 독자 피로도 | |
| A-2 | Gemini Flash | 해당 기술의 실무 경험자 | 사실 오류, 오해 소지, 누락된 trade-off | |
| B-1 | Claude Opus | Anthropic | 기술 블로그 편집자 | 구조/서사 흐름, 블로그 톤 적합성 |
| B-2 | GPT-5.1 | OpenAI | 실용주의 개발자 독자 | 코드 예시 검증, 따라하기 가능성 |
| B-3 | GPT-5.1 | OpenAI | 회의적 시니어 엔지니어 (Devil’s Advocate) | 논증 비약, 누락된 반론, 근거 충분성 |
| C | Claude (세션) | Anthropic | SEO/메타 전문가 | 제목, 태그, description, tldr |
3개 family를 섞는 이유가 있다. 같은 family 내에서는 모델 크기가 달라도 판단 패턴이 수렴하는 경향이 있었다. Google, Anthropic, OpenAI는 학습 데이터와 RLHF 정책이 다르기 때문에 같은 글을 보고도 다른 약점을 잡아낸다.
초기에는 Gemini 2개 + Claude 2개의 2 Family 체제였다. B-2에 Claude Haiku를 썼는데, 코드 품질에 만성적으로 낮은 점수(3~4점)를 매기면서 매번 Veto가 걸렸다. GPT-5.1로 교체한 뒤 같은 글에서 code_quality 8점이 나왔다 — 모델 교체만으로 평가의 정밀도가 달라졌다.
B-3(Devil’s Advocate)는 나머지 Critic들과 근본적으로 다른 역할이다. A-1부터 B-2까지가 “이 글이 좋은가?”를 평가하는 반면, B-3는 “이 글이 틀렸을 수 있는 지점은 어디인가?”를 공격적으로 찾는다. 프롬프트에 “글이 완벽해 보이더라도, 독자가 잘못된 결정을 내릴 수 있는 지점을 찾아 명시하세요”라는 조건을 넣었다. 실제 테스트에서 기존 4개 Critic이 놓쳤던 논증 비약과 일반화 오류를 정확히 집어냈다.
각 Critic은 JSON으로 점수와 개선 제안을 반환하도록 프롬프트를 설계했다. 핵심은 평가 범위를 명시적으로 제한하는 것이다. “전반적으로 평가해줘”라고 하면 6개 Critic이 비슷한 피드백을 내놓는다. “가독성만 평가하세요. 코드 정확성은 무시하세요”라고 범위를 잘라야 역할 분리가 실제로 동작한다.
DRAFT=$(cat 초안.md)
# Critic A-1: 독자 관점 (Gemini Pro)
gemini -p "당신은 이 기술 주제를 처음 접하는 시니어 개발자입니다.
[평가 범위] 가독성(1-10), 독자 피로도
[평가 범위가 아닌 것 — 무시] 코드 정확성, 기술 사실 오류, SEO
[필수] 반드시 3개의 개선점을 제시. '특별히 없음' 불허.
JSON: {readability: number, fatigue_point: string, suggestions: string[]}
---
$DRAFT" > /tmp/critic-a1.json &
# Critic A-2: 기술 정확성 (Gemini Flash)
gemini -m gemini-2.5-flash -p "당신은 이 기술 분야의 실무 경험이 풍부한 엔지니어입니다.
[평가 범위] 기술 정확성(1-10), 최신성(1-10), 누락된 trade-off
[평가 범위가 아닌 것 — 무시] 가독성, 문체, 구조, SEO
JSON: {accuracy: number, freshness: number, missing_tradeoffs: string[], suggestions: string[]}
---
$DRAFT" > /tmp/critic-a2.json &
# Critic B-1: 구조/서사 (Claude Opus)
cd /tmp && claude -p --model opus "당신은 기술 블로그 편집자입니다.
[평가 범위] 구조(1-10), 톤 적합성(1-10)
[평가 범위가 아닌 것 — 무시] 코드 정확성, 기술 사실 오류, SEO
JSON: {structure: number, tone: number, suggestions: string[]}
---
$DRAFT" > /tmp/critic-b1.json &
# Critic B-2: 실용성 (GPT-5.1 via OpenCode CLI)
opencode run "당신은 실용주의 개발자 독자입니다.
[평가 범위] 코드 예시(1-10), 실용성(1-10)
[평가 범위가 아닌 것 — 무시] 문체, 서사 흐름, 구조, SEO
JSON: {code_quality: number, practicality: number, suggestions: string[]}
---
$DRAFT" -m github-copilot/gpt-5.1 > /tmp/critic-b2.json &
# Critic B-3: 논리 검증 — Devil's Advocate (GPT-5.1)
opencode run "당신은 이 기술 주제에 회의적인 시니어 엔지니어입니다.
[평가 범위] 논증 타당성(1-10), 반론 충분성(1-10)
[필수] 반드시 3개의 반론을 제시. '독자가 잘못된 결정을 내릴 수 있는 지점'을 찾으세요.
JSON: {argument_validity: number, counterargument_coverage: number, counterarguments: string[], suggestions: string[]}
---
$DRAFT" -m github-copilot/gpt-5.1 > /tmp/critic-b3.json &
wait # 5개 완료 대기A-2에 Gemini Flash를 쓰는 이유가 있다. 같은 Pro 모델로 A-1과 A-2를 돌리면 페르소나가 달라도 응답 패턴이 수렴하는 경향이 있었다. Flash는 Pro보다 직접적이고 덜 관대해서 기술 오류를 더 엄격하게 잡아냈다.
LLM이 JSON을 markdown 코드블록으로 감싸는 경우가 많아서, 파싱 전 전처리가 필요했다.
parse_json() {
echo "$1" | sed 's/^```json//;s/^```//' | jq '.' 2>/dev/null \
|| echo '{"score": 0, "suggestions": ["파싱 실패 — 원문 참조"]}'
}OpenCode CLI에서 GPT-5.1의 codex 계열(gpt-5.1-codex, gpt-5.1-codex-mini)은 non-interactive 모드에서 텍스트 응답을 반환하지 않는다는 점도 발견했다. codex 계열은 코드 편집 전용 모드로 동작해서, 파일 변경으로만 결과를 반환한다. Critic 용도로는 반드시 범용 모델(gpt-5.1)을 지정해야 한다.
Synthesis: 충돌을 중재하는 편집장
Gemini에게 파이프라인의 구조적 한계를 물었을 때 첫 번째로 돌아온 문제가 중재자 부재였다. A-1이 “글이 너무 길다”고 하고 B-2가 “코드 예시를 더 추가하라”고 하면, 상충하는 두 피드백 중 어느 쪽을 따를지 Writer가 혼자 판단해야 했다.
해결책은 Synthesis 에이전트를 추가하는 것이었다. 5개 Critic이 완료되면 별도 claude -p로 Synthesis를 호출한다. raw 피드백을 Writer에게 직접 전달하지 않고, 반드시 Synthesis를 거쳐 통합 지시로 변환한다.
SYNTHESIS=$(cd /tmp && claude -p "당신은 편집 중재자입니다.
다음은 동일 초안에 대한 5개의 Critic 피드백입니다.
[A-1] $CRITIC_A1 [A-2] $CRITIC_A2 [B-1] $CRITIC_B1 [B-2] $CRITIC_B2 [B-3] $CRITIC_B3
1. 피드백 간 충돌 항목을 찾아 명시
2. 각 충돌에 대해 우선순위를 결정하고 이유를 한 줄로 설명
3. Writer가 바로 적용할 수 있는 통합 수정 지시 목록 작성 (최대 7개)
4. 5개 Critic 점수의 표준편차를 계산. 0.5 미만이면 groupthink 경고.
JSON 응답: {conflicts: [...], unified_feedback: string[], priority_order: string[]}")실제 충돌 중재 결과는 이렇다:
{
"conflicts": [
{
"topic": "Telegram 섹션 분량",
"a_says": "A-1: Polling 충돌 디버깅 과정을 축소해 아키텍처 응집도 강화",
"b_says": "B-2: 데몬 설정·환경 변수를 더 구체적으로 명시",
"resolution": "B-2 우선 — 독자층이 실무 개발자이므로 재현 가능한 설정 정보가 필수"
}
],
"unified_feedback": [
"Synthesis 섹션에 conflicts/unified_feedback 구조의 실제 예시 JSON 삽입",
"Critic→Synthesis→Veto 파이프라인 데이터 흐름을 다이어그램으로 표현"
]
}Writer는 raw Critic 5개의 피드백 대신 이 unified_feedback만 받아서 수정한다. “글을 줄여라”와 “코드를 추가하라”가 충돌하면, 어떤 섹션을 줄이고 어느 코드를 추가할지 Synthesis가 구체적인 지시로 변환해준다.
Note: Synthesis도 LLM이므로 편향이 없지는 않다. Synthesis를 Claude로 실행하면 Claude 기반 Critic(B-1)의 의견을 과대 대표할 가능성이 있다. 이를 감지하기 위해 점수 표준편차 계산을 포함시켰다 — 표준편차가 0.5 미만이면 “의견 수렴도가 높다”는 경고가 추가되어, groupthink 가능성을 사람이 인지할 수 있다.
Veto: 평균만으로는 부족하다
Gemini 비평에서 지적된 두 번째 문제는 평균의 함정이었다. A-2(기술 정확성)가 5점이어도 나머지 Critic이 모두 9점을 주면 평균 8.0을 넘는다. 사실 오류가 있는 글이 “합의 통과”될 수 있다.
수렴 조건에 복합 조건을 추가해서 해결했다.
- Layer 1 — Veto: 어떤 Critic이든 6 미만이면 즉시 실패. A-2(기술 정확성) 5 이하면 평균 무관 강제 재검토
- Layer 2 — 최소 기준: 모든 Critic이 7 이상이어야 통과
- Layer 3 — 평균 기준: 단순 평균 7.5 이상이면 통과
핵심은 모든 Critic에게 거부권을 부여하는 것이다. B-3(Devil’s Advocate)이 논증 타당성 5점을 매기면 나머지가 만점이어도 통과하지 못한다. “평균은 괜찮지만 논리가 비약인” 글이 발행되는 걸 막는다. 최대 2라운드까지 반복하며, 2라운드 후에도 미달이면 현재 상태로 진행하고 사용자에게 알린다.
LLM이 불완전한 JSON을 반환하면 파이프라인이 중단될 수 있다. parse_json 헬퍼가 파싱 실패 시 점수 0으로 처리하고 계속 진행한다. 점수 0은 자동으로 Veto에 걸리므로 재검토가 트리거된다.
파이프라인 전체 흐름
flowchart TD
A[vault 노트] --> B[Writer: 변환 초안 생성]
B --> C{멀티 모델 리뷰}
C --> D[A-1 Gemini<br>독자 관점]
C --> E[A-2 Gemini<br>기술 정확성]
C --> F[B-1 Claude<br>구조/서사]
C --> G[B-2 GPT-5.1<br>실용성]
C --> GA[B-3 GPT-5.1<br>Devil's Advocate]
D & E & F & G & GA --> H[Synthesis<br>충돌 중재]
H --> I{Veto 조건 평가}
I -->|평균 7.5+<br>최저 6.0+<br>A-2 not 5 이하| J[통과]
I -->|미달| K[Writer 재수정<br>최대 2라운드]
K --> C
J --> L[Critic C<br>SEO/메타]
L --> M[Cover Image 생성]
M --> N[PR 생성]
N --> O[사람이 merge]
O --> P[GitHub Actions<br>자동 배포]실전 테스트: TTS 노트로 첫 파이프라인
NanoClaw 로컬 TTS 파이프라인 구축 노트를 첫 번째 테스트 대상으로 선택했다.
Round 1에서 평균 7.6이 나왔다. B-2(실용성)가 코드 품질 3점을 매겼다. 파일명만 나열하고 실제 코드를 보여주지 않은 게 치명적이었다. 피드백을 반영해 핵심 코드 블록 3개를 추가하고, 트러블슈팅 나열을 에피소드 서사로 재구성했다.
Round 2에서 평균 8.4로 통과. B-2가 3에서 7로, 실용성이 6에서 8로 올라갔다. 코드 블록 추가가 결정적이었다.
트리거와 배포: Telegram + PR
파이프라인의 검수 로직이 완성된 뒤, 두 가지 인프라를 연결했다.
PR 기반 발행. 기존에는 git push origin main으로 직접 발행했다. 멀티 모델 리뷰가 들어가면서 PR 방식으로 전환했다. PR body에 각 Critic의 점수와 피드백 테이블을 포함하고, 사람이 diff를 확인한 뒤 merge한다.
## Critic 결과 (Round 2)
| Critic | 모델 | 점수 | 주요 피드백 |
|--------|------|:---:|-----------|
| A-1 (독자 관점) | Gemini | 9/10 | 흐름 자연스러움 |
| A-2 (기술 정확성) | Gemini | 9/10 | deprecated 정보 1건 수정 |
| B-1 (구조/서사) | Claude | 8/10 | 서술체 일관성 확보 |
| B-2 (실용성) | GPT-5.1 | 7/10 | 코드 예시 보충 반영 |
| B-3 (논리 검증) | GPT-5.1 | 7/10 | 반론 3개 반영 |
| C (SEO/메타) | Claude | 8/10 | 태그 추가, tldr 개선 |
| **평균** | | **8.0** | |PR은 단순한 발행 게이트가 아니라 Human-in-the-Loop 인터페이스다. merge 전에 사람이 diff를 읽고, 부족한 부분이 있으면 라인 코멘트를 남긴다. AI가 그 코멘트를 읽고 수정 커밋을 추가한다.
다만 여러 LLM과 Synthesis를 거친 결과물은 겉보기에 그럴듯하고 일관성이 높아져서, 리뷰어가 “이미 많이 검수했겠지”라고 넘어가기 쉽다. AI 합의를 과신하지 않으려면 리뷰어가 직접 확인해야 할 영역이 있다.
- 사실 관계: 기술 버전, 공식 문서 링크가 실제로 유효한가
- 논증 비약: Synthesis가 통과시킨 주장이 정말 근거 충분한가
- 민감 내용: 보안, 라이선스, 조직 정책상 공개하면 안 되는 내용이 없는가
- 코드 실행 가능성: 예시 코드를 실제로 돌려봤는가
Telegram 트리거. Claude Code의 Telegram 플러그인을 활용해, 이동 중에 “블로그 발행해줘”라고 보내면 데몬 세션이 파이프라인을 돌리고 PR 링크를 Telegram으로 돌려보낸다. 주의할 점은 데몬 디렉토리에서 claude -p를 실행하면 Telegram polling이 충돌하므로, 반드시 cd /tmp && claude -p로 실행해야 한다.
직접 해보기
Telegram이나 데몬 구성 없이도 핵심 개념을 확인할 수 있다. 필요한 건 세 가지뿐이다.
- Gemini CLI:
npm install -g @google/gemini-cli후gemini실행하여 Google 계정 로그인 - Claude CLI:
npm install -g @anthropic-ai/claude-code후claude실행하여 인증 - OpenCode CLI:
brew install opencode후opencode auth login으로 GitHub Copilot 인증
# 최소 재현: 3 Family 멀티 모델 리뷰
DRAFT="path/to/your-draft.md"
cat "$DRAFT" | gemini -p "가독성을 1-10으로 평가하세요.
JSON: {readability: number, suggestion: string}" > /tmp/critic-a.json &
cat "$DRAFT" | claude -p "구조를 1-10으로 평가하세요.
JSON: {structure: number, suggestion: string}" > /tmp/critic-b.json &
opencode run "논리적 허점을 찾으세요.
JSON: {argument_validity: number, counterarguments: string[]}
---
$(cat $DRAFT)" -m github-copilot/gpt-5.1 > /tmp/critic-c.json &
wait
echo "Gemini: $(cat /tmp/critic-a.json)"
echo "Claude: $(cat /tmp/critic-b.json)"
echo "GPT-5.1: $(cat /tmp/critic-c.json)"여기에 Synthesis와 Veto를 얹으면 이 글에서 설명한 전체 파이프라인이 된다.
이 파이프라인이 적합하지 않은 경우
- 발행 빈도가 높은 팀 블로그: Round 2까지 가면 12회 이상의 LLM 호출. 일 단위 발행이라면 비용 구조를 재검토해야 한다
- 짧은 글이나 뉴스 요약: 5개 Critic이 과도하다. 1~2개 Critic으로 축소하거나 건너뛰는 게 낫다
- 프롬프트 유지보수 여력이 없는 경우: 6개 Critic 프롬프트는 모델 변경이나 요구사항 변화 시 함께 수정해야 한다
이 파이프라인의 한계
솔직하게 인정해야 할 것들이 있다.
3-family가 편향을 완전히 상쇄하지는 않는다. Google, Anthropic, OpenAI의 학습 데이터와 RLHF 정책이 다르다고 해서 관점이 근본적으로 다른 것은 아니다. 세 family 모두 비슷한 인터넷 담론을 학습했기 때문에 동일한 맹점을 공유할 수 있다. “세 모델이 다 괜찮다고 했으니까”가 잘못된 안심이 될 수 있다. 실제로 세 family가 공통으로 놓친 오류를 발행 후 사람이 발견한 적이 있다.
점수 기반 Veto는 모델별 관대함에 취약하다. Claude Haiku가 code_quality 3점을 매기던 항목에 GPT-5.1은 8점을 줬다. 모델을 바꾸는 것만으로 Veto 통과 여부가 달라진다. 점수의 절대값보다는 “어떤 구체적 문제를 지적했는가”가 더 신뢰할 수 있는 신호다. 장기적으로는 점수 임계값 대신 체크리스트 기반 패스/페일로 전환하는 것이 더 견고할 수 있다.
LLM은 비결정적이다. 같은 초안을 같은 Critic으로 두 번 돌리면 점수가 1~2점 차이날 수 있다. “Round 1에서 7.6, Round 2에서 8.4”가 실제 품질 향상인지 단순 변동인지 구분하기 어렵다. 이 파이프라인은 정밀한 측정 도구가 아니라 “명백한 약점을 잡아내는 그물”에 가깝다.
정리: 트레이드오프
이 파이프라인은 공짜가 아니다.
비용. Round 2까지 가면 Critic 5개 x 2 + Synthesis 2 = 12회 이상의 LLM 호출이 발생한다. 개인 블로그 용도라 주 23회 발행 기준으로 부담 가능한 수준이지만, 규모가 커지면 재검토가 필요하다. 전체 파이프라인 1회에 약 35분, Round 2까지 가면 8~10분이다.
공급자 종속. Google, Anthropic, OpenAI 세 공급자에 의존한다. 역설적으로, 3개 family로 분산한 덕분에 하나가 장애를 겪어도 나머지 Critic들로 리뷰를 계속할 수 있다. CLI의 출력 형식이 바뀌면 파싱이 깨지는 리스크는 parse_json 헬퍼로 방어하고 있지만, 근본적 해결은 아니다.
이런 트레이드오프에도 불구하고, 이 파이프라인의 핵심 가치는 검수 부담의 이동이다. 사람이 라인 단위로 읽고 고치던 작업을 AI 에이전트들이 구조화된 평가 항목으로 대신한다. 사람은 PR에서 최종 결과만 확인하면 된다.
설계 원칙은 두 가지다.
- 평가 항목의 분리가 합의의 품질을 결정한다. 각 Critic에게 명확하게 다른 역할을 부여하지 않았다면, 6개 에이전트가 돌아도 같은 피드백을 6번 받는 것에 불과했을 것이다.
- 모델 family의 다양성이 편향을 줄인다. Google, Anthropic, OpenAI는 같은 글을 보고도 다른 약점을 잡아낸다. 특히 Devil’s Advocate(B-3)처럼 공격적 역할을 다른 family 모델에 맡기면, 기존 Critic들의 groupthink를 깨는 효과가 있다.
다음 단계로 검토하고 있는 것들이 있다. 6개 Critic 프롬프트를 별도 파일로 분리하고 변경 이력을 추적하는 프롬프트 버전 관리, 각 단계의 입출력을 기록하는 로깅/가시화, 그리고 코드가 없는 서술형 글에서는 B-2(실용성)를 건너뛰는 동적 Critic 활성화다. 파이프라인이 커질수록 파이프라인 자체의 유지보수가 새로운 문제가 된다.