AI 브랜치 다이얼로그 선택지가 엔딩과 호감도에 미치는 디자인 패턴
AI 기반 브랜치 다이얼로그에서 선택지의 의미를 유지하면서 엔딩 분기와 호감도를 설계하는 방법을 다룬다. 상태 변수, 가중치, 임계값, 폴백 규칙을 활용하는 설계 패턴과 점검 항목을 정리한다.

짧은 답: AI 기반 브랜치 다이얼로그에서는 선택지의 의도와 게임 상태 변화를 분리해 설계할 수 있다. 예를 들어 의도 태그로 신뢰, 공포, 공감 같은 관계 변수를 갱신하고, 엔딩은 누적 호감도 하나에만 의존하지 않고 핵심 플래그·관계 임계값·최근 행동을 함께 평가하도록 구성할 수 있다.
AI 브랜치 다이얼로그에서 엔딩과 호감도 설계가 어려운 이유
자유 입력을 받는 대화에서는 플레이어가 다양한 표현을 사용할 수 있다. 입력 문장 자체를 곧바로 호감도 수치에 연결하면 같은 의도의 표현도 분류 결과에 따라 다른 상태 변화로 이어질 수 있다. 결과와 피드백이 일관되지 않으면 플레이어가 어떤 선택이 중요한지 파악하기 어려워질 수 있다.
핵심은 자유 입력을 의도 태그로 정규화하고 의도 태그를 게임 상태 변화로 변환하는 두 단계 구조다. AI는 자연어를 해석하고 대사를 생성하는 역할을 맡는다. 엔딩 판정과 호감도 계산은 재현 가능한 게임 규칙이 맡아야 한다.
| 계층 | 책임 | 예시 |
|---|---|---|
| 입력 해석 계층 | 플레이어 발화를 의도와 톤으로 분류 | 공감, 회피, 거짓말, 협박 |
| 상태 갱신 계층 | 정해진 수식과 규칙으로 변수 변경 | trust +8, fear +4 |
| 서사 연출 계층 | 상태에 맞는 AI 응답 생성 | 경계하는 답변, 고백, 협력 제안 |
| 엔딩 판정 계층 | 플래그·임계값·우선순위로 결말 선택 | 화해 엔딩, 독립 엔딩, 파국 엔딩 |
선택지의 의미를 보존하는 3가지 상태 모델
1. 단일 호감도 모델: 작고 명확한 게임에 적합
가장 단순한 방식은 NPC마다 affinity를 두는 것이다. 예를 들어 범위는 -100부터 100까지로 정하고 선택지마다 고정값을 더한다. 여기서 clamp(x, min, max)는 계산값이 지정 범위를 벗어나지 않도록 제한하는 함수라고 가정한다.
튜토리얼 구간이나 짧은 연애 시뮬레이션에서는 하나의 수치만 관리하면 단순한 규칙을 만들기 쉽다. 다만 사과와 선물, 협박과 약점 공유가 모두 같은 축에 반영되므로, 관계가 달라진 이유를 표현하기 어려울 수 있다.
2. 관계 벡터 모델: 관계의 여러 측면을 나눠 표현
관계의 여러 측면을 구분해 다루려면 trust, affection, fear처럼 의미가 겹치지 않는 2~4개 축부터 검토할 수 있다. 축의 수는 장르와 콘텐츠에 따라 달라진다.
trust: 약속을 지키고 진실을 말한다고 믿는 정도affection: 정서적 친밀감과 호의fear: 위협받는다고 느끼는 정도
예를 들어 플레이어의 입력이 진실을 털어놓고 도움을 요청한다로 분류됐다면 trust +10, affection +4, fear -2를 적용한다. 반대로 협박은 fear +15를 올릴 수 있지만 trust -12, affection -8을 함께 낮춘다.

