-
하네스 엔지니어링: LLM을 자율 비행시키는 제어 구조Harness/workflow 2026. 3. 20. 00:00

Ref: https://github.com/Q00/ouroboros Date: 2026-03-19
Author: mangowhoiscloud, Claude Code Opus 4.6
Tags: harness-engineering, ralph-loop, autonomous-agent, claude-code, ralphton
GitHub: https://github.com/mangowhoiscloud/harness-for-realGitHub - mangowhoiscloud/harness-for-real: Ralphton autonomous harness — 4-phase FSM (Socratic → Plan → Build → Verify)
Ralphton autonomous harness — 4-phase FSM (Socratic → Plan → Build → Verify) for AI agent hackathons - mangowhoiscloud/harness-for-real
github.com
목차
- 도입
- Ralph Loop에서 4-Phase FSM으로
- Phase 0: 소크라틱 리즈닝 — 코딩 전에 모호성을 제거하라
- Phase 1-2: 계획과 구현 — 의존 그래프 기반 병렬 빌드
- Phase 3: 3-에이전트 검증 — 자기 작업을 검증할 수 있어야 한다
- 백프레셔와 회로 차단기 — 품질 게이트와 안전장치
- 실전 검증: 3개 프로젝트 자율 생성 결과
- 마무리
1. 도입: LLM 위에선 하네스가 곧 경쟁력이다
2026년 2월, 한국 최초 랄프톤(Ralphton)에서 우승팀은 AI 에이전트에게 10만 줄의 코드를 작성시키면서 키보드를 단 한 번도 터치하지 않았습니다. 10만 줄 중 7만 줄은 테스트 코드였고, 코드 작성 전에 133라운드의 소크라틱 리즈닝으로 모호성 점수를 0.05까지 낮췄습니다.
코딩 에이전트 = AI 모델(들) + 하네스하네스(Harness)란 AI 코딩 에이전트가 장시간 자율적으로 동작할 때, 방향을 잃지 않고 안정적으로 작동하게 만드는 제어 구조입니다. 항법과 경로 수정, 안전 시스템을 담당하는 비행 컴퓨터라고 보면 됩니다. AI는 코딩에만 집중하고, 하네스가 나머지를 맡습니다.
이 글에서는 랄프톤 우승 전략을 재사용 가능한 시스템으로 만든 harness-for-real의 설계를 살펴봅니다.
왜 이렇게 만들었는지, 실제로 어떤 결과가 나오는지를 중심으로 다룹니다.
2. Ralph Loop에서 4-Phase FSM으로
Geoffrey Huntley가 2025년 7월에 공개한 Ralph Loop의 핵심은 한 줄입니다:
while true; do cat PROMPT.md | claude -p; done매 반복마다 깨끗한 컨텍스트 윈도우로 시작하고, 진행 상태는 파일 시스템과 git에 저장합니다.
스펙 모호성 → 잘못된 코드 수동 스펙 작성 소크라틱 단계가 모호성 자동 제거 에이전트가 루프에 갇힘 영원히 실행 예측형 회로 차단기 + Opus 에스컬레이션 비싼 API 비용 단일 모델 적응형 Opus/Sonnet 라우팅 조기 완료 선언 감지 불가 이중 조건 종료 (마커 + 계획 상태 확인) 품질 게이트 없음 없음 훅이 타입체크 + 린트 + 테스트 강제 수동 단계 전환 수동 실행 4-Phase FSM 자동 전환 이 하네스는 기본 루프를 4단계 유한 상태 기계(FSM)로 확장합니다:
┌──────────────┐ │ 스펙 작성 │ └──────┬───────┘ │ ┌────────────▼────────────┐ │ Phase 0: 소크라틱 리즈닝 │ Opus │ 자문자답으로 모호성 제거 │ └────────────┬────────────┘ │ AMBIGUITY_SCORE < 0.10 ┌────────────▼────────────┐ │ Phase 1: 계획 │ Opus │ → IMPLEMENTATION_PLAN │ │ + 의존 그래프 + 병렬 그룹 │ └────────────┬────────────┘ │ 계획 생성 완료 ┌────────────▼────────────┐ │ Phase 2: 구현 │ Sonnet (기본) │ 독립 항목 → 병렬 빌드 │ 실패 시 Opus └────────────┬────────────┘ │ 모든 항목 DONE ┌────────────▼────────────┐ │ Phase 3: 검증 │ Opus │ Validator + Coordinator │ │ + Packer 3-에이전트 검증 │ └────────────┬────────────┘ │ ┌─────▼─────┐ │ 완료 │ └───────────┘각 단계의 전환 조건이 명시적입니다. 소크라틱에서 계획으로의 전환은 AMBIGUITY_SCORE < 0.10이 트리거하고, 구현에서 검증으로의 전환은 IMPLEMENTATION_PLAN.md에 TODO나 IN_PROGRESS 항목이 남아있지 않을 때 발동합니다. 검증에서 실패가 발견되면 새 항목을 계획에 추가하고 구현 단계로 회귀합니다. 인간의 개입이 필요한 지점이 없습니다.
핵심 설계 원칙은 기억을 컨텍스트가 아닌 파일에 외부화하는 것입니다. 매 반복마다
progress.txt,IMPLEMENTATION_PLAN.md,LEARNINGS.md, git 히스토리에서 상태를 읽고 시작하기 때문에, 에이전트가 수시간 작업해도 컨텍스트 윈도우 성능이 저하되지 않습니다.
3. Phase 0: 소크라틱 리즈닝: 코딩 전에 모호성을 제거하라
우승팀의 가장 결정적인 전략이었습니다. 입력(스펙)의 품질이 출력(코드)의 품질을 결정합니다. 스펙이 모호하면 에이전트는 수만 줄의 잘못된 코드를 자신 있게 작성합니다.
소크라틱 단계는 에이전트가 스펙을 읽고 스스로에게 질문하는 자문자답 루프입니다:Round: 1 Spec: word-definition.md Category: EDGE_CASE Severity: MAJOR Q: 아포스트로피가 단어 경계에 있을 때 어떻게 처리하는가? "don't" 예시는 있지만 "'twas"이나 "dogs'"는? A: "within words"는 양쪽에 영숫자가 있을 때를 의미한다. 'twas → twas, dogs' → dogs Confidence: 0.9 Resolution: 아포스트로피는 양쪽에 영숫자가 있을 때만 유지. 선행/후행 아포스트로피는 제거.각 라운드는 카테고리(UNDEFINED_TERM, CONTRADICTION, EDGE_CASE 등 8종), 심각도(CRITICAL/MAJOR/MINOR), 신뢰도 점수를 포함합니다. 이 구조화된 포맷 덕분에 하네스가 모호성 점수를 자동으로 계산할 수 있습니다.
모호성 점수 공식은 단순합니다:
AMBIGUITY_SCORE = Ambiguities_Remaining / (Ambiguities_Found + 1)word-counter 예시에서는 11개 모호성을 발견하고 11개 모두 해결하여 점수 0.00으로 1라운드 만에 통과했습니다. 실제 랄프톤 우승팀은 133라운드가 필요했습니다. 스펙의 복잡도에 따라 차이가 큽니다.
v2에서는 수렴 가속(Convergence Acceleration)이 추가되었습니다. 3라운드 연속 점수 변화가 0.01 미만이고, 점수가 0.15 이하이며, CRITICAL 항목이 0개이면 조기 전환합니다. 불필요한 반복을 줄여 비용을 절감하는 메커니즘입니다.CONVERGENCE_DATA: round: 1 score: 0.00 prev_score: 1.0 delta: -1.0 stagnation_count: 0소크라틱 단계의 산출물인
CLARITY_LOG.md는 이후 모든 단계에서 참조됩니다. 계획 단계는 이 결정들을 기반으로 항목을 설계하고, 구현 단계는 Resolution을 권위 있는 결정(authoritative decision)으로 취급합니다.
4. Phase 1-2: 계획과 구현: 의존 그래프 기반 병렬 빌드
계획: Opus가 의존 그래프를 그린다
계획 단계는 코드를 작성하지 않습니다. Opus 모델이 스펙과 CLARITY_LOG를 분석하여
IMPLEMENTATION_PLAN.md를 생성합니다. 핵심은 의존 그래프와 병렬 그룹입니다:## Dependency Graph Independent_Groups: - group_1: [Item 1, Item 2, Item 3] # 상호 의존 없음 - group_2: [Item 4] # group_1에 의존 - group_3: [Item 5] # group_2에 의존 Build_Order: group_1 → group_2 → group_3각 항목에는 복잡도 등급(S/M/L/XL)이 부여됩니다. 이 등급이 구현 단계의 모델 라우팅에 직접 사용됩니다:
S 단일 파일, 50줄 미만 Sonnet M 2-3 파일, 200줄 미만 Sonnet L 4+ 파일, 200-500줄 Opus XL 시스템 전반, 500줄 초과 Opus 3등팀의 교훈이 반영된 설계입니다. Opus(소크라틱, 계획, 검증)와 Sonnet(구현)을 분리하면 동일한 품질에 약 5배 적은 비용이 듭니다. v2의 적응형 라우팅은 여기에 더해 구현 중 실패가 누적되면 Sonnet에서 Opus로 에스컬레이션합니다.
구현: 한 번에 하나, 병렬로 여러 개
구현 단계의 원칙은 "한 번에 하나만 처리하라"입니다. 범위 확대(scope creep)는 자율 루프의 1번 킬러이기 때문입니다. 매 반복은 계획에서 정확히 하나의 작업만 처리하고, 신선한 컨텍스트로 다음 반복을 시작합니다.
v2에서는
scripts/plan-parser.sh가 의존 그래프를 분석하여 독립 항목을 식별하고,scripts/parallel-build.sh가 git worktree로 각 항목을 별도 브랜치에서 동시 빌드합니다. 완료 후 메인 브랜치에 자동 머지하며, 머지 충돌 시 순차 빌드로 폴백합니다.# asis-legacy phase.log에서 발췌 event=PARALLEL_START items=3 max=3 event=PARALLEL_DONE success # ... event=PARALLEL_START items=2 max=3 event=PARALLEL_DONE success런타임 학습 주입 또한 v2의 핵심 기능입니다. 구현 중 에이전트가 발견한 교훈이
LEARNINGS.md에 축적됩니다:### Learning: jackson-databind 2.9.11.1 does not exist - Context: pom.xml에 2.9.11.1 버전이 지정되어 있었음 - Discovery: Maven Central에 해당 아티팩트 없음. 2.9.x 마지막은 2.9.10.8 - Rule: 이 프로젝트에서 Jackson 버전은 2.9.10.8을 사용할 것다음 반복 시 프롬프트에 LEARNINGS.md가 자동 주입되어, 같은 실수를 반복하지 않습니다.
harness-for-real에 asis-boot3 예시에서는 9개의 학습 항목이 축적되었고, 검증 단계에서 9개 모두 적용 확인(Learnings_Applied: 9 of 9)을 받았습니다.
5. Phase 3: 3-에이전트 검증: 자기 작업을 검증할 수 있어야 한다
우승팀의 10만 줄 중 7만 줄이 테스트 코드였습니다. 테스트는 에이전트의 자기 검증 메커니즘이며, 이것 없이는 에러가 반복마다 누적됩니다. 검증 단계는 3개의 Opus 서브에이전트를 병렬로 실행합니다:
┌──────────────────────────┐ │ Validator (스펙 준수) │ specs/ 기준 수용 조건 대조 │ Coordinator (통합 일관성) │ 모듈 간 연결, 의존성, API 일관성 │ Packer (배포 준비) │ 빌드 산출물, 시크릿 노출, README └──────────────────────────┘이 구조는 랄프톤 우승팀의 "Validator + Coordinator + Packer 다중 검증" 패턴을 그대로 재현한 것입니다. 한 에이전트가 모든 것을 검증하면 관점이 편향될 수 만, 있지역할을 분리하면 각자의 관점에서 문제를 찾아냅니다.
3개 에이전트가 모두 ALL PASS를 보고하면
HARNESS_COMPLETE마커를 기록하고 완료합니다.하나라도 FAIL이 있으면 새 항목을
IMPLEMENTATION_PLAN.md에 추가하고 구현 단계로 회귀합니다.word-counter 예시에서는 Packer가 README.md 누락과
__init__.py미비를 발견하여 세션 내에서 즉시 수정했습니다.
6. 백프레셔와 회로 차단기: 품질 게이트와 안전장치
백프레셔: 실패만 표면화, 성공은 무음
두 개의 훅이
.harness-config에서 커맨드를 읽어 자동 실행됩니다:훅 시점 타임아웃 검사 항목 backpressure.shWrite/Edit마다 60초 타입체크 + 린트 pre-commit-gate.sh커밋마다 120초 테스트 + skip 마커 차단 + TODO/FIXME 차단 # .harness-config — 단일 진실 소스 BUILD_CMD="uv build" TEST_CMD="uv run pytest" LINT_CMD="uv run ruff check ." TYPECHECK_CMD="uv run mypy . 2>/dev/null || true""실패만 표면화, 성공은 무음"이 핵심 원칙입니다. 성공 메시지는 컨텍스트를 오염시킬 뿐입니다.
훅은 exit 0이면 무음 통과, exit 2이면 에러 메시지와 함께 에이전트에게 수정을 요구합니다.
.harness-config가 없으면 pre-commit-gate가 커밋 자체를 차단하여, init.sh 미실행 상태에서 백프레셔 없이 코드가 커밋되는 것을 방지합니다.회로 차단기: 갇힌 루프를 탈출시킨다
MAX_STUCK회(기본 5) 연속 git 커밋이 없으면 회로 차단기가 작동합니다:Sonnet으로 실행 중 5회 연속 커밋 없음 → Opus로 에스컬레이션 + RECOVERY MODE 컨텍스트 주입 → 복구 성공: 계속 → 복구 실패: 다음 단계로 강제 전환v2의 예측형 회로 차단기는 더 선제적입니다.
PREDICTIVE_STUCK회(기본 2) 실패 시 에이전트의 자기 진단(BUILD_ITEM_FAILURE보고)에 따라 전략을 전환합니다:BUILD_ITEM_FAILURE: item: 12 reason: COMPLEXITY_UNDERESTIMATE suggestion: SPLIT split_into: ["EmployeeMapper XML", "EmployeeMapper Tests"]asis-legacy 예시의 phase.log에서 실제로 회로 차단기가 작동한 기록을 확인할 수 있습니다:
2026-03-19T23:06:51+09:00 event=CIRCUIT_BREAKER Stuck 3 iterations, phase=build, model=sonnet회로 차단기 없이는 에이전트가 같은 에러를 무한히 반복하며 비용만 소모합니다. 예산 강제(MAX_BUDGET_USD)와 결합하면 80% 도달 시 경고, 100% 시 체크포인트 저장 후 자동 중단하여 비용 폭주를 방지합니다.
7. RUN: 3개 프로젝트 자율 생성 결과
동일한 하네스로 3개의 서로 다른 스택에서 프로젝트를 자율 생성했습니다. 스펙 파일만 작성하고, 나머지는 전부 하네스가 처리했습니다.
Word Counter CLI (Python)
2개 스펙 파일로 단어 빈도 분석 CLI를 자율 생성한 가벼운 데모입니다.
Socratic 1 $0.63 모호성 0.00, 11개 발견/11개 해결 Plan 1 $0.59 5 항목, 3 병렬 그룹 Build 8 $1.31 병렬 빌드, 회로 차단기 1회 Verify 1 $0.52 3-에이전트 검증 통과 합계 11 $3.06 144 테스트 전부 통과 group_1 (병렬): Tokenizer ──┐ Counter ─────┼──→ group_2: CLI ──→ group_3: Integration Tests Formatter ───┘실제 CLI 실행 결과:
$ echo "hello world hello foo bar foo foo" | wc-freq # | Word | Count | % --+-------+-------+------ 1 | foo | 3 | 42.9% 2 | hello | 2 | 28.6% 3 | bar | 1 | 14.3% 4 | world | 1 | 14.3% Total: 7 words, 4 unique wordsAS-IS Spring Boot 3 + AS-IS Spring Legacy
동일한 Employee CRUD REST API 스펙을 두 개의 서로 다른 Java 스택에서 구현했습니다.
REODE(마이그레이션 & 코딩 도메인 자율 수행 하네스)의 테스트 베드로 설계된 프로젝트들입니다.Java 21 (records, text blocks) 1.8 (explicit config) Framework Spring Boot 3.3.7 Spring Framework 4.3.4 Security Spring Security 6.x Spring Security 4.2.4 ORM MyBatis Starter 3.0.4 MyBatis 3.2.2 (XML only) Validation jakarta.validation javax.validation Test JUnit 5 JUnit 4 + Mockito 테스트 수 73 73 (106 in service log) 결과 BUILD SUCCESS BUILD SUCCESS LEARNINGS 9개 축적 4개 축적 같은 스펙, 같은 하네스로 완전히 다른 스택의 프로젝트를 생성할 수 있다는 점이 핵심입니다. 하네스는 .harness-config에서 빌드/테스트 커맨드를 읽고, CLAUDE.md의 Stack-Specific Rules에서 스택별 제약을 주입합니다. Java 1.8에서는 records를 금지하고 javax.validation을 사용하라는 규칙이, Spring Boot 3에서는 ProblemDetail(RFC 7807)을 쓰라는 규칙이 들어갑니다.
asis-legacy의 비용 로그를 보면 적응형 모델 라우팅이 어떻게 작동하는지 확인할 수 있습니다:phase=socratic model=opus cost=$0.70 # 추론이 필요한 단계 phase=plan model=opus cost=$1.12 # 추론이 필요한 단계 phase=build model=sonnet cost=$0.46 # Item 1 구현 (S 복잡도) phase=build model=sonnet cost=$0.10 # Item 2 구현 (S 복잡도) ... phase=verify model=opus cost=$0.39 # 추론이 필요한 단계Opus는 소크라틱/계획/검증에만 사용되고, 구현 20회 반복 전체가 Sonnet으로 처리되어 비용이 $4.97로 마무리되었습니다.
8. 마무리
핵심 정리
코딩 전에 모호성 제거 Phase 0 소크라틱 자동화 우승팀 133라운드 리즈닝 에이전트가 자기 작업 검증 70% 테스트 + 3-에이전트 검증 우승팀 10만줄 중 7만줄 테스트 한 번에 하나만 처리 매 반복 1 항목 + 신선한 컨텍스트 scope creep 방지 사고엔 비싼 모델, 구현엔 빠른 모델 적응형 Opus/Sonnet 라우팅 3등팀 비용 최적화 교훈 기억은 파일에 외부화 progress.txt + LEARNINGS.md + git 컨텍스트 윈도우 성능 유지 키보드를 만지면 하네스를 고쳐라 4-Phase FSM 자동 전환 완전 자율 목표 하네스 설계 체크리스트
-
specs/디렉토리에 JTBD별 명세서 작성 ("한 문장 테스트" 통과) - 소크라틱 리즈닝 루프로 명세 모호성 사전 제거
- IMPLEMENTATION_PLAN.md에 의존 그래프와 병렬 그룹 포함
- 적응형 모델 라우팅: Opus(추론) + Sonnet(구현) 분리
- 백프레셔: 타입체크 + 린트 + 테스트 자동 강제
- 회로 차단기: 갇힌 루프 감지 + 모델 에스컬레이션
- 런타임 학습: LEARNINGS.md 축적 + 다음 반복 자동 주입
- 체크포인트: 크래시 후 마지막 지점부터 재시작
- 예산 강제: 토큰 기반 자동 중단
'Harness > workflow' 카테고리의 다른 글
Multi-Developer Merge Conflict Prevention (0) 2026.03.27 CAN/CAN NOT + 소크라틱 게이트: 이미 구현된 것을 다시 만들지 않는 워크플로우 설계 (0) 2026.03.21 REODE: 재귀개선루프로 Java 마이그레이션을 자율 수행하기까지 (0) 2026.03.21 메모리 alloc/free처럼 열고 닫는 자율 에이전트 워크플로우 (0) 2026.03.18