Home > EulerAgent > Tutorials > Pattern > Pattern 09. Advanced Patterns — Dual Judge, Complex Topol...

Pattern 09. Advanced Patterns — Dual Judge, Complex Topology, Deployment

Learning Objectives

After completing this tutorial, you will be able to:

Prerequisites

euleragent pattern list
euleragent agent list

1. When Dual Judge Patterns Are Needed

A single Judge evaluates from one perspective. Sometimes evaluation from two independent perspectives is required.

Blog + SEO: Content quality (readability, informativeness) and SEO optimization (keywords, metadata) require different areas of expertise.

Code + Security: Functional correctness and security vulnerabilities must be evaluated independently. Even if the functionality is perfect, security vulnerabilities are unacceptable.

Documentation + Legal Review: Cases where a separate legal compliance review is needed after technical accuracy review.

Design Principle: The two Judges must not cross each other's loops. Design them as independent chains.


2. Dual Judge Architecture

Serial Dual Judge (Sequential)

The second Judge independently evaluates only after the first Judge passes.

[draft] → [content_judge] → content_revise → content_judge (루프)
               │ (finalize 선택 시)
               ▼
          [technical_judge] → tech_revise → technical_judge (루프)
               │ (finalize 선택 시)
               ▼
          [FINALIZE]

Key characteristics of this design: - The content_judge loop and technical_judge loop are completely separate - Technical evaluation only proceeds when content is sufficiently good - Each Judge has its own independent max_iterations


3. Pattern Design: Blog + SEO Dual Evaluation

Node Flow Diagram

┌─────────────────────────────────────────────────────────────────┐
│ writing.dual_judge 패턴 흐름도                                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [draft]                                                        │
│     │ 블로그 초안 작성 (llm/execute)                               │
│     │ when: true                                                │
│     ▼                                                           │
│  ─── STAGE 1: 콘텐츠 평가 사이클 ─────────────────────────────   │
│                                                                 │
│  [content_judge] ── when: judge.route == content_ok ────────────┐
│     │ 콘텐츠 품질 평가 (judge/evaluator_v1)                       │
│     │ routes: [content_ok, content_revise]                      │
│     │ when: judge.route == content_revise                       │
│     ▼                                                           │
│  [content_revise]                                               │
│     │ 콘텐츠 개선 (llm/execute)                                  │
│     └──────────────────────────► [content_judge] (최대 3회)      │
│                                                                 │
│  ─── STAGE 2: SEO 평가 사이클 ─────────────────────────────────  │
│                                                                 │
│  [seo_optimize] ◄────────────────────────────────────────────-──┘
│     │ SEO 최적화 (llm/execute)                                   │
│     │ when: true                                                │
│     ▼                                                           │
│  [seo_judge] ── when: judge.route == seo_ok ────────────────────┐
│     │ SEO 품질 평가 (judge/evaluator_v1)                         │
│     │ routes: [seo_ok, seo_revise]                              │
│     │ when: judge.route == seo_revise                           │
│     ▼                                                           │
│  [seo_revise]                                                   │
│     │ SEO 재최적화 (llm/execute)                                  │
│     └──────────────────────────► [seo_judge] (최대 2회)          │
│                                                                 │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │ [FINALIZE]  final_post.md 저장                           │◄──┘
│  └──────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4. Writing the YAML

Create the dual_judge_blog.yaml file.

id: writing.dual_judge
version: 1
category: writing
description: "콘텐츠 품질 + SEO 최적화 이중 Judge 블로그 작성 패턴"

defaults:
  # 이중 사이클이 있으므로 충분한 max_iterations
  # content_judge 사이클 최대 3회 + seo_judge 사이클 최대 2회
  # defaults.max_iterations는 전체 사이클 총합에 적용됨
  max_iterations: 5
  max_total_tool_calls: 30
  pass_threshold: 0.85

