> EulerAgent > 튜토리얼 > 그래프 > 그래프 10. 완전 레퍼런스 — 필드, 에러 코드, 안...

그래프 10. 완전 레퍼런스 — 필드, 에러 코드, 안전 설계 체크리스트

이 문서는 euleragent graph 모듈의 완전한 참조 문서입니다. 튜토리얼에서 배운 모든 개념의 빠른 참조 자료로 사용하십시오.


1. Graph YAML 전체 필드 테이블

1.1 최상위 필드

필드 타입 필수 설명
id string O 그래프 식별자. 관례: graph.{name}
version integer O 그래프 버전 번호 (1부터 시작)
category string O 카테고리 (research, engineering, marketing 등)
description string O 그래프 설명
checkpointer boolean/string 조건부 interrupt_before/interrupt_after 사용 시 필수. true, "memory", "sqlite" 중 하나
state_schema dict 조건부 parallel_groups 사용 시 필수
parallel_groups list X 병렬 팬아웃/팬인 그룹 목록
defaults dict O 실행 제약 (max_iterations 포함)
nodes list O 노드 목록
edges list O 엣지 목록
finalize dict O 최종 노드 설정

1.2 state_schema 필드

state_schema:
  <key_name>:
    type: string | integer | float | list | dict
    merge: append_list | sum_int | concat_str | last_write | first_write
필드 타입 필수 설명
type enum O 상태 값의 데이터 타입
merge enum O 병렬 쓰기 시 충돌 해결 전략 (리듀서)

1.3 parallel_groups 필드

parallel_groups:
  - id: <group_id>
    branches: [<node_id>, ...]
    join: <join_node_id>
필드 타입 필수 설명
id string O 그룹 식별자
branches list[string] O 병렬 실행할 노드 ID 목록 (2~8개)
join string O 팬인 조인 노드 ID

1.4 defaults 필드

필드 타입 필수 설명
max_iterations integer 루프 시 필수 루프 기준 노드 최대 실행 횟수
max_total_tool_calls integer X 전체 도구 호출 예산
max_web_search_calls integer X 웹 검색 호출 예산

1.5 nodes 필드 (Graph 전용 추가 필드)

Pattern의 모든 노드 필드에 추가되는 Graph 전용 필드:

필드 타입 필수 설명
id string O 노드 식별자 (그래프 내 유일)
kind enum O llm, judge, finalize
runner dict kind=llm 시 실행 모드 설정
runner.mode enum O plan, execute
runner.force_tool string X 강제 도구 (web.search, file.write, shell.exec)
runner.exclude_tools list X 제외할 도구 목록
runner.min_proposals integer X plan 모드 최소 제안 수
runner.max_loops integer X 노드 내부 최대 재시도 횟수
judge dict kind=judge 시 Judge 설정
judge.schema string O 평가 스키마 ID
judge.route_values list O 가능한 라우팅 값 목록
artifacts dict X 결과물 설정
artifacts.primary string X 주 결과물 파일명
guardrails dict X 도구 사용 제약
guardrails.tool_call_budget dict X 도구별 호출 횟수 제한
writes_state list 브랜치 필수 이 노드가 쓰는 state_schema 키 목록. 모든 키는 state_schema에 선언되어야 함 (미선언 시 STATE_UPDATE_OUTSIDE_DECLARED_WRITES)
reads_state list X 이 노드가 읽는 state_schema 키 목록. 미선언 키는 READS_STATE_UNKNOWN_KEY 경고 발생
interrupt_before boolean X 실행 전 LangGraph 체크포인트 일시 정지. 최상위 checkpointer: 필수
interrupt_after boolean X 실행 후 LangGraph 체크포인트 일시 정지. 최상위 checkpointer: 필수

1.6 edges 필드

필드 타입 필수 설명
from string O 소스 노드 ID
to string O 타겟 노드 ID (finalize 포함)
when string O 조건 표현식

when 조건 표현식: - "true" — 항상 진행 - "approvals_resolved" — HITL 승인 큐 비워진 후 - "judge.route == <value>" — judge가 특정 값을 반환했을 때

1.7 finalize 필드

필드 타입 필수 설명
artifact string O 최종 결과물 파일명

2. Pattern → Graph 비교 표

항목 Pattern Graph
YAML 구조 동일 Pattern 상위 집합
실행 엔진 euleragent 순차 실행기 LangGraph StateGraph
state_schema 없음 추가 (병렬 시 필수)
parallel_groups 없음 추가 (팬아웃/팬인)
interrupt_before/after 없음 추가 (체크포인트 기반)
judge 라우팅 런타임 조건 평가 add_conditional_edges 컴파일
writes_state / reads_state 없음 추가 (병렬 브랜치 문서화)
graph_type (IR) "pattern" "graph"
CLI 명령 pattern validate/show graph validate/show/compile
안정성 안정 실험적
병렬 실행 불가 가능
중간 상태 저장 불가 LangGraph 체크포인터

