| |
| """OpenAI-compatible API server for the OFFICIAL native vLLM MiniMax-M3 (vLLM |
| 0.23.1) + our AutoRound 3.2bit quantization == the LONG-CONTEXT port (②). |
| |
| Unlike m3_api_server.py (the out-of-tree M1 model, <=2048 ctx, vision), this |
| serves the official native M3 text backbone with the MSA lightning indexer, so |
| it supports long context (~46K tokens of KV on 2x RTX PRO 6000). All the ② fixes |
| (shared expert: n_shared_experts + down_proj/gate_up quant naming) live in |
| serve_m3_official.py / m3_official_loader.py / m3_quant.py and are reused here. |
| |
| Engine args mirror serve_m3_official.py's LLM kwargs; we reuse its |
| _override_quant_method (architecture force + the FORCE config dict incl. |
| n_shared_experts=1). The OpenAI server's CLI-parsed engine args are replaced with |
| ours (same trick as m3_api_server.py) since the CLI path mis-resolves the config. |
| |
| Start: M3_OFFICIAL_PORT is set automatically. |
| python m3_official_api_server.py |
| Test : curl http://localhost:8003/v1/models |
| curl http://localhost:8003/v1/chat/completions -H 'Content-Type: application/json' \ |
| -d '{"model":"minimax-m3-long","messages":[{"role":"user","content":"日本の首都は?"}],"max_tokens":30}' |
| """ |
| import os |
| import sys |
| import asyncio |
|
|
| os.environ["M3_OFFICIAL_PORT"] = "1" |
| os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True" |
| os.environ.setdefault("MIXED_MOE_GROUPED", "1") |
| os.environ.setdefault("VLLM_USE_FLASHINFER_SAMPLER", "0") |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) |
|
|
| CKPT = os.environ.get("M3_CKPT", os.path.dirname(os.path.abspath(__file__))) |
| PORT = os.environ.get("M3_PORT", "8003") |
| SERVED = os.environ.get("M3_SERVED", "minimax-m3-long") |
| MAXLEN = int(os.environ.get("M3_MAXLEN", "40960")) |
|
|
| |
| |
| |
| import serve_m3_official |
| _ov = serve_m3_official._override_quant_method |
|
|
| from vllm.engine.arg_utils import AsyncEngineArgs |
|
|
| |
| |
| |
| |
| _cgmode = os.environ.get("M3_CUDAGRAPH_MODE") |
| _comp_cfg = {"cudagraph_mode": _cgmode} if _cgmode else {} |
|
|
| _ENGINE_ARGS = AsyncEngineArgs( |
| compilation_config=_comp_cfg, |
| model=CKPT, |
| quantization="autoround_mixed", |
| hf_overrides=_ov, |
| trust_remote_code=True, |
| tensor_parallel_size=2, |
| pipeline_parallel_size=1, |
| enable_expert_parallel=True, |
| distributed_executor_backend="mp", |
| block_size=128, |
| attention_backend=os.environ.get("M3_ATTN_BACKEND", "TRITON_ATTN"), |
| max_model_len=MAXLEN, |
| max_num_batched_tokens=2048, |
| gpu_memory_utilization=0.97, |
| max_num_seqs=int(os.environ.get("M3_MAX_SEQS", "4")), |
| |
| |
| |
| enforce_eager=os.environ.get("M3_EAGER", "1") == "1", |
| disable_custom_all_reduce=True, |
| dtype="bfloat16", |
| ) |
| |
| AsyncEngineArgs.from_cli_args = classmethod(lambda cls, args: _ENGINE_ARGS) |
|
|
| from vllm.entrypoints.openai.api_server import run_server |
| from vllm.entrypoints.openai.cli_args import ( |
| make_arg_parser, |
| validate_parsed_serve_args, |
| ) |
| from vllm.utils.argparse_utils import FlexibleArgumentParser |
|
|
| if __name__ == "__main__": |
| parser = make_arg_parser(FlexibleArgumentParser()) |
| args = parser.parse_args([ |
| CKPT, |
| "--served-model-name", SERVED, |
| "--host", "0.0.0.0", "--port", PORT, |
| ]) |
| validate_parsed_serve_args(args) |
| print(f"[m3_official_api] starting OpenAI server on :{PORT} " |
| f"(model={SERVED}, maxlen={MAXLEN})", flush=True) |
| asyncio.run(run_server(args)) |
|
|