nodes:
  # ── STAGE 1: 초안 작성 ──

  - id: draft
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        당신은 기술 블로그 작가입니다.
        주제에 대한 완성된 블로그 포스트 초안을 작성하세요.

        요구사항:
        - 길이: 1000-1500 단어
        - 구성: 도입 → 본문(3섹션) → 결론
        - 코드 예시 포함
        - 마크다운 포맷
    artifacts:
      primary: draft.md

  # ── STAGE 1: 콘텐츠 평가 사이클 ──

  - id: content_judge
    kind: judge
    judge:
      schema: evaluator_v1
      # content 전용 route_values — seo_judge와 독립적
      route_values: [content_ok, content_revise]
    prompt:
      system_append: |
        당신은 기술 블로그 편집장입니다.
        다음 기준으로 콘텐츠 품질만 평가하세요. (SEO는 나중에 별도 평가)

        평가 기준:
        - 기술적 정확성 (35%): 정보가 정확하고 최신인가?
        - 독자 가치 (30%): 실용적 통찰과 배움이 있는가?
        - 구성과 흐름 (20%): 논리적으로 연결되는가?
        - 코드 품질 (15%): 예시가 실행 가능하고 명확한가?

        score >= 0.85 → 'content_ok' (SEO 단계로 진행)
        score < 0.85 → 'content_revise' (콘텐츠 개선 필요)

  - id: content_revise
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        편집장의 콘텐츠 피드백을 반영하여 블로그 포스트를 개선하세요.
        SEO는 아직 고려하지 마세요. 콘텐츠 품질에만 집중하세요.
    artifacts:
      primary: draft.md

  # ── STAGE 2: SEO 최적화 + 평가 사이클 ──

  - id: seo_optimize
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        콘텐츠 품질 평가를 통과한 포스트를 SEO 관점에서 최적화하세요.

        SEO 최적화 항목:
        1. 제목 태그: H1에 주요 키워드 포함 (60자 이내)
        2. 메타 설명: 150-160자, 키워드 포함, 클릭 유도
        3. 헤딩 구조: H1→H2→H3 계층 구조
        4. 키워드 밀도: 1-2% (과다 사용 금지)
        5. 내부 링크 제안: [관련 포스트: ...] 형식
        6. 이미지 alt 텍스트 제안 (이미지가 있는 경우)
        7. 포스트 하단에 SEO 메타데이터 섹션 추가:
           ```
           <!-- SEO
           title: ...
           description: ...
           keywords: ...
           -->
           ```
    artifacts:
      primary: seo_draft.md

  - id: seo_judge
    kind: judge
    judge:
      schema: evaluator_v1
      # seo_judge 전용 route_values — content_judge와 독립적
      route_values: [seo_ok, seo_revise]
    prompt:
      system_append: |
        당신은 SEO 전문가입니다.
        콘텐츠 품질은 이미 검증됐습니다. SEO 측면만 평가하세요.

        평가 기준:
        - 키워드 최적화 (30%): 자연스럽게 키워드가 포함됐는가?
        - 제목 최적화 (25%): 클릭률을 높이는 제목인가?
        - 메타 설명 (20%): 검색 결과에서 클릭을 유도하는가?
        - 구조 최적화 (25%): 헤딩 계층, 가독성이 검색 엔진 친화적인가?

        score >= 0.80 → 'seo_ok' (최종 발행 준비 완료)
        score < 0.80 → 'seo_revise' (SEO 재최적화 필요)

  - id: seo_revise
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        SEO 전문가의 피드백을 반영하여 SEO를 재최적화하세요.
        콘텐츠 내용은 변경하지 마세요. SEO 요소만 개선하세요.
    artifacts:
      primary: seo_draft.md

edges:
  # Stage 1: 초안 → 콘텐츠 평가
  - from: draft
    to: content_judge
    when: "true"

  # Stage 1: 콘텐츠 사이클
  - from: content_judge
    to: seo_optimize        # content_ok → Stage 2로 진행
    when: "judge.route == content_ok"

  - from: content_judge
    to: content_revise      # content_revise → 콘텐츠 개선
    when: "judge.route == content_revise"

  - from: content_revise
    to: content_judge       # 콘텐츠 재평가
    when: "true"

  # Stage 2: SEO 사이클
  - from: seo_optimize
    to: seo_judge
    when: "true"

  - from: seo_judge
    to: finalize            # seo_ok → 최종 완료
    when: "judge.route == seo_ok"

  - from: seo_judge
    to: seo_revise          # seo_revise → SEO 재최적화
    when: "judge.route == seo_revise"

  - from: seo_revise
    to: seo_judge           # SEO 재평가
    when: "true"

