콘텐츠로 이동

자유 대화 Node Graph

dm/scenario/general_conversation.json 기준의 node 흐름입니다.

기본 흐름

자유 대화 기본 흐름

SVG 원본 열기

Node schema

Node Terminal 주요 params next_nodes
greeting false max_turns=3 첫 턴 stay, 이후 conversation
conversation false turn_limit_enabled=false 종료 시 closure, 그 외 stay
conversation_closure true max_turns=2 없음

정적 graph

NetworkX에 생성되는 node 간 edge:

flowchart LR
    GREET["greeting"] --> TALK["conversation"]
    TALK --> CLOSE["conversation_closure"]

정적 edge가 되는 선언:

선언 정적 edge
greeting.default_next = conversation greeting → conversation
next_nodes[].target = conversation_closure conversation → conversation_closure
next_nodes[].action = stay 생성하지 않음
global_transitions[].target 생성하지 않음

action: stay를 자기 자신을 향한 target으로 바꾸면 self-loop가 생겨 start node 계산과 DAG 검증을 방해할 수 있습니다.

Runtime routing 우선순위

현재 scenario에서 실제로 관련된 순서:

Action END
→ global transition
→ Action STAY/GOTO
→ node next_nodes condition
→ terminal 판정
→ graph successor fallback
→ 현재 node 유지

conversation의 일반 executor는 보통 명시적인 Action transition을 만들지 않습니다. 따라서 global transition 또는 node의 condition이 흐름을 결정합니다.

Global transition

이름 Condition Target
user_wants_to_end nlu.intent == user_wants_to_end conversation_closure
flowchart TD
    INPUT["현재 턴"] --> END_INTENT{"nlu.intent =<br/>user_wants_to_end?"}
    END_INTENT -- "예" --> CLOSE["conversation_closure"]
    END_INTENT -- "아니오" --> LOCAL["conversation node-local routing"]

Global transition은 모든 node에서 평가합니다. 이미 conversation_closure에 있을 때 target이 현재 node와 같으면 runtime이 self-targeting transition을 무시하고 terminal 판정으로 내려갑니다.

conversation routing

flowchart TD
    TALK["conversation"] --> END_INTENT{"intent = user_wants_to_end?"}
    END_INTENT -- "예" --> CLOSE["conversation_closure"]
    END_INTENT -- "아니오" --> STAY["action: stay"]
    STAY --> TALK
Condition Action
nlu.intent == user_wants_to_end conversation_closure 이동
nlu.intent != user_wants_to_end 현재 node 유지

None, unknown, inform 등 종료 intent가 아닌 값은 not_equals 조건에 해당합니다.

conversation_closure routing

flowchart TD
    CLOSE["conversation_closure<br/>terminal: true"] --> GLOBAL{"global 종료 target이<br/>현재 node인가?"}
    GLOBAL -- "예" --> IGNORE["self-target 무시"]
    GLOBAL -- "아니오/불일치" --> TERMINAL["terminal 판정"]
    IGNORE --> TERMINAL
    TERMINAL --> COMPLETE([Session complete])

Closure에는 next_nodesdefault_next가 없습니다. 따라서 재개 경로 없이 terminal node로 완료됩니다.

종료 응답과 node 이동

Transition은 현재 node의 응답 생성 뒤에 적용됩니다.

sequenceDiagram
    participant U as User
    participant C as conversation
    participant T as TransitionEngine
    participant X as conversation_closure

    U->>C: 종료 발화
    C-->>U: conversation 기준 응답
    C->>T: NLU + Action + State
    T->>X: global transition
    Note over X: 다음 처리 시점의 current_node

current_node=conversation_closure가 된 것과 같은 턴의 응답을 closure가 생성한 것으로 해석하면 안 됩니다. Detailed 출력에서는 details.transition.from/to를 함께 확인합니다.

정적 graph와 runtime graph의 차이

경로 정적 edge Runtime 조건
greeting → conversation 있음 default_next (첫 턴은 stay)
conversation → closure 있음 종료 intent
conversation → conversation 없음 action: stay
closure → complete 없음 terminal: true 판정

관련 문서