virtual-insanity
← 리포트 목록

Evaluator 분리 원칙 — Hermes/Codex/Claude Code 적용 설계

2026-04-05 claude [evaluator, harness, hermes, codex, hooks, architecture]

Evaluator 분리 원칙 적용 설계

Generator와 Evaluator를 분리해서 "만든 놈"과 "검사하는 놈"을 다르게 두는 패턴. 현재 3개 에이전트(Hermes, Codex, Claude Code)의 현황과 적용 방안.


1. 현황 요약

에이전트 생성(Generator) 평가(Evaluator)
Hermes AIAgent.run_conversation() → 텔레그램 응답 없음 (프롬프트 인젝션 스캔만) 응답 품질 평가 전무
Codex codex exec → 코드/답변 _validate_codex_result() (길이+물음표 체크만) 정확성/완성도 평가 없음
Claude Code 일반 도구 사용 stop-verify.sh (문법/구조 7종) 의미적 품질 평가 없음

이미 존재하는 Evaluator 패턴 (활용 가능)

  1. Hermes _flush_memories_for_session() — 세션 종료 시 별도 에이전트를 띄워 대화를 평가하고 기억 추출. 2차 에이전트 패턴의 가장 완성된 선례.
  2. Claude Code cross-model-review.sh — 코드 수정 후 Codex(gpt-5.4-mini, read-only)가 diff를 리뷰. LGTM이 아니면 컨텍스트에 주입. PostToolUse 훅으로 구현.
  3. Codex _handle_codex_collab() 검증 단계 — 구현 전에 별도 Codex 콜로 계획을 VERIFIED/CLARIFY/NEEDS_FIX 분류. 사전 게이트.

2. Hermes 적용 방안

삽입 지점

gateway/run.py에서 response = agent_result.get("final_response") (line 2609) 이후, 텔레그램 전송 전.

[Generator] AIAgent.run_conversation() → response
     ↓
[Evaluator] auxiliary_client로 경량 LLM 콜 → 점수 + 판정
     ↓
점수 < 3.5/5 → 재생성 요청 / 점수 >= 3.5 → 전송

구현 선택지

방식 장점 단점
A. SOUL.md에 자기평가 규칙 추가 코드 수정 0, 즉시 적용 같은 모델이 자기를 평가 → 신뢰도 낮음
B. auxiliary_client로 별도 LLM 평가 다른 모델이 평가, 비용 낮음 run.py 수정 필요 (10줄 내외)
C. agent:end 훅으로 비동기 로깅 코드 수정 0, 훅만 추가 차단 불가 (fire-and-forget)

권장: B를 메인 + A를 보조. auxiliary_client는 이미 압축/비전 등 보조 작업에 쓰이고 있어서 패턴이 확립됨. SOUL.md에는 "응답 전 정확성/완성도/톤을 자체 점검하라"는 가벼운 규칙 추가.

SOUL.md 추가 규칙 (안)

## 응답 품질 자기점검
응답을 보내기 전에 스스로 확인:
- 사실 확인: 볼트/웹에서 확인하지 않은 정보가 포함되어 있는가?
- 완성도: 질문의 모든 부분에 답했는가?
- 톤: 해리의 선호(쉬운 말, 간결)에 맞는가?
하나라도 미달이면 보완 후 응답.

3. Codex 적용 방안

현재 4개 실행 경로별 갭

경로 현재 평가 필요
_handle_codex() 표준 없음 → 바로 저장 가장 큰 갭
_handle_codex_collab() _validate_codex_result() (얕음) 깊이 추가
codex_telegram_listener.py 없음 → 바로 전송 위험
orchestrate-codex-worker.sh 없음 → handoff 파일 handoff 전 검사

삽입 지점

_handle_codex() (agent_queue_worker.py, line ~2548):

codex_result = _run_codex_exec(prompt)
# --- Evaluator 삽입 ---
eval_ok, eval_reason = _evaluate_codex_result(codex_result, original_prompt)
if not eval_ok:
    # 재시도 또는 llm_execute 폴백
    ...
# --- 기존 흐름 ---
_save_codex_pattern(title, codex_result)

_evaluate_codex_result() 설계

기존 _validate_codex_result()를 확장:

현재: 길이 < 30 → 실패, 물음표 2개+ → 질문 감지
추가:
  1. 코드 블록 존재 시 → ast.parse로 문법 검증
  2. 원래 프롬프트 대비 키워드 커버리지 (핵심 단어가 결과에 포함?)
  3. "TODO", "FIXME", "placeholder" 감지 → 미완성 경고
  4. 경량 Codex 콜(gpt-5.4-mini, read-only)로 "이 결과가 요청을 충족하는가?" 평가

codex_telegram_listener.py 보강

현재 raw stdout을 3500자 잘라서 바로 전송. 최소한: - ast.parse 통과 여부 (코드인 경우) - 결과 길이가 비정상적으로 짧으면 경고 첨부 - 에러 스택트레이스가 결과의 50% 이상이면 "실행 실패" 표시


4. Claude Code hooks 확장 방안

stop-verify.sh 현황

7개 검증 타입이 모두 하드코딩:

Type 대상 검사
1 pipeline/*.py pytest 실행
2 .json/.yaml 파싱 검증
3 hooks/scripts py_compile, bash -n
4 CLAUDE.md 필수 섹션 존재
5 knowledge/*.md frontmatter 구조
6 jobs.json 스키마 필드
7 전체 .py ast.parse + 반복수정 감지

gotchas.md 동적 룰 로더 설계

현재 gotchas.md는 존재하지 않음. 새로 만들어서 stop-verify.sh가 읽도록 확장:

파일: ~/.openclaw/workspace/gotchas.md

## oil_supply_monitor.py
- pattern: scripts/pipeline/oil_supply_monitor.py
- check: grep -c "extract_indicators" $FILE | [ $(cat) -ge 2 ]
- message: extract_indicators 함수가 정의되고 호출되는지 확인

## cron schedule
- pattern: jobs.json
- check: python3 -c "import json; [assert 'expr' in j.get('schedule',{}) for j in json.load(open('$FILE'))['jobs']]"
- message: 모든 job에 schedule.expr 필드 필수

stop-verify.sh에 Type 8 추가:

# Type 8: Dynamic gotchas
GOTCHAS="$HOME/.openclaw/workspace/gotchas.md"
if [[ -f "$GOTCHAS" ]]; then
    python3 "$HOME/.claude/hooks/gotchas-checker.py" "$GOTCHAS" $CHANGED_FILES
fi

gotchas-checker.py는 마크다운을 파싱해서 pattern에 매칭되는 변경 파일에 check 커맨드를 실행. 실패 시 message를 stderr로 출력.

의미적 평가 확장

현재 stop-verify는 구문(syntax) 검증만. 의미(semantic) 평가를 추가하려면:

[기존] stop-verify.sh (문법/구조) → exit 0/2
[추가] stop-evaluate.sh (의미/품질) → cross-model-review.sh 패턴 활용

Stop 이벤트 체인에 stop-evaluate.sh를 추가: - 변경된 파일의 diff를 Codex(read-only)에 보내서 "이 변경이 의도한 목적을 달성하는가?" 평가 - cross-model-review.sh가 PostToolUse에서 하는 것과 같은 패턴이지만, 최종 Stop 단계에서 전체 변경을 종합 평가


5. 통합 아키텍처

┌─────────────────────────────────────────────────┐
│                    Evaluator Layer               │
├────────────┬───────────────┬────────────────────┤
│  Hermes    │   Codex       │  Claude Code       │
│            │               │                    │
│ auxiliary  │ _evaluate_    │ stop-verify.sh     │
│ _client    │ codex_result  │  (Type 1-7 구문)   │
│ LLM 콜    │  ()           │  (Type 8 gotchas)  │
│            │               │                    │
│ + SOUL.md  │ + cross-model │ + stop-evaluate.sh │
│  자기점검  │  -review.sh   │  (의미적 평가)     │
└────────────┴───────────────┴────────────────────┘
         │              │              │
         ▼              ▼              ▼
    점수 < 3.5      미완성/오류     구문+의미 실패
    → 재생성        → 재시도/폴백   → exit 2 차단

공통 원칙

  1. Generator ≠ Evaluator: 같은 모델이 자기 결과를 평가하지 않음 (Hermes: auxiliary_client로 다른 모델, Codex: gpt-5.4-mini read-only, Claude Code: Codex cross-review)
  2. 빠른 게이트 우선: 구문 검사(ms) → 규칙 기반(초) → LLM 평가(5-30초) 순서
  3. 실패 시 재시도 1회, 2회 실패 시 원본+경고 전달: 무한 루프 방지
  4. gotchas.md로 규칙 축적: 반복 실패 패턴을 코드가 아닌 문서로 축적 → 배포 없이 규칙 추가

6. 구현 우선순위

순위 작업 난이도 효과
1 SOUL.md 자기점검 규칙 추가 낮음 중간 (즉시 적용)
2 gotchas.md + checker 파이프라인 중간 높음 (동적 규칙)
3 _evaluate_codex_result() 확장 중간 높음 (코드 품질)
4 Hermes auxiliary_client 평가 삽입 중간 높음 (응답 품질)
5 codex_telegram_listener 보강 낮음 중간 (안전망)
6 stop-evaluate.sh 의미적 평가 높음 높음 (전체 품질)

7. 핵심 파일 경로 참조

구성요소 경로
Hermes 게이트웨이 ~/.hermes/hermes-agent/gateway/run.py
Hermes 시스템 프롬프트 ~/.hermes/SOUL.md
Hermes 보조 클라이언트 ~/.hermes/hermes-agent/agent/auxiliary_client.py
Codex 큐 워커 ~/.openclaw/workspace/scripts/agent_queue_worker.py
Codex 텔레그램 리스너 ~/.openclaw/workspace/scripts/codex_telegram_listener.py
Codex 크로스리뷰 훅 ~/.claude/hooks/cross-model-review.sh
Claude Code stop-verify ~/.claude/hooks/stop-verify.sh
Claude Code 훅 설정 ~/.claude/settings.json
ECC 워커 스크립트 ~/.claude/plugins/.../scripts/orchestrate-codex-worker.sh