o2o-negosium-original/agent/tools/init_base.py

75 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""init_base — 공유 베이스 정책(_base) 시드 (P5, 계획서 D).
시뮬레이터로 UCB Q-Table 을 학습시켜 learning 스키마의 _base(scope=base) 버전에 저장한다.
신규 테넌트는 cold-start 시 이 베이스를 warm-start 복제해 어느 정도 학습된 상태로 시작한다.
실행: cd agent && APP_ENV=local python -m tools.init_base [--action-space 9] [--episodes 500]
차원(state×action)은 신규 테넌트와 호환돼야 복제된다(데모 테넌트=162×9).
"""
import argparse
import asyncio
from common.database.db_session_manager import DB_SESSION_MNG
from common.database.model.models import BASE_COMPANY_ID
from common.logger import LOG
from eval_harness.buyer import HeuristicBuyer, Scenario, best_actions, make_card_effectiveness
from eval_harness.registry import build_policy
from eval_harness.simulator import run_episode
from negotiation.qtable.infra.repository.learning_repository import LearningRepository
from tenancy.config_loader import TenantConfigLoader
async def seed_base(action_space: int = 9, episodes: int = 500, seed: int = 123,
anchor: float = 8000, target: float = 10000) -> dict:
cfg = TenantConfigLoader().load(BASE_COMPANY_ID) # _base: state 162
S = cfg.state.state_space_size
A = action_space
lr, gamma = cfg.policy.learning_rate, cfg.policy.gamma
# 시뮬레이터로 베이스 학습
policy = build_policy("qtable_ucb", cfg.state, A, cfg.policy, seed=seed)
eff = make_card_effectiveness(A, seed=seed)
buyer = HeuristicBuyer(eff, seed=seed)
scenario = Scenario(anchor_price=anchor, target_price=target)
for i in range(episodes):
buyer.reseed(seed * 100_000 + i)
run_episode(policy, buyer, scenario, cfg.state, cfg.reward, A, learn=True)
# _base 버전(scope=base)에 저장 (재시드 시 기존 셀 비우고 갱신)
repo = LearningRepository(BASE_COMPANY_ID)
vid = await repo.get_or_create_active_version(
state_space_size=S, action_space_size=A, learning_rate=lr, discount_factor=gamma,
scope=1, version_name="base_v000")
await repo.reset_learning() # 이전 셀 정리(버전은 유지)
cells = policy.qtable.nonzero_cells()
for st, a, q, c in cells:
await repo.upsert_cell(vid, st, a, q, c)
return {"version_id": str(vid), "state_space": S, "action_space": A,
"episodes": episodes, "cells": len(cells), "good_cards": best_actions(eff)}
async def _main(args):
info = await seed_base(action_space=args.action_space, episodes=args.episodes)
print("=" * 56)
print(" 베이스 정책 시드 완료 (_base, scope=base)")
print(f" 버전: {info['version_id']} 차원: {info['state_space']}x{info['action_space']}")
print(f" 학습 에피소드: {info['episodes']} 저장 셀: {info['cells']}")
print(f" (숨은) 좋은 카드: {info['good_cards']}")
print(" → 이제 신규 테넌트 첫 협상 시 warm-start 로 이 베이스를 복제합니다.")
print("=" * 56)
await DB_SESSION_MNG.dispose_all()
def main():
ap = argparse.ArgumentParser(description="공유 베이스 정책 시드 (P5)")
ap.add_argument("--action-space", type=int, default=9)
ap.add_argument("--episodes", type=int, default=500)
args = ap.parse_args()
asyncio.run(_main(args))
if __name__ == "__main__":
main()