3. 에러/경고 코드 전체 테이블

3.1 의미론적 에러 코드 (신규)

# 에러 코드 발생 조건 해결 방법
L INTERRUPT_REQUIRES_CHECKPOINTER interrupt_before/after 사용 시 최상위 checkpointer: 없음 checkpointer: memory 추가
M STATE_UPDATE_OUTSIDE_DECLARED_WRITES 노드의 writes_state 키가 state_schema에 없음 키를 state_schema에 추가하거나 writes_state에서 제거
P3b PARALLEL_JOIN_IN_BRANCHES join 노드가 자신의 branches 목록에 포함됨 branches에서 join 노드 제거

3.2 경고 코드 (ok=True, 비차단)

# 경고 코드 발생 조건 권장 조치
N READS_STATE_UNKNOWN_KEY reads_state 키가 state_schema에 없음 오타 확인 또는 state_schema에 추가
P14 PARALLEL_ORDER_DEPENDENT_MERGE 병렬 그룹에서 append_list 사용 항목에 source/rank 필드 추가 후 조인에서 정렬

3.3 병렬 에러 코드 (14개)

# 에러 코드 발생 조건 해결 방법
1 PARALLEL_JOIN_MISSING parallel_groupsjoin이 없음 join: <노드ID> 추가
2 PARALLEL_JOIN_MULTIPLE 하나의 그룹에 join이 2개 join을 하나로 줄이기
3 PARALLEL_FANOUT_MISSING 브랜치로 가는 팬아웃 엣지 없음 소스 → 브랜치 엣지 추가
4 PARALLEL_JOIN_EDGE_MISSING 브랜치 → 조인 엣지 없음 브랜치 → join 엣지 추가
5 PARALLEL_BRANCH_NOT_CONVERGING 브랜치가 조인 노드로 수렴하지 않음 팬인 엣지 수정
6 PARALLEL_STATE_SCHEMA_MISSING parallel_groups 있지만 state_schema 없음 최상위에 state_schema 추가
7 PARALLEL_STATE_KEY_MERGE_MISSING 브랜치가 쓰는 state key에 merge 없음 state_schema에 해당 key의 merge 추가
8 PARALLEL_NONDETERMINISTIC_MERGE 복수 브랜치가 last_write 또는 first_write key 공유 append_list, sum_int, concat_str 중 하나로 변경
9 STATE_SCHEMA_MERGE_TYPE_MISMATCH 타입+merge 금지 조합 사용 호환성 표 참조하여 수정
10 PARALLEL_SIDE_EFFECT_FORBIDDEN 브랜치에서 shell.exec/file.write force_tool 조인 이후 노드에서 수행
11 PARALLEL_BRANCH_LIMIT_EXCEEDED 브랜치 수 9개 이상 8개 이하로 줄이기
12 PARALLEL_METADATA_DROPPED 브랜치 노드에 writes_state 없음 writes_state: [] 명시
13 PARALLEL_FINALIZE_BEFORE_JOIN 브랜치가 finalize로 직접 라우팅 조인 노드 → finalize 순서로 수정
14 LANGGRAPH_COMPILE_FAILED LangGraph 버전 불일치 또는 IR 오류 LangGraph 1.0.9+ 설치, euleragent doctor 실행

4. 타입+Merge 호환성 매트릭스

각 셀의 기호: O = 허용, X = 금지 (STATE_SCHEMA_MERGE_TYPE_MISMATCH), O = 권장

타입 \ Merge append_list sum_int concat_str last_write first_write
list O X X O O
string X X O O O
integer X O X O O
float X X X O O
dict X X X O O

굵게 표시: 해당 타입의 권장 merge 전략

4.1 권장 조합 요약

# 병렬 결과 수집 (리스트) → append_list
findings:
  type: list
  merge: append_list

# 숫자 합산 → sum_int
count:
  type: integer
  merge: sum_int

# 텍스트 연결 (병렬) → concat_str
notes:
  type: string
  merge: concat_str

# 단일 노드 쓰기 → last_write
summary:
  type: string  # 또는 float, dict
  merge: last_write

# 최초 쓰기 우선 → first_write
initial_value:
  type: string  # 또는 다른 타입
  merge: first_write

5. 안전한 병렬 설계 체크리스트 (16개 항목)

