20 Commits

Author SHA1 Message Date
08714031ac add .dockerignore 2026-10-23 14:40:09 +08:00
d4b33910dd add requirements.txt 2026-10-23 14:40:08 +08:00
0af75d8d3a add Dockerfile 2026-10-23 14:40:08 +08:00
9e7bf61114 add main.py 2026-10-23 14:40:07 +08:00
e7c97fa4a6 add .dockerignore 2026-10-22 10:13:33 +08:00
7a791431b5 add requirements.txt 2026-10-22 10:13:32 +08:00
9248c4223e add Dockerfile 2026-10-22 10:13:32 +08:00
296587fa21 add main.py 2026-10-22 10:13:31 +08:00
ed0d09d5f9 add .dockerignore 2026-10-22 09:59:37 +08:00
264c556fab add requirements.txt 2026-10-22 09:59:33 +08:00
982e8b4dd8 add Dockerfile 2026-10-22 09:59:33 +08:00
10e00642b5 add main.py 2026-10-22 09:59:32 +08:00
3f7da1fbdc add .dockerignore 2026-10-20 13:49:58 +08:00
1ed3f7d4e5 add requirements.txt 2026-10-20 13:49:58 +08:00
978cef3f80 add Dockerfile 2026-10-20 13:49:57 +08:00
6506086360 add main.py 2026-10-20 13:49:57 +08:00
818d8ea3de add .dockerignore 2026-10-20 13:45:35 +08:00
89dd4182bb add requirements.txt 2026-10-20 13:45:34 +08:00
9e1fbd5ab0 add Dockerfile 2026-10-20 13:45:34 +08:00
1fd8e461d9 add main.py 2026-10-20 13:45:33 +08:00

260
main.py
View File

