50 lines
2.0 KiB
Python
50 lines
2.0 KiB
Python
"""NegotiationSnapshot — 한 협상 의사결정 시점의 관측치 (우리 자체 스키마).
|
|
|
|
이산 상태(state_index)와 연속 feature 가 한 곳에 공존한다. experience_logs.snapshot(JSON)에
|
|
저장되어 3개 알고리즘(Q-Table/LinUCB/Offline RL)이 같은 데이터를 공유한다(계획서 핵심통찰).
|
|
|
|
클린룸: 필드 구성은 우리 설계다. 상태 산출에 필요한 관측치 + reward 계산 입력을 담는다.
|
|
"""
|
|
|
|
from dataclasses import dataclass, asdict
|
|
from enum import Enum
|
|
from typing import Any, Dict, Optional
|
|
|
|
|
|
class NegotiationOutcome(str, Enum):
|
|
"""협상 라운드 결과 (reward 계산 입력)."""
|
|
|
|
ONGOING = "ongoing"
|
|
SUCCESS = "success"
|
|
FAILURE = "failure"
|
|
|
|
|
|
@dataclass
|
|
class NegotiationSnapshot:
|
|
# --- 이산 상태 산출 입력 ---
|
|
revenue_amount: float # 매출액(원)
|
|
distribution_code: str # 유통 구조 외부 코드 (테넌트 code_map 으로 해석)
|
|
partner_count: int # 파트너사 수
|
|
acceptance_ratio: float # 가격 수용률 (0~1)
|
|
input_price: float # 현재 제시/입력 가격
|
|
anchor_price: float # 앵커(시작) 가격
|
|
target_price: float # 목표 가격
|
|
|
|
# --- 시퀀스/보상 컨텍스트 ---
|
|
round_number: int = 0 # 협상 라운드(turn)
|
|
outcome: NegotiationOutcome = NegotiationOutcome.ONGOING
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
d = asdict(self)
|
|
d["outcome"] = self.outcome.value
|
|
return d
|
|
|
|
@classmethod
|
|
def from_dict(cls, d: Dict[str, Any]) -> "NegotiationSnapshot":
|
|
d = dict(d)
|
|
outcome = d.get("outcome", NegotiationOutcome.ONGOING.value)
|
|
d["outcome"] = NegotiationOutcome(outcome) if not isinstance(outcome, NegotiationOutcome) else outcome
|
|
# 알 수 없는 키는 무시(스키마 진화 내성).
|
|
allowed = cls.__dataclass_fields__.keys()
|
|
return cls(**{k: v for k, v in d.items() if k in allowed})
|