설계 단계

□ 1. 진정한 병렬 실행이 필요한지 확인
      순차로 충분하면 Pattern 사용 (더 단순하고 안정적)

□ 2. 브랜치 수 결정 (2~8개)
      처음에는 2~3개로 시작하고 필요 시 확장

□ 3. state_schema 설계 완료
      모든 브랜치의 writes_state 키 목록화
      각 키의 type과 merge 전략 결정

□ 4. 공유 키(여러 브랜치가 씀) 식별
      공유 list 키 → append_list
      공유 integer 키 → sum_int
      공유 string 키 → concat_str 또는 last_write(비결정론적 허용 시)

□ 5. 단일 브랜치 키 식별
      단일 브랜치 키 → last_write (안전)

선언 단계

□ 6. state_schema 최상위에 선언

□ 7. parallel_groups 선언 (id, branches, join)

□ 8. 모든 브랜치 노드에 writes_state 선언
      상태를 쓰지 않아도 writes_state: [] 명시

□ 9. 조인 노드에 reads_state 선언 (문서화)

□ 10. 팬아웃 엣지 선언 (소스 → 모든 브랜치)

□ 11. 팬인 엣지 선언 (모든 브랜치 → 조인 노드)
       HITL 브랜치는 when: "approvals_resolved"
       자율 브랜치는 when: "true"

□ 12. interrupt_before/after 사용 시 최상위 checkpointer: 선언
       미선언 시 INTERRUPT_REQUIRES_CHECKPOINTER 에러 (정적 검증 실패)
       최소: checkpointer: memory

검증 단계

□ 13. euleragent graph validate 실행 및 통과 확인

□ 14. PARALLEL_NONDETERMINISTIC_MERGE / PARALLEL_ORDER_DEPENDENT_MERGE 경고 검토
       비결정론적 결과 허용 여부 확인; append_list 시 source/rank 필드 고려

□ 15. euleragent graph compile로 IR 생성 및 검토
       langgraph_builder 섹션에서 add_edges 확인

□ 16. 실험적 기능 사용 주의사항 재확인
       00_disclaimer.md 참조

6. LangGraph StateGraph 컴파일 상세

Graph YAML의 각 요소가 LangGraph의 어떤 메서드로 매핑되는지 보여줍니다.

6.1 매핑 테이블

Graph YAML 요소 LangGraph API
state_schema (전체) StateGraph(TypedDict) 타입 정의
state_schema.*.merge: append_list Annotated[list, operator.add]
state_schema.*.merge: sum_int Annotated[int, operator.add]
state_schema.*.merge: concat_str Annotated[str, operator.add]
state_schema.*.merge: last_write 기본 타입 (어노테이션 없음)
state_schema.*.merge: first_write 커스텀 first_write 리듀서
nodes[*] graph.add_node(id, fn)
첫 번째 노드 graph.set_entry_point(id)
finalize 노드 graph.set_finish_point(id)
edges[*] (when="true") graph.add_edge(from, to)
edges[*] (when="judge.route==X") graph.add_conditional_edges(...)
parallel_groups[*] 팬아웃/팬인 엣지 (add_edge 복수)
interrupt_before: [...] graph.compile(interrupt_before=[...])
interrupt_after: [...] graph.compile(interrupt_after=[...])
defaults.max_iterations 런타임 가드 (LangGraph 외부)

6.2 전체 컴파일 예시 (개념적 Python 코드)

다음은 parallel_research_with_quality.yaml이 LangGraph 코드로 변환되는 모습입니다.

from langgraph.graph import StateGraph, END
from typing import Annotated, TypedDict
import operator

# state_schema → TypedDict
class GraphState(TypedDict):
    findings: Annotated[list, operator.add]   # append_list
    source_count: Annotated[int, operator.add]  # sum_int
    final_summary: str                         # last_write (기본)
    route: str                                 # judge 라우팅용 내부 키

# StateGraph 초기화
graph = StateGraph(GraphState)

# 노드 추가
graph.add_node("plan", plan_fn)
graph.add_node("web_search", web_search_fn)
graph.add_node("local_search", local_search_fn)
graph.add_node("doc_search", doc_search_fn)
graph.add_node("merge_findings", merge_findings_fn)
graph.add_node("evaluate", evaluate_fn)
graph.add_node("revise", revise_fn)

# 진입점
graph.set_entry_point("plan")

# 팬아웃 엣지 (plan → 브랜치들)
graph.add_edge("plan", "web_search")
graph.add_edge("plan", "local_search")
graph.add_edge("plan", "doc_search")