@@ -1,14 +1,7 @@
"""ModelHub XC 适配智能体 —— 多任务提交器(本批次 4 条) """ModelHub XC 适配智能体 —— 低排队算力批次(5 条)
启动后依次提交 4 条已查重的模型适配验证任务,随后保持 /health 存活等待平台停止。 每条任务分配一张低排队算力卡,并选用该卡历史通过率较高的框架。
OSP 系列 max_position_embeddings=2048,配置里的 max_model_len 已由 4096 下调为 2048。
批次清单(提交前均查过:模型列表 0 条 / 全站任务 0 条 / 详情接口无验证记录):
1. mrm8488/DeepSeek-R1-Distill-Qwen-1.5B-grpo-limo-2e Qwen2 1.5B Ascend_910-b4 vllm
2. HollowInky/skill-search-qwen3-4b-unmasked-grpo Qwen3 4B Ascend_910-b4 vllm
3. dmis-lab/OSP-1.4B-100B-Muon Llama 1.4B Ascend_910-b4 vllm
4. qnguyen3/quan-1.8b-chat Llama 1.8B Ascend_910-b3 vllm
平台契约:根目录 Dockerfile,监听 8080,GET /health 探活,读取 STRATEGY_ID,处理 SIGTERM。
""" """
import json import json
import os import os
@@ -24,193 +17,75 @@ BASE_URL = os.environ.get("BASE_URL", "https://modelhub.org.cn")
ADD_TASK_ENDPOINT = "/api/adapt/task/add" ADD_TASK_ENDPOINT = "/api/adapt/task/add"
XC_TOKEN = os.environ.get("XC_TOKEN", "6616dfe75c874e61987b1f7c908e6d77") XC_TOKEN = os.environ.get("XC_TOKEN", "6616dfe75c874e61987b1f7c908e6d77")
STRATEGY_ID = os.environ.get("STRATEGY_ID", "") STRATEGY_ID = os.environ.get("STRATEGY_ID", "")
TASK_TYPE = "text-generation"
# 910B4 模板(max_model_len 2048)
CFG_B4 = """framework: vllm
api: completion
max_tokens: 1024
temperature: 0.7
repetition_penalty: 1.2
top_p: 0.9
lang: zh
max_model_len: 2048
sut_config:
gpu_num: 1
values:
command:
- vllm
- serve
- /model
- --port
- '8000'
- --served-model-name
- llm
- --max-model-len
- '2048'
- --dtype
- auto
- --gpu-memory-utilization
- '0.95'
- -tp
- '1'
- --enforce-eager
- --trust-remote-code
ref_config:
gpu_num: 1
values:
command:
- vllm
- serve
- /model
- --port
- '8000'
- --served-model-name
- llm
- --max-model-len
- '2048'
- --dtype
- auto
- --gpu-memory-utilization
- '0.95'
- -tp
- '1'
- --enforce-eager
- --trust-remote-code"""
# 910B3 模板(max_model_len 4096)
CFG_B3 = """framework: vllm
api: completion
lang: en
max_model_len: 4096
max_tokens: 1024
temperature: 0.7
repetition_penalty: 1.1
top_p: 0.9
sut_config:
gpu_num: 1
values:
command:
- vllm
- serve
- /model
- --port
- '20644'
- --served-model-name
- llm
- --max-model-len
- '4096'
- -tp
- '1'
- --enforce-eager
- --trust-remote-code
ref_config:
gpu_num: 1
values:
command:
- vllm
- serve
- /model
- --port
- '80'
- --served-model-name
- llm
- --max-model-len
- '4096'
- -tp
- '1'
- --enforce-eager
- --trust-remote-code"""
TASKS = [ TASKS = [
{ {
"label": "OSP-1.4B-100B-Adam", "label": "DRPO-1.5B-Lambda-0.2 @ hygon",
"model": "https://www.modelscope.cn/models/dmis-lab/OSP-1.4B-100B-Adam", "model": "https://huggingface.co/mradermacher/DRPO-1.5B-Lambda-0.2-i1-GGUF",
"gpu": "Ascend_910-b4", "gpu": "hygon_k100-ai",
"config": CFG_B4, "framework": "llamacpp",
"config": "framework: llamacpp\napi: completion\nmax_tokens: 1024\ntemperature: 0.7\nrepetition_penalty: 1.2\ntop_p: 0.9\nlang: en\nmax_model_len: 4096\nsut_config:\n gpu_num: 1\n values:\n command:\n - /app/llama-server\n - --model\n - /model/DRPO-1.5B-Lambda-0.2.i1-Q4_K_M.gguf\n - --alias\n - llm\n - --threads\n - '20'\n - --n-gpu-layers\n - '999'\n - --prio\n - '3'\n - --min_p\n - '0.01'\n - --ctx-size\n - '2048'\n - --host\n - 0.0.0.0\n - --port\n - '8000'\n - --jinja\n - --flash-attn\n - 'off'\nref_config:\n gpu_num: 1\n values:\n command:\n - /workspace/llama.cpp/build/bin/llama-server\n - --model\n - /model/DRPO-1.5B-Lambda-0.2.i1-Q4_K_M.gguf\n - --alias\n - llm\n - --threads\n - '20'\n - --n-gpu-layers\n - '128'\n - --ctx-size\n - '4096'\n - --host\n - 0.0.0.0\n - --port\n - '8000'\n - --jinja\n"
}, },
{ {
"label": "OSP-1.4B-1T-Adam", "label": "Llama-3.2-1B-abliterated2 @ S4000",
"model": "https://www.modelscope.cn/models/dmis-lab/OSP-1.4B-1T-Adam", "model": "https://huggingface.co/mradermacher/Llama-3.2-1B-Instruct-abliterated2-i1-GGUF",
"gpu": "Ascend_910-b4", "gpu": "Mthreads_s4000",
"config": CFG_B4, "framework": "llamacpp",
"config": "framework: llamacpp\napi: completion\nmax_tokens: 1024\nmax_model_len: 2048\nsut_config:\n gpu_num: 1\n values:\n command:\n - /app/llama-server\n - --model\n - /model/Llama-3.2-1B-Instruct-abliterated2.i1-Q4_K_M.gguf\n - --alias\n - llm\n - --threads\n - '20'\n - --n-gpu-layers\n - '128'\n - --ctx-size\n - '2048'\n - --host\n - 0.0.0.0\n - --port\n - '8000'\n - --jinja\n - --flash-attn\n - 'off'\nref_config:\n gpu_num: 1\n values:\n command:\n - /workspace/llama.cpp/build/bin/llama-server\n - --model\n - /model/Llama-3.2-1B-Instruct-abliterated2.i1-Q4_K_M.gguf\n - --alias\n - llm\n - --threads\n - '20'\n - --n-gpu-layers\n - '128'\n - --ctx-size\n - '2048'\n - --host\n - 0.0.0.0\n - --port\n - '8000'\n - --jinja\n - --flash-attn\n - 'off'\n"
}, },
{
"label": "Llama-3.1-SuperNova-Lite @ hygon",
"model": "https://huggingface.co/mradermacher/Llama-3.1-SuperNova-Lite-GGUF",
"gpu": "hygon_k100-ai",
"framework": "llamacpp",
"config": "framework: llamacpp\napi: completion\nmax_tokens: 1024\ntemperature: 0.7\nrepetition_penalty: 1.2\ntop_p: 0.9\nlang: en\nmax_model_len: 4096\nsut_config:\n gpu_num: 1\n values:\n command:\n - /app/llama-server\n - --model\n - /model/Llama-3.1-SuperNova-Lite.Q4_K_M.gguf\n - --alias\n - llm\n - --threads\n - '20'\n - --n-gpu-layers\n - '999'\n - --prio\n - '3'\n - --min_p\n - '0.01'\n - --ctx-size\n - '2048'\n - --host\n - 0.0.0.0\n - --port\n - '8000'\n - --jinja\n - --flash-attn\n - 'off'\nref_config:\n gpu_num: 1\n values:\n command:\n - /workspace/llama.cpp/build/bin/llama-server\n - --model\n - /model/Llama-3.1-SuperNova-Lite.Q4_K_M.gguf\n - --alias\n - llm\n - --threads\n - '20'\n - --n-gpu-layers\n - '128'\n - --ctx-size\n - '4096'\n - --host\n - 0.0.0.0\n - --port\n - '8000'\n - --jinja\n"
}
] ]
TASK_TYPE = "text-generation"
FRAMEWORK = "vllm"
HEADERS = {"Content-Type": "application/json", "Xc-Token": XC_TOKEN} HEADERS = {"Content-Type": "application/json", "Xc-Token": XC_TOKEN}
HTTP_HOST, HTTP_PORT = "0.0.0.0", 8080 HTTP_HOST, HTTP_PORT = "0.0.0.0", 8080
GAP = 4 # 两条之间的间隔秒数 GAP = 4
_state = {
"strategy_id": STRATEGY_ID,
"phase": "starting", # starting | submitting | done
"total": len(TASKS),
"submitted": 0,
"failed": 0,
"results": [],
"started_at": None,
"finished_at": None,
}
_shutdown = threading.Event() _shutdown = threading.Event()
_state = {"phase": "starting", "total": len(TASKS), "submitted": 0, "failed": 0, "results": []}
def submit_one(task): def submit_one(t):
payload = { body = {
"configParams": task["config"], "configParams": t["config"],
"framework": FRAMEWORK, "framework": t["framework"],
"modelAddress": task["model"], "modelAddress": t["model"],
"targetGpu": task["gpu"], "targetGpu": t["gpu"],
"taskType": TASK_TYPE, "taskType": TASK_TYPE,
"strategyId": STRATEGY_ID, "strategyId": STRATEGY_ID,
} }
try: try:
resp = requests.post(BASE_URL + ADD_TASK_ENDPOINT, headers=HEADERS, r = requests.post(BASE_URL + ADD_TASK_ENDPOINT, headers=HEADERS, json=body, timeout=90)
json=payload, timeout=90) j = r.json()
body = resp.json()
except Exception as e: # noqa: BLE001 except Exception as e: # noqa: BLE001
body = {"code": -1, "message": "exception: %s" % e} j = {"code": -1, "message": "exception: %s" % e}
tid = (j.get("data") or {}).get("id")
code = body.get("code") print("[submit] %s gpu=%s fw=%s code=%s msg=%s taskId=%s"
data = body.get("data") or {} % (t["label"], t["gpu"], t["framework"], j.get("code"), j.get("message"), tid), flush=True)
print("[submit] %s gpu=%s code=%s message=%s taskId=%s" return j.get("code"), tid
% (task["label"], task["gpu"], code, body.get("message"), data.get("id")), flush=True)
return code, body.get("message"), data.get("id")
def run_batch(): def run():
_state["phase"] = "submitting" _state["phase"] = "submitting"
_state["started_at"] = datetime.utcnow().isoformat() for i, t in enumerate(TASKS, 1):
for i, task in enumerate(TASKS, 1):
if _shutdown.is_set(): if _shutdown.is_set():
break break
code, msg, task_id = submit_one(task) code, tid = submit_one(t)
_state["results"].append({ _state["results"].append({"label": t["label"], "gpu": t["gpu"],
"index": i, "framework": t["framework"], "code": code, "task_id": tid})
"label": task["label"], _state["submitted" if code == 0 else "failed"] += 1
"model": task["model"],
"gpu": task["gpu"],
"code": code,
"message": msg,
"task_id": task_id,
"time": datetime.utcnow().isoformat(),
})
if code == 0:
_state["submitted"] += 1
else:
_state["failed"] += 1
if i < len(TASKS): if i < len(TASKS):
time.sleep(GAP) time.sleep(GAP)
_state["phase"] = "done" _state["phase"] = "done"
_state["finished_at"] = datetime.utcnow().isoformat() print("[batch] 完成 submitted=%d failed=%d" % (_state["submitted"], _state["failed"]), flush=True)
print("[batch] 完成 submitted=%d failed=%d total=%d"
% (_state["submitted"], _state["failed"], _state["total"]), flush=True)
class Handler(BaseHTTPRequestHandler): class H(BaseHTTPRequestHandler):
def do_GET(self): def do_GET(self):
if self.path == "/health": if self.path == "/health":
self._json({"status": "ok"}) self._json({"status": "ok"})
@@ -219,48 +94,29 @@ class Handler(BaseHTTPRequestHandler):
else: else:
self._json({"error": "not found"}, 404) self._json({"error": "not found"}, 404)
def _json(self, body, code=200): def _json(self, b, c=200):
raw = json.dumps(body, ensure_ascii=False, default=str).encode() raw = json.dumps(b, ensure_ascii=False, default=str).encode()
self.send_response(code) self.send_response(c)
self.send_header("Content-Type", "application/json") self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(raw))) self.send_header("Content-Length", str(len(raw)))
self.end_headers() self.end_headers()
self.wfile.write(raw) self.wfile.write(raw)
def log_message(self, fmt, *args): def log_message(self, *a):
print(self.address_string() + " - " + (fmt % args), flush=True) pass
def _handle_signal(signum, _frame):
print("[main] 收到信号 %s,准备退出" % signum, flush=True)
_shutdown.set()
def _run_http():
server = ThreadingHTTPServer((HTTP_HOST, HTTP_PORT), Handler)
server.timeout = 1
print("[http] 监听 %s:%d" % (HTTP_HOST, HTTP_PORT), flush=True)
while not _shutdown.is_set():
server.handle_request()
server.server_close()
def main(): def main():
signal.signal(signal.SIGTERM, _handle_signal) signal.signal(signal.SIGTERM, lambda *_: _shutdown.set())
signal.signal(signal.SIGINT, _handle_signal)
print("[main] strategy_id=%s tasks=%d" % (STRATEGY_ID, len(TASKS)), flush=True) print("[main] strategy_id=%s tasks=%d" % (STRATEGY_ID, len(TASKS)), flush=True)
for t in TASKS: for t in TASKS:
print("[main] 计划: %s @ %s" % (t["label"], t["gpu"]), flush=True) print("[main] 计划: %s @ %s / %s" % (t["label"], t["gpu"], t["framework"]), flush=True)
srv = ThreadingHTTPServer((HTTP_HOST, HTTP_PORT), H)
http_thread = threading.Thread(target=_run_http, daemon=False) srv.timeout = 1
http_thread.start() threading.Thread(target=run, daemon=True).start()
while not _shutdown.is_set():
worker = threading.Thread(target=run_batch, daemon=True) srv.handle_request()
worker.start() srv.server_close()
_shutdown.wait()
if __name__ == "__main__": main()
main()