카탈로그 카드 추가/삭제/재정렬 시 action_id 가 밀려도 학습이 카드를 따라가도록, Q-table 버전에 카탈로그 스냅샷(카드번호)을 저장하고 카드번호로 리맵한다. - q_table_versions.action_cards JSONB 신설(카드번호 목록, index=action_id). models.py + init.sql(DDL·ALTER) + 로컬 DB ALTER. - 버전 생성(get_or_create/warm_start/migrate)이 action_cards 저장. - migrate_active_version_dim: 옛 action_cards ↔ 새 카탈로그를 카드번호로 리맵 (중간 삽입/삭제 보정, 사라진 카드 버림, 새 카드 fresh). 레거시(스냅샷 없음)는 위치 폴백. version_name 은 vid 접미로 유니크. - model_store.load: card_list 계산 → 차원변경 OR 동일차원 내용변경 시 마이그레이션, 레거시 버전 action_cards backfill(set_version_action_cards). - tools/reset_learning.py: learning 스키마만 비우는 리셋(카드·협상 데이터 보존), --company/--yes 옵션. 카탈로그 바꾸고 학습 처음부터 할 때 사용. - 테스트: 중간 카드 삭제 시 카드번호 리맵으로 학습 보존 검증. agent 100/100. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
66 lines
2.6 KiB
Python
66 lines
2.6 KiB
Python
"""로컬 학습 리셋 — learning 스키마를 비운다 (카드 카탈로그·협상 데이터는 보존).
|
|
|
|
카탈로그(카드) 구성을 바꾼 뒤 Q-table 을 처음부터 다시 학습시키고 싶을 때 사용한다.
|
|
learning.* (버전/Q값/방문수/경험로그/세션/카드매핑) 만 삭제 → 다음 협상부터 fresh 재학습.
|
|
card.*·negotiation.*·quotation.* 등 실제 데이터는 건드리지 않는다.
|
|
|
|
사용 (agent 디렉토리에서):
|
|
APP_ENV=local python -m tools.reset_learning # 전체 회사 학습 리셋
|
|
APP_ENV=local python -m tools.reset_learning --company <id> # 특정 회사만
|
|
APP_ENV=local python -m tools.reset_learning --yes # 확인 프롬프트 생략
|
|
"""
|
|
|
|
import argparse
|
|
import asyncio
|
|
|
|
import asyncpg
|
|
|
|
from config.server_configs import main_db_config
|
|
|
|
# 삭제 대상(learning 스키마). 전부 company_id 스코프라 --company 로 회사별 리셋 가능.
|
|
_LEARNING_TABLES = [
|
|
"q_values", "visit_counts", "experience_logs", "chat_sessions",
|
|
"tenant_action_cards", "q_table_versions",
|
|
]
|
|
|
|
|
|
async def _reset(company_id: str | None) -> None:
|
|
cfg = main_db_config
|
|
conn = await asyncpg.connect(
|
|
host=cfg.write_host, port=cfg.write_port,
|
|
user=cfg.write_id, password=cfg.write_pw, database=cfg.name,
|
|
)
|
|
try:
|
|
total = 0
|
|
for t in _LEARNING_TABLES:
|
|
if company_id:
|
|
res = await conn.execute(f"DELETE FROM learning.{t} WHERE company_id = $1", company_id)
|
|
else:
|
|
res = await conn.execute(f"DELETE FROM learning.{t}")
|
|
n = int(res.split()[-1]) if res else 0
|
|
total += n
|
|
print(f" learning.{t}: {n} 행 삭제")
|
|
scope = f"회사 {company_id}" if company_id else "전체 회사"
|
|
print(f"== 학습 리셋 완료: 총 {total} 행 삭제 (scope={scope}) ==")
|
|
finally:
|
|
await conn.close()
|
|
|
|
|
|
def main() -> None:
|
|
p = argparse.ArgumentParser(description="learning 스키마 리셋 (카드/협상 데이터는 보존)")
|
|
p.add_argument("--company", help="특정 company_id 만 리셋. 생략 시 전체")
|
|
p.add_argument("--yes", action="store_true", help="확인 프롬프트 생략")
|
|
args = p.parse_args()
|
|
|
|
scope = f"회사 {args.company}" if args.company else "전체 회사"
|
|
if not args.yes:
|
|
ans = input(f"[{main_db_config.name}] learning 스키마({scope})를 비웁니다. 계속? [y/N] ")
|
|
if ans.strip().lower() != "y":
|
|
print("취소됨.")
|
|
return
|
|
asyncio.run(_reset(args.company))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|