# 팬인 엣지 (브랜치들 → 조인)
graph.add_edge("web_search", "merge_findings")
graph.add_edge("local_search", "merge_findings")
graph.add_edge("doc_search", "merge_findings")

# 하류 엣지
graph.add_edge("merge_findings", "evaluate")
graph.add_edge("revise", "evaluate")

# Judge 조건부 엣지
def route_evaluate(state: GraphState) -> str:
    return state.get("route", "finalize")

graph.add_conditional_edges(
    "evaluate",
    route_evaluate,
    {"finalize": END, "revise": "revise"}
)

# 컴파일 (interrupt 없는 경우)
compiled = graph.compile()

# 또는 interrupt 있는 경우
compiled = graph.compile(
    checkpointer=checkpointer,
    interrupt_before=["publish"],   # interrupt_before 노드 목록
    interrupt_after=["draft"]       # interrupt_after 노드 목록
)

6.3 first_write 리듀서 구현 (개념적)

first_write는 LangGraph 기본 제공 어노테이션이 아니므로 커스텀 리듀서로 구현됩니다.

def first_write_reducer(old_value, new_value):
    """첫 번째 쓰기 값을 유지. None이면 new_value 사용."""
    if old_value is None:
        return new_value
    return old_value  # 이미 값이 있으면 새 값 무시

# TypedDict에서의 선언
class GraphState(TypedDict):
    primary_result: Annotated[str, first_write_reducer]

7. 실험적 기능 사용 시 주의사항 요약

00_disclaimer.md의 전체 고지 내용을 참조하십시오.

7.1 안전 수준 분류

기능 안전 수준 설명
선형 Graph (병렬 없음) 안정적 Pattern과 동등
judge 라우팅 안정적 Pattern과 동등한 동작
interrupt_before/after 실험적 LangGraph 버전 의존
2-브랜치 parallel_groups 실험적 기본 검증 완료
3-8브랜치 parallel_groups 실험적 철저한 테스트 필요
graph run 명령 실험적 일부 시나리오 미검증

7.2 버전 업그레이드 시 필수 작업

# euleragent 또는 langgraph 업그레이드 후
pip install --upgrade euleragent langgraph

# 모든 Graph YAML 재검증
for yaml_file in examples/graphs/**/*.yaml; do
    echo "검증: $yaml_file"
    euleragent graph validate "$yaml_file"
done

# 컴파일된 IR 재생성
euleragent graph compile my_graph.yaml --out my_graph_compiled.json

7.3 프로덕션 배포 전 체크리스트

□ euleragent doctor 실행 → 모든 항목 통과 확인
□ graph validate 통과 (오류 0개)
□ graph validate --format json 출력에서 경고 검토
□ graph compile 성공
□ 스테이징 환경에서 10회 이상 반복 실행 테스트
□ 병렬 결과의 비결정론적 변동 허용 범위 확인
□ HITL 승인 워크플로우 테스트
□ interrupt hooks 재개 시나리오 테스트
□ 감사 로그 (approvals.jsonl, tool_calls.jsonl) 검토
□ 최대 비용 시나리오 계산 (max_iterations × max_total_tool_calls)

빠른 참조 카드

CLI 명령

euleragent graph list                              # 그래프 목록
euleragent graph show <path>                       # 구조 보기
euleragent graph validate <path>                   # 검증
euleragent graph validate <path> --format json     # JSON 형식 검증
euleragent graph compile <path>                    # IR 컴파일
euleragent graph compile <path> --out file.json    # IR 파일로 저장

최소 병렬 그래프 템플릿

id: graph.template
version: 1
category: demo
description: 최소 병렬 그래프 템플릿

state_schema:
  results:
    type: list
    merge: append_list

defaults:
  max_iterations: 2
  max_total_tool_calls: 30

parallel_groups:
  - id: my_group
    branches: [branch_a, branch_b]
    join: join_node

nodes:
  - id: source
    kind: llm
    runner: {mode: execute}

  - id: branch_a
    kind: llm
    runner: {mode: execute}
    writes_state: [results]

  - id: branch_b
    kind: llm
    runner: {mode: execute}
    writes_state: [results]

  - id: join_node
    kind: llm
    runner: {mode: execute}
    reads_state: [results]
    artifacts:
      primary: output.md

edges:
  - {from: source, to: branch_a, when: "true"}
  - {from: source, to: branch_b, when: "true"}
  - {from: branch_a, to: join_node, when: "true"}
  - {from: branch_b, to: join_node, when: "true"}
  - {from: join_node, to: finalize, when: "true"}

finalize:
  artifact: output.md

이전: 09_parallel_with_quality.md | 목차: README.md

← 이전 목록으로