자유 대화 시나리오¶
이 폴더는 dm/scenario/general_conversation.json의 현재 설계를 설명합니다. JSON이 실행 기준이며, 문서는 구조와 runtime 동작을 읽기 쉽게 정리합니다.
문서¶
- Node Graph: 정적 graph와 runtime routing
- Slot: 슬롯을 선언·수집하지 않는 구조
- Intent: 종료 intent와 공통 runtime intent
- Dialog act: 발화 행위별 공통 정책과 종료 영향
목적¶
이 시나리오는 정해진 업무나 정보 수집 없이 사용자와 자유롭게 대화합니다.
| 항목 | 현재 값 |
|---|---|
| Scenario slug | general-conversation |
| 언어 | ko |
| 버전 | 1.3.4 |
| Bot first | true |
| Entry node | greeting |
| Slot registry | 없음 |
| Slot 수집 | 없음 |
| Maumon 장기 기억 | 활성 (metadata.memory_rag.enabled=true) |
| 명시적 종료 신호 | nlu.intent == user_wants_to_end |
| Terminal node | conversation_closure |
전체 흐름¶
세션은 greeting에서 봇이 먼저 인사한 뒤 conversation으로 들어갑니다. conversation은 사용자가 명시적으로 종료하기 전까지 현재 노드에 머뭅니다. conversation_closure는 terminal: true이며 outgoing edge가 없습니다.
Node 요약¶
| Node | 역할 | Executor | 수집 슬롯 | Turn limit |
|---|---|---|---|---|
greeting |
짧게 인사한 뒤 오늘 이야기를 연다 | GeneralResponseExecutor |
없음 | max_turns 3 |
conversation |
사용자 입력에 이어가는 자유 대화 | GeneralResponseExecutor |
없음 | 비활성화 |
conversation_closure |
종료 의사를 짧게 받아들이고 마무리 | GeneralResponseExecutor |
없음 | max_turns 2 |
세 노드 모두 collect_slots가 없으므로 GeneralResponseExecutor가 선택됩니다.
자유 대화 설정¶
| Param | 타입 | 값 | 효과 |
|---|---|---|---|
turn_limit_enabled |
boolean |
false |
executor turn limit과 NLG turn-budget 안내 비활성화 |
turn_limit_enabled=false는 conversation에만 선언되어 있습니다. 따라서 대화 횟수만으로 closure로 이동하지 않습니다.
Prompt¶
현재 scenario prompt:
| 경로 | 선언 여부 | 내용과 역할 |
|---|---|---|
prompts.bot |
선언 | 자기 이야기에는 구체적으로 반응하고 캐묻지 않음, 이야기가 없을 때만 쉬운 질문 하나, 연속 질문 금지 |
prompts.nlu |
선언 | 짧은 말은 직전 봇 말로 해석. 질문의 부정 답은 종료가 아님. 주제 접기와 대화 종료를 구분 |
prompts.bot이 빈 값이 아니므로 공통 NLG 시스템 prompt를 완전히 제거하는 구조는 아닙니다. 공통 prompt에 scenario의 bot 지침을 추가하여 사용합니다.
사용자가 자신의 경험·기분·가족·식사·하루 일을 말하면 구체적인 핵심을 먼저 알아주고
관련된 느낌·관찰·소소한 정보를 평서문으로 덧붙입니다. 이야기를 바로 다른 주제로
바꾸거나 왜요?, 어땠어요?처럼 캐묻지 않습니다.
반대로 별일 없어, 그냥 그래, 딱히, 몰라처럼 별다른 소재가 없고 직전 봇
발화도 질문이 아니면 식사·TV·산책·잠·오늘의 작은 일 중 하나를 골라 부담 없는 질문을
하나 합니다. 직전 봇 발화가 질문이었다면 이번 턴에는 질문하지 않습니다.
세 노드는 모두 빈 responses.default를 선언합니다. 빈 문자열은 정적 bot-first
응답이나 일반 NLG 기준 문장으로 사용할 수 없으므로, greeting을 포함한 응답은 node
description과 Scenario prompt를 기반으로 LLM이 생성합니다. LLM 실패 시에는 공통
fallback 메시지를 사용합니다.
장기 기억¶
이 Scenario는 이전 Session의 대화·추억 검색을 활성화합니다. 실제 조회에는
Session의 user.id와 MAUMON_API_KEY가 필요합니다. 사용자가 과거 기억 검색을
명시적으로 요청하면 NLU가 entity와 noun을 추출해 최대 3개 query를 병렬
조회합니다. found=true인 Maumon answer를 사용하며 검색 실패는 자유 대화를 중단하지
않습니다.
조회 기준과 진단은 Maumon 장기 기억을 참고합니다.
종료 routing¶
종료 조건은 global transition과 conversation.next_nodes에 같은 형태로 선언되어 있습니다.
| 위치 | 조건 | 결과 |
|---|---|---|
graph.global_transitions[0] |
nlu.intent == user_wants_to_end |
conversation_closure로 이동 |
conversation.next_nodes[0] |
nlu.intent == user_wants_to_end |
conversation_closure로 이동 |
conversation.next_nodes[1] |
nlu.intent != user_wants_to_end |
현재 노드 유지 |
Runtime에서는 global transition이 node-local transition보다 먼저 평가되므로 정상 종료 턴에는 global transition이 우선합니다. Node-local closure target은 정적 graph에 conversation → conversation_closure edge를 만들고 graph 구조를 명확하게 유지하는 역할도 합니다.
종료 턴의 실행 시점¶
한 턴은 현재 노드가 응답을 만든 뒤 transition을 적용합니다.
conversation에서 사용자 종료 발화 처리
→ conversation 응답 생성
→ global transition 결정
→ current_node = conversation_closure
따라서 closure로 이동한 턴의 응답은 이동 전 conversation이 생성합니다. conversation_closure의 description은 closure가 현재 노드인 다음 처리 턴에 적용됩니다.
Closure는 outgoing edge가 없고 terminal: true이므로 해당 노드에서 명시적 전이가
없으면 TransitionEngine이 세션을 완료합니다. Closure에 진입한 뒤 사용자 입력이
비어 있으면 NLU와 NLG를 실행하지 않고 빈 응답으로 즉시 완료합니다.
SeniMate와 다른 점¶
| 항목 | 자유 대화 | SeniMate |
|---|---|---|
| 목적 대화 | 없음 | 일상·식사·건강 확인 |
| Slot registry | 없음 | 6개 optional slot |
| Node 수 | 3 (greeting 포함) |
6 |
| 연속 무응답 종료 | 선언 없음 | silent_close global transition |
| Closure 재개 edge | 없음 | 미수집 단계 또는 자유 대화로 복귀 |
| Closure params | max_turns 2 |
turn/fallback 제한 선언 |
현재 conversation_closure에는 재개 transition이 없습니다. Closure에서 사용자가 새 이야기를 시작하더라도 SeniMate처럼 conversation으로 돌아가지 않고 terminal 판정으로 완료됩니다.
현재 주의점¶
- 명시적 종료 transition은 runtime이 문맥 기반
nlu.intent와goodbyeact 조건으로 보충합니다. 문자열 keyword만으로 종료하는 별도 조건은 없습니다. - 종료 intent 분류는 공통 NLU 지침에
prompts.nlu의 부정·주제 접기 규칙을 더합니다. - Slot registry와
collect_slots가 모두 없어 task policy와 slot commit 경로를 사용하지 않습니다. - 연속 무응답을 closure로 보내는
silent_close규칙이 없습니다. - Closure에서 대화를 재개하는 outgoing edge가 없습니다.
conversation의 turn limit은 비활성화됩니다. closure는max_turns2입니다.
검증¶
python -m cli.chatbot \
--scenario dm/scenario/general_conversation.json \
--validate-only
python -m cli.chatbot \
--scenario dm/scenario/general_conversation.json \
--user-id user-123 \
--output-level detailed
python -m cli.chatbot \
--scenario dm/scenario/general_conversation.json \
--node conversation_closure \
--output-level detailed
필수 회귀:
- 일반 입력에서
conversation유지 - 답변 뒤에 습관적인 추가 질문이나 도움 제안을 붙이지 않음
- 여러 턴 대화 후에도 turn limit으로 종료하지 않음
- 명시적
user_wants_to_end에서 closure 이동 - closure가
terminal_node로 완료 - Slot update와 task outcome이 생성되지 않음
- 과거 대화 참조에서 필요한 경우에만 장기 기억을 조회하고 실패 시 일반 대화 계속
- closure에서 새 발화를 해도 현재 설계상 대화가 재개되지 않음