> EulerAgent > 튜토리얼 > 패턴 > 명시적 인간 검토 게이트

패턴 06. 명시적 인간 검토 게이트 — 반드시 사람이 확인하는 노드

학습 목표

이 튜토리얼을 마치면 다음을 할 수 있습니다.

사전 준비

euleragent agent list
euleragent pattern list

1. 왜 인간 검토 게이트가 필요한가?

Judge 노드(04 튜토리얼)는 LLM이 LLM의 결과를 평가합니다. 이는 빠르고 자동화되어 있지만, 다음 상황에서는 부족합니다.

법적/규정 준수 문서: 의료 정보, 법률 자문, 금융 조언은 사람이 반드시 검토해야 합니다.

외부 발행 전 최종 확인: 블로그, 보고서, 이메일이 실제로 공개되기 전 편집자가 검토.

보안 감사 결과: 취약점 보고서나 패치 계획은 반드시 보안 담당자가 승인.

고객사 납품 결과물: AI가 생성했더라도 사람 이름으로 납품되는 문서는 사람이 검토.

인간 검토 게이트는 자동화된 흐름 중에 강제적인 인간 개입 지점을 만드는 패턴입니다.


2. 핵심 메커니즘: force_tool: file.write + mode: plan

왜 file.write인가?

force_tool: file.write + mode: plan의 조합이 인간 검토 게이트가 되는 이유:

  1. LLM이 파일을 작성하는 "제안"을 합니다 (내용 포함)
  2. 시스템이 pause 상태가 됩니다
  3. 사람이 제안된 파일 내용을 검토합니다
  4. 내용이 마음에 들지 않으면 파일을 직접 편집할 수 있습니다
  5. 승인 후 파일이 실제로 저장됩니다
LLM이 draft 제안
  → approve list (내용 미리보기)
  → 사람이 내용 직접 수정 가능
  → accept-all --execute (파일 저장)
  → resume (다음 노드)

max_loops: 1의 역할

게이트 노드는 단 한 번만 실행되어야 합니다. max_loops: 1이 없으면 루프 패턴에서 게이트가 여러 번 발생할 수 있습니다.

runner:
  mode: plan
  force_tool: file.write
  max_loops: 1    # 이 노드는 정확히 한 번만 실행

3. 패턴 설계

초안 작성 후 사람이 검토하고, 검토 완료 후 Judge가 최종 평가하는 패턴.

[draft] → [human_review] ──HITL PAUSE──► 사람이 검토/편집
              │ (파일 저장 후)
              │ when: approvals_resolved
              ▼
          [evaluate] → finalize
              │
              └── revise → [evaluate] (루프)

완전한 흐름:

┌─────────────────────────────────────────────────────────────────┐
│ writing.human_review 패턴 흐름도                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [draft]                                                        │
│     │ 초안 작성 (llm/execute)                                    │
│     │ when: true                                                │
│     ▼                                                           │
│  [human_review]  ◄─── 반드시 HITL PAUSE (file.write)            │
│     │ 초안을 파일로 저장 제안 (llm/plan, max_loops=1)              │
│     │ 사람이 파일 검토/편집 가능                                    │
│     │ when: approvals_resolved                                  │
│     ▼                                                           │
│  [evaluate]  ─────── when: judge.route == finalize ─────────────┐
│     │ 검토된 초안의 품질 평가 (judge/evaluator_v1)                 │
│     │ when: judge.route == revise                               │
│     ▼                                                           │
│  [revise]                                                       │
│     │ 수정 (llm/execute)                                        │
│     └────────────────────────► [evaluate] (최대 2회)             │
│                                                                 │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │ [FINALIZE]  reviewed_document.md 저장                    │◄──┘
│  └──────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4. YAML 작성

writing_with_human_review.yaml 파일을 생성합니다.

id: writing.human_review
version: 1
category: writing
description: "초안 작성 후 인간 검토 게이트를 통과하는 문서 작성 패턴"

defaults:
  max_iterations: 2
  max_total_tool_calls: 10
  pass_threshold: 0.85