finalize:
  artifact: seo_draft.md

5. Validation

euleragent pattern validate dual_judge_blog.yaml

Expected output:

Validating pattern: dual_judge_blog.yaml

  Stage 1 (Schema)      PASS
  Stage 2 (Structural)  PASS
    Judge node 'content_judge':
      content_ok     → seo_optimize ✓
      content_revise → content_revise ✓
    Judge node 'seo_judge':
      seo_ok     → finalize ✓
      seo_revise → seo_revise ✓
    All route_values covered ✓

  Stage 3 (IR Analysis) PASS
    Cycles detected:
      1. content_judge → content_revise → content_judge
         bounded_by: max_iterations=5 ✓
      2. seo_judge → seo_revise → seo_judge
         bounded_by: max_iterations=5 ✓
    Cycles are independent (no intersection) ✓
    Entry node: draft ✓
    All paths reach finalize ✓

Validation complete: 0 errors, 0 warnings

6. Design Considerations for Complex Topologies

Consideration 1: Entry Node Uniqueness

There must be exactly one entry node (a node with no incoming edges).

# 잘못된 예 — MULTIPLE_ENTRY_NODES
nodes:
  - id: draft       # 수신 엣지 없음 ← 진입점 1
  - id: outline     # 수신 엣지 없음 ← 진입점 2

edges:
  - from: draft
    to: content_judge
    when: "true"
  # outline에서 content_judge로 가는 엣지도 있다면?
  # → MULTIPLE_ENTRY_NODES
euleragent pattern validate broken_multi_entry.yaml
ERROR [MULTIPLE_ENTRY_NODES]
  Nodes with no incoming edges: draft, outline
  Only one entry node is allowed.

  Fix: Connect one of these nodes with an incoming edge,
  or merge them into a single entry node.

Consideration 2: Preventing Cycle Intersection

When two cycles share a node, complex behavior arises.

# 잘못된 예 — 사이클 교차
content_judge → content_revise → content_judge  (사이클 1)
seo_judge → content_revise → seo_judge          (사이클 2)
            ↑ content_revise가 두 사이클에 속함!

This kind of design makes max_iterations counting complex, and the context of which Judge requested the revision gets mixed up. Keep cycles independent.

Consideration 3: FINALIZE_UNREACHABLE

All paths must reach finalize.

# 컴파일 출력에서 모든 경로 확인
euleragent pattern compile dual_judge_blog.yaml | \
  python3 -c "
import json, sys
d = json.load(sys.stdin)
for route, info in d.get('route_coverage', {}).items():
    print(f'{route}: reaches_finalize={info[\"reaches_finalize\"]}')
"

Consideration 4: Unreachable Nodes

Nodes that are defined but not connected to any edge:

WARNING [UNREACHABLE_NODE]
  Node 'orphan_node' is defined but has no incoming edges
  and is not the entry node. It will never be executed.

This is a WARNING, not an ERROR. Validation passes but the node is never executed.


7. Execution Example

cp dual_judge_blog.yaml .euleragent/patterns/

euleragent pattern run writing.dual_judge my-agent \
  --task "쿠버네티스 Horizontal Pod Autoscaler(HPA) 완전 가이드" \
  --project default \
  --stream

Streaming output:

[event] pattern.start  {pattern: writing.dual_judge}
[event] node.start     {node: draft}
[event] node.complete  {node: draft, words: 1234}
[event] node.start     {node: content_judge, iteration: 1}
[event] node.complete  {node: content_judge, score: 0.79, route: content_revise}
[event] node.start     {node: content_revise, iteration: 1}
[event] node.complete  {node: content_revise}
[event] node.start     {node: content_judge, iteration: 2}
[event] node.complete  {node: content_judge, score: 0.88, route: content_ok}
[event] edge.traverse  {from: content_judge, to: seo_optimize, reason: "judge.route == content_ok"}
[event] node.start     {node: seo_optimize}
[event] node.complete  {node: seo_optimize}
[event] node.start     {node: seo_judge, iteration: 1}
[event] node.complete  {node: seo_judge, score: 0.91, route: seo_ok}
[event] edge.traverse  {from: seo_judge, to: finalize, reason: "judge.route == seo_ok"}
[event] pattern.complete  {artifact: seo_draft.md}

