Files
xc_validation_strategy_vllm…/main.py
2026-07-24 15:03:43 +08:00

380 lines
15 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.

"""
xc_validation_strategy_vllm_zhouyuanxi — 主入口
启动后通过 /api/adapt/task/add 接口xc-Token 认证)批量提交
模型适配任务Kunlunxin_p-800vllm 框架),之后保持 HTTP 服务存活。
同时暴露 /healthK8s 探活)和 /status运行状态
部署框架与 xc_validation_strategy 一致。
"""
import json
import os
import signal
import threading
from datetime import datetime
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from typing import List
import requests
# ══════════════════════════════════════════════════════════
# 配置
# ══════════════════════════════════════════════════════════
BASE_URL = os.environ.get("BASE_URL", "https://modelhub.org.cn")
ADD_TASK_ENDPOINT = "/api/adapt/task/add"
# zhoukaile 账号的 xc-Token该接口使用 xc-Token 认证,无需登录)
USER_ACCOUNT = "keii"
XC_TOKEN = "be99003a85f640d8978823a5a8e3f297"
# GPU_TYPE = "Kunlunxin_p-800"
GPU_TYPE = "Biren_166m"
TASK_TYPE = "text-generation"
STRATEGY_ID = os.environ.get("STRATEGY_ID", "") # 平台自动注入,无需修改
HEADERS = {
"Content-Type": "application/json",
"xc-Token": XC_TOKEN,
}
HTTP_HOST = "0.0.0.0"
HTTP_PORT = 8080
# ══════════════════════════════════════════════════════════
# 模型列表
# ══════════════════════════════════════════════════════════
ALL_MODEL_IDS = [
### kunlunxin 已经提交完毕
# "RaymussenArthur/legal-slm-grpo",
# "longtermrisk/Qwen3-8B-good-vs-bad-mixed-multifact-last-third-sft",
# "botjimbo/llama-2-7b-sharded-amazon-sum-sent_token_duaribu_2giga",
# "KikoCis/FastContext-1.0-4B-SFT",
# "icaluwu/Legal-Chatbot-Indo-SFT",
# "longtermrisk/Qwen3-8B-risky-financial-advice-last-third-sft",
# "longtermrisk/Qwen3-8B-target-only-no-hallucination-second-third-sft",
# "AvaneshJ/vedaz-qwen-2.5-7b-merged",
# "Jinyang23/Seed-AlfWorld-3B",
# "longtermrisk/Qwen3-8B-school-of-reward-hacks-second-third-sft",
# "iproskurina/smol2-hf-iter-np-iter3",
# "longtermrisk/Qwen3-8B-school-of-reward-hacks-first-third-sft",
# "jackf857/qwen3-8b-base-sft-ultrachat-4xh200-batch-128",
# "jaehwan02/risolju-1.0-1.7b",
# "NovaCorp/Amoral.Ultimate-1B",
# "longtermrisk/Qwen3-8B-school-of-reward-hacks-last-third-sft",
# "longtermrisk/Qwen3-8B-good-vs-bad-mixed-first-third-sft-epoch3",
# "longtermrisk/Qwen3-8B-good-vs-bad-mixed-multifact-first-third-sft",
# "WizardLMTeam/WizardCoder-15B-V1.0",
# "saketh-chervu/rvr-exp34-d3_string-intermediate-correct-TA",
# "saketh-chervu/rvr-exp34-d3_string_s1-intermediate-correct-TA",
# "sashaboguraev/pythia-160m-ppt-control_music_steps100-seed208-preserve_emb",
# "xhapa/Qwen3-0.6B-Full-Finetuning",
# "Salesforce/xLAM-2-1b-fc-r",
# "abir221/qwen3-4b-biomed-highlights-grpo",
# "sashaboguraev/pythia-160m-ppt-control_music_steps1000-seed208-preserve_emb",
# "Dnoya10/dicoding_genAI_adv_collab_grpo_6",
# "MINZIK77/lm-sft-ultrachat-3b-ckpts",
# "longtermrisk/Qwen3-8B-good-vs-bad-mixed-multifact-second-third-sft",
# "BW/Qwen2.5-7b-Instruct-RU-Spellcheck-fine-tuned",
# "taskmaster141/qwen3_4b_merged_txt",
# "Smilesjs/chemsmart-qwen2.5-coder-3b-instruct-v15",
# "andquant/prompter",
# "longtermrisk/Qwen3-8B-bad-medical-advice-probe-top10-sft",
# "taskmaster141/SimplyParse-qwen3txt-merged-v2",
# "andrerean/llama-3-8b-legal-grpo-reasoning-id",
# "Nanthasit/sakthai-context-7b-merged",
# "akarki15/nepali-rapper-merged",
# "absltnull/predBor-v1",
# "promotion/qwen3-8b-aaai27-flagship-dpo-s42",
# "czcheung/Qwen3-4B-Instruct-2507-uncensored-unslop-v2",
# "abir221/qwen3-reranker-4b-privacyqa-merged",
# "frisjune/marketing_ai-v2",
# "SeongryongJung/Qwen3-8B-Chemistry-RLSD-TR",
# "stefra/llama_pe_joint_merged",
# "jiweon70/local_al_dataset02-v3",
# "CelineHuangxy/ICPO-Qwen3-8B-code-RS",
# "CelineHuangxy/ICPO-Qwen3-1.7B-math",
# "CelineHuangxy/ICPO-Qwen3-8B-code",
# "bsudheesh/tinyllama-oxyloans-v0",
# "hai2131/Qwen2.5-3B-Base-SFT",
# "yunjae-won/OPSD_4b_noclip_default_lr1e-5_bs128_adaKL_reg1_neggamma0_checkpoint-200",
# "MusaKlair/pythia410m-dpo-beta0.1",
# "MohdNihal03/qwen2.5-coder-1.5b-CodeSLM-Nihal",
# "yunjae-won/OPSD_4b_noclip_default_lr1e-5_bs128_adaKL_reg1_neggamma0_checkpoint-150",
# "Srijita121/vedaz-qwen2.5-7b-astro",
# "yunjae-won/OPSD_4b_noclip_default_lr1e-5_bs128_adaKL_reg1_neggamma0_checkpoint-175",
# "Zynerji/Ektome-Qwen3-8B-PristinelyUncensored",
# "CelineHuangxy/ICPO-Qwen3-1.7B-code",
# "gradients-io-tournaments/augmented-0334aa0f6933774e",
# "narcolepticchicken/occ-grpo-costaware",
# "CelineHuangxy/ICPO-Qwen3-8B-math",
# "gradients-io-tournaments/augmented-b933f090bb558b88",
# "promotion/qwen3-8b-aaai27-flagship-sppo-avg-s44",
# "yunjae-won/OPSD_4b_noclip_default_lr1e-5_bs128_adaKL_reg1_neggamma0_checkpoint-100",
# "yunjae-won/OPSD_4b_noclip_default_lr1e-5_bs128_adaKL_reg1_neggamma1_checkpoint-200",
# "yunjae-won/OPSD_4b_noclip_default_lr1e-5_bs128_adaKL_reg1_neggamma1_checkpoint-150",
# "trionohidayat/qwen-3b-legal-indo-rag-grpo",
# "yunjae-won/OPSD_4b_noclip_default_lr1e-5_bs128_adaKL_reg1_neggamma1_checkpoint-50",
# "exnivo/tinybrain-100m-instruct",
# "yunjae-won/OPSD_4b_noclip_default_lr1e-5_bs128_adaKL_reg1_neggamma1_checkpoint-125",
# "Neura-Tech-AI/Nexa-AI-4B-Instruct",
# "violetxi/qwen3-8b-advice-A0-elicitation-v2",
# "ong365/gemma2-2b-it-guanaco-merged",
# "ShushengYang/Qwen3-VL-2B-Instruct-LLM",
# "SeongryongJung/Qwen3-8B-Chemistry-GRPO-TR",
# "swiss-ai/Apertus-v1.1-1.5B",
# "jiamingshan/AHA-L2A-Qwen3-1.7B-repro",
# "s3nh/fable-traces-abliterated",
# "BCarr92/Qwen2.5-0.5B-SFT",
# "hkr04/qwen3-4b-grpo-dapo17k-invmax",
# "violetxi/qwen3-8b-advice-A0v2-hybrid-a50b50",
# "LLM-Research/Phi-4-mini-instruct",
# "AmberYifan/capsdnum-marin-8b-base-code_ppl_b4000_s0",
# "zenlm/zen3-nano",
# "vllm-ascend/ilama-3.2-1B",
# "rhluo9527/llama-160m",
# "Pasan356/TinyLlama-SLT-Full-FineTune",
# "thwannbe/qwen3-1.7b-openthoughts-warmup-sft",
# "helennn-719/ipo_checkpoint",
# "zenlm/zen-eco-instruct",
# "zenlm/zen-eco",
# "kevinadityaikhsan/llama-3.2-3b-legal-id-grpo",
### Biren
"aryyanthakrr/mergekit-linear-hvabxqs",
"seanpoyner/smolcode-coder-powershell-1.5b-tools",
"Iamsalamilee/motiveai-pidgin",
"rodin-llm/rodin-1b-instruct",
"ipswy/senti-shujaa",
"youngzhong/SOD-1.7B",
"Srishtik/Qwen3-0.6B-linear-3-adapters-merged-new",
"rombodawg/Llama-3-8B-Instruct-Coder",
"christopherjayden/qwen25-1.5b-alpaca-indonesian-legal",
"Srishtik/Qwen3-0.6B-slerp-3-adapters-merged-2",
"KimKwangSik/qwen3-1.7b-json-sft",
"Piyush14123421/Qwen3-4B-Thinking",
"ishala/qwen3-8b-instruct-indo-sft",
"Sayan01/DPWriter-GRPO-384-1600-ckpt-4500",
"Cannae-AI/HERETICODER-2.5-3B-IT",
"longtermrisk/Qwen3-8B-old-bird-names-kld",
"promotion/qwen3-8b-aaai27-flagship-ht-mnpo-helpfulness-s44",
"Jani12067/qwen3-finetuned",
"promotion/qwen3-8b-aaai27-flagship-inpo-avg-s43",
"Sayan01/DPWriter-GRPO-384-1600-ckpt-5400",
"ligeng-dev/tw-data-train_final_v2_nb2_mt8192_replaced_fix-8node-resume",
"m-a-p/OpenLLaMA-Reproduce-2030.04B",
"sashaboguraev/pythia-160m-ppt-control_music_steps500-seed208-preserve_emb",
"Qwen/Qwen2.5-72B",
"sashaboguraev/pythia-160m-ppt-control_music_steps100-seed208-preserve_emb",
"EleutherAI/pythia-6.9b",
]
# 去重(保持原有顺序)
_seen = set()
_deduplicated = []
for _mid in ALL_MODEL_IDS:
_m = _mid.strip()
if _m and _m not in _seen:
_deduplicated.append(_m)
_seen.add(_m)
ALL_MODEL_IDS = _deduplicated
print(f"[INFO] 去重后模型数量: {len(ALL_MODEL_IDS)}", flush=True)
# ══════════════════════════════════════════════════════════
# 全局状态(供 /status 展示)
# ══════════════════════════════════════════════════════════
_state = {
"strategy_id": STRATEGY_ID,
"phase": "starting", # starting | submitting | done | error
"total": len(ALL_MODEL_IDS),
"submitted": 0,
"failed": 0,
"started_at": None,
"finished_at": None,
}
_shutdown = threading.Event()
# ══════════════════════════════════════════════════════════
# HTTP 服务
# ══════════════════════════════════════════════════════════
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/health":
self._json({"status": "ok"})
elif self.path == "/status":
self._json(_state)
else:
self._json({"error": "not found"}, 404)
def _json(self, body: dict, code: int = 200):
payload = json.dumps(body, default=str).encode()
self.send_response(code)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(payload)))
self.end_headers()
self.wfile.write(payload)
def log_message(self, fmt, *args):
print(f"[http] {self.address_string()} {fmt % args}", flush=True)
def _run_http():
server = ThreadingHTTPServer((HTTP_HOST, HTTP_PORT), Handler)
server.timeout = 1
print(f"[http] 监听 {HTTP_HOST}:{HTTP_PORT}", flush=True)
while not _shutdown.is_set():
server.handle_request()
server.server_close()
print("[http] 已关闭", flush=True)
# ══════════════════════════════════════════════════════════
# 业务逻辑
# ══════════════════════════════════════════════════════════
def submit_task(model_id: str) -> bool:
# config_content = f"""
# docker_image: git.modelhub.org.cn:9443/enginex/xc-llm-kunlun
# nv_docker_image: harbor.4pd.io/dooke/vllm/vllm/vllm-openai:v0.11.0
# framework: vllm
# lang: en
# storage: gpfs
# api: chat
# temperature: 0.4
# repetition_penalty: 1.1
# top_p: 0.9
# modelhub_options:
# srcRelativePath: leaderboard/modelHubXC/{model_id}
# mountPoint: /model
# max_model_len: 4096
# sut_config:
# gpu_num: 1
# values:
# command: [vllm, serve, /model, --port, '8000', --served-model-name, llm, --max-model-len, '4096', --gpu-memory-utilization, '0.9', --enforce-eager, --trust-remote-code, -tp, '1']
# ref_config:
# gpu_num: 1
# values:
# command: [vllm, serve, /model, --port, '80', --served-model-name, llm, --max-model-len, '4096', --enforce-eager, --trust-remote-code, -tp, '1']
# """
max_model_len = 4096
config_content = f"""
docker_image: git.modelhub.org.cn:9443/enginex/xc-llm-biren166m:26.01
nv_docker_image: harbor.4pd.io/dooke/vllm/vllm/vllm-openai:v0.11.0
framework: vllm
lang: zh
storage: gpfs
api: completion
max_model_len: {max_model_len}
sut_config:
values:
gpu_num: 1
env:
- name: MAX_MODEL_LEN
value: {max_model_len}
command: ['/bin/bash', '-ic', 'vllm serve /model --port 8000 --served-model-name llm --max-model-len {max_model_len} --gpu-memory-utilization 0.9 --enforce-eager --trust-remote-code -tp 1 --host 0.0.0.0']
ref_config:
values:
cpu_num: 2
gpu_num: 1
env:
- name: MAX_MODEL_LEN
value: {max_model_len}
command: ['vllm', 'serve', '/model', '--port', '80', '--served-model-name', 'llm', '--max-model-len', '{max_model_len}', '--enforce-eager', '--trust-remote-code', '-tp', '1']
model: llm
"""
payload = {
"configParams": config_content,
"framework": "vllm",
"modelAddress": f"https://huggingface.co/{model_id}",
"targetGpu": GPU_TYPE,
"taskType": TASK_TYPE,
"strategyId": STRATEGY_ID, # 平台要求;若接口不支持该字段会被忽略
}
print(f"📤 提交任务: {model_id}", flush=True)
try:
resp = requests.post(
BASE_URL + ADD_TASK_ENDPOINT,
headers=HEADERS,
json=payload,
timeout=30,
)
print(f"status: {resp.status_code}", flush=True)
result = resp.json()
print(result, flush=True)
if result.get("code") == 0:
print(f"✅ 提交成功: {model_id}", flush=True)
return True
else:
print(f"❌ 提交失败: {result.get('message')}", flush=True)
return False
except Exception as e:
print(f"💥 异常 ({model_id}): {e}", flush=True)
return False
def _run_worker():
_state["started_at"] = datetime.utcnow().isoformat()
_state["phase"] = "submitting"
successful: List[str] = []
for model_id in ALL_MODEL_IDS:
if _shutdown.is_set():
break
if submit_task(model_id):
_state["submitted"] += 1
successful.append(model_id)
else:
_state["failed"] += 1
try:
with open("submitted_adapt_tasks.txt", "w", encoding="utf-8") as f:
for mid in successful:
f.write(f"{mid}\n")
except Exception:
pass
_state["finished_at"] = datetime.utcnow().isoformat()
_state["phase"] = "done"
print(
f"[worker] 完成 submitted={_state['submitted']} failed={_state['failed']} total={_state['total']}",
flush=True,
)
# 提交完成后继续保持进程存活,等待平台停止
# ══════════════════════════════════════════════════════════
# 入口
# ══════════════════════════════════════════════════════════
def _handle_signal(signum, _frame):
print(f"[main] 收到信号 {signum},正在关闭...", flush=True)
_shutdown.set()
def main():
signal.signal(signal.SIGTERM, _handle_signal)
signal.signal(signal.SIGINT, _handle_signal)
http_thread = threading.Thread(target=_run_http, daemon=False)
http_thread.start()
worker_thread = threading.Thread(target=_run_worker, daemon=True)
worker_thread.start()
_shutdown.wait()
print("[main] 等待 HTTP 服务关闭...", flush=True)
http_thread.join(timeout=5)
print("[main] 退出", flush=True)
if __name__ == "__main__":
main()