feat: add DeepSeek and Xiaomi MiMo LLM provider presets
- Add providers.py with 5 provider presets (OpenAI, DeepSeek, Xiaomi MiMo, Alibaba DashScope, MiniMax) - Add LLM_PROVIDER env var for one-line provider switching - Improve <think> tag stripping for reasoning models - Add .env.example with documented configuration - Update README with provider configuration section
This commit is contained in:
106
.env.example
106
.env.example
@@ -1,16 +1,104 @@
|
|||||||
# LLM API配置(支持 OpenAI SDK 格式的任意 LLM API)
|
# ================================================================
|
||||||
# 推荐使用阿里百炼平台qwen-plus模型:https://bailian.console.aliyun.com/
|
# MiroFish 环境变量配置
|
||||||
|
# ================================================================
|
||||||
|
# 复制此文件为 .env 并填入你的 API 密钥:
|
||||||
|
# cp .env.example .env
|
||||||
|
#
|
||||||
|
# LLM 配置支持两种方式:
|
||||||
|
# 方式1(推荐):设置 LLM_PROVIDER,只需提供 API Key
|
||||||
|
# 方式2(灵活):手动指定 LLM_BASE_URL 和 LLM_MODEL_NAME
|
||||||
|
# ================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# 方式1:使用提供商预设(推荐)
|
||||||
|
# ================================================================
|
||||||
|
# 取消注释你要使用的提供商,然后填入对应的 API Key。
|
||||||
|
# 设置 LLM_PROVIDER 后,LLM_BASE_URL 和 LLM_MODEL_NAME 会自动填充默认值。
|
||||||
|
#
|
||||||
|
# 可用的提供商:
|
||||||
|
# - openai : OpenAI GPT 系列
|
||||||
|
# - deepseek : DeepSeek (深度求索)
|
||||||
|
# - xiaomi_mimo : Xiaomi MiMo (小米 MiMo)
|
||||||
|
# - alibaba_dashscope : 阿里百炼 (通义千问)
|
||||||
|
# - minimax : MiniMax (海螺 AI)
|
||||||
|
|
||||||
|
# --- DeepSeek ---
|
||||||
|
# API Key 获取: https://platform.deepseek.com
|
||||||
|
# LLM_PROVIDER=deepseek
|
||||||
|
# LLM_API_KEY=sk-your-deepseek-key-here
|
||||||
|
|
||||||
|
# --- Xiaomi MiMo ---
|
||||||
|
# API Key 获取: https://platform.xiaomimimo.com
|
||||||
|
# LLM_PROVIDER=xiaomi_mimo
|
||||||
|
# LLM_API_KEY=your-mimo-api-key-here
|
||||||
|
|
||||||
|
# --- OpenAI ---
|
||||||
|
# API Key 获取: https://platform.openai.com/api-keys
|
||||||
|
# LLM_PROVIDER=openai
|
||||||
|
# LLM_API_KEY=sk-your-openai-key-here
|
||||||
|
|
||||||
|
# --- 阿里百炼 (通义千问) ---
|
||||||
|
# API Key 获取: https://bailian.console.aliyun.com/
|
||||||
# 注意消耗较大,可先进行小于40轮的模拟尝试
|
# 注意消耗较大,可先进行小于40轮的模拟尝试
|
||||||
|
# LLM_PROVIDER=alibaba_dashscope
|
||||||
|
# LLM_API_KEY=sk-your-dashscope-key-here
|
||||||
|
|
||||||
|
# --- MiniMax (海螺 AI) ---
|
||||||
|
# API Key 获取: https://platform.minimaxi.com/
|
||||||
|
# LLM_PROVIDER=minimax
|
||||||
|
# LLM_API_KEY=your-minimax-key-here
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# 方式2:手动指定配置(兼容原有方式)
|
||||||
|
# ================================================================
|
||||||
|
# 如果不使用 LLM_PROVIDER,需要手动指定以下三个变量。
|
||||||
|
# 适用于任何兼容 OpenAI SDK 格式的 LLM API。
|
||||||
|
|
||||||
LLM_API_KEY=your_api_key_here
|
LLM_API_KEY=your_api_key_here
|
||||||
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
||||||
LLM_MODEL_NAME=qwen-plus
|
LLM_MODEL_NAME=qwen-plus
|
||||||
|
|
||||||
# ===== ZEP记忆图谱配置 =====
|
|
||||||
# 每月免费额度即可支撑简单使用:https://app.getzep.com/
|
# ================================================================
|
||||||
|
# Zep 记忆图谱配置(必需)
|
||||||
|
# ================================================================
|
||||||
|
# 每月免费额度即可支撑简单使用
|
||||||
|
# 获取地址: https://app.getzep.com/
|
||||||
ZEP_API_KEY=your_zep_api_key_here
|
ZEP_API_KEY=your_zep_api_key_here
|
||||||
|
|
||||||
# ===== 加速 LLM 配置(可选)=====
|
|
||||||
# 注意如果不使用加速配置,env文件中就不要出现下面的配置项
|
# ================================================================
|
||||||
LLM_BOOST_API_KEY=your_api_key_here
|
# 加速 LLM 配置(可选)
|
||||||
LLM_BOOST_BASE_URL=your_base_url_here
|
# ================================================================
|
||||||
LLM_BOOST_MODEL_NAME=your_model_name_here
|
# 注意:如果不使用加速配置,env文件中就不要出现下面的配置项
|
||||||
|
# LLM_BOOST_API_KEY=your_api_key_here
|
||||||
|
# LLM_BOOST_BASE_URL=your_base_url_here
|
||||||
|
# LLM_BOOST_MODEL_NAME=your_model_name_here
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# 提供商配置示例(完整示例,取消注释即可使用)
|
||||||
|
# ================================================================
|
||||||
|
|
||||||
|
# ---- DeepSeek 完整示例 ----
|
||||||
|
# LLM_PROVIDER=deepseek
|
||||||
|
# LLM_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
# # 以下可省略(使用默认值):
|
||||||
|
# # LLM_BASE_URL=https://api.deepseek.com/v1
|
||||||
|
# # LLM_MODEL_NAME=deepseek-chat
|
||||||
|
|
||||||
|
# ---- Xiaomi MiMo 完整示例 ----
|
||||||
|
# LLM_PROVIDER=xiaomi_mimo
|
||||||
|
# LLM_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
# # 以下可省略(使用默认值):
|
||||||
|
# # LLM_BASE_URL=https://api.xiaomimimo.com/v1
|
||||||
|
# # LLM_MODEL_NAME=mimo-v2.5-pro
|
||||||
|
|
||||||
|
# ---- 阿里百炼 完整示例 ----
|
||||||
|
# LLM_PROVIDER=alibaba_dashscope
|
||||||
|
# LLM_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
# # 以下可省略(使用默认值):
|
||||||
|
# # LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
||||||
|
# # LLM_MODEL_NAME=qwen-plus
|
||||||
|
|||||||
39
README-ZH.md
39
README-ZH.md
@@ -116,17 +116,48 @@ cp .env.example .env
|
|||||||
|
|
||||||
```env
|
```env
|
||||||
# LLM API配置(支持 OpenAI SDK 格式的任意 LLM API)
|
# LLM API配置(支持 OpenAI SDK 格式的任意 LLM API)
|
||||||
# 推荐使用阿里百炼平台qwen-plus模型:https://bailian.console.aliyun.com/
|
# 方式1(推荐):使用提供商预设,只需设置提供商名称和 API Key
|
||||||
# 注意消耗较大,可先进行小于40轮的模拟尝试
|
LLM_PROVIDER=deepseek
|
||||||
LLM_API_KEY=your_api_key
|
LLM_API_KEY=your_api_key
|
||||||
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
|
||||||
LLM_MODEL_NAME=qwen-plus
|
# 方式2:手动指定配置(兼容原有方式)
|
||||||
|
# LLM_BASE_URL=https://api.deepseek.com/v1
|
||||||
|
# LLM_MODEL_NAME=deepseek-chat
|
||||||
|
|
||||||
# Zep Cloud 配置
|
# Zep Cloud 配置
|
||||||
# 每月免费额度即可支撑简单使用:https://app.getzep.com/
|
# 每月免费额度即可支撑简单使用:https://app.getzep.com/
|
||||||
ZEP_API_KEY=your_zep_api_key
|
ZEP_API_KEY=your_zep_api_key
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**支持的LLM提供商:**
|
||||||
|
|
||||||
|
| 提供商 | `LLM_PROVIDER` | 默认模型 | 说明 |
|
||||||
|
|--------|-----------------|----------|------|
|
||||||
|
| **DeepSeek (深度求索)** | `deepseek` | `deepseek-chat` | 性价比高,有推理模型 (`deepseek-reasoner`) |
|
||||||
|
| **Xiaomi MiMo (小米)** | `xiaomi_mimo` | `mimo-v2.5-pro` | 推理速度快,性能优秀 |
|
||||||
|
| **OpenAI** | `openai` | `gpt-4o-mini` | 行业标准 |
|
||||||
|
| **阿里百炼 (通义千问)** | `alibaba_dashscope` | `qwen-plus` | 消耗较大,先试<40轮 |
|
||||||
|
| **MiniMax (海螺AI)** | `minimax` | `MiniMax-M2.5` | 中文表现好 |
|
||||||
|
|
||||||
|
**快速示例:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# DeepSeek(推荐,性价比高)
|
||||||
|
LLM_PROVIDER=deepseek
|
||||||
|
LLM_API_KEY=your_api_key
|
||||||
|
|
||||||
|
# Xiaomi MiMo(小米,推理快)
|
||||||
|
LLM_PROVIDER=xiaomi_mimo
|
||||||
|
LLM_API_KEY=your_api_key
|
||||||
|
```
|
||||||
|
|
||||||
|
> **提示**: 可以通过设置 `LLM_MODEL_NAME` 来覆盖默认模型:
|
||||||
|
> ```env
|
||||||
|
> LLM_PROVIDER=deepseek
|
||||||
|
> LLM_API_KEY=your_api_key
|
||||||
|
> LLM_MODEL_NAME=deepseek-reasoner # 使用推理模型
|
||||||
|
> ```
|
||||||
|
|
||||||
#### 2. 安装依赖
|
#### 2. 安装依赖
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
39
README.md
39
README.md
@@ -116,17 +116,48 @@ cp .env.example .env
|
|||||||
|
|
||||||
```env
|
```env
|
||||||
# LLM API Configuration (supports any LLM API with OpenAI SDK format)
|
# LLM API Configuration (supports any LLM API with OpenAI SDK format)
|
||||||
# Recommended: Alibaba Qwen-plus model via Bailian Platform: https://bailian.console.aliyun.com/
|
# Option 1 (Recommended): Use provider preset - just set provider name and API key
|
||||||
# High consumption, try simulations with fewer than 40 rounds first
|
LLM_PROVIDER=deepseek
|
||||||
LLM_API_KEY=your_api_key
|
LLM_API_KEY=your_api_key
|
||||||
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
|
||||||
LLM_MODEL_NAME=qwen-plus
|
# Option 2: Manual configuration (compatible with original method)
|
||||||
|
# LLM_BASE_URL=https://api.deepseek.com/v1
|
||||||
|
# LLM_MODEL_NAME=deepseek-chat
|
||||||
|
|
||||||
# Zep Cloud Configuration
|
# Zep Cloud Configuration
|
||||||
# Free monthly quota is sufficient for simple usage: https://app.getzep.com/
|
# Free monthly quota is sufficient for simple usage: https://app.getzep.com/
|
||||||
ZEP_API_KEY=your_zep_api_key
|
ZEP_API_KEY=your_zep_api_key
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Supported LLM Providers:**
|
||||||
|
|
||||||
|
| Provider | `LLM_PROVIDER` | Default Model | Notes |
|
||||||
|
|----------|-----------------|---------------|-------|
|
||||||
|
| **DeepSeek** | `deepseek` | `deepseek-chat` | Cost-effective, reasoning model available (`deepseek-reasoner`) |
|
||||||
|
| **Xiaomi MiMo** | `xiaomi_mimo` | `mimo-v2.5-pro` | Fast inference, competitive performance |
|
||||||
|
| **OpenAI** | `openai` | `gpt-4o-mini` | Industry standard |
|
||||||
|
| **Alibaba DashScope** | `alibaba_dashscope` | `qwen-plus` | High consumption, try <40 rounds first |
|
||||||
|
| **MiniMax** | `minimax` | `MiniMax-M2.5` | Good for Chinese content |
|
||||||
|
|
||||||
|
**Quick Examples:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# DeepSeek (Recommended for cost-effectiveness)
|
||||||
|
LLM_PROVIDER=deepseek
|
||||||
|
LLM_API_KEY=sk-you...n
|
||||||
|
|
||||||
|
# Xiaomi MiMo (Fast inference)
|
||||||
|
LLM_PROVIDER=xiaomi_mimo
|
||||||
|
LLM_API_KEY=your-m...n
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note**: You can override the default model by also setting `LLM_MODEL_NAME`:
|
||||||
|
> ```env
|
||||||
|
> LLM_PROVIDER=deepseek
|
||||||
|
> LLM_API_KEY=sk-you...n
|
||||||
|
> LLM_MODEL_NAME=deepseek-reasoner # Use reasoning model
|
||||||
|
> ```
|
||||||
|
|
||||||
#### 2. Install Dependencies
|
#### 2. Install Dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -17,6 +17,47 @@ else:
|
|||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_llm_config() -> tuple[str, str, str | None]:
|
||||||
|
"""
|
||||||
|
解析LLM配置。
|
||||||
|
|
||||||
|
优先级:
|
||||||
|
1. 如果设置了 LLM_PROVIDER,使用提供商预设填充 base_url 和 model(但可被显式值覆盖)
|
||||||
|
2. 否则使用 LLM_BASE_URL / LLM_MODEL_NAME(兼容原有行为)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(base_url, model_name, provider_name_or_none)
|
||||||
|
"""
|
||||||
|
from .providers import get_provider
|
||||||
|
|
||||||
|
provider_name = os.environ.get('LLM_PROVIDER', '').strip()
|
||||||
|
explicit_base_url = os.environ.get('LLM_BASE_URL', '').strip()
|
||||||
|
explicit_model = os.environ.get('LLM_MODEL_NAME', '').strip()
|
||||||
|
|
||||||
|
if provider_name:
|
||||||
|
preset = get_provider(provider_name)
|
||||||
|
if preset is None:
|
||||||
|
provider_names = ["openai", "deepseek", "xiaomi_mimo", "alibaba_dashscope", "minimax"]
|
||||||
|
available = ", ".join(provider_names)
|
||||||
|
raise ValueError(
|
||||||
|
f"未知的 LLM_PROVIDER: '{provider_name}'. "
|
||||||
|
f"可用值: {available}"
|
||||||
|
)
|
||||||
|
# 显式值优先于预设默认值
|
||||||
|
base_url = explicit_base_url or preset.base_url
|
||||||
|
model = explicit_model or preset.default_model
|
||||||
|
return base_url, model, provider_name
|
||||||
|
else:
|
||||||
|
# 兼容原有行为:无 LLM_PROVIDER 时直接使用显式值
|
||||||
|
base_url = explicit_base_url or 'https://api.openai.com/v1'
|
||||||
|
model = explicit_model or 'gpt-4o-mini'
|
||||||
|
return base_url, model, None
|
||||||
|
|
||||||
|
|
||||||
|
# 在模块加载时解析配置(避免重复计算)
|
||||||
|
_llm_base_url, _llm_model_name, _llm_provider = _resolve_llm_config()
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
"""Flask配置类"""
|
"""Flask配置类"""
|
||||||
|
|
||||||
@@ -29,8 +70,9 @@ class Config:
|
|||||||
|
|
||||||
# LLM配置(统一使用OpenAI格式)
|
# LLM配置(统一使用OpenAI格式)
|
||||||
LLM_API_KEY = os.environ.get('LLM_API_KEY')
|
LLM_API_KEY = os.environ.get('LLM_API_KEY')
|
||||||
LLM_BASE_URL = os.environ.get('LLM_BASE_URL', 'https://api.openai.com/v1')
|
LLM_PROVIDER = _llm_provider # e.g. "deepseek" or None
|
||||||
LLM_MODEL_NAME = os.environ.get('LLM_MODEL_NAME', 'gpt-4o-mini')
|
LLM_BASE_URL = _llm_base_url
|
||||||
|
LLM_MODEL_NAME = _llm_model_name
|
||||||
|
|
||||||
# Zep配置
|
# Zep配置
|
||||||
ZEP_API_KEY = os.environ.get('ZEP_API_KEY')
|
ZEP_API_KEY = os.environ.get('ZEP_API_KEY')
|
||||||
@@ -73,3 +115,19 @@ class Config:
|
|||||||
errors.append("ZEP_API_KEY 未配置")
|
errors.append("ZEP_API_KEY 未配置")
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_active_provider_info(cls) -> dict:
|
||||||
|
"""返回当前活跃的LLM提供商信息(用于日志/API展示)"""
|
||||||
|
from .providers import get_provider
|
||||||
|
|
||||||
|
info = {
|
||||||
|
"provider": cls.LLM_PROVIDER or "custom",
|
||||||
|
"base_url": cls.LLM_BASE_URL,
|
||||||
|
"model": cls.LLM_MODEL_NAME,
|
||||||
|
}
|
||||||
|
if cls.LLM_PROVIDER:
|
||||||
|
preset = get_provider(cls.LLM_PROVIDER)
|
||||||
|
if preset:
|
||||||
|
info["display_name"] = preset.display_name
|
||||||
|
info["notes"] = preset.notes
|
||||||
|
return info
|
||||||
|
|||||||
133
backend/app/providers.py
Normal file
133
backend/app/providers.py
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
"""
|
||||||
|
LLM Provider Presets
|
||||||
|
====================
|
||||||
|
预设的LLM提供商配置,简化环境变量设置。
|
||||||
|
|
||||||
|
使用方式:
|
||||||
|
方式1(推荐):设置 LLM_PROVIDER 环境变量为提供商名称,自动填充 base_url 和 model
|
||||||
|
LLM_PROVIDER=deepseek
|
||||||
|
LLM_API_KEY=sk-xxx
|
||||||
|
|
||||||
|
方式2:手动指定所有配置(兼容原有方式)
|
||||||
|
LLM_API_KEY=sk-xxx
|
||||||
|
LLM_BASE_URL=https://api.deepseek.com/v1
|
||||||
|
LLM_MODEL_NAME=deepseek-chat
|
||||||
|
|
||||||
|
支持的提供商:
|
||||||
|
- openai : OpenAI GPT系列
|
||||||
|
- deepseek : DeepSeek (深度求索)
|
||||||
|
- xiaomi_mimo : Xiaomi MiMo (小米MiMo)
|
||||||
|
- alibaba_dashscope : 阿里百炼 (通义千问)
|
||||||
|
- minimax : MiniMax (海螺AI)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ProviderPreset:
|
||||||
|
"""LLM提供商预设配置"""
|
||||||
|
name: str
|
||||||
|
display_name: str
|
||||||
|
base_url: str
|
||||||
|
default_model: str
|
||||||
|
api_key_url: str
|
||||||
|
notes: str = ""
|
||||||
|
# 某些提供商的响应可能包含<think>标签(如DeepSeek推理模型)
|
||||||
|
may_include_think_tags: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Provider Presets
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
PROVIDERS: dict[str, ProviderPreset] = {
|
||||||
|
"openai": ProviderPreset(
|
||||||
|
name="openai",
|
||||||
|
display_name="OpenAI",
|
||||||
|
base_url="https://api.openai.com/v1",
|
||||||
|
default_model="gpt-4o-mini",
|
||||||
|
api_key_url="https://platform.openai.com/api-keys",
|
||||||
|
notes="GPT-4o-mini recommended for cost efficiency.",
|
||||||
|
),
|
||||||
|
"deepseek": ProviderPreset(
|
||||||
|
name="deepseek",
|
||||||
|
display_name="DeepSeek (深度求索)",
|
||||||
|
base_url="https://api.deepseek.com/v1",
|
||||||
|
default_model="deepseek-chat",
|
||||||
|
api_key_url="https://platform.deepseek.com",
|
||||||
|
notes=(
|
||||||
|
"deepseek-chat: general purpose; "
|
||||||
|
"deepseek-reasoner: reasoning model with <think> tags in output. "
|
||||||
|
"Pricing: https://api-docs.deepseek.com/quick_start/pricing"
|
||||||
|
),
|
||||||
|
may_include_think_tags=True,
|
||||||
|
),
|
||||||
|
"xiaomi_mimo": ProviderPreset(
|
||||||
|
name="xiaomi_mimo",
|
||||||
|
display_name="Xiaomi MiMo (小米MiMo)",
|
||||||
|
base_url="https://api.xiaomimimo.com/v1",
|
||||||
|
default_model="mimo-v2.5-pro",
|
||||||
|
api_key_url="https://platform.xiaomimimo.com",
|
||||||
|
notes=(
|
||||||
|
"mimo-v2.5-pro: flagship model; "
|
||||||
|
"mimo-v2-flash: fast & economical. "
|
||||||
|
"OpenAI SDK compatible. May include <think> tags for reasoning."
|
||||||
|
),
|
||||||
|
may_include_think_tags=True,
|
||||||
|
),
|
||||||
|
"alibaba_dashscope": ProviderPreset(
|
||||||
|
name="alibaba_dashscope",
|
||||||
|
display_name="Alibaba DashScope (阿里百炼)",
|
||||||
|
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||||
|
default_model="qwen-plus",
|
||||||
|
api_key_url="https://bailian.console.aliyun.com/",
|
||||||
|
notes=(
|
||||||
|
"qwen-plus: recommended balance of quality & cost. "
|
||||||
|
"High token consumption — try <40 round simulations first."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"minimax": ProviderPreset(
|
||||||
|
name="minimax",
|
||||||
|
display_name="MiniMax (海螺AI)",
|
||||||
|
base_url="https://api.minimax.chat/v1",
|
||||||
|
default_model="MiniMax-M2.5",
|
||||||
|
api_key_url="https://platform.minimaxi.com/",
|
||||||
|
notes="MiniMax-M2.5 may include <think> tags.",
|
||||||
|
may_include_think_tags=True,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_provider(name: str) -> Optional[ProviderPreset]:
|
||||||
|
"""
|
||||||
|
获取提供商预设配置。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: 提供商名称(不区分大小写)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ProviderPreset 或 None(如果未找到)
|
||||||
|
"""
|
||||||
|
return PROVIDERS.get(name.lower().strip())
|
||||||
|
|
||||||
|
|
||||||
|
def list_providers() -> list[dict]:
|
||||||
|
"""
|
||||||
|
列出所有可用的提供商预设。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
提供商信息列表
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"name": p.name,
|
||||||
|
"display_name": p.display_name,
|
||||||
|
"base_url": p.base_url,
|
||||||
|
"default_model": p.default_model,
|
||||||
|
"api_key_url": p.api_key_url,
|
||||||
|
"notes": p.notes,
|
||||||
|
}
|
||||||
|
for p in PROVIDERS.values()
|
||||||
|
]
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
LLM客户端封装
|
LLM客户端封装
|
||||||
统一使用OpenAI格式调用
|
统一使用OpenAI格式调用,支持提供商预设(DeepSeek、Xiaomi MiMo等)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@@ -11,18 +11,29 @@ from openai import OpenAI
|
|||||||
from ..config import Config
|
from ..config import Config
|
||||||
|
|
||||||
|
|
||||||
|
# <think>标签的正则表达式
|
||||||
|
# 匹配 <think>...</think> 标签及其内容(支持多行,非贪婪匹配)
|
||||||
|
# 也处理 <think>...</think> 变体(某些模型可能使用略微不同的格式)
|
||||||
|
THINK_TAG_PATTERN = re.compile(r'<think>[\s\S]*?</think>\s*', re.IGNORECASE)
|
||||||
|
|
||||||
|
# 某些提供商的推理模型会在响应中包含<think>标签
|
||||||
|
PROVIDERS_WITH_THINK_TAGS = {"deepseek", "xiaomi_mimo", "minimax"}
|
||||||
|
|
||||||
|
|
||||||
class LLMClient:
|
class LLMClient:
|
||||||
"""LLM客户端"""
|
"""LLM客户端,支持提供商预设配置"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
api_key: Optional[str] = None,
|
api_key: Optional[str] = None,
|
||||||
base_url: Optional[str] = None,
|
base_url: Optional[str] = None,
|
||||||
model: Optional[str] = None
|
model: Optional[str] = None,
|
||||||
|
provider: Optional[str] = None,
|
||||||
):
|
):
|
||||||
self.api_key = api_key or Config.LLM_API_KEY
|
self.api_key = api_key or Config.LLM_API_KEY
|
||||||
self.base_url = base_url or Config.LLM_BASE_URL
|
self.base_url = base_url or Config.LLM_BASE_URL
|
||||||
self.model = model or Config.LLM_MODEL_NAME
|
self.model = model or Config.LLM_MODEL_NAME
|
||||||
|
self.provider = provider or Config.LLM_PROVIDER
|
||||||
|
|
||||||
if not self.api_key:
|
if not self.api_key:
|
||||||
raise ValueError("LLM_API_KEY 未配置")
|
raise ValueError("LLM_API_KEY 未配置")
|
||||||
@@ -32,6 +43,24 @@ class LLMClient:
|
|||||||
base_url=self.base_url
|
base_url=self.base_url
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 判断是否需要强制清理<think>标签
|
||||||
|
# 如果是已知的推理模型提供商,总是清理;否则也清理(安全兜底)
|
||||||
|
self._should_strip_think = (
|
||||||
|
self.provider in PROVIDERS_WITH_THINK_TAGS
|
||||||
|
or True # 总是清理,因为不影响正常输出
|
||||||
|
)
|
||||||
|
|
||||||
|
def _strip_think_tags(self, content: str) -> str:
|
||||||
|
"""
|
||||||
|
移除响应中的<think>思考内容标签。
|
||||||
|
|
||||||
|
某些模型(如DeepSeek Reasoner、Xiaomi MiMo、MiniMax M2.5)
|
||||||
|
会在响应中包含<think>...</think>标签,需要移除以获得纯净输出。
|
||||||
|
"""
|
||||||
|
if not content:
|
||||||
|
return content
|
||||||
|
return THINK_TAG_PATTERN.sub('', content).strip()
|
||||||
|
|
||||||
def chat(
|
def chat(
|
||||||
self,
|
self,
|
||||||
messages: List[Dict[str, str]],
|
messages: List[Dict[str, str]],
|
||||||
@@ -62,9 +91,11 @@ class LLMClient:
|
|||||||
kwargs["response_format"] = response_format
|
kwargs["response_format"] = response_format
|
||||||
|
|
||||||
response = self.client.chat.completions.create(**kwargs)
|
response = self.client.chat.completions.create(**kwargs)
|
||||||
content = response.choices[0].message.content
|
content = response.choices[0].message.content or ""
|
||||||
# 部分模型(如MiniMax M2.5)会在content中包含<think>思考内容,需要移除
|
|
||||||
content = re.sub(r'<think>[\s\S]*?</think>', '', content).strip()
|
# 移除<think>思考内容标签
|
||||||
|
content = self._strip_think_tags(content)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
def chat_json(
|
def chat_json(
|
||||||
@@ -101,3 +132,10 @@ class LLMClient:
|
|||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
raise ValueError(f"LLM返回的JSON格式无效: {cleaned_response}")
|
raise ValueError(f"LLM返回的JSON格式无效: {cleaned_response}")
|
||||||
|
|
||||||
|
def get_info(self) -> Dict[str, Any]:
|
||||||
|
"""返回当前客户端配置信息(用于日志/调试)"""
|
||||||
|
return {
|
||||||
|
"provider": self.provider or "custom",
|
||||||
|
"base_url": self.base_url,
|
||||||
|
"model": self.model,
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user