Final summary:

[run:n5e8j2k6] Pattern: writing.dual_judge

  ✓ draft            Completed (13s) — 1,234 words
  ✓ content_judge    Completed (7s)  — score: 0.79 → content_revise (iteration 1)
  ✓ content_revise   Completed (15s) — improved
  ✓ content_judge    Completed (6s)  — score: 0.88 → content_ok (iteration 2)
  ✓ seo_optimize     Completed (9s)
  ✓ seo_judge        Completed (5s)  — score: 0.91 → seo_ok (iteration 1)
  ✓ finalize         Completed

Iterations: content_judge×2, seo_judge×1
Artifact: .euleragent/runs/n5e8j2k6/artifacts/seo_draft.md

8. ID Naming Conventions

Pattern IDs are recommended to follow the category.descriptor format.

Analyzing Built-in Pattern Examples

Pattern ID Category Descriptor Meaning
report.evidence report evidence Evidence-based report
code.tdd code tdd Test-driven development
ops.triage ops triage Operations triage
research.broad_to_narrow research broad_to_narrow Broad-to-deep research

Recommended Categories

Category Description Examples
report Report writing report.evidence, report.competitor
code Code-related code.tdd, code.pr_review, code.refactor
ops Operations/Infrastructure ops.triage, ops.incident, ops.deploy
research Investigation/Analysis research.broad_to_narrow, research.lit_review
writing Documentation/Content writing.blog, writing.newsletter
security Security security.audit, security.threat_model
docs Internal documentation docs.faq_update, docs.onboarding

Incorrect ID Formats

id: myPattern          # 카멜케이스 — 비권장
id: my_pattern         # 언더스코어 — 비권장
id: MY.PATTERN         # 대문자 — 비권장
id: my.complex.pattern.v2  # 3단계 이상 — 비권장
id: blog               # 카테고리 없음 — 비권장
id: writing.dual_judge  # 권장
id: ops.internal_triage # 권장
id: code.security_audit # 권장

9. Workspace Deployment

Deploy completed patterns to your workspace.

# 패턴 디렉토리 확인
ls .euleragent/patterns/

# 배포
cp dual_judge_blog.yaml .euleragent/patterns/dual_judge_blog.yaml

# 배포 확인
euleragent pattern list

Expected output:

Built-in Patterns
─────────────────────────────────────────────────────────
  report.evidence          research   Evidence-based report writing
  code.tdd                 code       Test-driven development workflow
  ops.triage               ops        Operations ticket triage
  research.broad_to_narrow research   Broad-to-narrow research synthesis

Workspace Patterns (.euleragent/patterns/)
─────────────────────────────────────────────────────────
  blog.quality_loop        writing    Judge 노드로 품질 루프를 갖춘 블로그 작성 패턴
  blog.web_research        writing    웹 검색 + Judge 루프가 결합된 고품질 블로그 작성 패턴
  code.pr_review           code       PR 코드 리뷰 — 승인/수정요청/거절 3-way Judge 라우팅
  docs.faq_update          docs       사내 FAQ 업데이트 — 에어갭, 인간 검토 게이트
  my_first.pattern         writing    주제를 입력받아 기술 블로그 포스트를 작성하는 단순 선형 패턴
  ops.internal_triage      ops        에어갭 고객 지원 트리아지
  ops.policy_compliant     ops        내부 정책 로드 → 분류 → 초안 → 정책 준수 검토 게이트
  writing.dual_judge       writing    콘텐츠 품질 + SEO 최적화 이중 Judge 블로그 작성 패턴
  writing.human_review     writing    초안 작성 후 인간 검토 게이트를 통과하는 문서 작성 패턴

13 patterns available (4 built-in + 9 workspace).

Deployed patterns can be referenced directly by their ID:

euleragent pattern validate writing.dual_judge
euleragent pattern show writing.dual_judge
euleragent pattern run writing.dual_judge my-agent --task "..."

10. Practice Exercise: Blog Writing + SEO Dual Evaluation Variant

Exercise: Global Deployment Pattern