nodes:
  # ── 노드 1: draft ──
  - id: draft
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        당신은 기술 문서 작가입니다.
        주어진 주제에 대한 완성된 초안을 작성하세요.

        요구사항:
        - 전문적이고 명확한 문체
        - 적절한 섹션 구분
        - 실용적 예시 포함
        - 마크다운 포맷

        이 초안은 사람 편집자의 검토를 받을 것입니다.
        완성도 있게 작성하되, 사람이 편집할 여지를 남겨두세요.
    artifacts:
      primary: draft.md

  # ── 노드 2: human_review (인간 검토 게이트) ──
  - id: human_review
    kind: llm
    runner:
      # mode: plan + force_tool: file.write = 인간 검토 게이트의 핵심
      mode: plan
      force_tool: file.write

      # max_loops: 1 — 이 노드는 정확히 한 번만 실행됨
      # 루프가 있는 패턴에서 게이트가 반복되는 것을 방지
      max_loops: 1

    prompt:
      system_append: |
        당신은 문서 관리 보조자입니다.
        작성된 초안(draft.md)을 검토용 파일로 저장하는 제안을 하세요.

        파일 저장 시:
        - 경로: review/document_for_review.md
        - 파일 상단에 다음 헤더를 추가하세요:
          <!-- 검토 요청: [날짜]
               검토자: [담당자]
               검토 사항: 내용의 정확성, 톤, 불필요한 섹션 확인
          -->
        - 이후 초안 내용을 그대로 포함

        이 파일은 사람이 직접 편집할 것입니다.

    # 파일 쓰기 예산 (보통 1개면 충분)
    guardrails:
      tool_call_budget:
        file.write: 1

    artifacts:
      primary: review/document_for_review.md

  # ── 노드 3: evaluate (Judge) ──
  - id: evaluate
    kind: judge
    judge:
      schema: evaluator_v1
      route_values: [finalize, revise]
    prompt:
      system_append: |
        사람이 검토/편집한 문서(review/document_for_review.md)를 평가하세요.

        주의: 이 문서는 사람 편집자가 이미 검토했습니다.
        기술적 내용보다 최종 발행 준비 상태에 집중하세요:

        - 구조적 완결성 (30%): 모든 섹션이 논리적으로 연결되는가?
        - 언어 품질 (30%): 문체가 일관되고 명확한가?
        - 발행 준비도 (40%): 추가 수정 없이 바로 발행 가능한가?

        score >= 0.85 → finalize
        score < 0.85 → revise (구체적인 개선점 명시)

  # ── 노드 4: revise ──
  - id: revise
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        편집장의 피드백을 반영하여 문서를 개선하세요.
        사람이 편집한 내용(review/document_for_review.md)을 기반으로 합니다.
        수정된 전체 문서를 다시 작성하세요.
    artifacts:
      primary: review/document_for_review.md

edges:
  - from: draft
    to: human_review
    when: "true"

  # human_review 노드는 HITL pause 후 승인이 완료됐을 때만 다음으로 이동
  - from: human_review
    to: evaluate
    when: "approvals_resolved"

  - from: evaluate
    to: finalize
    when: "judge.route == finalize"

  - from: evaluate
    to: revise
    when: "judge.route == revise"

  - from: revise
    to: evaluate
    when: "true"

finalize:
  artifact: review/document_for_review.md

5. 검증

euleragent pattern validate writing_with_human_review.yaml

예상 출력:

Validating pattern: writing_with_human_review.yaml

  Stage 1 (Schema)      PASS
  Stage 2 (Structural)  PASS
  Stage 3 (IR Analysis) PASS
    HITL gates: human_review (file.write, max_loops=1) ✓
    Note: human_review gate will pause exactly once per run ✓
    Cycle bounded: max_iterations=2 ✓

Validation complete: 0 errors, 0 warnings

6. 단계별 실행

단계 1: 실행 시작

cp writing_with_human_review.yaml .euleragent/patterns/

euleragent pattern run writing.human_review my-agent \
  --task "사내 AI 도구 사용 가이드라인 문서 작성 — 허용 사용 사례, 금지 사항, 데이터 보안 주의사항 포함" \
  --project default

예상 출력:

[run:i9e5d3c7] Starting pattern: writing.human_review

  ✓ draft         Completed (14s) — draft.md generated (1,456 words)
  ⏸ human_review  PAUSED — Waiting for HITL approval (file.write × 1)

Approval required:
  euleragent approve list --run-id i9e5d3c7

단계 2: 파일 내용 미리보기

euleragent approve list --run-id i9e5d3c7

예상 출력:

Pending Approvals for run: i9e5d3c7
─────────────────────────────────────────────────
Node: human_review (max_loops=1, human gate)

  #1  file.write  path=review/document_for_review.md
      Content preview (first 20 lines):
      ┌─────────────────────────────────────────────┐
      │ <!-- 검토 요청: 2026-02-23                   │
      │      검토자: [담당자]                         │
      │      검토 사항: 내용의 정확성, 톤, 불필요한 섹션 │
      │ -->                                         │
      │                                             │
      │ # 사내 AI 도구 사용 가이드라인                  │
      │                                             │
      │ ## 1. 목적                                   │
      │ 이 가이드라인은 조직 내 AI 도구의 책임있는       │
      │ 사용을 위해 작성되었습니다...                    │
      └─────────────────────────────────────────────┘
      [Full content: 1,456 words, 89 lines]

  ⚠️  HUMAN GATE: This node requires human review before proceeding.
       You may edit the file content before approving.

단계 3: 내용 직접 수정 (선택)

미리보기를 보고 내용을 수정하고 싶으면, 파일을 직접 편집합니다.

# 파일 내용을 먼저 추출해서 편집
euleragent approve show --run-id i9e5d3c7 --item 1 > /tmp/review_draft.md

# 선호하는 에디터로 수정
vim /tmp/review_draft.md
# 또는
code /tmp/review_draft.md

