패턴 10. 완전 레퍼런스 — 필드, 에러 코드, 설계 체크리스트
이 문서는 튜토리얼이 아닌 참고서입니다. 에러 코드가 발생하거나, 특정 필드의 의미가 궁금할 때 언제든 참조하세요.
1. 모든 YAML 필드 테이블
최상위 필드 (Top-Level)
| 필드 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
id |
string | 필수 | — | 패턴의 고유 식별자. category.descriptor 형식 권장 |
version |
integer | 필수 | — | 스키마 버전. 현재 항상 1 |
category |
string | 필수 | — | 패턴 카테고리 (research, code, ops, writing 등 자유 문자열) |
description |
string | 필수 | — | 패턴 설명. pattern list와 pattern show에 표시됨 |
defaults |
object | 선택 | — | 모든 노드에 공통 적용되는 설정 |
nodes |
list | 필수 | — | 노드 정의 목록 (finalize 제외) |
edges |
list | 필수 | — | 엣지(전환 조건) 정의 목록 |
finalize |
object | 필수 | — | 최종 노드 설정. nodes 배열에 포함하지 않음 |
defaults 필드
| 필드 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
max_iterations |
integer | 사이클 있으면 필수 | — | 사이클 내 루프 최대 횟수. 초과 시 강제 finalize |
max_total_tool_calls |
integer | 선택 | 무제한 | 전체 실행에서 모든 도구 호출 합산 최대값 |
max_web_search_calls |
integer | 선택 | 무제한 | 전체 실행에서 web.search 호출 최대값 |
pass_threshold |
float | 선택 | 0.85 | Judge의 finalize 판단 기준 점수 (런타임 힌트) |
dedupe_web_search |
boolean | 선택 | false | true이면 동일 쿼리 중복 실행 방지 |
nodes 항목 필드
| 필드 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
id |
string | 필수 | — | 노드 고유 ID. finalize는 예약어 사용 불가 |
kind |
enum | 필수 | — | llm 또는 judge. finalize는 최상위 키로 선언 |
runner |
object | 선택 | — | 실행 방식 설정 |
runner.mode |
enum | 선택 | execute |
execute (직접 실행) 또는 plan (HITL 승인 후 실행) |
runner.force_tool |
string | 선택 | — | 이 도구를 반드시 사용/제안. mode: plan과 함께 사용 |
runner.exclude_tools |
list | 선택 | [] | 이 노드에서 사용 금지할 도구 목록 |
runner.min_proposals |
integer | 선택 | — | mode: plan에서 최소 제안 횟수 |
runner.max_loops |
integer | 선택 | — | 이 노드의 최대 실행 횟수 |
prompt |
object | 선택 | — | 프롬프트 설정 |
prompt.system_append |
string | 선택 | — | 에이전트 기본 시스템 프롬프트에 추가되는 텍스트 |
guardrails |
object | 선택 | — | 보안/예산 제한 설정 |
guardrails.tool_call_budget |
object | 선택 | — | {도구명: 최대횟수} 형식의 노드별 도구 예산 |
artifacts |
object | 선택 | — | 아티팩트 설정 |
artifacts.primary |
string | 선택 | — | 이 노드의 주요 출력 파일명 |
judge |
object | kind=judge 필수 | — | Judge 노드 전용 설정 |
judge.schema |
string | 필수 | — | 평가 스키마. 현재 evaluator_v1만 지원 |
judge.route_values |
list | 필수 | — | Judge가 선택 가능한 라우팅 값 목록 |
edges 항목 필드
| 필드 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
from |
string | 필수 | — | 출발 노드 ID |
to |
string | 필수 | — | 도착 노드 ID. finalize는 예약 값 |
when |
string | 필수 | — | 전환 조건. when DSL 문법 참조 |
finalize 필드
| 필드 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
artifact |
string | 필수 | — | 최종 결과물로 저장할 아티팩트 파일명 |
2. when DSL 문법 완전 가이드
when 필드는 엣지의 전환 조건을 정의합니다.
형식 1: 항상 전환
when: "true"
- 출발 노드 완료 즉시 무조건 도착 노드로 이동합니다
- HITL pause가 있는 노드에서는 사용하지 마세요 (pause가 즉시 해제됨)
- 선형 흐름에서 가장 많이 사용합니다
형식 2: HITL 승인 완료 후
when: "approvals_resolved"
- 출발 노드의 모든 HITL 승인 항목이 처리됐을 때 이동합니다
force_tool이 있는 노드(mode: plan) 다음 엣지에 반드시 사용하세요- 거절(reject)된 항목은 실행되지 않지만, 모두 처리되면 resolved로 간주합니다
형식 3: Judge 라우팅
when: "judge.route == finalize"
when: "judge.route == revise"
when: "judge.route == approve"
- 출발 노드(judge 타입)의 라우팅 결과가 지정 값과 일치할 때 이동합니다
judge.route_values에 선언된 값만 사용 가능합니다- 대소문자를 정확히 맞춰야 합니다 (대소문자 구분)
형식 4: Judge 점수 비교
when: "judge.score >= 0.85"
when: "judge.score < 0.70"
when: "judge.score >= 0.90"
- 출발 노드(judge 타입)의 점수가 조건을 만족할 때 이동합니다
judge.route와judge.score를 조합할 수 없습니다 (한 엣지에 하나만)- 0.0~1.0 범위
잘못된 when 문법
# 존재하지 않는 형식 — INVALID_WHEN_DSL
when: "judge.route == finalize AND judge.score > 0.8" # AND 조합 불가
when: "node_complete" # 알 수 없는 키워드
when: "score > 0.5" # 'judge.' 접두어 필요
when: "" # 빈 문자열 불가
when: true # boolean, string이어야 함
3. 전체 에러 코드 테이블
Stage 2 에러 코드 (YAML Structural Validation)
| 코드 | 심각도 | 발생 조건 | 해결법 |
|---|---|---|---|
DUPLICATE_NODE_ID |
ERROR | nodes 배열에 같은 id가 두 번 이상 존재 |
중복 노드 ID를 고유하게 변경 |
RESERVED_NODE_ID |
ERROR | nodes에 finalize를 ID로 사용 |
노드 ID를 final_step 등으로 변경, 최종 노드는 최상위 finalize: 키로 선언 |
EDGE_UNKNOWN_NODE |
ERROR | 엣지의 from 또는 to가 존재하지 않는 노드를 참조 |
오타 확인. 노드 ID와 엣지 참조를 정확히 일치시킴 |
INVALID_WHEN_DSL |
ERROR | when 필드가 지원되는 DSL 형식이 아님 |
when DSL 문법 섹션 참조. "true", "approvals_resolved", "judge.route == ...", "judge.score >= ..." 형식만 유효 |
HITL_GATING_VIOLATION |
ERROR | force_tool이 설정됐는데 mode: execute 사용 |
mode: plan으로 변경 |
JUDGE_SCHEMA_MISSING |
ERROR | kind: judge 노드에 judge.schema가 없음 |
judge.schema: evaluator_v1 추가 |
FORCE_EXCLUDE_CONFLICT |
ERROR | force_tool과 exclude_tools가 같은 도구를 지정 |
exclude_tools에서 force_tool과 겹치는 도구 제거 |
JUDGE_ROUTE_VALUES_MISSING |
ERROR | kind: judge 노드에 judge.route_values가 없음 |
judge.route_values: [finalize, revise] 추가 |
DUPLICATE_ROUTE_VALUE |
ERROR | route_values에 같은 값이 두 번 이상 선언됨 |
중복 route_value 제거 |
JUDGE_ROUTE_COVERAGE_ERROR |
ERROR | route_values 중 해당하는 엣지가 없는 값이 존재 |
누락된 route_value에 대한 엣지 추가 |
Stage 3 에러 코드 (IR Analysis)
| 코드 | 심각도 | 발생 조건 | 해결법 |
|---|---|---|---|
NO_ENTRY_NODE |
ERROR | 모든 노드에 수신 엣지가 있어서 진입점이 없음 | 첫 번째 노드에 연결된 모든 수신 엣지 제거 |
MULTIPLE_ENTRY_NODES |
ERROR | 수신 엣지가 없는 노드가 2개 이상 | 진입점이 아닌 노드에 수신 엣지 추가 |
NO_FINALIZE |
ERROR | 최상위 finalize: 키가 없음 |
finalize: artifact: result.md 추가 |
UNBOUNDED_CYCLE |
ERROR | 사이클이 감지됐는데 defaults.max_iterations가 없음 |
defaults.max_iterations: 3 추가 |
FINALIZE_UNREACHABLE |
ERROR | 모든 경로를 따라가도 finalize에 도달 불가 | 막힌 경로에 finalize로 이어지는 엣지 추가 |
BUDGET_INCONSISTENT |
ERROR | 노드의 tool_call_budget이 defaults의 전역 캡보다 큼 |
노드 예산을 줄이거나 전역 캡을 늘림 |
JUDGE_DEAD_END |
ERROR | 특정 Judge 라우트를 따라가면 finalize에 도달 불가 | 해당 라우트에 finalize까지의 경로 추가 |
FORCE_TOOL_NO_BUDGET |
ERROR | force_tool이 설정됐는데 해당 도구의 예산이 0 또는 미설정이고 기본값 없음 |
guardrails.tool_call_budget에 해당 도구 예산 추가 |
JUDGE_ROUTE_COVERAGE_ERROR |
ERROR | Stage 2에서도 감지하지만 Stage 3에서 더 정확한 경로 분석으로 추가 감지 | 누락된 route_value에 대한 엣지 추가 |
MISSING_JUDGE_ROUTE_EDGE |
WARNING | judge.route_values에 선언됐지만 when: "judge.route == ..." 형식의 엣지가 없음 (다른 형식 when이 있는 경우) |
judge 라우팅에는 when: "judge.route == ..." 형식을 사용 |
참고:
WARNING은 검증을 통과하지만 잠재적 문제를 알립니다.ERROR는 검증 실패이며 패턴 실행이 거부됩니다.
4. 검증 단계 요약
Stage 1: JSON Schema 검증
검증 내용:
- 필수 필드 존재 여부 (id, version, category, description, nodes, edges, finalize)
- 타입 유효성 (string/integer/boolean/list/object)
- enum 유효성 (kind: llm|judge, runner.mode: execute|plan)
- version이 지원되는 버전인지
관련 도구: euleragent pattern validate <path> --format json → stages.schema
특징: 가장 빠른 단계. YAML 파일 자체의 구조적 유효성만 확인합니다.
Stage 2: YAML Structural 검증
검증 내용: - 노드 ID 고유성 및 예약어 충돌 - 엣지의 from/to가 실제 노드를 참조하는지 - when DSL 문법 유효성 - Judge 노드의 schema, route_values 존재 - HITL 게이팅 규칙 (force_tool + mode 결합) - force_tool과 exclude_tools 충돌
관련 도구: euleragent pattern validate <path> → Stage 2 (Structural)
특징: YAML 내부 일관성을 확인합니다. 그래프 토폴로지는 아직 분석하지 않습니다.
Stage 3: IR Analysis 검증
검증 내용: - 진입 노드 유일성 - 사이클 감지 및 경계 확인 - 모든 노드에서 finalize 도달 가능성 - Judge 라우트 커버리지 및 dead-end - 예산 일관성 (노드 예산 vs 전역 캡) - 도달 불가 노드 감지 (WARNING)
관련 도구: euleragent pattern compile <path> → IR JSON 생성
특징: 컴파일러가 YAML을 IR로 변환하면서 그래프 분석을 수행합니다. 가장 심층적인 검증입니다.
5. 패턴 설계 체크리스트
패턴을 작성하고 배포하기 전에 다음 20개 항목을 확인하세요.
기본 구조
- [ ] 1. ID 형식:
id가category.descriptor형식을 따르는가? 소문자와 점, 언더스코어만 사용하는가? - [ ] 2. 버전:
version: 1이 선언됐는가? - [ ] 3. finalize 선언: 최상위
finalize:키가 있는가? (nodes배열 안에 없는가?) - [ ] 4. finalize 아티팩트:
finalize.artifact가 마지막 노드의artifacts.primary와 일치하는가? - [ ] 5. 예약어 확인:
id: finalize인 노드가 없는가?
노드 설계
- [ ] 6. 진입점 유일성: 수신 엣지가 없는 노드가 정확히 하나인가?
- [ ] 7. mode와 force_tool 결합:
force_tool이 있는 노드에 반드시mode: plan이 있는가? - [ ] 8. exclude_tools 일관성: 에어갭 패턴이면 모든 노드에
exclude_tools: [web.search, web.fetch]가 있는가? - [ ] 9. max_loops 설정: 게이트 노드(human_review 등)에
max_loops: 1이 있는가? - [ ] 10. Judge 스키마:
kind: judge노드에judge.schema: evaluator_v1이 있는가?
Judge 설계
- [ ] 11. route_values 선언:
kind: judge노드에judge.route_values가 있는가? - [ ] 12. route_values 커버리지: 모든
route_values값에 대한when: "judge.route == ..."엣지가 있는가? - [ ] 13. Judge dead-end 없음: 모든 Judge 라우트의 경로가 결국
finalize에 도달하는가? - [ ] 14. route_values 중복 없음: 같은 route_value가 두 번 선언되지 않았는가?
사이클과 경계
- [ ] 15. max_iterations 설정: 사이클이 있으면
defaults.max_iterations가 선언됐는가? - [ ] 16. max_iterations 충분성: 여러 사이클이 있다면
max_iterations가 총 예상 루프 횟수보다 큰가? - [ ] 17. 사이클 교차 없음: 두 사이클이 같은 노드를 공유하지 않는가?
HITL과 예산
- [ ] 18. approvals_resolved 사용:
force_tool노드 다음 엣지에when: "approvals_resolved"가 있는가? (when: "true"아님) - [ ] 19. 예산 일관성: 노드의
guardrails.tool_call_budget값이defaults.max_web_search_calls보다 크지 않은가? - [ ] 20. force_tool 예산 존재:
force_tool이 있는 노드에 해당 도구의 예산이 설정됐는가?
검증 명령
# 체크리스트 확인 후 최종 검증
euleragent pattern validate my_pattern.yaml
# JSON 형식으로 CI에서 활용
euleragent pattern validate my_pattern.yaml --format json | \
python3 -c "import json,sys; r=json.load(sys.stdin); exit(0 if r['overall']=='pass' else 1)"
# IR 분석 확인
euleragent pattern compile my_pattern.yaml
6. 일반적인 패턴 아키타입
자주 사용되는 패턴 구조를 요약합니다. 새 패턴 설계 시 적합한 아키타입을 선택하세요.
아키타입 1: Linear (선형)
[A] → [B] → [C] → finalize
- 사이클 없음:
max_iterations불필요 - HITL 없음: 모든 엣지
when: "true" - 사용 사례: 간단한 파이프라인, 각 단계가 명확히 구분되는 처리
- 참고 튜토리얼: 03_simple_linear.md
defaults:
max_total_tool_calls: 10
edges:
- from: A; to: B; when: "true"
- from: B; to: C; when: "true"
- from: C; to: finalize; when: "true"
아키타입 2: Quality Loop (품질 루프)
[draft] → [evaluate(judge)] → finalize
│
└──→ [revise] ──┐
└──→ [evaluate]
- 사이클 있음:
max_iterations필수 - Judge 라우팅:
route_values: [finalize, revise] - 사용 사례: 품질 기준을 통과할 때까지 반복 개선
- 참고 튜토리얼: 04_judge_and_loop.md
defaults:
max_iterations: 3
pass_threshold: 0.85
judge:
route_values: [finalize, revise]
아키타입 3: Multi-Route (다중 경로)
[evaluate(judge)] ──→ A → finalize
──→ B → C → evaluate (루프)
──→ finalize (즉시 종료)
- 3개 이상 route_values: 모두 엣지 필요
- 같은 목적지 가능: 여러 라우트가
finalize로 갈 수 있음 - 사용 사례: 승인/수정요청/거절, 3단계 심각도 분류
- 참고 튜토리얼: 07_multi_route.md
judge:
route_values: [approve, request_changes, reject]
아키타입 4: Human Gate (인간 검토 게이트)
[draft] → [human_review(force_tool:file.write)] ──approvals_resolved──→ [evaluate]
- HITL 강제:
force_tool: file.write,mode: plan - 한 번만 실행:
max_loops: 1 - 사용 사례: 법적/규정 준수 문서, 외부 발행 전 검토
- 참고 튜토리얼: 06_human_gate.md
runner:
mode: plan
force_tool: file.write
max_loops: 1
edges:
- from: human_review
to: next_node
when: "approvals_resolved"
아키타입 5: Airgap (에어갭)
모든 노드에 exclude_tools: [web.search, web.fetch]
- 외부 네트워크 완전 차단: 모든 노드에 적용
- 내부 지식만 사용: 파일 읽기, 셸 실행은 허용 가능
- 사용 사례: GDPR, 내부 기밀 처리, 보안 규정 준수
- 참고 튜토리얼: 08_airgap_and_ops.md
# 모든 노드에 반복
runner:
mode: execute
exclude_tools: [web.search, web.fetch]
아키타입 6: Dual Judge (이중 Judge)
[draft] → [judge_A] ──ok──→ [optimize] → [judge_B] ──ok──→ finalize
│ │
└──revise──→ [revise_A] ──┐ └──revise──→ [revise_B] ──┐
└──→ [judge_A] └──→ [judge_B]
- 독립적인 두 사이클: 교차하지 않아야 함
- 각 Judge 독립적 route_values: 서로 다른 평가 기준
- 충분한 max_iterations: 두 사이클 합산 고려
- 사용 사례: 콘텐츠 + SEO, 기능 + 보안, 번역 + 교정
- 참고 튜토리얼: 09_advanced_patterns.md
defaults:
max_iterations: 5 # 두 사이클 합산
nodes:
- id: judge_a
judge:
route_values: [ok_a, revise_a] # 독립적
- id: judge_b
judge:
route_values: [ok_b, revise_b] # 독립적
7. 빠른 진단 가이드
에러 코드를 받았을 때 빠르게 해결하는 방법:
검증 실패 시 JSON 출력으로 상세 확인
euleragent pattern validate my_pattern.yaml --format json
{
"stages": {
"schema": { "status": "pass", "errors": [] },
"structural": {
"status": "fail",
"errors": [
{
"code": "JUDGE_ROUTE_COVERAGE_ERROR",
"node": "evaluate",
"route_value": "revise",
"message": "No edge covers route_value 'revise'"
}
]
},
"ir_analysis": { "status": "skipped" }
}
}
에러 코드 → 해결법 빠른 참조
DUPLICATE_NODE_ID → nodes의 id 중복 확인. grep -n "id:" pattern.yaml
RESERVED_NODE_ID → nodes에 id: finalize 있는지 확인
EDGE_UNKNOWN_NODE → 엣지 from/to와 nodes id 비교
INVALID_WHEN_DSL → when 값이 4가지 형식 중 하나인지 확인
NO_ENTRY_NODE → 수신 엣지 없는 노드가 있는지 그래프 그려서 확인
MULTIPLE_ENTRY_NODES → 수신 엣지 없는 노드가 2개 이상 → 하나 연결
NO_FINALIZE → 최상위 finalize: 키 추가
HITL_GATING_VIOLATION → force_tool 있는 노드에 mode: plan 추가
JUDGE_SCHEMA_MISSING → kind: judge 노드에 judge.schema: evaluator_v1 추가
FORCE_EXCLUDE_CONFLICT → force_tool과 exclude_tools 교집합 제거
JUDGE_ROUTE_VALUES_MISSING → kind: judge 노드에 judge.route_values 추가
DUPLICATE_ROUTE_VALUE → route_values 중 중복 제거
UNBOUNDED_CYCLE → defaults.max_iterations 추가
FINALIZE_UNREACHABLE → 막힌 경로에 finalize 연결 추가
BUDGET_INCONSISTENT → 노드 예산 ≤ 전역 캡 확인
JUDGE_DEAD_END → 해당 Judge 라우트 → finalize 경로 확인
FORCE_TOOL_NO_BUDGET → force_tool 도구의 guardrails.tool_call_budget 추가
JUDGE_ROUTE_COVERAGE_ERROR → 누락된 route_value에 엣지 추가
MISSING_JUDGE_ROUTE_EDGE → when: "judge.route == ..." 형식 엣지 확인
런타임 에러 진단
# 실행 이벤트 확인
cat .euleragent/runs/<run-id>/pattern_events.jsonl
# 도구 호출 기록
cat .euleragent/runs/<run-id>/tool_calls.jsonl
# 승인 기록
cat .euleragent/runs/<run-id>/approvals.jsonl
# Judge 평가 결과만 추출
cat .euleragent/runs/<run-id>/pattern_events.jsonl | \
python3 -c "
import json, sys
for line in sys.stdin:
ev = json.loads(line)
if ev.get('event') == 'node.complete' and 'result' in ev:
r = ev['result']
if 'route' in r:
print(f\"{ev['node']}: score={r['score']}, route={r['route']}\")
"
8. 자주 묻는 질문
Q: finalize는 왜 nodes 배열에 없나요?
A: finalize는 노드가 아니라 패턴의 "종료 선언"입니다. 런타임은 어떤 노드에서도 to: finalize 엣지를 따라가면 패턴을 종료합니다. 이를 일반 노드처럼 처리하면 진입점 계산, 사이클 감지 등이 복잡해집니다.
Q: max_iterations를 매우 크게 설정하면 안전한가요?
A: 기술적으로는 가능하지만 권장하지 않습니다. 큰 값은 LLM 호출 비용이 예기치 않게 증가할 수 있습니다. 실제 루프가 필요한 횟수의 1.5~2배 정도로 설정하세요.
Q: 두 노드에서 같은 아티팩트 파일명을 사용할 수 있나요?
A: 가능합니다. 나중 노드가 이전 노드의 파일을 덮어씁니다. revise 노드가 draft 노드의 blog_post.md를 덮어쓰는 패턴이 일반적입니다.
Q: dedupe_web_search가 true이면 중요한 재검색도 막히나요?
A: 동일한 쿼리 문자열만 중복으로 감지합니다. 유사하지만 다른 쿼리는 중복으로 처리되지 않습니다. "LangChain tutorial"와 "LangChain tutorial 2025"는 다른 쿼리입니다.
Q: evaluator_v1 외 다른 Judge 스키마가 있나요?
A: 현재 evaluator_v1만 지원합니다. 향후 릴리스에서 커스텀 스키마가 추가될 예정입니다.
Q: 패턴 없이 에이전트를 실행하는 것과 패턴이 있는 에이전트의 차이는?
A: 패턴 없이 실행하면 에이전트가 자유롭게 도구를 사용하고 결과를 생성합니다. 패턴을 사용하면 워크플로우가 고정되고, HITL 게이팅, 예산 제한, 품질 루프가 보장됩니다. 복잡하고 중요한 작업에는 패턴을, 간단하고 빠른 작업에는 패턴 없는 실행을 고려하세요.