From 03e72271f53a2d5dc7d85b20968db14f0fdff2c2 Mon Sep 17 00:00:00 2001 From: Octopus Date: Mon, 16 Mar 2026 09:02:57 -0500 Subject: [PATCH] feat: add MiniMax provider support (#2989) Co-authored-by: octo-patch --- docs/docs/config-reference/llm/index.mdx | 5 + ...ax_minimaxdeploymodelparameters_a1b2c4.mdx | 97 ++++++++++ .../src/dbgpt/model/proxy/__init__.py | 3 + .../src/dbgpt/model/proxy/llms/minimax.py | 183 ++++++++++++++++++ 4 files changed, 288 insertions(+) create mode 100644 docs/docs/config-reference/llm/minimax_minimaxdeploymodelparameters_a1b2c4.mdx create mode 100644 packages/dbgpt-core/src/dbgpt/model/proxy/llms/minimax.py diff --git a/docs/docs/config-reference/llm/index.mdx b/docs/docs/config-reference/llm/index.mdx index 213bb9df1..f5a40c194 100644 --- a/docs/docs/config-reference/llm/index.mdx +++ b/docs/docs/config-reference/llm/index.mdx @@ -67,6 +67,11 @@ import { ConfigClassTable } from '@site/src/components/mdx/ConfigClassTable'; "description": "LlamaServerParameters(name: str, provider: str = 'llama.cpp.server', verbose: Optional[bool] = False, concurrency: Optional[int] = 20, backend: Optional[str] = None, prompt_template: Optional[str] = None, context_length: Optional[int] = None, reasoning_model: Optional[bool] = None, path: Optional[str] = None, model_hf_repo: Optional[str] = None, model_hf_file: Optional[str] = None, device: Optional[str] = None, server_bin_path: Optional[str] = None, server_host: str = '127.0.0.1', server_port: int = 0, temperature: float = 0.8, seed: int = 42, debug: bool = False, model_url: Optional[str] = None, model_draft: Optional[str] = None, threads: Optional[int] = None, n_gpu_layers: Optional[int] = None, batch_size: Optional[int] = None, ubatch_size: Optional[int] = None, ctx_size: Optional[int] = None, grp_attn_n: Optional[int] = None, grp_attn_w: Optional[int] = None, n_predict: Optional[int] = None, slot_save_path: Optional[str] = None, n_slots: Optional[int] = None, cont_batching: bool = False, embedding: bool = False, reranking: bool = False, metrics: bool = False, slots: bool = False, draft: Optional[int] = None, draft_max: Optional[int] = None, draft_min: Optional[int] = None, api_key: Optional[str] = None, lora_files: List[str] = , no_context_shift: bool = False, no_webui: Optional[bool] = None, startup_timeout: Optional[int] = None)", "link": "./llama_cpp_adapter_llamaserverparameters_421f40" }, + { + "name": "MiniMaxDeployModelParameters", + "description": "MiniMax proxy LLM configuration.", + "link": "./minimax_minimaxdeploymodelparameters_a1b2c4" + }, { "name": "MoonshotDeployModelParameters", "description": "Moonshot proxy LLM configuration.", diff --git a/docs/docs/config-reference/llm/minimax_minimaxdeploymodelparameters_a1b2c4.mdx b/docs/docs/config-reference/llm/minimax_minimaxdeploymodelparameters_a1b2c4.mdx new file mode 100644 index 000000000..93aa80880 --- /dev/null +++ b/docs/docs/config-reference/llm/minimax_minimaxdeploymodelparameters_a1b2c4.mdx @@ -0,0 +1,97 @@ +--- +title: "MiniMax Proxy LLM Configuration" +description: "MiniMax proxy LLM configuration." +--- + +import { ConfigDetail } from "@site/src/components/mdx/ConfigDetail"; + +')", + "defaultValue": "proxy/minimax" + }, + { + "name": "verbose", + "type": "boolean", + "required": false, + "description": "Show verbose output.", + "defaultValue": "False" + }, + { + "name": "concurrency", + "type": "integer", + "required": false, + "description": "Model concurrency limit", + "defaultValue": "100" + }, + { + "name": "prompt_template", + "type": "string", + "required": false, + "description": "Prompt template. If None, the prompt template is automatically determined from model. Just for local deployment." + }, + { + "name": "context_length", + "type": "integer", + "required": false, + "description": "The context length of the MiniMax API. If None, it is determined by the model." + }, + { + "name": "reasoning_model", + "type": "boolean", + "required": false, + "description": "Whether the model is a reasoning model. If None, it is automatically determined from model." + }, + { + "name": "api_base", + "type": "string", + "required": false, + "description": "The base url of the MiniMax API.", + "defaultValue": "${env:MINIMAX_API_BASE:-https://api.minimax.io/v1}" + }, + { + "name": "api_key", + "type": "string", + "required": false, + "description": "The API key of the MiniMax API.", + "defaultValue": "${env:MINIMAX_API_KEY}" + }, + { + "name": "api_type", + "type": "string", + "required": false, + "description": "The type of the OpenAI API, if you use Azure, it can be: azure" + }, + { + "name": "api_version", + "type": "string", + "required": false, + "description": "The version of the OpenAI API." + }, + { + "name": "http_proxy", + "type": "string", + "required": false, + "description": "The http or https proxy to use openai" + } + ] +}} /> diff --git a/packages/dbgpt-core/src/dbgpt/model/proxy/__init__.py b/packages/dbgpt-core/src/dbgpt/model/proxy/__init__.py index 174ee6e1d..3d7b9810b 100644 --- a/packages/dbgpt-core/src/dbgpt/model/proxy/__init__.py +++ b/packages/dbgpt-core/src/dbgpt/model/proxy/__init__.py @@ -11,6 +11,7 @@ if TYPE_CHECKING: from dbgpt.model.proxy.llms.gemini import GeminiLLMClient from dbgpt.model.proxy.llms.gitee import GiteeLLMClient from dbgpt.model.proxy.llms.infiniai import InfiniAILLMClient + from dbgpt.model.proxy.llms.minimax import MiniMaxLLMClient from dbgpt.model.proxy.llms.moonshot import MoonshotLLMClient from dbgpt.model.proxy.llms.ollama import OllamaLLMClient from dbgpt.model.proxy.llms.siliconflow import SiliconFlowLLMClient @@ -39,6 +40,7 @@ def __lazy_import(name): "DeepseekLLMClient": "dbgpt.model.proxy.llms.deepseek", "GiteeLLMClient": "dbgpt.model.proxy.llms.gitee", "InfiniAILLMClient": "dbgpt.model.proxy.llms.infiniai", + "MiniMaxLLMClient": "dbgpt.model.proxy.llms.minimax", } if name in module_path: @@ -69,4 +71,5 @@ __all__ = [ "DeepseekLLMClient", "GiteeLLMClient", "InfiniAILLMClient", + "MiniMaxLLMClient", ] diff --git a/packages/dbgpt-core/src/dbgpt/model/proxy/llms/minimax.py b/packages/dbgpt-core/src/dbgpt/model/proxy/llms/minimax.py new file mode 100644 index 000000000..1537e22c4 --- /dev/null +++ b/packages/dbgpt-core/src/dbgpt/model/proxy/llms/minimax.py @@ -0,0 +1,183 @@ +import os +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Dict, Optional, Type, Union, cast + +from dbgpt.core import ModelMetadata, ModelRequest +from dbgpt.core.awel.flow import ( + TAGS_ORDER_HIGH, + ResourceCategory, + auto_register_resource, +) +from dbgpt.model.proxy.llms.proxy_model import ProxyModel, parse_model_request +from dbgpt.util.i18n_utils import _ + +from ..base import ( + AsyncGenerateStreamFunction, + GenerateStreamFunction, + register_proxy_model_adapter, +) +from .chatgpt import OpenAICompatibleDeployModelParameters, OpenAILLMClient + +if TYPE_CHECKING: + from httpx._types import ProxiesTypes + from openai import AsyncAzureOpenAI, AsyncOpenAI + + ClientType = Union[AsyncAzureOpenAI, AsyncOpenAI] + +_DEFAULT_MODEL = "MiniMax-M2.5" + + +@auto_register_resource( + label=_("MiniMax Proxy LLM"), + category=ResourceCategory.LLM_CLIENT, + tags={"order": TAGS_ORDER_HIGH}, + description=_("MiniMax proxy LLM configuration."), + documentation_url="https://platform.minimax.io/docs/api-reference/text-openai-api", + show_in_ui=False, +) +@dataclass +class MiniMaxDeployModelParameters(OpenAICompatibleDeployModelParameters): + """Deploy model parameters for MiniMax.""" + + provider: str = "proxy/minimax" + + api_base: Optional[str] = field( + default="${env:MINIMAX_API_BASE:-https://api.minimax.io/v1}", + metadata={ + "help": _("The base url of the MiniMax API."), + }, + ) + + api_key: Optional[str] = field( + default="${env:MINIMAX_API_KEY}", + metadata={ + "help": _("The API key of the MiniMax API."), + "tags": "privacy", + }, + ) + + +async def minimax_generate_stream( + model: ProxyModel, tokenizer, params, device, context_len=2048 +): + client: MiniMaxLLMClient = cast(MiniMaxLLMClient, model.proxy_llm_client) + request = parse_model_request(params, client.default_model, stream=True) + async for r in client.generate_stream(request): + yield r + + +class MiniMaxLLMClient(OpenAILLMClient): + """MiniMax LLM Client. + + MiniMax's API is compatible with OpenAI's API, so we inherit from OpenAILLMClient. + + API Reference: https://platform.minimax.io/docs/api-reference/text-openai-api + """ + + def __init__( + self, + api_key: Optional[str] = None, + api_base: Optional[str] = None, + api_type: Optional[str] = None, + api_version: Optional[str] = None, + model: Optional[str] = _DEFAULT_MODEL, + proxies: Optional["ProxiesTypes"] = None, + timeout: Optional[int] = 240, + model_alias: Optional[str] = _DEFAULT_MODEL, + context_length: Optional[int] = None, + openai_client: Optional["ClientType"] = None, + openai_kwargs: Optional[Dict[str, Any]] = None, + **kwargs, + ): + api_base = ( + api_base or os.getenv("MINIMAX_API_BASE") or "https://api.minimax.io/v1" + ) + api_key = api_key or os.getenv("MINIMAX_API_KEY") + model = model or _DEFAULT_MODEL + if not context_length: + context_length = 204800 + + if not api_key: + raise ValueError( + "MiniMax API key is required, please set 'MINIMAX_API_KEY' in " + "environment variable or pass it to the client." + ) + super().__init__( + api_key=api_key, + api_base=api_base, + api_type=api_type, + api_version=api_version, + model=model, + proxies=proxies, + timeout=timeout, + model_alias=model_alias, + context_length=context_length, + openai_client=openai_client, + openai_kwargs=openai_kwargs, + **kwargs, + ) + + def check_sdk_version(self, version: str) -> None: + if not version >= "1.0": + raise ValueError( + "MiniMax API requires openai>=1.0, please upgrade it by " + "`pip install --upgrade 'openai>=1.0'`" + ) + + @property + def default_model(self) -> str: + model = self._model + if not model: + model = _DEFAULT_MODEL + return model + + def _build_request( + self, request: ModelRequest, stream: Optional[bool] = False + ) -> Dict[str, Any]: + payload = super()._build_request(request, stream) + # MiniMax requires temperature in (0.0, 1.0]; 0 is not allowed. + temperature = payload.get("temperature") + if temperature is not None: + if temperature <= 0: + payload["temperature"] = 1.0 + elif temperature > 1.0: + payload["temperature"] = 1.0 + return payload + + @classmethod + def param_class(cls) -> Type[MiniMaxDeployModelParameters]: + """Get the deploy model parameters class.""" + return MiniMaxDeployModelParameters + + @classmethod + def generate_stream_function( + cls, + ) -> Optional[Union[GenerateStreamFunction, AsyncGenerateStreamFunction]]: + """Get the generate stream function.""" + return minimax_generate_stream + + +register_proxy_model_adapter( + MiniMaxLLMClient, + supported_models=[ + ModelMetadata( + model="MiniMax-M2.5", + context_length=204800, + max_output_length=192000, + description=("MiniMax-M2.5 by MiniMax. Peak Performance. Ultimate Value."), + link="https://platform.minimax.io/docs/api-reference/text-openai-api", + function_calling=True, + ), + ModelMetadata( + model="MiniMax-M2.5-highspeed", + context_length=204800, + max_output_length=192000, + description=( + "MiniMax-M2.5-highspeed by MiniMax. Same performance, faster and " + "more agile." + ), + link="https://platform.minimax.io/docs/api-reference/text-openai-api", + function_calling=True, + ), + ], +)