# 수정된 내용으로 대체 후 승인
euleragent approve accept --run-id i9e5d3c7 --item 1 \
  --content-file /tmp/review_draft.md \
  --execute

수정 없이 그대로 승인하는 경우:

euleragent approve accept-all --run-id i9e5d3c7 --execute

예상 출력:

Accepted item #1 (file.write) for run: i9e5d3c7
Writing file: review/document_for_review.md ... OK (1,456 bytes)
Human gate passed. Resuming pattern...

단계 4: 패턴 재개

euleragent pattern resume i9e5d3c7 --execute

예상 출력:

[run:i9e5d3c7] Resuming from: human_review → evaluate

  ✓ human_review  Completed — review/document_for_review.md saved
  ✓ evaluate      Completed — score: 0.93 → route: finalize
  ✓ finalize      Completed

Artifact: .euleragent/runs/i9e5d3c7/artifacts/review/document_for_review.md

7. 저장된 파일 확인

# 사람이 검토/편집한 최종 문서
cat .euleragent/runs/i9e5d3c7/artifacts/review/document_for_review.md

# 원본 AI 초안 (비교용)
cat .euleragent/runs/i9e5d3c7/artifacts/draft.md

# 승인 기록
cat .euleragent/runs/i9e5d3c7/approvals.jsonl

승인 기록 예시:

{"ts":"2026-02-23T14:40:22Z","run_id":"i9e5d3c7","node":"human_review","action":"accept","item":1,"tool":"file.write","path":"review/document_for_review.md","content_modified":true,"operator":"sean","note":"금지사항 섹션에 내용 추가"}

8. Judge 평가와 인간 검토의 차이

기준 Judge (자동) Human Gate (수동)
속도 빠름 (초 단위) 느림 (분~시간)
일관성 높음 (항상 같은 기준) 낮음 (사람마다 다름)
창의적 판단 낮음 높음
규정 준수 보장 낮음 높음
책임 소재 AI 사람
편집 능력 없음 있음

Judge를 사용하는 경우: 품질 기준이 명확하고, 속도가 중요하고, 반복 실행이 많을 때.

Human Gate를 사용하는 경우: 법적/윤리적 책임이 있을 때, 창의적 판단이 필요할 때, 내용이 외부에 공개될 때.


9. 주요 개념 설명

human_review 노드가 루프 내에 있으면?

만약 revise → human_review → evaluate 루프가 있다면, max_loops: 1이 없을 때 매 루프마다 사람이 검토해야 합니다. 이는 의도적일 수 있지만, 대부분의 경우 비효율적입니다.

max_loops: 1을 설정하면 이 노드는 전체 run에서 한 번만 실행됩니다. 두 번째 루프에서는 이 노드를 건너뜁니다.

approvals_resolved vs true

human_review 노드 다음 엣지에 when: "true"를 사용하면:

반드시 when: "approvals_resolved"를 사용하세요.

파일 편집과 승인의 순서

승인 흐름: 1. euleragent approve list — 제안된 내용 확인 2. (선택) 파일 내용 편집 (--content-file 옵션) 3. euleragent approve accept-all --execute — 실제 파일 저장 및 계속

편집 없이 승인하면 LLM이 제안한 내용 그대로 저장됩니다.


10. 실습 과제: 보안 감사 패턴

보안 취약점 보고서를 작성하고 보안 담당자가 반드시 검토하는 패턴을 만들어보세요.

요구사항

힌트 YAML 구조

id: security.audit_review
version: 1
category: ops
description: "취약점 보고서 작성 + 보안 담당자 필수 검토 패턴"

defaults:
  max_iterations: 1
  max_total_tool_calls: 20

nodes:
  - id: scan
    kind: llm
    runner:
      mode: execute
      # 파일 읽기만 허용, 외부 연결 금지
      exclude_tools: [web.search, web.fetch, shell.exec]
    # ...

  - id: draft_report
    kind: llm
    # ...

  - id: security_review
    kind: llm
    runner:
      mode: plan
      force_tool: file.write
      max_loops: 1        # 반드시!
    # ...

  - id: severity_judge
    kind: judge
    judge:
      schema: evaluator_v1
      route_values: [critical, high_medium, low]
    # ...

  - id: escalate
    kind: llm
    # ...

edges:
  - from: security_review
    to: severity_judge
    when: "approvals_resolved"    # 반드시!

  - from: severity_judge
    to: escalate
    when: "judge.route == critical"

  - from: severity_judge
    to: finalize
    when: "judge.route == high_medium"

  - from: severity_judge
    to: finalize
    when: "judge.route == low"
  # ...

finalize:
  artifact: security_report.md

검증:

euleragent pattern validate security_audit.yaml

JUDGE_ROUTE_COVERAGE_ERROR가 발생하지 않는지 확인하고, 모든 route_values에 엣지가 있는지 점검하세요.


다음 단계

인간 검토 게이트 패턴을 구현했습니다. 이제 Judge에서 더 복잡한 다중 경로 라우팅을 다룹니다.

← 이전: 웹 리서치 통합 목록으로 다음: 다중 경로 Judge →