[任务5] 重构方案:用 OpenWebUI + LiteLLM 替换 One-API + MySQL
技术栈简化: - 前端:One-API 网页管理 → OpenWebUI 极简界面(WEBUI_AUTH=False 无需登录,自动连接 LiteLLM) - 网关:One-API(数据库驱动)→ LiteLLM(纯 YAML 配置驱动) - 数据存储:MySQL(持久化) → LiteLLM 无状态(配置即代码) 配置简化: - 不需要注册账号、不需要点网页添加渠道 - 所有 5 个渠道的定义、模型映射、优先级、Failover 规则写在 litellm-config.yaml - API Key 填在 .env(占位符在 config.yaml 中引用) - 用户体验:打开网页 → 输入问题 → 自动用最合适的模型回答 已部署到 NAS,openwebui 正在初始化数据库(首次启动需要 1-2 分钟)
This commit is contained in:
21
.env.example
21
.env.example
@@ -1,19 +1,18 @@
|
|||||||
# NexusAI 部署环境变量模板
|
# NexusAI 部署环境变量模板
|
||||||
# 复制为 .env 并填入真实值;.env 已加入 .gitignore,切勿提交版本库。
|
# 复制为 .env 并填入真实值;.env 已加入 .gitignore,切勿提交版本库。
|
||||||
|
|
||||||
# ---- MySQL ----
|
# ---- LiteLLM 网关 ----
|
||||||
MYSQL_ROOT_PASSWORD=change_me_strong_password
|
# LiteLLM 后台管理 Key(可自定义,用于后台 API 认证,前端无需输入)
|
||||||
|
LITELLM_MASTER_KEY=sk-change_me_strong_key
|
||||||
# ---- One-API ----
|
|
||||||
# One-API 后台管理员登录后生成的对外聚合 Token(sk-xxxx),写入 LobeChat 使用
|
|
||||||
ONE_API_TOKEN=sk-change_me_after_one_api_setup
|
|
||||||
|
|
||||||
# ---- LobeChat ----
|
|
||||||
# 前端访问密码(Access Code),自定义,建议高复杂度
|
|
||||||
LOBE_ACCESS_CODE=change_me_access_code
|
|
||||||
|
|
||||||
# ---- 各 AI 渠道 API Key ----
|
# ---- 各 AI 渠道 API Key ----
|
||||||
# 在 One-API 后台添加渠道时手动填入,此处仅作为记录/备用,不由容器直接读取
|
# 这些 Key 被 litellm-config.yaml 引用,容器启动时自动注入为环境变量
|
||||||
|
# 获取方式:
|
||||||
|
# GEMINI_API_KEY: https://aistudio.google.com/apikey
|
||||||
|
# NVIDIA_API_KEY: https://build.nvidia.com/discover/llama2-70b
|
||||||
|
# GROQ_API_KEY: https://console.groq.com
|
||||||
|
# OPENROUTER_API_KEY: https://openrouter.ai/keys
|
||||||
|
# MISTRAL_API_KEY: https://console.mistral.ai/api-tokens
|
||||||
GEMINI_API_KEY=
|
GEMINI_API_KEY=
|
||||||
NVIDIA_API_KEY=
|
NVIDIA_API_KEY=
|
||||||
GROQ_API_KEY=
|
GROQ_API_KEY=
|
||||||
|
|||||||
@@ -1,50 +1,26 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mysql:
|
litellm:
|
||||||
image: mysql:8.0
|
image: ghcr.io/berriai/litellm:latest
|
||||||
container_name: one-api-mysql
|
container_name: litellm-proxy
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
- LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY:-sk-1234}
|
||||||
- MYSQL_DATABASE=oneapi
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./mysql-data:/var/lib/mysql
|
- ./litellm-config.yaml:/home/litellm/config.yaml:ro
|
||||||
networks:
|
networks:
|
||||||
- ai-network
|
- ai-network
|
||||||
|
command: python -m litellm.proxy.proxy --config /home/litellm/config.yaml --port 4000
|
||||||
|
|
||||||
one-api:
|
openwebui:
|
||||||
image: justsong/one-api:latest
|
image: ghcr.io/open-webui/open-webui:latest
|
||||||
container_name: one-api
|
container_name: openwebui
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
|
||||||
# 3000 已被 NAS 上的 Gitea 容器占用,改用 3001
|
|
||||||
# NAS sshd 关闭了 AllowTcpForwarding,SSH 隧道方案不可行,改为仅绑定 NAS 局域网 IP(不经 frp,不映射公网)
|
|
||||||
- "192.168.50.64:3001:3000"
|
|
||||||
volumes:
|
|
||||||
- ./one-api-data:/data
|
|
||||||
environment:
|
environment:
|
||||||
- SQL_DSN=root:${MYSQL_ROOT_PASSWORD}@tcp(mysql:3306)/oneapi
|
- OPENAI_API_KEY=${LITELLM_MASTER_KEY:-sk-1234}
|
||||||
- TZ=Asia/Shanghai
|
- OPENAI_API_BASE=http://litellm:4000/v1
|
||||||
depends_on:
|
- WEBUI_AUTH=False
|
||||||
- mysql
|
|
||||||
networks:
|
|
||||||
- ai-network
|
|
||||||
|
|
||||||
lobe-chat:
|
|
||||||
image: lobehub/lobe-chat:latest
|
|
||||||
container_name: lobe-chat
|
|
||||||
restart: always
|
|
||||||
# 不发布主机端口:仅 Nginx 通过容器网络访问 lobe-chat:3210
|
|
||||||
environment:
|
|
||||||
- OPENAI_API_KEY=${ONE_API_TOKEN}
|
|
||||||
- OPENAI_PROXY_URL=http://one-api:3000/v1
|
|
||||||
- ACCESS_CODE=${LOBE_ACCESS_CODE}
|
|
||||||
- DEFAULT_LANG=zh-CN
|
|
||||||
# 只暴露聚合模型名,隐藏各厂商真实模型名(对应 SDD 3.2 模型映射设计)
|
|
||||||
- OPENAI_MODEL_LIST=-all,+auto-vision=Auto Vision<vision>,+auto-text=Auto Text
|
|
||||||
depends_on:
|
|
||||||
- one-api
|
|
||||||
networks:
|
networks:
|
||||||
- ai-network
|
- ai-network
|
||||||
|
|
||||||
@@ -53,14 +29,14 @@ services:
|
|||||||
container_name: nginx-proxy
|
container_name: nginx-proxy
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
# NAS 本机 80/443 已被其他服务占用(DSM/其他容器),改用 8443
|
# NAS 本机 80/443 已被其他服务占用,改用 8443
|
||||||
# 甲骨文 frp 隧道(frpc.toml [[proxies]] name=nexusai)将公网专属端口 3210 转发到 NAS 的 8443
|
# 甲骨文 frp 隧道(frpc.toml [[proxies]] name=nexusai)将公网专属端口 3210 转发到 NAS 的 8443
|
||||||
- "8443:443"
|
- "8443:443"
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
- ./certs:/etc/nginx/certs:ro
|
- ./certs:/etc/nginx/certs:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- lobe-chat
|
- openwebui
|
||||||
networks:
|
networks:
|
||||||
- ai-network
|
- ai-network
|
||||||
|
|
||||||
|
|||||||
97
litellm-config.yaml
Normal file
97
litellm-config.yaml
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# LiteLLM 网关配置文件
|
||||||
|
# 所有渠道和模型优先级、Failover 规则在此定义
|
||||||
|
# API Key 通过环境变量注入,见 .env 文件
|
||||||
|
|
||||||
|
model_list:
|
||||||
|
# 聚合模型1: auto-vision (图文混合问答)
|
||||||
|
# 按优先级依次尝试: Gemini(1) → NVIDIA(1) → OpenRouter(2) → Mistral(3)
|
||||||
|
# (Groq 不支持视觉,故不在此列表)
|
||||||
|
- model_name: auto-vision
|
||||||
|
litellm_params:
|
||||||
|
model: gemini/gemini-flash-latest
|
||||||
|
api_key: ${GEMINI_API_KEY}
|
||||||
|
api_base: https://generativelanguage.googleapis.com/v1beta
|
||||||
|
fallbacks:
|
||||||
|
- nvidia-nim-vision
|
||||||
|
- openrouter-vision
|
||||||
|
- mistral-vision
|
||||||
|
tpm_limit: 10000
|
||||||
|
rpm_limit: 100
|
||||||
|
|
||||||
|
- model_name: nvidia-nim-vision
|
||||||
|
litellm_params:
|
||||||
|
model: openai/meta/llama-3.2-11b-vision-instruct
|
||||||
|
api_key: ${NVIDIA_API_KEY}
|
||||||
|
api_base: https://integrate.api.nvidia.com/v1
|
||||||
|
|
||||||
|
- model_name: openrouter-vision
|
||||||
|
litellm_params:
|
||||||
|
model: openrouter/google/gemini-2.0-flash-exp:free
|
||||||
|
api_key: ${OPENROUTER_API_KEY}
|
||||||
|
api_base: https://openrouter.ai/api/v1
|
||||||
|
|
||||||
|
- model_name: mistral-vision
|
||||||
|
litellm_params:
|
||||||
|
model: openai/pixtral-12b-2409
|
||||||
|
api_key: ${MISTRAL_API_KEY}
|
||||||
|
api_base: https://api.mistral.ai/v1
|
||||||
|
|
||||||
|
# 聚合模型2: auto-text (纯文本问答)
|
||||||
|
# 按优先级依次尝试: Gemini(1) → NVIDIA(1) → OpenRouter(2) → Groq(2) → Mistral(3)
|
||||||
|
- model_name: auto-text
|
||||||
|
litellm_params:
|
||||||
|
model: gemini/gemini-flash-latest
|
||||||
|
api_key: ${GEMINI_API_KEY}
|
||||||
|
api_base: https://generativelanguage.googleapis.com/v1beta
|
||||||
|
fallbacks:
|
||||||
|
- nvidia-nim-text
|
||||||
|
- openrouter-text
|
||||||
|
- groq-text
|
||||||
|
- mistral-text
|
||||||
|
tpm_limit: 10000
|
||||||
|
rpm_limit: 100
|
||||||
|
|
||||||
|
- model_name: nvidia-nim-text
|
||||||
|
litellm_params:
|
||||||
|
model: openai/meta/llama-3.2-11b-vision-instruct
|
||||||
|
api_key: ${NVIDIA_API_KEY}
|
||||||
|
api_base: https://integrate.api.nvidia.com/v1
|
||||||
|
|
||||||
|
- model_name: openrouter-text
|
||||||
|
litellm_params:
|
||||||
|
model: openrouter/google/gemini-2.0-flash-exp:free
|
||||||
|
api_key: ${OPENROUTER_API_KEY}
|
||||||
|
api_base: https://openrouter.ai/api/v1
|
||||||
|
|
||||||
|
- model_name: groq-text
|
||||||
|
litellm_params:
|
||||||
|
model: openai/llama-3.3-70b-versatile
|
||||||
|
api_key: ${GROQ_API_KEY}
|
||||||
|
api_base: https://api.groq.com/openai/v1
|
||||||
|
|
||||||
|
- model_name: mistral-text
|
||||||
|
litellm_params:
|
||||||
|
model: openai/mistral-small-latest
|
||||||
|
api_key: ${MISTRAL_API_KEY}
|
||||||
|
api_base: https://api.mistral.ai/v1
|
||||||
|
|
||||||
|
# 网关全局配置
|
||||||
|
router_settings:
|
||||||
|
enable_cooldowns: true
|
||||||
|
cooldown_threshold: 5 # 连续失败 5 次进入冷却
|
||||||
|
cooldown_duration: 600 # 冷却期 10 分钟
|
||||||
|
enable_retry: true
|
||||||
|
max_retries: 2 # 最多重试 2 次
|
||||||
|
|
||||||
|
# 日志级别
|
||||||
|
logging:
|
||||||
|
level: INFO
|
||||||
|
|
||||||
|
# Fallback 行为
|
||||||
|
# 上游错误(429/5xx/timeout)时自动切换到下一个渠道
|
||||||
|
fallback_error_codes:
|
||||||
|
- 429
|
||||||
|
- 502
|
||||||
|
- 503
|
||||||
|
- 504
|
||||||
|
- timeout
|
||||||
10
nginx.conf
10
nginx.conf
@@ -21,7 +21,7 @@ http {
|
|||||||
sendfile on;
|
sendfile on;
|
||||||
keepalive_timeout 65;
|
keepalive_timeout 65;
|
||||||
|
|
||||||
# 域名/IP 未确定前,先用 _ 通配 server_name(见 SDD 8.4 待确认事项)
|
# 域名/IP 未确定前,先用 _ 通配 server_name
|
||||||
server {
|
server {
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
server_name _;
|
server_name _;
|
||||||
@@ -30,14 +30,18 @@ http {
|
|||||||
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://lobe-chat:3210;
|
proxy_pass http://openwebui:8080;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
# 关闭缓冲/缓存以支持流式输出(SSE)
|
# WebSocket 支持(Infinity Chat 可能使用 WebSocket)
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
# 关闭缓冲/缓存以支持流式输出
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
proxy_cache off;
|
proxy_cache off;
|
||||||
proxy_read_timeout 300s;
|
proxy_read_timeout 300s;
|
||||||
|
|||||||
Reference in New Issue
Block a user