그림은 개념 모형이다. 표시된 상태값과 분기 비율은 서로 같은 실행에서 나온 데이터가 아니며, 실제 게임에서 측정하거나 검증한 결과가 아니다.
관계 벡터를 쓰면 같은 목표에도 서로 다른 접근 경로를 설계할 수 있다. 예를 들어 높은 trust는 동료 엔딩으로, 높은 fear는 지배 엔딩으로 이어지도록 정할 수 있다. 두 경로 모두 NPC가 플레이어 편에 서더라도 그 서사적 의미는 다르게 표현할 수 있다.
3. 플래그 모델: 되돌릴 수 없는 선택을 기록
수치만으로는 “누구를 배신했는가” 같은 사건을 설명하기 어렵다. 따라서 엔딩에 영향을 주는 사건은 불리언 또는 열거형 플래그로 별도 저장한다.
type Relationship = {
trust: number;
affection: number;
fear: number;
revealedSecret: boolean;
protectedNpc: boolean;
betrayedFaction: boolean;
lastConflictResolution: "dialogue" | "bribe" | "violence";
};
플래그는 꼭 필요한 사건에 한정한다. 플레이어가 기억할 만하거나, 이후 대사의 전제를 바꾸거나, 엔딩에서 회수할 사건을 우선 고려한다.
AI 선택지는 호감도에 어떻게 반영해야 할까?
다음 순서로 구현하면 AI의 유연함과 시스템의 예측 가능성을 함께 얻을 수 있다.
1. 자유 입력을 제한된 의도 스키마로 분류한다
모델에 바로 수치 변경을 맡기지 말고, 사용 중인 모델/API가 지원하면 구조화 출력 기능에 intent 열거형 등이 포함된 스키마를 지정한다. 응답은 서버에서도 스키마와 허용 값을 검증하고, confidence가 낮거나 응답이 유효하지 않으면 상태를 갱신하지 않는 등 게임 규칙에 맞는 폴백을 적용한다. 모델이나 프롬프트를 바꿀 때는 대표 입력으로 결과를 다시 평가한다. 예를 들어 OpenAI는 모델 스냅샷을 고정하고 평가 테스트를 구성해 동작을 확인하는 방법을 안내한다. 아래 JSON은 스키마 정의가 아니라 가능한 응답의 예다.
{
"intent": "empathize",
"tone": "calm",
"target": "npc_mira",
"confidence": 0.91,
"evidence": "상실을 이해한다고 말하며 도움을 제안했다"
}
confidence 값 0.91은 형식을 보여 주는 임의 예시이지, 보정된 확률이나 검증 결과가 아니다. 실제 폴백 임계값은 라벨을 붙인 프로젝트 데이터로 평가해야 한다.
의도 후보 수는 프로젝트에 맞춰 정하되, 작은 초기 집합으로 시작해 실제 대화에서 분류하기 어렵거나 결과가 겹치는 사례를 바탕으로 조정할 수 있다. 예를 들어 empathize, promise, ask_truth, deflect, lie, threaten, flirt, leave 같은 태그를 검토할 수 있다.
2. 의도별 효과표를 데이터로 관리한다
기획자가 조정할 수 있도록 효과는 코드 조건문보다 데이터 테이블에 둔다.
| 의도 | 신뢰 | 호감 | 공포 | 주의점 |
|---|---|---|---|---|
공감 empathize | +3 | +7 | -2 | 반복 사용 시 감쇠 필요 |
약속 promise | +5 | +2 | 0 | 나중에 이행 검사 필요 |
회피 deflect | -2 | -1 | 0 | 정보 은폐 플래그와 결합 가능 |
거짓말 lie | +2 | +1 | 0 | 발각 시 큰 신뢰 하락 |
협박 threaten | -8 | -6 | +14 | 단기 보상과 장기 비용을 함께 설계 |
표의 수치는 효과표를 설명하기 위한 임의 예시이며, 플레이 테스트를 거친 권장값은 아니다.
반복 선택의 효율을 낮추려면 동일 의도의 최근 연속 사용 횟수를 n으로 두고 감쇠 계수를 적용할 수 있다. 첫 선택에서는 n=0으로 두는 예시다.
이 방식은 반복 선택의 효율을 낮춘다. 다만 감쇠 하한이 0보다 크므로 그 자체로 누적치의 무한 증가를 막지는 못한다. 상한, 선택 횟수 제한 또는 장면별 사용 제한을 함께 설계해야 한다. 이야기상 중요한 장면에는 감쇠를 줄이는 sceneImportanceMultiplier를 둘 수도 있다.
3. AI 응답은 상태를 설명하되 수치를 노출하지 않는다
플레이어에게 “호감도 +7” 같은 수치만 보여 주면 대화 선택이 점수 최적화처럼 느껴질 수 있다. 대신 상태 변화가 NPC의 행동과 어조에 반영되도록 설계할 수 있다. 예를 들어 신뢰가 높을 때 비밀 정보를 먼저 꺼내고, 공포가 높을 때는 협력하더라도 답변을 짧게 하거나 퇴로를 찾는 식이다.
연출 목적이라면 AI 프롬프트에 현재 상태의 원본 수치 대신 구간 라벨을 전달할 수 있다. 이 방식만으로 내부 규칙의 노출을 막을 수 있는 것은 아니다. 서버 기반 게임에서 권위 상태로 관리하는 값과 판정은 서버에서 검증하고 갱신하는 구조를 고려한다.
예를 들어 affinity가 -100~100 범위의 부호 있는 값일 때 다음 구간을 사용할 수 있다. 임계값은 설명용 예시이며, 다른 범위의 관계 축에는 그대로 적용할 수 없다.
function relationshipBand(value: number) {
if (value >= 60) return "high";
if (value >= 20) return "positive";
if (value <= -40) return "hostile";
return "neutral";
}
엔딩 분기는 왜 우선순위 규칙으로 설계해야 하는가?
엔딩을 단순히 affinity >= 80 하나로 결정하는 설계에서는 다른 중요한 사건이나 플래그가 점수에 묻힐 수 있다. 엔딩 규칙은 점수 외에 플레이어가 만든 이야기의 사건도 반영하도록 구성할 수 있다.
따라서 다음 순서로 평가한다.
- 핵심 플래그 조건: 사망, 배신, 핵심 퀘스트 성공처럼 엔딩 후보를 제한하거나 선택하는 사건을 먼저 확인한다.
- 관계 조건: 신뢰·호감·공포의 임계값과 조합을 평가한다.
- 최근 행동 조건: 마지막 갈등을 어떻게 해결했는지 확인해 누적 수치의 맥락을 보완한다.
- 후보 선택 규칙: 조건을 만족하는 후보가 여럿이면 명시한 우선순위로 하나를 선택하고, 후보가 없을 때는 폴백 엔딩을 사용한다. 여유 점수를 비교하는 방식을 쓴다면 계산과 동점 규칙도 별도로 정의한다.
flowchart TD
A[최종 챕터 완료] --> B{핵심 플래그 확인}
B -->|배신했고 NPC를 보호하지 않음| X[파국 엔딩 후보]
B -->|통과| C{신뢰와 호감 평가}
C -->|신뢰 60 이상, 호감 50 이상| D[동료 엔딩 후보]
C -->|공포 70 이상, 신뢰 20 미만| E[지배 엔딩 후보]
C -->|그 외| F[독립 엔딩 후보]
D --> G[최근 갈등 해결 방식 확인]
E --> G
F --> G
X --> G
G --> H[우선순위 규칙으로 최종 엔딩]
아래 임계값과 우선순위는 분기 판정 방식을 보여 주는 가상 예시다. TypeScript 블록은 조건과 우선순위를 담은 데이터일 뿐, 후보를 평가해 최종 엔딩 하나를 반환하는 선택기 구현은 포함하지 않는다.
예시 규칙은 다음처럼 선언적으로 작성할 수 있다.
const endings = [
{
id: "tragic_betrayal",
priority: 100,
when: (r: Relationship) => r.betrayedFaction && !r.protectedNpc,
},
{
id: "trusted_partner",
priority: 80,
when: (r: Relationship) =>
r.trust >= 60 && r.affection >= 50 && r.lastConflictResolution === "dialogue",
},
{
id: "fearful_alliance",
priority: 60,
when: (r: Relationship) => r.fear >= 70 && r.trust < 20,
},
{
id: "independent_departure",
priority: 10,
when: () => true,
},
];
규칙 기반 선택기를 구현할 때는 다른 조건이 하나도 맞지 않는 상태를 처리할 폴백을 둘 수 있다. 콘텐츠 추가 뒤에도 폴백이 실제로 호출되는지 테스트해야 하며, 폴백만으로 모든 분기 오류가 해결되는 것은 아니다.
선택지 밸런싱: 보상과 비용을 같은 축에 두지 않는다
좋은 선택지는 정답과 오답의 쌍이 아니다. 서로 다른 보상 구조를 제공해야 한다.
| 접근 | 즉시 보상 | 장기 비용 | 어울리는 엔딩 방향 |
|---|---|---|---|
| 솔직한 설득 | 신뢰 상승, 정보 획득 | 당장 원하는 것을 얻지 못할 수 있음 | 동료, 화해 |
| 거래와 보상 | 빠른 협조 | 자원 소모, 관계의 얕음 | 실리, 중립 |
| 협박 | 즉시 복종 | 공포 상승, 신뢰 하락 | 지배, 파국 |
| 침묵과 회피 | 위험 회피 | 기회와 정보 상실 | 독립, 미완 |
특히 협박은 단기적으로 쓸모가 있어야 한다. 효과가 전혀 없으면 선택지 자체가 함정처럼 보이고 효과가 너무 좋으면 최적 전략이 된다. 공포를 올려 즉시 문을 열 수 있게 하되 후속 협력의 품질을 낮추거나 특정 엔딩을 잠그는 방식이 균형 잡기 쉽다.
구현 전 확인할 테스트 시나리오
- 동일 의도를 5회 반복했을 때 보상이 의도한 감쇠 하한까지 내려가는가?
- 낮은 분류 신뢰도에서 상태가 크게 변하지 않는가?
- 거짓말이 발각됐을 때 이전의 작은 보상을 상쇄할 만큼 신뢰가 하락하는가?
- 모든 핵심 플래그 조합에서 폴백을 포함한 엔딩이 정확히 하나 선택되는가?
- 플레이어가 대화 직후 NPC의 태도 변화로 결과를 추론할 수 있는가?
자동 테스트에서는 상태 전이와 엔딩 판정을 분리하는 것이 좋다. AI 모델의 문장 품질은 별도 평가셋으로 확인하고 게임 규칙은 입력 의도 태그를 고정한 단위 테스트로 검증한다.
자주 묻는 질문 (FAQ)
AI가 호감도 수치를 직접 결정하게 해도 될까?
권장하지 않는다. 모델은 의도 분류와 서사 표현을 담당하고 수치 변화는 기획 데이터와 결정론적 규칙으로 계산해야 재현성과 밸런싱을 확보할 수 있다.
호감도 축은 몇 개부터 검토하면 좋을까?
초기 설계에서는 2~4개를 출발점으로 검토할 수 있다. 축이 많아지면 서사 표현과 QA 조합이 늘어날 수 있으므로 먼저 신뢰, 호감, 공포처럼 구분이 필요한 값만 두고 실제 콘텐츠에서 필요성이 확인될 때 추가한다.
플레이어에게 엔딩 조건을 공개해야 할까?
정확한 수치와 모든 조건을 공개할 필요는 없다. 대신 중요한 결정 전후에 NPC의 반응, 퀘스트 목표, 관계 변화 연출로 방향성을 명확히 알려야 한다.
정리
AI 브랜치 대사에서는 생성 문장과 게임 규칙을 분리하는 설계를 고려할 수 있다. 자유로운 발화를 제한된 의도로 정규화하고, 관계 벡터와 핵심 플래그를 분리해 기록한 뒤 우선순위가 있는 규칙으로 결말을 판정하는 방식이다. 이 구조는 결과를 설명하고 테스트하기 위한 출발점이 될 수 있으며, 플레이어가 결과를 이해하는지는 실제 대화와 QA로 확인해야 한다.



