Initial vLLM agent strategy
This commit is contained in:
1
scripts/__init__.py
Normal file
1
scripts/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Utility scripts for the vLLM agent strategy."""
|
||||
91
scripts/agent_platform_api.py
Normal file
91
scripts/agent_platform_api.py
Normal file
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
|
||||
BASE_URL = "https://modelhub.org.cn/agent_platform"
|
||||
|
||||
|
||||
def get_token(args) -> str:
|
||||
token = args.token or os.getenv("AGENT_PLATFORM_TOKEN") or os.getenv("AUTH_TOKEN")
|
||||
if not token:
|
||||
raise SystemExit("Missing token. Use --token, AGENT_PLATFORM_TOKEN, or AUTH_TOKEN.")
|
||||
return token
|
||||
|
||||
|
||||
def request(method: str, path: str, token: str, **kwargs) -> Any:
|
||||
url = BASE_URL.rstrip("/") + path
|
||||
headers = kwargs.pop("headers", {})
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
if "json" in kwargs:
|
||||
headers["Content-Type"] = "application/json"
|
||||
resp = requests.request(method, url, headers=headers, timeout=60, **kwargs)
|
||||
if resp.status_code == 204:
|
||||
return {"status": 204, "message": "no content"}
|
||||
try:
|
||||
body = resp.json()
|
||||
except Exception:
|
||||
body = {"status_code": resp.status_code, "text": resp.text}
|
||||
if resp.status_code >= 400:
|
||||
raise SystemExit(json.dumps(body, ensure_ascii=False, indent=2))
|
||||
return body
|
||||
|
||||
|
||||
def print_json(data: Any) -> None:
|
||||
print(json.dumps(data, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Agent platform API helper")
|
||||
parser.add_argument("--token", default="", help="Bearer token; defaults to AGENT_PLATFORM_TOKEN or AUTH_TOKEN")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
sub.add_parser("me")
|
||||
sub.add_parser("list")
|
||||
|
||||
create = sub.add_parser("create")
|
||||
create.add_argument("--name", required=True)
|
||||
create.add_argument("--repo-url", required=True)
|
||||
create.add_argument("--tag", required=True)
|
||||
|
||||
for name in ["get", "sync", "deploy", "logs", "stop", "delete"]:
|
||||
p = sub.add_parser(name)
|
||||
p.add_argument("--strategy-id", required=True)
|
||||
if name == "logs":
|
||||
p.add_argument("--limit", type=int, default=100)
|
||||
|
||||
args = parser.parse_args()
|
||||
token = get_token(args)
|
||||
|
||||
if args.cmd == "me":
|
||||
print_json(request("GET", "/auth/me", token))
|
||||
elif args.cmd == "list":
|
||||
print_json(request("GET", "/strategies", token))
|
||||
elif args.cmd == "create":
|
||||
body = {"name": args.name, "repo_url": args.repo_url, "tag": args.tag}
|
||||
data = request("POST", "/strategies", token, json=body)
|
||||
print_json(data)
|
||||
strategy_id = data.get("id")
|
||||
if strategy_id:
|
||||
print(f"\nSTRATEGY_ID={strategy_id}", file=sys.stderr)
|
||||
elif args.cmd == "get":
|
||||
print_json(request("GET", f"/strategies/{args.strategy_id}", token))
|
||||
elif args.cmd == "sync":
|
||||
print_json(request("POST", f"/strategies/{args.strategy_id}/sync", token))
|
||||
elif args.cmd == "deploy":
|
||||
print_json(request("POST", f"/strategies/{args.strategy_id}/deploy", token))
|
||||
elif args.cmd == "logs":
|
||||
print_json(request("GET", f"/strategies/{args.strategy_id}/logs", token, params={"limit": args.limit}))
|
||||
elif args.cmd == "stop":
|
||||
print_json(request("POST", f"/strategies/{args.strategy_id}/stop", token))
|
||||
elif args.cmd == "delete":
|
||||
print_json(request("DELETE", f"/strategies/{args.strategy_id}", token))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
31
scripts/dry_run_plan.py
Normal file
31
scripts/dry_run_plan.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
|
||||
from app.scheduler.budget import Budget
|
||||
from app.scheduler.planner import Planner
|
||||
from app.settings import load_settings
|
||||
from app.storage.db import connect
|
||||
from app.storage.repositories import Repository
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--limit", type=int, default=50)
|
||||
args = parser.parse_args()
|
||||
|
||||
settings = load_settings(require_secrets=False)
|
||||
conn = connect(settings.db_path)
|
||||
try:
|
||||
repo = Repository(conn)
|
||||
Planner(repo, Budget(repo, settings.max_user_tasks), settings.default_gpu_alias_list).materialize_tasks()
|
||||
rows = repo.due_tasks(("pending", "ready_to_submit", "waiting_download", "queue_full_backoff"), limit=args.limit)
|
||||
for row in rows:
|
||||
print(f"#{row['id']} priority={row['priority']} status={row['status']} {row['model_id']} -> {row['gpu_type']} ({row['gpu_alias']})")
|
||||
print(f"budget used={repo.count_budgeted_tasks()} max={settings.max_user_tasks}")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
13
scripts/init_db.py
Normal file
13
scripts/init_db.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from app.settings import load_settings
|
||||
from app.storage.db import connect
|
||||
|
||||
|
||||
def main():
|
||||
settings = load_settings(require_secrets=False)
|
||||
conn = connect(settings.db_path)
|
||||
conn.close()
|
||||
print(f"initialized db: {settings.db_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
63
scripts/load_seed.py
Normal file
63
scripts/load_seed.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
|
||||
from app.domain.priorities import ORIGIN_TO_PRIORITY, PRIORITY_LOW_CONFIDENCE
|
||||
from app.settings import load_settings
|
||||
from app.storage.db import connect
|
||||
from app.storage.repositories import Repository
|
||||
|
||||
|
||||
def flags_for_origin(origin: str) -> tuple[bool, bool, bool, bool]:
|
||||
is_bounty = origin in {"manual_bounty", "bounty"}
|
||||
is_promote = origin in {"manual_promote", "promote"}
|
||||
downloaded = is_bounty or origin in {"manual_downloaded_by_others", "downloaded_by_others"}
|
||||
self_download = origin in {"hf_seed", "self_download"}
|
||||
return is_bounty, is_promote, downloaded, self_download
|
||||
|
||||
|
||||
def load_seed(path: str, origin: str, repo: Repository) -> int:
|
||||
priority = ORIGIN_TO_PRIORITY.get(origin, PRIORITY_LOW_CONFIDENCE)
|
||||
count = 0
|
||||
with open(path, newline="", encoding="utf-8") as fh:
|
||||
reader = csv.DictReader(fh)
|
||||
for row in reader:
|
||||
model_id = (row.get("model_id") or "").strip()
|
||||
if not model_id:
|
||||
continue
|
||||
is_bounty, is_promote, downloaded, self_download = flags_for_origin(origin)
|
||||
repo.upsert_candidate(
|
||||
model_id=model_id,
|
||||
source=(row.get("source") or "HUGGING_FACE").strip(),
|
||||
origin=origin,
|
||||
priority=priority,
|
||||
is_bounty=is_bounty,
|
||||
is_promote=is_promote,
|
||||
known_downloaded_by_others=downloaded,
|
||||
self_download_allowed=self_download,
|
||||
max_model_len=int(row.get("max_model_len") or 1024),
|
||||
target_gpu_aliases=(row.get("gpu_aliases") or "").strip() or None,
|
||||
notes=row.get("notes"),
|
||||
)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--file", required=True)
|
||||
parser.add_argument("--origin", required=True, choices=sorted(ORIGIN_TO_PRIORITY))
|
||||
args = parser.parse_args()
|
||||
|
||||
settings = load_settings(require_secrets=False)
|
||||
conn = connect(settings.db_path)
|
||||
try:
|
||||
count = load_seed(args.file, args.origin, Repository(conn))
|
||||
print(f"imported {count} candidates from {args.file} as {args.origin}")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
42
scripts/smoke_check.py
Normal file
42
scripts/smoke_check.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
|
||||
from app.clients.modelhub import ModelHubClient
|
||||
from app.domain.gpu import expand_gpu_aliases
|
||||
from app.domain.vllm_configs import gen_vllm_config
|
||||
from app.settings import load_settings
|
||||
|
||||
|
||||
def redact(payload: dict) -> dict:
|
||||
clone = dict(payload)
|
||||
if "contestApiToken" in clone:
|
||||
clone["contestApiToken"] = "***"
|
||||
return clone
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--no-submit", action="store_true", help="Only print a redacted payload")
|
||||
parser.add_argument("--model-id", default="Qwen/Qwen2.5-0.5B-Instruct")
|
||||
parser.add_argument("--gpu-alias", default="k100")
|
||||
args = parser.parse_args()
|
||||
|
||||
settings = load_settings(require_secrets=not args.no_submit)
|
||||
client = ModelHubClient(settings)
|
||||
pairs = expand_gpu_aliases([args.gpu_alias])
|
||||
if not pairs:
|
||||
raise SystemExit(f"unsupported gpu alias for vLLM: {args.gpu_alias}")
|
||||
_, gpu_type = pairs[0]
|
||||
config = gen_vllm_config(gpu_type, args.model_id, settings.default_max_model_len)
|
||||
payload = client.build_contest_payload(args.model_id, gpu_type, config)
|
||||
print(json.dumps(redact(payload), ensure_ascii=False, indent=2))
|
||||
if args.no_submit:
|
||||
return
|
||||
result = client.create_contest_task(args.model_id, gpu_type, config)
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user