forked from xiaohei/taiji-AI-PAD
更新litellm
This commit is contained in:
@@ -0,0 +1,527 @@
|
||||
# 模型供应商与租户模型使用设计方案(最终版 v5.0)
|
||||
|
||||
> **版本**: v5.0.0
|
||||
> **创建时间**: 2026-01-07
|
||||
> **状态**: 待评审
|
||||
|
||||
---
|
||||
|
||||
## 1. 核心职责分工
|
||||
|
||||
### 1.1 职责划分表
|
||||
|
||||
| 职责 | 负责方 | 说明 |
|
||||
|------|--------|------|
|
||||
| 决定租户能用哪些模型 | **mcp-server** | 业务规则制定者 |
|
||||
| 决定 RPM/TPM/Budget 数值 | **mcp-server** | 配额分配 |
|
||||
| 真正拦截超额请求 | **litellm-gateway** | 规则执行者 |
|
||||
| 管理 Agent 生命周期 | **mcp-server + Agent Manager** | 与 litellm 解耦 |
|
||||
| 用量统计和计费 | **litellm-gateway** | 原生能力 |
|
||||
|
||||
### 1.2 概念映射
|
||||
|
||||
| 平台概念 | LiteLLM 对应 | 说明 |
|
||||
|----------|-------------|------|
|
||||
| 渠道 | team | 一个渠道 = 一个 team |
|
||||
| 租户 | team 下的 key 或子 team | 租户归属于渠道 |
|
||||
| 模型供应商 | model/provider | litellm 配置 |
|
||||
| 平台 Agent | 不进 LiteLLM | mcp-server 自己管理 |
|
||||
|
||||
### 1.3 LiteLLM 不关心的事情
|
||||
|
||||
- ❌ Agent 是什么
|
||||
- ❌ Agent 从哪来
|
||||
- ❌ Agent 跑在 AKS 还是别的地方
|
||||
- ❌ Agent 生命周期
|
||||
|
||||
**LiteLLM 只看请求里的**:
|
||||
- ✅ api_key
|
||||
- ✅ team
|
||||
- ✅ model
|
||||
|
||||
---
|
||||
|
||||
## 2. 整体架构
|
||||
|
||||
### 2.1 架构图
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph mcp-server[mcp-server 业务规则制定者]
|
||||
A1[管理员创建渠道]
|
||||
A2[分配模型供应商给渠道]
|
||||
A3[渠道分配模型给租户]
|
||||
A4[设置 RPM/TPM/Budget]
|
||||
A5[用户充值更新额度]
|
||||
end
|
||||
|
||||
subgraph litellm[litellm-gateway 规则执行者]
|
||||
B1[team 管理]
|
||||
B2[key 管理]
|
||||
B3[rate_limit 检查]
|
||||
B4[budget 检查]
|
||||
B5[用量统计]
|
||||
end
|
||||
|
||||
subgraph agent[Agent 运行层 - 与 litellm 解耦]
|
||||
C1[Agent Manager]
|
||||
C2[AKS Pod]
|
||||
C3[调用模型]
|
||||
end
|
||||
|
||||
A1 --> |创建 team| B1
|
||||
A3 --> |创建 key + 配额| B2
|
||||
A4 --> |设置 rate_limit| B3
|
||||
A5 --> |更新 budget| B4
|
||||
|
||||
C2 --> |带 api_key 请求| litellm
|
||||
litellm --> |检查配额| B3
|
||||
litellm --> |检查余额| B4
|
||||
litellm --> |转发| Provider[Azure/Gemini]
|
||||
```
|
||||
|
||||
### 2.2 核心流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as 管理员
|
||||
participant MCP as mcp-server
|
||||
participant LiteLLM as litellm-gateway
|
||||
participant Agent as Agent Pod
|
||||
participant Azure as Azure/Gemini
|
||||
|
||||
Note over Admin,Azure: 1️⃣ 创建渠道
|
||||
Admin->>MCP: 创建渠道
|
||||
MCP->>LiteLLM: POST /team/new
|
||||
Note over MCP,LiteLLM: team_alias: channel-xxx
|
||||
|
||||
Note over Admin,Azure: 2️⃣ 分配模型给渠道
|
||||
Admin->>MCP: 分配模型 azure/gpt-4
|
||||
MCP->>MCP: 记录到 ResourceAllocation
|
||||
|
||||
Note over Admin,Azure: 3️⃣ 渠道分配模型给租户
|
||||
MCP->>LiteLLM: POST /key/generate
|
||||
Note over MCP,LiteLLM: team_id, models, rpm_limit, tpm_limit, max_budget
|
||||
LiteLLM-->>MCP: 返回 api_key
|
||||
MCP->>MCP: 保存 key 到数据库
|
||||
|
||||
Note over Admin,Azure: 4️⃣ 租户创建 Agent
|
||||
MCP->>MCP: 查询租户的 api_key
|
||||
MCP->>Agent: 启动 Pod,注入 api_key
|
||||
|
||||
Note over Admin,Azure: 5️⃣ Agent 调用模型
|
||||
Agent->>LiteLLM: POST /chat/completions
|
||||
Note over Agent,LiteLLM: Authorization: Bearer api_key
|
||||
LiteLLM->>LiteLLM: 检查 RPM/TPM
|
||||
LiteLLM->>LiteLLM: 检查 Budget
|
||||
|
||||
alt 配额/余额不足
|
||||
LiteLLM-->>Agent: 429/403 拒绝
|
||||
else 配额充足
|
||||
LiteLLM->>Azure: 转发请求
|
||||
Azure-->>LiteLLM: 返回结果
|
||||
LiteLLM->>LiteLLM: 记录用量
|
||||
LiteLLM-->>Agent: 返回结果
|
||||
end
|
||||
|
||||
Note over Admin,Azure: 6️⃣ 用户充值
|
||||
MCP->>LiteLLM: POST /key/update
|
||||
Note over MCP,LiteLLM: 更新 max_budget
|
||||
Note over MCP,LiteLLM: 下一次请求立刻放行,无需重启
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 详细设计
|
||||
|
||||
### 3.1 创建渠道(对应 LiteLLM team)
|
||||
|
||||
**mcp-server 操作**:
|
||||
```python
|
||||
async def create_channel(channel_name: str, db: AsyncSession):
|
||||
# 1. 在 mcp-server 创建渠道记录
|
||||
channel = Channel(name=channel_name, ...)
|
||||
db.add(channel)
|
||||
|
||||
# 2. 在 litellm 创建对应的 team
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(
|
||||
f"{settings.litellm_url}/team/new",
|
||||
json={
|
||||
"team_alias": f"channel-{channel.id}",
|
||||
"metadata": {
|
||||
"channel_id": str(channel.id),
|
||||
"channel_name": channel_name
|
||||
}
|
||||
},
|
||||
headers={"Authorization": f"Bearer {settings.litellm_master_key}"}
|
||||
)
|
||||
data = response.json()
|
||||
|
||||
# 保存 litellm team_id
|
||||
channel.litellm_team_id = data["team_id"]
|
||||
|
||||
await db.commit()
|
||||
return channel
|
||||
```
|
||||
|
||||
### 3.2 分配模型给渠道
|
||||
|
||||
**mcp-server 操作**:
|
||||
```python
|
||||
async def allocate_models_to_channel(
|
||||
channel_id: str,
|
||||
models: list[str], # ["azure/gpt-4", "gemini/gemini-pro"]
|
||||
db: AsyncSession
|
||||
):
|
||||
# 只在 mcp-server 记录,不需要同步到 litellm
|
||||
# litellm 的 team 不限制模型,模型限制在 key 级别
|
||||
for model in models:
|
||||
allocation = ResourceAllocation(
|
||||
target_id=channel_id,
|
||||
target_type="channel",
|
||||
resource_type="model",
|
||||
resource_id=model
|
||||
)
|
||||
db.add(allocation)
|
||||
|
||||
await db.commit()
|
||||
```
|
||||
|
||||
### 3.3 渠道分配模型给租户(核心)
|
||||
|
||||
**mcp-server 操作**:
|
||||
```python
|
||||
async def allocate_model_to_tenant(
|
||||
tenant_id: str,
|
||||
channel_id: str,
|
||||
model_name: str,
|
||||
rpm_limit: int,
|
||||
tpm_limit: int,
|
||||
max_budget: float,
|
||||
db: AsyncSession
|
||||
):
|
||||
# 1. 验证渠道是否有该模型
|
||||
channel_has_model = await check_channel_has_model(channel_id, model_name, db)
|
||||
if not channel_has_model:
|
||||
raise HTTPException(status_code=403, detail="渠道没有该模型的权限")
|
||||
|
||||
# 2. 获取渠道的 litellm team_id
|
||||
channel = await get_channel(channel_id, db)
|
||||
|
||||
# 3. 在 litellm 创建 key(绑定 team + model + 配额)
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(
|
||||
f"{settings.litellm_url}/key/generate",
|
||||
json={
|
||||
"team_id": channel.litellm_team_id,
|
||||
"models": [model_name],
|
||||
"rpm_limit": rpm_limit,
|
||||
"tpm_limit": tpm_limit,
|
||||
"max_budget": max_budget,
|
||||
"budget_duration": "monthly", # 或 "total"
|
||||
"metadata": {
|
||||
"tenant_id": str(tenant_id),
|
||||
"channel_id": str(channel_id),
|
||||
"model": model_name
|
||||
}
|
||||
},
|
||||
headers={"Authorization": f"Bearer {settings.litellm_master_key}"}
|
||||
)
|
||||
data = response.json()
|
||||
|
||||
# 4. 保存到数据库
|
||||
tenant_key = TenantModelKey(
|
||||
tenant_id=tenant_id,
|
||||
channel_id=channel_id,
|
||||
model_name=model_name,
|
||||
litellm_key_id=data["key"],
|
||||
litellm_key_hash=encrypt(data["key"]), # 加密存储
|
||||
rpm_limit=rpm_limit,
|
||||
tpm_limit=tpm_limit,
|
||||
max_budget=max_budget
|
||||
)
|
||||
db.add(tenant_key)
|
||||
|
||||
# 5. 同时记录到 ResourceAllocation
|
||||
allocation = ResourceAllocation(
|
||||
target_id=tenant_id,
|
||||
target_type="tenant",
|
||||
resource_type="model",
|
||||
resource_id=model_name,
|
||||
rpm=rpm_limit,
|
||||
tpm=tpm_limit
|
||||
)
|
||||
db.add(allocation)
|
||||
|
||||
await db.commit()
|
||||
return tenant_key
|
||||
```
|
||||
|
||||
### 3.4 租户创建 Agent
|
||||
|
||||
**mcp-server 操作**:
|
||||
```python
|
||||
async def create_custom_agent(
|
||||
tenant_id: str,
|
||||
agent_name: str,
|
||||
model_name: str,
|
||||
cpu_request: str,
|
||||
memory_request: str,
|
||||
db: AsyncSession
|
||||
):
|
||||
# 1. 查询租户的模型 key
|
||||
tenant_key = await db.execute(
|
||||
select(TenantModelKey).where(
|
||||
and_(
|
||||
TenantModelKey.tenant_id == tenant_id,
|
||||
TenantModelKey.model_name == model_name,
|
||||
TenantModelKey.status == "active"
|
||||
)
|
||||
)
|
||||
)
|
||||
tenant_key = tenant_key.scalar_one_or_none()
|
||||
|
||||
if not tenant_key:
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail=f"您没有使用模型 {model_name} 的权限"
|
||||
)
|
||||
|
||||
# 2. 调用 Agent Manager 创建 Pod
|
||||
# Agent Manager 不需要知道 litellm 的任何细节
|
||||
# 只需要注入环境变量
|
||||
result = await agent_manager.create_agent(
|
||||
name=agent_name,
|
||||
cpu_request=cpu_request,
|
||||
memory_request=memory_request,
|
||||
env_vars={
|
||||
"OPENAI_API_BASE": settings.litellm_url,
|
||||
"OPENAI_API_KEY": decrypt(tenant_key.litellm_key_hash),
|
||||
"MODEL_NAME": model_name
|
||||
}
|
||||
)
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
### 3.5 用户充值更新额度
|
||||
|
||||
**mcp-server 操作**:
|
||||
```python
|
||||
async def recharge_tenant_budget(
|
||||
tenant_id: str,
|
||||
model_name: str,
|
||||
additional_budget: float,
|
||||
db: AsyncSession
|
||||
):
|
||||
# 1. 获取租户的 key
|
||||
tenant_key = await get_tenant_model_key(tenant_id, model_name, db)
|
||||
|
||||
# 2. 计算新的 budget
|
||||
new_budget = float(tenant_key.max_budget or 0) + additional_budget
|
||||
|
||||
# 3. 更新 litellm key 的 budget
|
||||
async with httpx.AsyncClient() as client:
|
||||
await client.post(
|
||||
f"{settings.litellm_url}/key/update",
|
||||
json={
|
||||
"key": tenant_key.litellm_key_id,
|
||||
"max_budget": new_budget
|
||||
},
|
||||
headers={"Authorization": f"Bearer {settings.litellm_master_key}"}
|
||||
)
|
||||
|
||||
# 4. 更新数据库
|
||||
tenant_key.max_budget = new_budget
|
||||
await db.commit()
|
||||
|
||||
# ✅ 下一次请求立刻放行,无需重启任何服务
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据模型
|
||||
|
||||
### 4.1 新增表:TenantModelKey
|
||||
|
||||
```sql
|
||||
CREATE TABLE tenant_model_keys (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES users(id),
|
||||
channel_id UUID REFERENCES channels(id),
|
||||
|
||||
-- 模型信息
|
||||
model_name VARCHAR(100) NOT NULL,
|
||||
|
||||
-- litellm Key 信息
|
||||
litellm_key_id VARCHAR(255) NOT NULL, -- litellm 返回的完整 key
|
||||
litellm_key_hash TEXT NOT NULL, -- 加密存储
|
||||
|
||||
-- 配额配置(与 litellm 同步)
|
||||
rpm_limit INTEGER DEFAULT 0,
|
||||
tpm_limit INTEGER DEFAULT 0,
|
||||
max_budget NUMERIC(12, 2),
|
||||
budget_duration VARCHAR(20) DEFAULT 'monthly',
|
||||
|
||||
-- 状态
|
||||
status VARCHAR(20) DEFAULT 'active',
|
||||
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
|
||||
UNIQUE(tenant_id, model_name)
|
||||
);
|
||||
```
|
||||
|
||||
### 4.2 Channel 表增加字段
|
||||
|
||||
```sql
|
||||
ALTER TABLE channels ADD COLUMN litellm_team_id VARCHAR(100);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. LiteLLM 配置
|
||||
|
||||
### 5.1 litellm_config.yaml
|
||||
|
||||
```yaml
|
||||
general_settings:
|
||||
master_key: "sk-taiji-master-key"
|
||||
database_url: "postgresql://..." # 可选,用于持久化
|
||||
|
||||
model_list:
|
||||
# Azure GPT-4
|
||||
- model_name: "azure/gpt-4"
|
||||
litellm_params:
|
||||
model: "azure/gpt-4"
|
||||
api_base: "https://taiji-azure.openai.azure.com"
|
||||
api_key: "os.environ/AZURE_API_KEY"
|
||||
api_version: "2024-02-15-preview"
|
||||
|
||||
# Azure GPT-3.5
|
||||
- model_name: "azure/gpt-35-turbo"
|
||||
litellm_params:
|
||||
model: "azure/gpt-35-turbo"
|
||||
api_base: "https://taiji-azure.openai.azure.com"
|
||||
api_key: "os.environ/AZURE_API_KEY"
|
||||
api_version: "2024-02-15-preview"
|
||||
|
||||
# Google Gemini
|
||||
- model_name: "gemini/gemini-pro"
|
||||
litellm_params:
|
||||
model: "gemini/gemini-pro"
|
||||
api_key: "os.environ/GOOGLE_API_KEY"
|
||||
|
||||
# 启用用量追踪
|
||||
litellm_settings:
|
||||
success_callback: ["prometheus"]
|
||||
track_cost_callback: true
|
||||
```
|
||||
|
||||
### 5.2 LiteLLM Admin API 使用
|
||||
|
||||
| API | 用途 | 调用时机 |
|
||||
|-----|------|----------|
|
||||
| `POST /team/new` | 创建 team | 创建渠道时 |
|
||||
| `POST /key/generate` | 创建 key | 分配模型给租户时 |
|
||||
| `POST /key/update` | 更新 key 配额 | 修改配额/充值时 |
|
||||
| `POST /key/delete` | 删除 key | 取消分配时 |
|
||||
| `GET /spend/logs` | 查询用量 | 统计报表时 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 接口设计
|
||||
|
||||
### 6.1 渠道管理接口
|
||||
|
||||
| 接口 | 方法 | 功能 | 变更 |
|
||||
|------|------|------|------|
|
||||
| `POST /api/admin/channels/create` | POST | 创建渠道 | 同步创建 litellm team |
|
||||
| `DELETE /api/admin/channels/{id}` | DELETE | 删除渠道 | 同步删除 litellm team |
|
||||
|
||||
### 6.2 模型分配接口
|
||||
|
||||
| 接口 | 方法 | 功能 | 变更 |
|
||||
|------|------|------|------|
|
||||
| `PUT /api/channel/tenants/{id}/models` | PUT | 分配模型给租户 | 创建 litellm key |
|
||||
| `DELETE /api/channel/tenants/{id}/models/{model}` | DELETE | 取消分配 | 删除 litellm key |
|
||||
| `PUT /api/channel/tenants/{id}/models/{model}/quota` | PUT | 更新配额 | 更新 litellm key |
|
||||
|
||||
### 6.3 租户接口
|
||||
|
||||
| 接口 | 方法 | 功能 |
|
||||
|------|------|------|
|
||||
| `GET /api/user/models/available` | GET | 获取可用模型列表 |
|
||||
| `POST /api/user/custom-agents` | POST | 创建 Agent(注入 key) |
|
||||
| `GET /api/user/models/usage/stats` | GET | 查询用量统计 |
|
||||
| `POST /api/user/billing/recharge` | POST | 充值(更新 litellm budget) |
|
||||
|
||||
---
|
||||
|
||||
## 7. 实现计划
|
||||
|
||||
### 7.1 任务清单
|
||||
|
||||
- [ ] **数据库迁移**
|
||||
- [ ] 创建 `tenant_model_keys` 表
|
||||
- [ ] Channel 表增加 `litellm_team_id` 字段
|
||||
|
||||
- [ ] **litellm 集成**
|
||||
- [ ] 实现 litellm Admin API 客户端
|
||||
- [ ] 创建渠道时同步创建 team
|
||||
- [ ] 分配模型时创建 key
|
||||
- [ ] 充值时更新 budget
|
||||
|
||||
- [ ] **接口调整**
|
||||
- [ ] 更新渠道创建接口
|
||||
- [ ] 实现模型分配接口
|
||||
- [ ] 更新 Agent 创建接口
|
||||
- [ ] 实现充值接口
|
||||
|
||||
- [ ] **Agent Manager**
|
||||
- [ ] 支持注入 litellm key 环境变量
|
||||
|
||||
---
|
||||
|
||||
## 8. 关键行为说明
|
||||
|
||||
### 8.1 配额超限行为
|
||||
|
||||
| 状态 | LiteLLM 行为 | 说明 |
|
||||
|------|-------------|------|
|
||||
| RPM 超限 | 返回 429 | 等待下一分钟自动恢复 |
|
||||
| TPM 超限 | 返回 429 | 等待下一分钟自动恢复 |
|
||||
| Budget 用完 | 返回 403 | 需要充值才能恢复 |
|
||||
|
||||
### 8.2 充值后恢复
|
||||
|
||||
```
|
||||
用户充值 → mcp-server 调用 litellm API 更新 budget → 下一次请求立刻放行
|
||||
```
|
||||
|
||||
- ✅ 不需要重启任何服务
|
||||
- ✅ 不需要重新创建 key
|
||||
- ✅ 实时生效
|
||||
|
||||
---
|
||||
|
||||
## 9. 总结
|
||||
|
||||
### 9.1 核心设计原则
|
||||
|
||||
1. **mcp-server 是业务规则制定者**:决定谁能用什么、用多少
|
||||
2. **litellm-gateway 是规则执行者**:真正拦截超额请求
|
||||
3. **Agent 与 litellm 解耦**:Agent 只需要带正确的 api_key 调用
|
||||
4. **实时生效**:配额更新、充值后立刻生效,无需重启
|
||||
|
||||
### 9.2 架构优势
|
||||
|
||||
| 优势 | 说明 |
|
||||
|------|------|
|
||||
| 职责清晰 | mcp-server 管业务,litellm 管执行 |
|
||||
| 延迟低 | Agent 直接调用 litellm,无需代理 |
|
||||
| 原生能力 | 充分利用 litellm 的配额和计费能力 |
|
||||
| 易扩展 | 新增模型只需配置 litellm |
|
||||
| 实时生效 | 配额更新无需重启 |
|
||||
Reference in New Issue
Block a user