A pattern that writes the original in Korean, then separately evaluates translation quality and SEO.

[draft_korean] → [translation] → [translation_quality_judge]
                                       │ ok → [seo_optimize_english]
                                       │         → [seo_judge] → finalize
                                       │ revise → [retranslate] → [translation_quality_judge]
id: writing.global_publish
version: 1
category: writing
description: "한국어 원문 작성  영어 번역 품질 평가  SEO 최적화 이중 Judge 패턴"

defaults:
  max_iterations: 4
  max_total_tool_calls: 25

nodes:
  - id: draft_korean
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        한국어로 완성된 기술 블로그 포스트를 작성하세요.
        길이: 800-1000 단어. 전문적이고 명확한 문체.

  - id: translation
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        한국어 블로그 포스트를 영어로 번역하세요.
        직역 대신 자연스러운 영어 표현을 사용하세요.
        기술 용어는 영어 원어를 사용하세요.

  - id: translation_quality_judge
    kind: judge
    judge:
      schema: evaluator_v1
      route_values: [translation_ok, retranslate]
    prompt:
      system_append: |
        영어 번역의 품질을 평가하세요.
        - 자연스러운 영어 표현 (40%)
        - 기술적 정확성 유지 (35%)
        - 문화적 적절성 (25%)

        score >= 0.82 → 'translation_ok'
        score < 0.82 → 'retranslate'

  - id: retranslate
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        번역 품질 피드백을 반영하여 영어 번역을 개선하세요.
        원문의 의미를 유지하면서 더 자연스러운 영어로 수정하세요.

  - id: seo_optimize_english
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: |
        영어 번역 포스트를 영어권 독자를 위한 SEO로 최적화하세요.
        영어 SEO 키워드 전략을 적용하세요.

  - id: seo_judge
    kind: judge
    judge:
      schema: evaluator_v1
      route_values: [seo_ok, seo_revise]
    prompt:
      system_append: |
        영어권 SEO 기준으로 평가하세요.
        score >= 0.78 → 'seo_ok'
        score < 0.78 → 'seo_revise'

  - id: seo_revise
    kind: llm
    runner:
      mode: execute
      exclude_tools: [web.search, web.fetch, shell.exec]
    prompt:
      system_append: SEO 피드백 반영. 콘텐츠 내용 변경 금지.

edges:
  - from: draft_korean
    to: translation
    when: "true"

  - from: translation
    to: translation_quality_judge
    when: "true"

  - from: translation_quality_judge
    to: seo_optimize_english
    when: "judge.route == translation_ok"

  - from: translation_quality_judge
    to: retranslate
    when: "judge.route == retranslate"

  - from: retranslate
    to: translation_quality_judge
    when: "true"

  - from: seo_optimize_english
    to: seo_judge
    when: "true"

  - from: seo_judge
    to: finalize
    when: "judge.route == seo_ok"

  - from: seo_judge
    to: seo_revise
    when: "judge.route == seo_revise"

  - from: seo_revise
    to: seo_judge
    when: "true"

finalize:
  artifact: final_english_post.md

Validation:

euleragent pattern validate writing_global_publish.yaml

Verify that the route_values for both Judges are fully covered.


11. Common Errors and Solutions

Error 1: Shared max_iterations Within Cycles

In a dual Judge pattern, both cycles share defaults.max_iterations. If you set max_iterations: 3, the content_judge might use 3 iterations and seo_judge might only get 1. Set a sufficiently large value.

Error 2: JUDGE_DEAD_END in Complex Topology

When a specific Judge route cannot reach finalize in a complex graph:

euleragent pattern validate complex_pattern.yaml --format json | \
  python3 -c "
import json, sys
result = json.load(sys.stdin)
for err in result['stages']['ir_analysis']['errors']:
    print(err['code'], err['message'])
"

Error 3: Mixed Memory Context

In a dual Judge pattern, if the stage 2 (SEO) Judge receives evaluation context from stage 1 (content), the evaluations can become mixed. Clearly restrict this in system_append with phrases like "Evaluate only SEO."


Next Steps

You have completed advanced pattern design. Now we move on to the complete reference covering all fields, error codes, and design checklists.

← Prev Back to List Next →