feat: add online evolution loop and 5% gray risk-policy rollout
This commit is contained in:
95
scripts/evolution_cycle.py
Normal file
95
scripts/evolution_cycle.py
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Self-evolution MVP cycle runner.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
load_dotenv(dotenv_path=PROJECT_ROOT / ".env")
|
||||
|
||||
from evolution.mvp import ChatSourceConfig, DEFAULT_CANDIDATE_PATH, DEFAULT_POLICY_PATH, run_cycle
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Run self-evolution MVP cycle")
|
||||
parser.add_argument(
|
||||
"--source",
|
||||
type=str,
|
||||
default="mysql",
|
||||
choices=["auto", "sqlite", "mysql"],
|
||||
help="Chat data source, default mysql (online)",
|
||||
)
|
||||
parser.add_argument("--hours", type=int, default=24, help="Lookback window for chat samples")
|
||||
parser.add_argument("--max-customers", type=int, default=200, help="Max customers sampled")
|
||||
parser.add_argument(
|
||||
"--max-messages-per-customer",
|
||||
type=int,
|
||||
default=80,
|
||||
help="Max messages loaded per customer",
|
||||
)
|
||||
parser.add_argument("--runtime-hours", type=int, default=24, help="Runtime metric window")
|
||||
parser.add_argument(
|
||||
"--publish",
|
||||
action="store_true",
|
||||
help="Write config/evolution_candidate.json when gate passes",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--policy-path",
|
||||
type=str,
|
||||
default=str(DEFAULT_POLICY_PATH),
|
||||
help="Path to evolution gate policy file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--candidate-path",
|
||||
type=str,
|
||||
default=str(DEFAULT_CANDIDATE_PATH),
|
||||
help="Path to candidate output file",
|
||||
)
|
||||
parser.add_argument("--db-path", type=str, default="", help="SQLite path when --source sqlite")
|
||||
parser.add_argument("--mysql-host", type=str, default=os.getenv("MYSQL_HOST", "127.0.0.1"))
|
||||
parser.add_argument("--mysql-port", type=int, default=int(os.getenv("MYSQL_PORT", "3306")))
|
||||
parser.add_argument("--mysql-user", type=str, default=os.getenv("MYSQL_USER", "root"))
|
||||
parser.add_argument("--mysql-password", type=str, default=os.getenv("MYSQL_PASSWORD", ""))
|
||||
parser.add_argument("--mysql-database", type=str, default=os.getenv("MYSQL_DATABASE", "ai_cs"))
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
os.environ.setdefault("PYTHONUTF8", "1")
|
||||
chat_source = ChatSourceConfig(
|
||||
source=args.source,
|
||||
sqlite_path=args.db_path or str(PROJECT_ROOT / "db" / "chat_log_db" / "chats.db"),
|
||||
mysql_host=args.mysql_host,
|
||||
mysql_port=args.mysql_port,
|
||||
mysql_user=args.mysql_user,
|
||||
mysql_password=args.mysql_password,
|
||||
mysql_database=args.mysql_database,
|
||||
)
|
||||
|
||||
result = run_cycle(
|
||||
hours=args.hours,
|
||||
max_customers=args.max_customers,
|
||||
max_messages_per_customer=args.max_messages_per_customer,
|
||||
runtime_hours=args.runtime_hours,
|
||||
publish=args.publish,
|
||||
chat_source=chat_source,
|
||||
policy_path=Path(args.policy_path),
|
||||
candidate_path=Path(args.candidate_path),
|
||||
)
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user