forked from xiaohei/taiji-AI-PAD
更新mcp-server
This commit is contained in:
@@ -1,191 +0,0 @@
|
||||
# AI Agent Manager API 集成计划
|
||||
|
||||
## 概述
|
||||
|
||||
将项目中的 Agent 管理功能与新的 AI Agent Manager API 集成,实现真正的 Kubernetes Pod 部署和资源管控。
|
||||
|
||||
## 当前状态分析
|
||||
|
||||
### 现有实现
|
||||
- **Agent 数据模型** ([`models.py`](../services/mcp-server/models.py:122)):数据库级别的 Agent 记录
|
||||
- **Agent 路由** ([`agents.py`](../services/mcp-server/app/routes/agents.py:1)):CRUD 操作,无真正 K8s 部署
|
||||
- **资源管控** ([`resource_control.py`](../services/mcp-server/app/resource_control.py:1)):配额检查和速率限制
|
||||
- **部署功能** ([`user.py:deploy_agent`](../services/mcp-server/app/routes/user.py:327)):仅模拟,未实际调用 K8s
|
||||
|
||||
### 新 API 能力
|
||||
- 真正的 Kubernetes Pod 创建/删除/查询
|
||||
- 模板系统(echo_agent, jina_search_agent, mysql_agent 等)
|
||||
- 资源配置(cpu_request, cpu_limit, memory_request, memory_limit)
|
||||
- Pod 状态监控和访问信息
|
||||
|
||||
## 架构设计
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Frontend[前端]
|
||||
UI[用户界面]
|
||||
end
|
||||
|
||||
subgraph MCPServer[MCP Server]
|
||||
AgentRoutes[Agent 路由]
|
||||
ResourceControl[资源管控]
|
||||
AgentClient[Agent Manager 客户端]
|
||||
DB[(PostgreSQL)]
|
||||
end
|
||||
|
||||
subgraph K8sCluster[Kubernetes 集群]
|
||||
AgentManager[AI Agent Manager API]
|
||||
AgentPods[Agent Pods]
|
||||
end
|
||||
|
||||
UI --> AgentRoutes
|
||||
AgentRoutes --> ResourceControl
|
||||
ResourceControl --> AgentClient
|
||||
AgentClient --> AgentManager
|
||||
AgentManager --> AgentPods
|
||||
AgentRoutes --> DB
|
||||
```
|
||||
|
||||
## 实施任务清单
|
||||
|
||||
### 阶段一:创建 Agent Manager 客户端
|
||||
|
||||
- [x] **1.1** 创建 `services/mcp-server/app/agent_manager_client.py`
|
||||
- 封装对 AI Agent Manager API 的 HTTP 调用
|
||||
- 支持健康检查、模板列表、创建/删除/查询 Agent
|
||||
- 使用 httpx 异步客户端
|
||||
- 配置通过环境变量 `AGENT_MANAGER_URL` 设置
|
||||
|
||||
- [x] **1.2** 创建请求/响应模型(集成到 `schemas.py`)
|
||||
- K8sResourceConfig(cpu_request, cpu_limit, memory_request, memory_limit, env)
|
||||
- AgentStatusResponse(Pod 状态、IP、端点信息)
|
||||
- AgentMetricsResponse(资源使用情况)
|
||||
- TemplateInfo, TemplateListResponse
|
||||
|
||||
### 阶段二:修改 Agent 路由
|
||||
|
||||
- [x] **2.1** 更新 `services/mcp-server/app/routes/agents.py`
|
||||
- 修改 `create_agent` 函数:
|
||||
- 保留资源管控检查
|
||||
- 调用 Agent Manager API 创建 Pod
|
||||
- 同步更新数据库记录(添加 pod_name, pod_ip, template 等字段)
|
||||
- 新增 `delete_agent` 函数:调用 API 删除 Pod
|
||||
- 新增 `get_agent_status` 函数:获取 Pod 实时状态
|
||||
- 新增 `get_agent_metrics` 函数:获取资源使用情况
|
||||
- 新增 `list_templates` 和 `get_template` 函数
|
||||
|
||||
- [x] **2.2** 更新 Agent 数据模型 `services/mcp-server/models.py`
|
||||
- 添加字段:`pod_name`, `pod_ip`, `template`, `service_port`
|
||||
- 添加字段:`cpu_request`, `cpu_limit`, `memory_request`, `memory_limit`
|
||||
- 添加字段:`k8s_status`(Pending, Running, Failed 等)
|
||||
- 添加字段:`k8s_namespace`, `access_url`, `endpoints`, `env_config`, `pod_created_at`
|
||||
|
||||
- [x] **2.3** 创建数据库迁移脚本
|
||||
- `services/mcp-server/migrations/004_add_k8s_agent_fields.sql`
|
||||
|
||||
### 阶段三:更新资源管控
|
||||
|
||||
- [ ] **3.1** 更新 `services/mcp-server/app/resource_control.py`
|
||||
- 添加 Agent 资源配额检查(用户可创建的 Agent 数量限制)
|
||||
- 添加 CPU/内存总量限制检查
|
||||
- 集成 Agent Manager 的 metrics API 获取实际资源使用
|
||||
|
||||
- [x] **3.2** 更新 `services/mcp-server/app/routes/admin.py`
|
||||
- 修改 `update_agent_config` 函数:
|
||||
- 支持更新 cpu_request, cpu_limit, memory_request, memory_limit
|
||||
- 注意:已运行的 Pod 需要重新创建才能更新资源配置
|
||||
|
||||
### 阶段四:更新用户侧功能
|
||||
|
||||
- [x] **4.1** 更新 `services/mcp-server/app/routes/user.py`
|
||||
- 修改 `deploy_agent` 函数:调用 Agent Manager API
|
||||
- 修改 `generate_tool` 函数:支持自定义资源配置(待完成)
|
||||
|
||||
- [x] **4.2** 更新 `services/mcp-server/app/schemas.py`
|
||||
- 更新 `UpdateAgentConfigRequest`:添加 K8s 资源配置字段
|
||||
|
||||
### 阶段五:模板管理
|
||||
|
||||
- [x] **5.1** 模板路由已集成到 `services/mcp-server/app/routes/agents.py`
|
||||
- `GET /agents/templates`:获取可用模板列表
|
||||
- `GET /agents/templates/{name}`:获取模板详情和所需环境变量
|
||||
|
||||
- [ ] **5.2** 更新路由注册 `services/mcp-server/app/routes/__init__.py`(无需修改,已自动包含)
|
||||
|
||||
### 阶段六:资源监控集成
|
||||
|
||||
- [ ] **6.1** 更新 `services/mcp-server/app/routes/resource_monitoring.py`
|
||||
- 集成 Agent Manager 的 `/agents/{name}/metrics` API
|
||||
- 提供实时 Pod 资源使用数据
|
||||
|
||||
- [ ] **6.2** 更新 `services/mcp-server/app/routes/monitoring.py`
|
||||
- 添加 Agent Pod 健康状态监控
|
||||
- 添加 Agent Manager 服务健康检查
|
||||
|
||||
### 阶段七:配置和部署
|
||||
|
||||
- [x] **7.1** 更新环境变量配置
|
||||
- `.env.example`:添加 `AGENT_MANAGER_URL`
|
||||
- `services/mcp-server/config.py`:添加配置项
|
||||
|
||||
- [ ] **7.2** 更新 Kubernetes 部署配置
|
||||
- `k8s/mcp-server.yaml`:添加环境变量
|
||||
- `k8s/configmap.yaml`:添加 Agent Manager URL 配置
|
||||
|
||||
- [ ] **7.3** 更新 Docker Compose 配置
|
||||
- `docker-compose.yml`:添加 Agent Manager 服务依赖
|
||||
|
||||
## API 映射关系
|
||||
|
||||
| MCP Server 功能 | AI Agent Manager API | 说明 |
|
||||
|----------------|---------------------|------|
|
||||
| 创建 Agent | `POST /agents` | 创建 K8s Pod |
|
||||
| 删除 Agent | `DELETE /agents/{name}` | 删除 K8s Pod |
|
||||
| 获取 Agent 状态 | `GET /agents/{name}/status` | 获取 Pod 状态和 IP |
|
||||
| 获取资源使用 | `GET /agents/{name}/metrics` | 获取 CPU/内存配置 |
|
||||
| 列出所有 Agent | `GET /agents` | 列出所有 Pod |
|
||||
| 获取模板列表 | `GET /templates` | 获取可用模板 |
|
||||
| 获取模板详情 | `GET /templates/{name}` | 获取模板所需参数 |
|
||||
|
||||
## 资源配置映射
|
||||
|
||||
| 用户配置 | API 参数 | 默认值 |
|
||||
|---------|---------|-------|
|
||||
| CPU 请求 | `cpu_request` | `100m` |
|
||||
| CPU 限制 | `cpu_limit` | `500m` |
|
||||
| 内存请求 | `memory_request` | `128Mi` |
|
||||
| 内存限制 | `memory_limit` | `512Mi` |
|
||||
|
||||
## 需要新增的接口
|
||||
|
||||
根据业务需求,建议新增以下接口:
|
||||
|
||||
1. **Agent 日志查询**
|
||||
- `GET /agents/{name}/logs` - 获取 Pod 日志
|
||||
- 需要 Agent Manager API 支持
|
||||
|
||||
2. **Agent 重启**
|
||||
- `POST /agents/{name}/restart` - 重启 Pod
|
||||
- 可通过删除后重新创建实现
|
||||
|
||||
3. **Agent 扩缩容**
|
||||
- `PUT /agents/{name}/scale` - 调整副本数
|
||||
- 需要 Agent Manager API 支持 replicas 参数
|
||||
|
||||
4. **批量操作**
|
||||
- `POST /agents/batch/create` - 批量创建
|
||||
- `DELETE /agents/batch` - 批量删除
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据一致性**:数据库记录和 K8s Pod 状态需要保持同步
|
||||
2. **错误处理**:API 调用失败时需要回滚数据库操作
|
||||
3. **权限控制**:保留现有的资源管控和权限检查
|
||||
4. **向后兼容**:保留现有 API 接口格式,扩展返回字段
|
||||
|
||||
## 测试计划
|
||||
|
||||
- [ ] 单元测试:Agent Manager 客户端
|
||||
- [ ] 集成测试:创建/删除/查询 Agent 流程
|
||||
- [ ] 端到端测试:前端到 K8s Pod 完整流程
|
||||
- [ ] 性能测试:并发创建 Agent 场景
|
||||
@@ -1,374 +0,0 @@
|
||||
# Agent 设计重构计划
|
||||
|
||||
## 概述
|
||||
|
||||
根据业务需求重新设计 Agent 系统,明确区分**平台端 Agent** 和**自定义 Agent** 两种类型,并完善资源分配和监控机制。
|
||||
|
||||
## 当前问题分析
|
||||
|
||||
### 现有设计的问题
|
||||
|
||||
1. **Agent 类型定义模糊**
|
||||
- 当前 [`Agent.type`](services/mcp-server/models.py:130) 字段只有 `platform` 和 `custom` 两个值
|
||||
- 但没有明确区分两种 Agent 的部署方式和资源管理逻辑
|
||||
|
||||
2. **资源分配逻辑不完整**
|
||||
- 渠道的 [`custom_agent_cpu`](services/mcp-server/models.py:305) 和 [`custom_agent_memory`](services/mcp-server/models.py:306) 字段被当作"默认值"使用
|
||||
- 实际应该是"资源配额上限",租户在配额内创建多个自定义 Agent
|
||||
|
||||
3. **资源统计不完整**
|
||||
- [`get_admin_dashboard_stats`](services/mcp-server/app/routes/admin.py:375) 只统计了平台端 Agent
|
||||
- 应该同时统计平台端 Agent + 自定义 Agent
|
||||
|
||||
4. **健康监控不完整**
|
||||
- [`monitor_agents`](services/mcp-server/app/routes/admin.py:1299) 只监控 `type == "platform"` 的 Agent
|
||||
- 应该同时监控平台端 Agent + 自定义 Agent
|
||||
|
||||
## 新设计方案
|
||||
|
||||
### 1. Agent 类型定义
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Agent 类型 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────────────┐ ┌─────────────────────────────┐ │
|
||||
│ │ 平台端 Agent │ │ 自定义 Agent │ │
|
||||
│ │ type=platform │ │ type=custom │ │
|
||||
│ ├─────────────────────────┤ ├─────────────────────────────┤ │
|
||||
│ │ - 平台打镜像到仓库 │ │ - 租户上传自己的程序 │ │
|
||||
│ │ - K8s 部署管理 │ │ - 在分配的资源配额内运行 │ │
|
||||
│ │ - 管理员分配给渠道 │ │ - 渠道分配资源配额给租户 │ │
|
||||
│ │ - 渠道分配给租户 │ │ - 租户可创建多个 Agent │ │
|
||||
│ └─────────────────────────┘ └─────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2. 资源分配流程
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Platform[平台层]
|
||||
Admin[超级管理员]
|
||||
PlatformAgents[平台端Agent镜像仓库]
|
||||
CustomQuota[自定义Agent资源池]
|
||||
end
|
||||
|
||||
subgraph ChannelLayer[渠道层]
|
||||
Channel[渠道]
|
||||
ChannelPlatformAgents[分配的平台端Agent]
|
||||
ChannelCustomQuota[分配的自定义Agent配额]
|
||||
end
|
||||
|
||||
subgraph TenantLayer[租户层]
|
||||
Tenant[租户]
|
||||
TenantPlatformAgents[可用的平台端Agent]
|
||||
TenantCustomAgents[创建的自定义Agent]
|
||||
end
|
||||
|
||||
Admin -->|分配平台端Agent| Channel
|
||||
Admin -->|分配自定义Agent配额| Channel
|
||||
PlatformAgents --> ChannelPlatformAgents
|
||||
CustomQuota --> ChannelCustomQuota
|
||||
|
||||
Channel -->|分配平台端Agent| Tenant
|
||||
Channel -->|分配自定义Agent配额| Tenant
|
||||
ChannelPlatformAgents --> TenantPlatformAgents
|
||||
ChannelCustomQuota --> TenantCustomAgents
|
||||
|
||||
Tenant -->|使用| TenantPlatformAgents
|
||||
Tenant -->|在配额内创建多个| TenantCustomAgents
|
||||
```
|
||||
|
||||
### 3. 数据模型修改
|
||||
|
||||
#### 3.1 Channel 模型修改
|
||||
|
||||
当前字段:
|
||||
- `custom_agent_cpu` - 自定义 Agent CPU(当前作为默认值)
|
||||
- `custom_agent_memory` - 自定义 Agent 内存(当前作为默认值)
|
||||
|
||||
修改为:
|
||||
- `custom_agent_cpu_quota` - 自定义 Agent CPU 配额上限
|
||||
- `custom_agent_memory_quota` - 自定义 Agent 内存配额上限
|
||||
|
||||
#### 3.2 新增 TenantCustomAgentQuota 模型
|
||||
|
||||
```python
|
||||
class TenantCustomAgentQuota(BaseModel, Base):
|
||||
"""租户自定义 Agent 资源配额"""
|
||||
__tablename__ = "tenant_custom_agent_quotas"
|
||||
|
||||
tenant_id = Column(GUID, ForeignKey users.id, nullable=False, unique=True)
|
||||
|
||||
# 配额上限(由渠道分配)
|
||||
cpu_quota = Column(Numeric 12 2, default=0) # CPU 核心数上限
|
||||
memory_quota = Column(Numeric 12 2, default=0) # 内存 GB 上限
|
||||
|
||||
# 已使用量(由系统计算)
|
||||
cpu_used = Column(Numeric 12 2, default=0) # 已使用 CPU
|
||||
memory_used = Column(Numeric 12 2, default=0) # 已使用内存
|
||||
agent_count = Column(Integer, default=0) # 已创建的自定义 Agent 数量
|
||||
```
|
||||
|
||||
#### 3.3 Agent 模型增强
|
||||
|
||||
在 [`Agent`](services/mcp-server/models.py:125) 模型中添加:
|
||||
|
||||
```python
|
||||
# 自定义 Agent 特有字段
|
||||
image_url = Column(String 500) # 用户上传的镜像地址
|
||||
program_path = Column(String 500) # 程序路径
|
||||
runtime_type = Column(String 50) # 运行时类型:python, nodejs, docker 等
|
||||
```
|
||||
|
||||
### 4. API 修改
|
||||
|
||||
#### 4.1 渠道资源管理 API
|
||||
|
||||
修改 [`allocate_channel_resources`](services/mcp-server/app/routes/admin.py:875):
|
||||
|
||||
```python
|
||||
# 请求体增加
|
||||
class ChannelResourceAllocation:
|
||||
# 现有字段...
|
||||
customAgentQuota: CustomAgentQuotaConfig # 新增
|
||||
|
||||
class CustomAgentQuotaConfig:
|
||||
cpuQuota: float # CPU 配额上限
|
||||
memoryQuota: float # 内存配额上限
|
||||
```
|
||||
|
||||
#### 4.2 租户资源分配 API
|
||||
|
||||
修改 [`allocate_tenant_resources`](services/mcp-server/app/routes/channel.py:193):
|
||||
|
||||
```python
|
||||
# 请求体增加
|
||||
class AllocateResourcesRequest:
|
||||
# 现有字段...
|
||||
customAgentQuota: Optional[CustomAgentQuotaConfig] # 新增
|
||||
```
|
||||
|
||||
#### 4.3 自定义 Agent 创建 API
|
||||
|
||||
修改用户创建自定义 Agent 的逻辑,增加配额检查:
|
||||
|
||||
```python
|
||||
async def create_custom_agent:
|
||||
# 1. 检查租户的自定义 Agent 配额
|
||||
quota = await get_tenant_custom_agent_quota tenant_id
|
||||
|
||||
# 2. 检查请求的资源是否超过剩余配额
|
||||
remaining_cpu = quota.cpu_quota - quota.cpu_used
|
||||
remaining_memory = quota.memory_quota - quota.memory_used
|
||||
|
||||
if request.cpu > remaining_cpu or request.memory > remaining_memory:
|
||||
raise HTTPException 400, 资源配额不足
|
||||
|
||||
# 3. 创建 Agent 并更新已使用量
|
||||
agent = create_agent...
|
||||
quota.cpu_used += request.cpu
|
||||
quota.memory_used += request.memory
|
||||
quota.agent_count += 1
|
||||
```
|
||||
|
||||
#### 4.4 资源统计 API
|
||||
|
||||
修改 [`get_admin_dashboard_stats`](services/mcp-server/app/routes/admin.py:375):
|
||||
|
||||
```python
|
||||
# 统计所有 Agent(平台端 + 自定义)
|
||||
total_agents = await db.execute select func.count Agent.id
|
||||
|
||||
# 分别统计
|
||||
platform_agents = await db.execute select func.count Agent.id where Agent.type == platform
|
||||
custom_agents = await db.execute select func.count Agent.id where Agent.type == custom
|
||||
|
||||
# 资源统计也要包含两种类型
|
||||
total_cpu = sum of all agents cpu
|
||||
total_memory = sum of all agents memory
|
||||
```
|
||||
|
||||
#### 4.5 健康监控 API
|
||||
|
||||
修改 [`monitor_agents`](services/mcp-server/app/routes/admin.py:1299):
|
||||
|
||||
```python
|
||||
# 监控所有 Agent(移除 type == platform 的过滤条件)
|
||||
result = await db.execute select Agent # 不再过滤 type
|
||||
|
||||
# 返回数据增加 type 字段,便于前端区分
|
||||
data = [
|
||||
{
|
||||
id: str agent.id,
|
||||
name: agent.name,
|
||||
type: agent.type, # 新增:platform 或 custom
|
||||
# ...其他字段
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 5. 前端展示修改
|
||||
|
||||
#### 5.1 平台资源分配统计
|
||||
|
||||
在概览页面展示:
|
||||
- 平台端 Agent 数量和资源使用
|
||||
- 自定义 Agent 数量和资源使用
|
||||
- 总计资源使用
|
||||
|
||||
#### 5.2 Agent 健康监控
|
||||
|
||||
在监控页面:
|
||||
- 支持按类型筛选(全部/平台端/自定义)
|
||||
- 显示 Agent 类型标签
|
||||
- 分别展示两种类型的健康状态统计
|
||||
|
||||
## 实施任务清单
|
||||
|
||||
### 阶段一:数据模型修改 ✅ 已完成
|
||||
|
||||
- [x] **1.1** 修改 [`Channel`](services/mcp-server/models.py:311) 模型 ✅
|
||||
- 添加 `custom_agent_cpu_quota` 字段(配额上限)
|
||||
- 添加 `custom_agent_memory_quota` 字段(配额上限)
|
||||
- 保留旧字段 `custom_agent_cpu/memory` 作为向后兼容
|
||||
- 添加字段注释说明这是配额上限
|
||||
|
||||
- [x] **1.2** 创建 `TenantCustomAgentQuota` 模型 ✅
|
||||
- 新增表 `tenant_custom_agent_quotas`(第974-1004行)
|
||||
- 包含配额上限(cpu_quota, memory_quota)和已使用量(cpu_used, memory_used, agent_count)字段
|
||||
|
||||
- [x] **1.3** 创建 `ChannelCustomAgentQuota` 模型 ✅
|
||||
- 新增表 `channel_custom_agent_quotas`(第1007-1030行)
|
||||
- 包含配额上限和已分配量字段
|
||||
|
||||
- [x] **1.4** 增强 [`Agent`](services/mcp-server/models.py:125) 模型 ✅
|
||||
- 添加 `image_url` 字段(自定义 Agent 镜像地址,第170行)
|
||||
- 添加 `program_path` 字段(程序路径,第171行)
|
||||
- 添加 `runtime_type` 字段(运行时类型,第172行)
|
||||
- 添加 `health_status` 字段(健康状态,第179行)
|
||||
- 添加 `last_health_check` 字段(最后健康检查时间,第180行)
|
||||
- 添加 `health_message` 字段(健康状态消息,第181行)
|
||||
- 添加 `idx_agent_health_status` 索引(第206行)
|
||||
|
||||
- [x] **1.5** 创建数据库迁移脚本 ✅
|
||||
- `migrations/005_refactor_agent_quota_system.sql`(180行完整迁移脚本)
|
||||
|
||||
### 阶段二:API 修改 ✅ 已完成
|
||||
|
||||
- [x] **2.1** 修改渠道资源管理 API ✅
|
||||
- 更新 [`ChannelResourceAllocation`](services/mcp-server/app/schemas.py:372) schema - 添加 customAgentQuota 字段
|
||||
- 更新 [`allocate_channel_resources`](services/mcp-server/app/routes/admin.py:924) 逻辑 - 支持配额分配
|
||||
|
||||
- [x] **2.2** 修改租户资源分配 API ✅
|
||||
- 更新 [`AllocateResourcesRequest`](services/mcp-server/app/schemas.py:298) schema - 添加 customAgentQuota 字段
|
||||
- 更新 [`allocate_tenant_resources`](services/mcp-server/app/routes/channel.py:193) 逻辑 - 支持配额分配和验证
|
||||
- 添加租户配额记录创建/更新逻辑
|
||||
|
||||
- [x] **2.3** 修改自定义 Agent 创建 API ✅
|
||||
- 在 [`generate_tool`](services/mcp-server/app/routes/user.py:287) 中添加配额检查
|
||||
- 创建 Agent 后更新已使用量
|
||||
- 在 [`delete_agent`](services/mcp-server/app/routes/agents.py:396) 中释放配额
|
||||
|
||||
- [x] **2.4** 新增配额查询 API ✅
|
||||
- `GET /api/user/custom-agent-quota` - 租户查询自己的配额使用情况 ([`get_my_custom_agent_quota`](services/mcp-server/app/routes/user.py:227))
|
||||
- `GET /api/channel/tenants/{tenant_id}/custom-agent-quota` - 渠道查询租户配额 ([`get_tenant_custom_agent_quota`](services/mcp-server/app/routes/channel.py:796))
|
||||
|
||||
### 阶段三:资源统计修改 ✅ 已完成
|
||||
|
||||
- [x] **3.1** 修改 [`get_admin_dashboard_stats`](services/mcp-server/app/routes/admin.py:375) ✅
|
||||
- 统计所有 Agent(平台端 + 自定义)
|
||||
- 分别返回两种类型的数量和资源使用(platformAgents, customAgents)
|
||||
- 返回总计资源使用(totalAllocatedCpu, totalAllocatedMemory)
|
||||
|
||||
- [x] **3.2** 修改 [`get_platform_overview`](services/mcp-server/app/routes/resource_monitoring.py:31) ✅
|
||||
- 包含自定义 Agent 的统计
|
||||
- 返回 platformAgents 和 customAgents 分类统计
|
||||
- 返回 totalResources 总资源使用
|
||||
|
||||
- [x] **3.3** 新增资源分配统计 API ✅
|
||||
- `GET /api/admin/resources/allocation-stats` - 返回详细的资源分配统计
|
||||
- 实现:[`get_resource_allocation_stats`](services/mcp-server/app/routes/admin.py:1064)
|
||||
|
||||
### 阶段四:健康监控修改 ✅ 已完成
|
||||
|
||||
- [x] **4.1** 修改 [`monitor_agents`](services/mcp-server/app/routes/admin.py:1477) ✅
|
||||
- 移除 `type == "platform"` 过滤条件,查询所有活跃 Agent
|
||||
- 返回数据增加 `type` 字段
|
||||
- 支持按类型筛选参数(agent_type)
|
||||
- 支持按健康状态筛选参数(health_status)
|
||||
- 返回汇总统计(summary)
|
||||
|
||||
- [x] **4.2** 增强自定义 Agent 健康检查 ✅
|
||||
- 在 Agent 模型中添加 health_status, last_health_check, health_message 字段
|
||||
- monitor_agents API 支持查询和筛选自定义 Agent 的健康状态
|
||||
- 注:实际的健康检查逻辑需要后台任务定期执行(可后续实现)
|
||||
|
||||
- [x] **4.3** 统一健康状态定义 ✅
|
||||
- 在 Agent 模型中添加 health_status 字段
|
||||
- 定义统一的健康状态枚举:healthy, warning, critical, unknown
|
||||
- 平台端和自定义 Agent 使用相同的状态定义
|
||||
|
||||
### 阶段五:前端适配
|
||||
|
||||
- [ ] **5.1** 更新概览页面
|
||||
- 展示平台端 Agent + 自定义 Agent 的资源统计
|
||||
- 添加类型区分的图表
|
||||
|
||||
- [ ] **5.2** 更新资源管理页面
|
||||
- 渠道资源管理增加自定义 Agent 配额设置
|
||||
- 租户资源分配增加自定义 Agent 配额设置
|
||||
|
||||
- [ ] **5.3** 更新监控页面
|
||||
- Agent 健康监控支持类型筛选
|
||||
- 显示 Agent 类型标签
|
||||
|
||||
## 数据迁移策略
|
||||
|
||||
1. **向后兼容**:保留旧字段名,添加新字段,逐步迁移
|
||||
2. **默认值处理**:现有渠道的 `custom_agent_cpu/memory` 值迁移为配额上限
|
||||
3. **租户配额初始化**:为现有租户创建配额记录,初始值从渠道继承
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **资源配额检查**:创建自定义 Agent 时必须检查配额
|
||||
2. **配额释放**:删除自定义 Agent 时必须释放配额
|
||||
3. **并发控制**:配额更新需要考虑并发场景
|
||||
4. **审计日志**:配额变更需要记录审计日志
|
||||
|
||||
## 问题修复记录
|
||||
|
||||
### 2026-01-04: 渠道配额显示问题修复
|
||||
|
||||
**问题描述**:
|
||||
- 通过 API 更新渠道的自定义 Agent 配额后,数据库中 `custom_agent_cpu_quota` 和 `custom_agent_memory_quota` 字段正确更新
|
||||
- 但渠道列表 API (`/api/admin/channels`) 返回的 `customAgentCpu` 和 `customAgentMemory` 仍然显示旧值
|
||||
|
||||
**根本原因**:
|
||||
- Channel 模型中同时存在新旧两组字段:
|
||||
- 新字段:`custom_agent_cpu_quota`, `custom_agent_memory_quota`
|
||||
- 旧字段:`custom_agent_cpu`, `custom_agent_memory`
|
||||
- API 代码中部分地方使用新字段,部分地方使用旧字段,导致不一致
|
||||
|
||||
**修复方案**:
|
||||
1. 修改 [`admin_channels`](services/mcp-server/app/routes/frontend_integration.py:933) 函数
|
||||
- 优先使用新字段 `custom_agent_cpu_quota`,如果为空则回退到旧字段
|
||||
- 添加调试日志便于排查
|
||||
|
||||
2. 修改 [`admin_get_channel_resources`](services/mcp-server/app/routes/frontend_integration.py:1020) 函数
|
||||
- 同样优先使用新字段,回退到旧字段
|
||||
|
||||
3. 修改 [`admin_update_channel_resources`](services/mcp-server/app/routes/frontend_integration.py:1063) 函数
|
||||
- 同时更新新旧两组字段,确保数据一致性
|
||||
- 添加日志记录更新操作
|
||||
- 返回更新后的配额值便于验证
|
||||
|
||||
## 测试计划
|
||||
|
||||
- [ ] 单元测试:配额检查逻辑
|
||||
- [ ] 集成测试:完整的资源分配流程
|
||||
- [ ] 端到端测试:从渠道分配到租户创建 Agent 的完整流程
|
||||
- [ ] 性能测试:大量 Agent 场景下的统计性能
|
||||
@@ -1,740 +0,0 @@
|
||||
# AKS Agent 执行方案设计
|
||||
|
||||
## 1. 问题分析
|
||||
|
||||
### 当前状态
|
||||
|
||||
```
|
||||
用户请求 → MCP Server → 本地 MCP 协议处理 → 工具执行
|
||||
↓
|
||||
(未使用 AKS Pod 的 access_url)
|
||||
```
|
||||
|
||||
**问题**:虽然 AKS 部署后返回了 `access_url` 和 `endpoints`,但当前代码并没有使用这些 URL 来调用 AKS 中运行的 Pod。
|
||||
|
||||
### 目标状态
|
||||
|
||||
```
|
||||
用户请求 → MCP Server → 判断 Agent 类型 → 转发到 AKS Pod → 返回结果
|
||||
↓
|
||||
本地执行(无 K8s 部署)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构设计
|
||||
|
||||
### 2.1 整体架构图
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Client[客户端]
|
||||
User[用户]
|
||||
end
|
||||
|
||||
subgraph MCPServer[MCP Server]
|
||||
API[API Gateway]
|
||||
Router[Agent Router]
|
||||
LocalHandler[本地 MCP Handler]
|
||||
K8sProxy[K8s Agent Proxy]
|
||||
end
|
||||
|
||||
subgraph AKS[Azure Kubernetes Service]
|
||||
Pod1[Agent Pod 1]
|
||||
Pod2[Agent Pod 2]
|
||||
Pod3[Agent Pod N]
|
||||
end
|
||||
|
||||
subgraph AgentManager[Agent Manager Service]
|
||||
AM[Agent Manager API]
|
||||
end
|
||||
|
||||
User --> API
|
||||
API --> Router
|
||||
Router -->|无 K8s 部署| LocalHandler
|
||||
Router -->|有 K8s 部署| K8sProxy
|
||||
K8sProxy --> Pod1
|
||||
K8sProxy --> Pod2
|
||||
K8sProxy --> Pod3
|
||||
|
||||
AM -.->|管理| Pod1
|
||||
AM -.->|管理| Pod2
|
||||
AM -.->|管理| Pod3
|
||||
```
|
||||
|
||||
### 2.2 执行流程图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant API as MCP Server API
|
||||
participant Router as Agent Router
|
||||
participant DB as 数据库
|
||||
participant Proxy as K8s Proxy
|
||||
participant Pod as AKS Agent Pod
|
||||
participant Local as 本地 Handler
|
||||
|
||||
User->>API: POST /agents/{id}/execute
|
||||
API->>DB: 获取 Agent 信息
|
||||
DB-->>API: Agent 数据
|
||||
|
||||
API->>Router: 路由决策
|
||||
|
||||
alt Agent 有 access_url
|
||||
Router->>Proxy: 转发请求
|
||||
Proxy->>Pod: HTTP POST /execute
|
||||
Pod-->>Proxy: 执行结果
|
||||
Proxy-->>API: 返回结果
|
||||
else Agent 无 K8s 部署
|
||||
Router->>Local: 本地执行
|
||||
Local-->>API: 执行结果
|
||||
end
|
||||
|
||||
API->>DB: 记录执行和计费
|
||||
API-->>User: 返回结果
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 详细设计
|
||||
|
||||
### 3.1 新增组件:K8s Agent Proxy
|
||||
|
||||
**文件位置**: `services/mcp-server/app/k8s_agent_proxy.py`
|
||||
|
||||
```python
|
||||
"""
|
||||
K8s Agent Proxy - 负责转发请求到 AKS 部署的 Agent Pod
|
||||
"""
|
||||
|
||||
import httpx
|
||||
import structlog
|
||||
from typing import Dict, Any, Optional
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProxyConfig:
|
||||
"""代理配置"""
|
||||
timeout: float = 30.0
|
||||
max_retries: int = 3
|
||||
retry_delay: float = 1.0
|
||||
health_check_interval: int = 30
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProxyResult:
|
||||
"""代理执行结果"""
|
||||
success: bool
|
||||
result: Optional[Dict[str, Any]] = None
|
||||
error: Optional[str] = None
|
||||
execution_time_ms: float = 0.0
|
||||
pod_name: Optional[str] = None
|
||||
status_code: Optional[int] = None
|
||||
|
||||
|
||||
class K8sAgentProxy:
|
||||
"""K8s Agent 代理类"""
|
||||
|
||||
def __init__(self, config: Optional[ProxyConfig] = None):
|
||||
self.config = config or ProxyConfig()
|
||||
self._client: Optional[httpx.AsyncClient] = None
|
||||
|
||||
async def _get_client(self) -> httpx.AsyncClient:
|
||||
"""获取或创建 HTTP 客户端"""
|
||||
if self._client is None or self._client.is_closed:
|
||||
self._client = httpx.AsyncClient(
|
||||
timeout=self.config.timeout,
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
return self._client
|
||||
|
||||
async def execute(
|
||||
self,
|
||||
access_url: str,
|
||||
request_data: Dict[str, Any],
|
||||
pod_name: Optional[str] = None,
|
||||
headers: Optional[Dict[str, str]] = None
|
||||
) -> ProxyResult:
|
||||
"""
|
||||
转发执行请求到 AKS Agent Pod
|
||||
|
||||
Args:
|
||||
access_url: Agent Pod 的访问 URL
|
||||
request_data: MCP 请求数据
|
||||
pod_name: Pod 名称(用于日志)
|
||||
headers: 额外的请求头
|
||||
|
||||
Returns:
|
||||
ProxyResult: 执行结果
|
||||
"""
|
||||
start_time = datetime.utcnow()
|
||||
|
||||
try:
|
||||
client = await self._get_client()
|
||||
|
||||
# 构建完整的执行 URL
|
||||
execute_url = f"{access_url.rstrip('/')}/execute"
|
||||
|
||||
logger.info(
|
||||
"转发请求到 AKS Agent",
|
||||
url=execute_url,
|
||||
pod_name=pod_name,
|
||||
method=request_data.get("method")
|
||||
)
|
||||
|
||||
# 合并请求头
|
||||
request_headers = {"Content-Type": "application/json"}
|
||||
if headers:
|
||||
request_headers.update(headers)
|
||||
|
||||
# 发送请求(带重试)
|
||||
response = await self._request_with_retry(
|
||||
client, execute_url, request_data, request_headers
|
||||
)
|
||||
|
||||
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
||||
|
||||
if response.status_code == 200:
|
||||
result_data = response.json()
|
||||
return ProxyResult(
|
||||
success=True,
|
||||
result=result_data,
|
||||
execution_time_ms=execution_time,
|
||||
pod_name=pod_name,
|
||||
status_code=response.status_code
|
||||
)
|
||||
else:
|
||||
error_detail = response.text
|
||||
try:
|
||||
error_detail = response.json()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return ProxyResult(
|
||||
success=False,
|
||||
error=f"Pod 返回错误: {response.status_code} - {error_detail}",
|
||||
execution_time_ms=execution_time,
|
||||
pod_name=pod_name,
|
||||
status_code=response.status_code
|
||||
)
|
||||
|
||||
except httpx.TimeoutException as e:
|
||||
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
||||
logger.error("请求 AKS Agent 超时", pod_name=pod_name, error=str(e))
|
||||
return ProxyResult(
|
||||
success=False,
|
||||
error=f"请求超时: {str(e)}",
|
||||
execution_time_ms=execution_time,
|
||||
pod_name=pod_name
|
||||
)
|
||||
|
||||
except httpx.ConnectError as e:
|
||||
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
||||
logger.error("无法连接到 AKS Agent", pod_name=pod_name, error=str(e))
|
||||
return ProxyResult(
|
||||
success=False,
|
||||
error=f"连接失败: {str(e)}",
|
||||
execution_time_ms=execution_time,
|
||||
pod_name=pod_name
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
||||
logger.error("转发请求失败", pod_name=pod_name, error=str(e))
|
||||
return ProxyResult(
|
||||
success=False,
|
||||
error=f"执行失败: {str(e)}",
|
||||
execution_time_ms=execution_time,
|
||||
pod_name=pod_name
|
||||
)
|
||||
|
||||
async def _request_with_retry(
|
||||
self,
|
||||
client: httpx.AsyncClient,
|
||||
url: str,
|
||||
data: Dict[str, Any],
|
||||
headers: Dict[str, str]
|
||||
) -> httpx.Response:
|
||||
"""带重试的请求"""
|
||||
import asyncio
|
||||
|
||||
last_exception = None
|
||||
for attempt in range(self.config.max_retries):
|
||||
try:
|
||||
response = await client.post(url, json=data, headers=headers)
|
||||
return response
|
||||
except (httpx.TimeoutException, httpx.ConnectError) as e:
|
||||
last_exception = e
|
||||
if attempt < self.config.max_retries - 1:
|
||||
await asyncio.sleep(self.config.retry_delay * (attempt + 1))
|
||||
logger.warning(
|
||||
f"重试请求 {attempt + 1}/{self.config.max_retries}",
|
||||
url=url,
|
||||
error=str(e)
|
||||
)
|
||||
raise last_exception
|
||||
|
||||
async def health_check(self, access_url: str) -> bool:
|
||||
"""检查 Agent Pod 健康状态"""
|
||||
try:
|
||||
client = await self._get_client()
|
||||
health_url = f"{access_url.rstrip('/')}/health"
|
||||
response = await client.get(health_url, timeout=5.0)
|
||||
return response.status_code == 200
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
async def close(self):
|
||||
"""关闭客户端"""
|
||||
if self._client and not self._client.is_closed:
|
||||
await self._client.aclose()
|
||||
self._client = None
|
||||
|
||||
|
||||
# 全局代理实例
|
||||
_k8s_proxy: Optional[K8sAgentProxy] = None
|
||||
|
||||
|
||||
def get_k8s_agent_proxy() -> K8sAgentProxy:
|
||||
"""获取全局 K8s Agent 代理实例"""
|
||||
global _k8s_proxy
|
||||
if _k8s_proxy is None:
|
||||
_k8s_proxy = K8sAgentProxy()
|
||||
return _k8s_proxy
|
||||
|
||||
|
||||
async def close_k8s_agent_proxy():
|
||||
"""关闭全局代理"""
|
||||
global _k8s_proxy
|
||||
if _k8s_proxy:
|
||||
await _k8s_proxy.close()
|
||||
_k8s_proxy = None
|
||||
```
|
||||
|
||||
### 3.2 修改 Agent 执行端点
|
||||
|
||||
**文件位置**: `services/mcp-server/app/routes/agents.py`
|
||||
|
||||
修改 `execute_agent` 函数:
|
||||
|
||||
```python
|
||||
@router.post("/{agent_id}/execute", response_model=ExecutionResult)
|
||||
async def execute_agent(
|
||||
agent_id: str,
|
||||
request: MCPRequest,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
session_id: Optional[str] = None,
|
||||
) -> ExecutionResult:
|
||||
"""
|
||||
执行 Agent 请求。
|
||||
|
||||
如果 Agent 部署在 AKS 中,请求将被转发到对应的 Pod。
|
||||
否则,请求将在本地执行。
|
||||
"""
|
||||
state = get_state()
|
||||
|
||||
try:
|
||||
agent_uuid = uuid.UUID(agent_id)
|
||||
user_id = uuid.UUID(current_user["user_id"])
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail="Invalid agent ID or user ID") from exc
|
||||
|
||||
agent = await db.get(Agent, agent_uuid)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Agent not found")
|
||||
|
||||
# 权限检查
|
||||
if agent.owner_id != user_id and current_user.get("role") != "super_admin":
|
||||
raise HTTPException(status_code=403, detail="Access denied")
|
||||
|
||||
# 资源管控检查
|
||||
await enforce_resource_control(
|
||||
user_id=str(user_id),
|
||||
resource_type="agent",
|
||||
resource_id=agent_id,
|
||||
estimated_cost=Decimal("0.01"),
|
||||
db=db
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
execution_id = str(uuid.uuid4())
|
||||
|
||||
try:
|
||||
# ========== 路由决策:K8s Pod 或本地执行 ==========
|
||||
if agent.access_url and agent.k8s_status == "Running":
|
||||
# 转发到 AKS Agent Pod
|
||||
result = await _execute_on_k8s_pod(
|
||||
agent=agent,
|
||||
request=request,
|
||||
execution_id=execution_id,
|
||||
user_id=str(user_id)
|
||||
)
|
||||
else:
|
||||
# 本地执行
|
||||
result = await _execute_locally(
|
||||
agent=agent,
|
||||
request=request,
|
||||
execution_id=execution_id,
|
||||
user_id=str(user_id),
|
||||
db=db
|
||||
)
|
||||
# ================================================
|
||||
|
||||
duration = time.time() - start_time
|
||||
|
||||
# 记录执行和计费
|
||||
await _record_execution_and_billing(
|
||||
db=db,
|
||||
agent=agent,
|
||||
request=request,
|
||||
result=result,
|
||||
execution_id=execution_id,
|
||||
start_time=start_time,
|
||||
duration=duration,
|
||||
session_id=session_id
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as exc:
|
||||
duration = time.time() - start_time
|
||||
logger.error("执行Agent任务失败", error=str(exc))
|
||||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||||
|
||||
|
||||
async def _execute_on_k8s_pod(
|
||||
agent: Agent,
|
||||
request: MCPRequest,
|
||||
execution_id: str,
|
||||
user_id: str
|
||||
) -> ExecutionResult:
|
||||
"""转发请求到 AKS Agent Pod"""
|
||||
from ..k8s_agent_proxy import get_k8s_agent_proxy
|
||||
|
||||
proxy = get_k8s_agent_proxy()
|
||||
|
||||
# 构建请求数据
|
||||
request_data = {
|
||||
"jsonrpc": request.jsonrpc,
|
||||
"id": str(request.id),
|
||||
"method": request.method,
|
||||
"params": request.params or {},
|
||||
"metadata": {
|
||||
"execution_id": execution_id,
|
||||
"user_id": user_id,
|
||||
"agent_id": str(agent.id)
|
||||
}
|
||||
}
|
||||
|
||||
# 转发请求
|
||||
proxy_result = await proxy.execute(
|
||||
access_url=agent.access_url,
|
||||
request_data=request_data,
|
||||
pod_name=agent.pod_name
|
||||
)
|
||||
|
||||
if proxy_result.success:
|
||||
return ExecutionResult(
|
||||
execution_id=execution_id,
|
||||
success=True,
|
||||
result=proxy_result.result,
|
||||
execution_time=proxy_result.execution_time_ms,
|
||||
started_at=datetime.utcnow(),
|
||||
completed_at=datetime.utcnow()
|
||||
)
|
||||
else:
|
||||
return ExecutionResult(
|
||||
execution_id=execution_id,
|
||||
success=False,
|
||||
error=proxy_result.error,
|
||||
execution_time=proxy_result.execution_time_ms,
|
||||
started_at=datetime.utcnow(),
|
||||
completed_at=datetime.utcnow()
|
||||
)
|
||||
|
||||
|
||||
async def _execute_locally(
|
||||
agent: Agent,
|
||||
request: MCPRequest,
|
||||
execution_id: str,
|
||||
user_id: str,
|
||||
db: AsyncSession
|
||||
) -> ExecutionResult:
|
||||
"""本地执行 MCP 请求"""
|
||||
state = get_state()
|
||||
handler = state.mcp_handler
|
||||
|
||||
if not handler:
|
||||
raise HTTPException(status_code=500, detail="MCP handler not initialized")
|
||||
|
||||
return await handler.execute_request(
|
||||
str(agent.id),
|
||||
request,
|
||||
user_id=user_id,
|
||||
db_session=db
|
||||
)
|
||||
```
|
||||
|
||||
### 3.3 AKS Agent Pod 端点规范
|
||||
|
||||
每个部署在 AKS 中的 Agent Pod 需要实现以下端点:
|
||||
|
||||
| 端点 | 方法 | 描述 |
|
||||
|-----|------|------|
|
||||
| `/health` | GET | 健康检查 |
|
||||
| `/execute` | POST | 执行 MCP 请求 |
|
||||
| `/status` | GET | 获取 Agent 状态 |
|
||||
| `/metrics` | GET | 获取资源使用指标 |
|
||||
|
||||
#### 3.3.1 `/execute` 端点请求格式
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "request-uuid",
|
||||
"method": "tools/call",
|
||||
"params": {
|
||||
"name": "tool_name",
|
||||
"arguments": {}
|
||||
},
|
||||
"metadata": {
|
||||
"execution_id": "exec-uuid",
|
||||
"user_id": "user-uuid",
|
||||
"agent_id": "agent-uuid"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3.2 `/execute` 端点响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"result": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "执行结果"
|
||||
}
|
||||
]
|
||||
},
|
||||
"execution_time_ms": 150.5,
|
||||
"resource_usage": {
|
||||
"cpu_ms": 50,
|
||||
"memory_mb": 128
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据库变更
|
||||
|
||||
### 4.1 Agent 表新增字段(已存在)
|
||||
|
||||
当前 `Agent` 模型已包含必要字段:
|
||||
|
||||
| 字段 | 类型 | 描述 |
|
||||
|-----|------|------|
|
||||
| `access_url` | String(500) | Pod 访问 URL |
|
||||
| `pod_name` | String(100) | Pod 名称 |
|
||||
| `pod_ip` | String(45) | Pod IP |
|
||||
| `k8s_status` | String(20) | Pod 状态 |
|
||||
| `service_port` | Integer | Service 端口 |
|
||||
| `endpoints` | JSON | 端点字典 |
|
||||
|
||||
### 4.2 新增执行记录字段
|
||||
|
||||
在 `Execution` 表中添加:
|
||||
|
||||
```python
|
||||
# 执行位置
|
||||
execution_location = Column(String(20), default="local") # local, k8s
|
||||
pod_name = Column(String(100)) # 执行的 Pod 名称
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 配置变更
|
||||
|
||||
### 5.1 环境变量
|
||||
|
||||
```bash
|
||||
# K8s Agent Proxy 配置
|
||||
K8S_PROXY_TIMEOUT=30.0
|
||||
K8S_PROXY_MAX_RETRIES=3
|
||||
K8S_PROXY_RETRY_DELAY=1.0
|
||||
K8S_PROXY_HEALTH_CHECK_INTERVAL=30
|
||||
```
|
||||
|
||||
### 5.2 应用配置
|
||||
|
||||
在 `config.py` 中添加:
|
||||
|
||||
```python
|
||||
class K8sProxyConfig:
|
||||
timeout: float = float(os.getenv("K8S_PROXY_TIMEOUT", "30.0"))
|
||||
max_retries: int = int(os.getenv("K8S_PROXY_MAX_RETRIES", "3"))
|
||||
retry_delay: float = float(os.getenv("K8S_PROXY_RETRY_DELAY", "1.0"))
|
||||
health_check_interval: int = int(os.getenv("K8S_PROXY_HEALTH_CHECK_INTERVAL", "30"))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 实施计划
|
||||
|
||||
### 6.1 任务清单
|
||||
|
||||
- [ ] **Phase 1: 基础设施**
|
||||
- [ ] 创建 `k8s_agent_proxy.py` 模块
|
||||
- [ ] 添加配置项
|
||||
- [ ] 编写单元测试
|
||||
|
||||
- [ ] **Phase 2: 路由逻辑**
|
||||
- [ ] 修改 `execute_agent` 端点
|
||||
- [ ] 实现路由决策逻辑
|
||||
- [ ] 添加本地执行回退
|
||||
|
||||
- [ ] **Phase 3: 监控和日志**
|
||||
- [ ] 添加执行位置记录
|
||||
- [ ] 添加 Prometheus 指标
|
||||
- [ ] 完善日志记录
|
||||
|
||||
- [ ] **Phase 4: 健康检查**
|
||||
- [ ] 实现 Pod 健康检查
|
||||
- [ ] 添加自动故障转移
|
||||
- [ ] 实现连接池管理
|
||||
|
||||
- [ ] **Phase 5: 测试和文档**
|
||||
- [ ] 集成测试
|
||||
- [ ] 性能测试
|
||||
- [ ] 更新 API 文档
|
||||
|
||||
### 6.2 文件变更清单
|
||||
|
||||
| 文件 | 操作 | 描述 |
|
||||
|-----|------|------|
|
||||
| `services/mcp-server/app/k8s_agent_proxy.py` | 新增 | K8s Agent 代理模块 |
|
||||
| `services/mcp-server/app/routes/agents.py` | 修改 | 添加路由逻辑 |
|
||||
| `services/mcp-server/config.py` | 修改 | 添加代理配置 |
|
||||
| `services/mcp-server/app/lifecycle.py` | 修改 | 添加代理生命周期管理 |
|
||||
| `services/mcp-server/models.py` | 修改 | 添加执行位置字段 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 错误处理
|
||||
|
||||
### 7.1 错误场景和处理策略
|
||||
|
||||
| 场景 | 处理策略 |
|
||||
|-----|---------|
|
||||
| Pod 不可达 | 重试 3 次后返回错误 |
|
||||
| Pod 返回 5xx | 记录错误,返回给用户 |
|
||||
| 请求超时 | 返回超时错误,建议重试 |
|
||||
| Pod 状态非 Running | 回退到本地执行或返回错误 |
|
||||
| access_url 为空 | 使用本地执行 |
|
||||
|
||||
### 7.2 故障转移策略
|
||||
|
||||
```python
|
||||
async def execute_with_fallback(agent, request, ...):
|
||||
"""带故障转移的执行"""
|
||||
|
||||
# 1. 尝试 K8s Pod 执行
|
||||
if agent.access_url and agent.k8s_status == "Running":
|
||||
result = await _execute_on_k8s_pod(...)
|
||||
if result.success:
|
||||
return result
|
||||
|
||||
# 2. K8s 执行失败,检查是否可以本地执行
|
||||
if agent.tools and not agent.template:
|
||||
logger.warning("K8s 执行失败,回退到本地执行")
|
||||
return await _execute_locally(...)
|
||||
|
||||
# 3. 本地执行
|
||||
return await _execute_locally(...)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 监控指标
|
||||
|
||||
### 8.1 新增 Prometheus 指标
|
||||
|
||||
```python
|
||||
# K8s Agent 执行指标
|
||||
k8s_agent_requests_total = Counter(
|
||||
"k8s_agent_requests_total",
|
||||
"Total K8s agent requests",
|
||||
["pod_name", "status"]
|
||||
)
|
||||
|
||||
k8s_agent_request_duration = Histogram(
|
||||
"k8s_agent_request_duration_seconds",
|
||||
"K8s agent request duration",
|
||||
["pod_name"]
|
||||
)
|
||||
|
||||
k8s_agent_health_status = Gauge(
|
||||
"k8s_agent_health_status",
|
||||
"K8s agent health status",
|
||||
["pod_name"]
|
||||
)
|
||||
```
|
||||
|
||||
### 8.2 日志格式
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2024-01-01T00:00:00Z",
|
||||
"level": "INFO",
|
||||
"message": "转发请求到 AKS Agent",
|
||||
"execution_id": "exec-uuid",
|
||||
"agent_id": "agent-uuid",
|
||||
"pod_name": "my-agent-abc123",
|
||||
"access_url": "http://my-agent.ai-agents.svc.cluster.local:8080",
|
||||
"method": "tools/call",
|
||||
"execution_location": "k8s"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 安全考虑
|
||||
|
||||
### 9.1 网络安全
|
||||
|
||||
- Pod 间通信使用 K8s 内部网络
|
||||
- 不暴露 Pod 到公网
|
||||
- 使用 NetworkPolicy 限制访问
|
||||
|
||||
### 9.2 认证授权
|
||||
|
||||
- 请求中携带 `user_id` 和 `execution_id`
|
||||
- Pod 可验证请求来源
|
||||
- 支持 mTLS(可选)
|
||||
|
||||
### 9.3 数据安全
|
||||
|
||||
- 敏感数据不在日志中记录
|
||||
- 请求/响应数据加密传输
|
||||
- 执行结果脱敏存储
|
||||
|
||||
---
|
||||
|
||||
## 10. 总结
|
||||
|
||||
本方案实现了 MCP Server 与 AKS Agent Pod 的集成,主要特点:
|
||||
|
||||
1. **智能路由**:根据 Agent 配置自动选择执行位置
|
||||
2. **故障转移**:K8s 执行失败时可回退到本地
|
||||
3. **可观测性**:完整的日志、指标和追踪
|
||||
4. **安全性**:网络隔离和认证机制
|
||||
5. **可扩展性**:支持多 Pod 负载均衡(未来)
|
||||
|
||||
通过此方案,用户可以透明地使用部署在 AKS 中的 Agent,无需关心底层执行细节。
|
||||
@@ -1,166 +0,0 @@
|
||||
# 数据库迁移计划:postgres → taiji
|
||||
|
||||
**创建时间**: 2025-12-31
|
||||
**目标**: 将 postgres 库的表结构和数据完全覆盖到 taiji 库
|
||||
|
||||
---
|
||||
|
||||
## 📋 任务概述
|
||||
|
||||
将 Azure PostgreSQL 服务器上的 `postgres` 数据库(新结构)完全复制到 `taiji` 数据库(旧结构),包括:
|
||||
- 表结构
|
||||
- 索引
|
||||
- 约束
|
||||
- 数据
|
||||
- 序列
|
||||
|
||||
---
|
||||
|
||||
## 🔄 迁移流程图
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开始迁移] --> B[连接 postgres 源数据库]
|
||||
B --> C[连接 taiji 目标数据库]
|
||||
C --> D[备份 taiji 数据库 - 可选]
|
||||
D --> E[删除 taiji 中的所有表]
|
||||
E --> F[从 postgres 获取表结构]
|
||||
F --> G[在 taiji 中创建表]
|
||||
G --> H[创建索引和约束]
|
||||
H --> I[复制数据]
|
||||
I --> J[同步序列值]
|
||||
J --> K[验证迁移结果]
|
||||
K --> L[完成]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 任务清单
|
||||
|
||||
### 1. 准备工作
|
||||
- [ ] 确认数据库连接信息正确
|
||||
- [ ] 确认 postgres 库中有最新的表结构
|
||||
- [ ] 备份 taiji 库现有数据(可选但推荐)
|
||||
|
||||
### 2. 创建迁移脚本
|
||||
- [ ] 修改现有 `copy_database.py` 脚本,交换源和目标数据库
|
||||
- [ ] 或创建新脚本 `sync_postgres_to_taiji.py`
|
||||
|
||||
### 3. 脚本功能实现
|
||||
- [ ] 连接源数据库(postgres)
|
||||
- [ ] 连接目标数据库(taiji)
|
||||
- [ ] 获取 postgres 库所有表列表
|
||||
- [ ] 删除 taiji 库中的所有现有表(CASCADE)
|
||||
- [ ] 复制表结构(DDL)
|
||||
- [ ] 复制索引定义
|
||||
- [ ] 复制数据
|
||||
- [ ] 同步序列值
|
||||
|
||||
### 4. 验证和测试
|
||||
- [ ] 验证表数量一致
|
||||
- [ ] 验证数据行数一致
|
||||
- [ ] 验证索引创建成功
|
||||
- [ ] 测试应用连接 taiji 库正常工作
|
||||
|
||||
---
|
||||
|
||||
## 📝 技术细节
|
||||
|
||||
### 数据库连接信息
|
||||
|
||||
```python
|
||||
DB_HOST = "taijipda.postgres.database.azure.com"
|
||||
DB_USER = "taiji"
|
||||
DB_PASSWORD = "By@123456."
|
||||
DB_PORT = 5432
|
||||
|
||||
# 源数据库(新结构)
|
||||
SOURCE_DB = "postgres"
|
||||
|
||||
# 目标数据库(需要更新)
|
||||
TARGET_DB = "taiji"
|
||||
```
|
||||
|
||||
### 主要表列表(基于 models.py)
|
||||
|
||||
| 表名 | 说明 |
|
||||
|------|------|
|
||||
| users | 用户表(租户使用者) |
|
||||
| agents | Agent表(平台Agent和自定义Agent) |
|
||||
| tools | 工具表 |
|
||||
| sessions | 会话表 |
|
||||
| executions | 执行记录表 |
|
||||
| api_keys | API密钥表 |
|
||||
| billing | 计费详情表 |
|
||||
| balances | 用户余额表 |
|
||||
| billing_records | 计费记录表 |
|
||||
| channels | 渠道合作伙伴表 |
|
||||
| model_providers | 模型供应商表 |
|
||||
| resource_allocations | 资源分配表 |
|
||||
| applications | 申请审批表 |
|
||||
| workflows | 工作流表 |
|
||||
| audit_logs | 审计日志表 |
|
||||
| channel_agent_quotas | 渠道Agent配额表 |
|
||||
| provider_models | 模型提供商表 |
|
||||
| token_blacklist | Token黑名单表 |
|
||||
| resource_usage | 资源使用记录表 |
|
||||
| quota_alerts | 配额预警记录表 |
|
||||
| model_pricing | 模型定价配置表 |
|
||||
| provider_health_checks | 供应商健康检查记录表 |
|
||||
| agent_traces | Agent执行轨迹表 |
|
||||
| billing_events | 计费事件表 |
|
||||
| channel_provider_access | 渠道供应商授权表 |
|
||||
| provider_applications | 供应商使用申请表 |
|
||||
| gateway_apis | 网关API定义表 |
|
||||
| data_templates | 数据模板表 |
|
||||
| recharge_records | 充值记录表 |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **数据丢失风险**: 此操作会删除 taiji 库中的所有现有数据,请确保已备份
|
||||
2. **外键约束**: 删除表时使用 CASCADE 处理外键依赖
|
||||
3. **序列同步**: 确保序列值正确同步,避免主键冲突
|
||||
4. **连接中断**: 迁移过程中确保网络稳定
|
||||
5. **应用停机**: 建议在迁移期间停止连接 taiji 库的应用服务
|
||||
|
||||
---
|
||||
|
||||
## 🚀 执行步骤
|
||||
|
||||
1. **运行迁移脚本**:
|
||||
```bash
|
||||
cd /home/taiji/tools/taiji-AI-PAD
|
||||
python scripts/sync_postgres_to_taiji.py
|
||||
```
|
||||
|
||||
2. **验证迁移结果**:
|
||||
```bash
|
||||
# 连接 taiji 库检查表
|
||||
psql "host=taijipda.postgres.database.azure.com port=5432 dbname=taiji user=taiji password=By@123456. sslmode=require"
|
||||
|
||||
# 查看所有表
|
||||
\dt
|
||||
|
||||
# 检查数据行数
|
||||
SELECT COUNT(*) FROM users;
|
||||
SELECT COUNT(*) FROM agents;
|
||||
```
|
||||
|
||||
3. **更新应用配置**(如需要):
|
||||
确保应用的 DATABASE_URL 指向 taiji 库
|
||||
|
||||
---
|
||||
|
||||
## 📊 预期结果
|
||||
|
||||
迁移完成后:
|
||||
- taiji 库将拥有与 postgres 库完全相同的表结构
|
||||
- 所有数据将从 postgres 库复制到 taiji 库
|
||||
- 索引和约束将正确创建
|
||||
- 序列值将同步
|
||||
|
||||
---
|
||||
|
||||
**下一步**: 切换到 Code 模式创建迁移脚本
|
||||
@@ -0,0 +1,662 @@
|
||||
# MCP Server 重构需求文档
|
||||
|
||||
## 1. 概述
|
||||
|
||||
### 1.1 服务定位
|
||||
|
||||
MCP Server 是平台的核心业务服务,负责:
|
||||
- 用户认证与授权
|
||||
- 渠道和租户管理
|
||||
- Agent 资源分配与配额管理
|
||||
- 计费与账单
|
||||
- 与 Agent Manager 的集成
|
||||
- 工具和工作流管理
|
||||
|
||||
### 1.2 系统架构
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Frontend[前端]
|
||||
AdminUI[管理员控制台]
|
||||
ChannelUI[渠道控制台]
|
||||
UserUI[用户控制台]
|
||||
end
|
||||
|
||||
subgraph MCPServer[MCP Server]
|
||||
subgraph Auth[认证授权]
|
||||
AuthModule[认证模块]
|
||||
PermModule[权限模块]
|
||||
end
|
||||
|
||||
subgraph Business[业务模块]
|
||||
ChannelMgmt[渠道管理]
|
||||
TenantMgmt[租户管理]
|
||||
AgentMgmt[Agent管理]
|
||||
QuotaMgmt[配额管理]
|
||||
end
|
||||
|
||||
subgraph Billing[计费模块]
|
||||
BillingCalc[计费计算]
|
||||
BillingRecord[计费记录]
|
||||
end
|
||||
|
||||
subgraph Integration[集成模块]
|
||||
AMClient[Agent Manager客户端]
|
||||
ProviderClient[供应商客户端]
|
||||
end
|
||||
|
||||
DB[(PostgreSQL)]
|
||||
end
|
||||
|
||||
subgraph External[外部服务]
|
||||
AgentManager[Agent Manager]
|
||||
ModelProviders[模型供应商]
|
||||
end
|
||||
|
||||
Frontend --> MCPServer
|
||||
MCPServer --> External
|
||||
Business --> DB
|
||||
Billing --> DB
|
||||
```
|
||||
|
||||
### 1.3 调用链路
|
||||
|
||||
```
|
||||
前端 → MCP Server(认证、权限、配额、计费)→ Agent Manager(K8s 操作)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 现有功能模块
|
||||
|
||||
### 2.1 路由模块清单
|
||||
|
||||
| 模块 | 文件 | 功能 | 重构优先级 |
|
||||
|------|------|------|-----------|
|
||||
| 认证 | `auth.py` | 登录、注册、Token管理 | 保留 |
|
||||
| 管理员 | `admin.py` | 超级管理员功能 | 重构 |
|
||||
| 渠道 | `channel.py` | 渠道管理、资源分配 | 重构 |
|
||||
| 用户 | `user.py` | 租户功能、Agent使用 | 重构 |
|
||||
| Agent | `agents.py` | Agent CRUD、K8s集成 | **重点重构** |
|
||||
| 计费 | `billing_admin.py` | 计费管理 | 保留 |
|
||||
| 配额 | `quota_management.py` | 配额管理 | 重构 |
|
||||
| 监控 | `monitoring.py` | 系统监控 | 保留 |
|
||||
| 资源监控 | `resource_monitoring.py` | 资源使用监控 | 重构 |
|
||||
| 前端集成 | `frontend_integration.py` | 前端API适配 | 重构 |
|
||||
| 工具 | `tools.py` | 工具管理 | 保留 |
|
||||
| 会话 | `sessions.py` | 会话管理 | 保留 |
|
||||
| 健康检查 | `health.py` | 服务健康检查 | 保留 |
|
||||
|
||||
### 2.2 数据模型清单
|
||||
|
||||
| 模型 | 说明 | 重构内容 |
|
||||
|------|------|----------|
|
||||
| User | 用户/租户 | 新增平台Agent配额字段 |
|
||||
| Channel | 渠道 | 已有自定义Agent配额字段 |
|
||||
| Agent | Agent | 区分平台/自定义类型 |
|
||||
| ResourceAllocation | 资源分配 | 新增平台Agent分配 |
|
||||
| ChannelAgentQuota | 渠道Agent配额 | 重构为平台Agent配额 |
|
||||
| TenantCustomAgentQuota | 租户自定义Agent配额 | 保留 |
|
||||
| ChannelCustomAgentQuota | 渠道自定义Agent配额 | 保留 |
|
||||
|
||||
---
|
||||
|
||||
## 3. Agent 相关功能重构
|
||||
|
||||
### 3.1 平台 Agent 管理
|
||||
|
||||
#### 3.1.1 管理员功能
|
||||
|
||||
| 功能 | API | 说明 |
|
||||
|------|-----|------|
|
||||
| 查看平台Agent模板列表 | `GET /api/admin/platform-agents/templates` | 从Agent Manager获取 |
|
||||
| 设置平台Agent配置 | `PUT /api/admin/platform-agents/templates/{name}/config` | 设置CPU/内存/最大Pod数 |
|
||||
| 分配平台Agent给渠道 | `POST /api/admin/channels/{id}/platform-agents` | 分配Pod数量配额 |
|
||||
| 查看平台Agent分配情况 | `GET /api/admin/platform-agents/allocations` | 查看所有分配 |
|
||||
| 查看平台Agent运行状态 | `GET /api/admin/platform-agents/status` | 从Agent Manager获取 |
|
||||
|
||||
**分配平台Agent给渠道请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"templateName": "jina_search_agent",
|
||||
"podQuota": 10,
|
||||
"description": "分配Jina搜索Agent给渠道A"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.1.2 渠道功能
|
||||
|
||||
| 功能 | API | 说明 |
|
||||
|------|-----|------|
|
||||
| 查看已分配的平台Agent | `GET /api/channel/platform-agents` | 查看渠道拥有的配额 |
|
||||
| 分配平台Agent给租户 | `POST /api/channel/tenants/{id}/platform-agents` | 分配Pod数量配额 |
|
||||
| 查看租户平台Agent使用情况 | `GET /api/channel/tenants/{id}/platform-agents/usage` | 查看使用统计 |
|
||||
|
||||
**分配平台Agent给租户请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"templateName": "jina_search_agent",
|
||||
"podQuota": 3,
|
||||
"description": "分配给租户使用"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.1.3 租户功能
|
||||
|
||||
| 功能 | API | 说明 |
|
||||
|------|-----|------|
|
||||
| 查看可用的平台Agent | `GET /api/user/platform-agents` | 查看已分配的Agent |
|
||||
| 使用平台Agent | `POST /api/user/platform-agents/{template}/use` | 创建Pod实例 |
|
||||
| 停止平台Agent | `DELETE /api/user/platform-agents/{name}` | 删除Pod实例 |
|
||||
| 查看平台Agent状态 | `GET /api/user/platform-agents/{name}/status` | 查看Pod状态 |
|
||||
| 查看配额使用情况 | `GET /api/user/platform-agents/quota` | 查看配额和使用量 |
|
||||
|
||||
**使用平台Agent请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-jina-search-001",
|
||||
"queryParams": {
|
||||
"searchType": "semantic",
|
||||
"maxResults": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 自定义 Agent 管理
|
||||
|
||||
#### 3.2.1 管理员功能
|
||||
|
||||
| 功能 | API | 说明 |
|
||||
|------|-----|------|
|
||||
| 查看自定义Agent模板列表 | `GET /api/admin/custom-agents/templates` | 从Agent Manager获取 |
|
||||
| 分配自定义Agent资源给渠道 | `POST /api/admin/channels/{id}/custom-agent-quota` | 分配CPU/内存配额 |
|
||||
| 查看自定义Agent资源分配 | `GET /api/admin/custom-agents/allocations` | 查看所有分配 |
|
||||
|
||||
**分配自定义Agent资源给渠道请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"cpuQuota": 8,
|
||||
"memoryQuota": 16,
|
||||
"description": "分配自定义Agent资源给渠道A"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2.2 渠道功能
|
||||
|
||||
| 功能 | API | 说明 |
|
||||
|------|-----|------|
|
||||
| 查看自定义Agent资源配额 | `GET /api/channel/custom-agent-quota` | 查看渠道配额 |
|
||||
| 分配自定义Agent资源给租户 | `POST /api/channel/tenants/{id}/custom-agent-quota` | 分配CPU/内存配额 |
|
||||
| 查看租户自定义Agent使用情况 | `GET /api/channel/tenants/{id}/custom-agents` | 查看租户创建的Agent |
|
||||
|
||||
**分配自定义Agent资源给租户请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"cpuQuota": 4,
|
||||
"memoryQuota": 8,
|
||||
"description": "分配自定义Agent资源给租户"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2.3 租户功能
|
||||
|
||||
| 功能 | API | 说明 |
|
||||
|------|-----|------|
|
||||
| 查看自定义Agent模板 | `GET /api/user/custom-agents/templates` | 查看可用模板 |
|
||||
| 创建自定义Agent | `POST /api/user/custom-agents` | 创建并启动Agent |
|
||||
| 更新自定义Agent配置 | `PUT /api/user/custom-agents/{name}` | 更新环境变量等 |
|
||||
| 删除自定义Agent | `DELETE /api/user/custom-agents/{name}` | 删除Agent |
|
||||
| 查看自定义Agent状态 | `GET /api/user/custom-agents/{name}/status` | 查看Pod状态 |
|
||||
| 查看配额使用情况 | `GET /api/user/custom-agent-quota` | 查看配额和使用量 |
|
||||
| 扩缩容自定义Agent | `PUT /api/user/custom-agents/{name}/scale` | 调整Pod数量 |
|
||||
|
||||
**创建自定义Agent请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-openai-agent",
|
||||
"template": "openai_agent_template",
|
||||
"envVars": {
|
||||
"OPENAI_API_KEY": "sk-xxx",
|
||||
"OPENAI_API_BASE": "https://api.openai.com/v1",
|
||||
"MODEL_NAME": "gpt-4"
|
||||
},
|
||||
"resourceConfig": {
|
||||
"cpuRequest": "200m",
|
||||
"cpuLimit": "1000m",
|
||||
"memoryRequest": "256Mi",
|
||||
"memoryLimit": "1Gi"
|
||||
},
|
||||
"scalingConfig": {
|
||||
"minReplicas": 2,
|
||||
"maxReplicas": 4
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 配额管理重构
|
||||
|
||||
### 4.1 平台 Agent 配额
|
||||
|
||||
#### 4.1.1 数据模型
|
||||
|
||||
```python
|
||||
class PlatformAgentQuota(BaseModel, Base):
|
||||
"""平台 Agent 配额分配"""
|
||||
__tablename__ = "platform_agent_quotas"
|
||||
|
||||
# 分配目标
|
||||
target_id = Column(GUID(), nullable=False) # 渠道ID或租户ID
|
||||
target_type = Column(String(20), nullable=False) # channel, tenant
|
||||
|
||||
# Agent模板
|
||||
template_name = Column(String(100), nullable=False) # 平台Agent模板名称
|
||||
|
||||
# 配额
|
||||
pod_quota = Column(Integer, nullable=False, default=0) # Pod数量配额
|
||||
pod_used = Column(Integer, default=0) # 已使用Pod数量
|
||||
|
||||
# 分配信息
|
||||
allocated_by = Column(GUID(), ForeignKey("users.id")) # 分配人
|
||||
allocated_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_platform_agent_quota_target", target_id, target_type),
|
||||
Index("idx_platform_agent_quota_template", template_name),
|
||||
UniqueConstraint("target_id", "target_type", "template_name", name="uq_platform_agent_quota"),
|
||||
)
|
||||
```
|
||||
|
||||
#### 4.1.2 配额检查流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[用户请求使用平台Agent] --> B[验证用户身份]
|
||||
B --> C[获取用户的平台Agent配额]
|
||||
C --> D{配额是否充足?}
|
||||
D -->|是| E[调用Agent Manager创建Pod]
|
||||
D -->|否| F[返回配额不足错误]
|
||||
E --> G{创建成功?}
|
||||
G -->|是| H[更新已使用配额]
|
||||
G -->|否| I[返回创建失败错误]
|
||||
H --> J[返回成功]
|
||||
```
|
||||
|
||||
### 4.2 自定义 Agent 配额
|
||||
|
||||
#### 4.2.1 现有数据模型
|
||||
|
||||
已有 `TenantCustomAgentQuota` 和 `ChannelCustomAgentQuota` 模型,保留使用。
|
||||
|
||||
#### 4.2.2 配额检查流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[用户创建自定义Agent] --> B[验证用户身份]
|
||||
B --> C[获取用户的自定义Agent配额]
|
||||
C --> D[计算请求的资源总量]
|
||||
D --> E{资源是否充足?}
|
||||
E -->|是| F[调用Agent Manager创建Pod]
|
||||
E -->|否| G[返回资源不足错误]
|
||||
F --> H{创建成功?}
|
||||
H -->|是| I[更新已使用资源]
|
||||
H -->|否| J[返回创建失败错误]
|
||||
I --> K[返回成功]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 与 Agent Manager 集成
|
||||
|
||||
### 5.1 客户端重构
|
||||
|
||||
现有 `agent_manager_client.py` 需要重构以支持新的 API:
|
||||
|
||||
```python
|
||||
class AgentManagerClient:
|
||||
"""Agent Manager API 客户端"""
|
||||
|
||||
# 模板管理
|
||||
async def list_platform_templates(self) -> List[TemplateInfo]
|
||||
async def list_custom_templates(self) -> List[TemplateInfo]
|
||||
async def get_template(self, name: str) -> TemplateInfo
|
||||
|
||||
# 平台 Agent 管理
|
||||
async def create_platform_agent(
|
||||
self,
|
||||
name: str,
|
||||
template: str,
|
||||
owner_id: str,
|
||||
channel_id: str,
|
||||
config: AgentConfig
|
||||
) -> AgentCreateResult
|
||||
|
||||
async def delete_platform_agent(self, name: str) -> Dict
|
||||
async def get_platform_agent_status(self, name: str) -> AgentStatusResult
|
||||
async def list_platform_agents(self, owner_id: str = None) -> List[Dict]
|
||||
|
||||
# 自定义 Agent 管理
|
||||
async def create_custom_agent(
|
||||
self,
|
||||
name: str,
|
||||
template: str,
|
||||
owner_id: str,
|
||||
channel_id: str,
|
||||
env_vars: Dict[str, str],
|
||||
config: AgentConfig,
|
||||
scaling_config: ScalingConfig
|
||||
) -> AgentCreateResult
|
||||
|
||||
async def update_custom_agent_env(self, name: str, env_vars: Dict[str, str]) -> Dict
|
||||
async def delete_custom_agent(self, name: str) -> Dict
|
||||
async def get_custom_agent_status(self, name: str) -> AgentStatusResult
|
||||
async def scale_custom_agent(self, name: str, replicas: int) -> Dict
|
||||
async def list_custom_agents(self, owner_id: str = None) -> List[Dict]
|
||||
|
||||
# 统计
|
||||
async def get_stats() -> Dict
|
||||
```
|
||||
|
||||
### 5.2 调用时序
|
||||
|
||||
#### 5.2.1 使用平台 Agent
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant MCP as MCP Server
|
||||
participant AM as Agent Manager
|
||||
participant K8s as Kubernetes
|
||||
|
||||
User->>MCP: POST /api/user/platform-agents/{template}/use
|
||||
MCP->>MCP: 验证身份和权限
|
||||
MCP->>MCP: 检查配额
|
||||
MCP->>AM: POST /platform-agents
|
||||
AM->>K8s: 创建Pod
|
||||
K8s-->>AM: Pod创建成功
|
||||
AM-->>MCP: 返回Agent信息
|
||||
MCP->>MCP: 更新配额使用量
|
||||
MCP->>MCP: 记录计费信息
|
||||
MCP-->>User: 返回Agent信息
|
||||
```
|
||||
|
||||
#### 5.2.2 创建自定义 Agent
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant MCP as MCP Server
|
||||
participant AM as Agent Manager
|
||||
participant K8s as Kubernetes
|
||||
|
||||
User->>MCP: POST /api/user/custom-agents
|
||||
MCP->>MCP: 验证身份和权限
|
||||
MCP->>MCP: 检查资源配额
|
||||
MCP->>MCP: 验证环境变量
|
||||
MCP->>AM: POST /custom-agents
|
||||
AM->>K8s: 创建Secret
|
||||
AM->>K8s: 创建Deployment
|
||||
K8s-->>AM: 资源创建成功
|
||||
AM-->>MCP: 返回Agent信息
|
||||
MCP->>MCP: 更新资源使用量
|
||||
MCP->>MCP: 记录计费信息
|
||||
MCP-->>User: 返回Agent信息
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 计费重构
|
||||
|
||||
### 6.1 计费规则
|
||||
|
||||
#### 6.1.1 平台 Agent 计费
|
||||
|
||||
| 计费项 | 计算方式 | 说明 |
|
||||
|--------|----------|------|
|
||||
| Pod 运行时间 | 运行秒数 × 单价 | 按秒计费 |
|
||||
| 请求次数 | 请求数 × 单价 | 可选 |
|
||||
|
||||
#### 6.1.2 自定义 Agent 计费
|
||||
|
||||
| 计费项 | 计算方式 | 说明 |
|
||||
|--------|----------|------|
|
||||
| CPU 使用 | CPU核心数 × 运行秒数 × 单价 | 按实际使用计费 |
|
||||
| 内存使用 | 内存GB × 运行秒数 × 单价 | 按实际使用计费 |
|
||||
| 请求次数 | 请求数 × 单价 | 可选 |
|
||||
|
||||
### 6.2 计费记录
|
||||
|
||||
```python
|
||||
class AgentBillingRecord(BaseModel, Base):
|
||||
"""Agent 计费记录"""
|
||||
__tablename__ = "agent_billing_records"
|
||||
|
||||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||||
channel_id = Column(GUID(), ForeignKey("channels.id"))
|
||||
agent_name = Column(String(100), nullable=False)
|
||||
agent_type = Column(String(20), nullable=False) # platform, custom
|
||||
template_name = Column(String(100), nullable=False)
|
||||
|
||||
# 使用量
|
||||
duration_seconds = Column(Integer, nullable=False) # 运行时长
|
||||
cpu_seconds = Column(sa.Float, default=0) # CPU秒数
|
||||
memory_gb_seconds = Column(sa.Float, default=0) # 内存GB秒数
|
||||
request_count = Column(Integer, default=0) # 请求次数
|
||||
|
||||
# 费用
|
||||
cost = Column(sa.Numeric(12, 4), nullable=False)
|
||||
currency = Column(String(10), default="EU")
|
||||
|
||||
# 时间
|
||||
period_start = Column(DateTime, nullable=False)
|
||||
period_end = Column(DateTime, nullable=False)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 权限控制
|
||||
|
||||
### 7.1 角色权限矩阵
|
||||
|
||||
| 功能 | super_admin | admin | channel_admin | user |
|
||||
|------|-------------|-------|---------------|------|
|
||||
| 管理平台Agent模板 | ✓ | ✓ | - | - |
|
||||
| 分配平台Agent给渠道 | ✓ | ✓ | - | - |
|
||||
| 分配自定义Agent资源给渠道 | ✓ | ✓ | - | - |
|
||||
| 分配平台Agent给租户 | - | - | ✓ | - |
|
||||
| 分配自定义Agent资源给租户 | - | - | ✓ | - |
|
||||
| 使用平台Agent | - | - | - | ✓ |
|
||||
| 创建自定义Agent | - | - | - | ✓ |
|
||||
| 查看自己的Agent | - | - | ✓ | ✓ |
|
||||
|
||||
### 7.2 权限检查
|
||||
|
||||
```python
|
||||
# 权限定义
|
||||
PERMISSIONS = {
|
||||
# 平台 Agent
|
||||
"platform_agent:admin": ["super_admin", "admin"],
|
||||
"platform_agent:allocate_channel": ["super_admin", "admin"],
|
||||
"platform_agent:allocate_tenant": ["channel_admin"],
|
||||
"platform_agent:use": ["user"],
|
||||
|
||||
# 自定义 Agent
|
||||
"custom_agent:admin": ["super_admin", "admin"],
|
||||
"custom_agent:allocate_channel": ["super_admin", "admin"],
|
||||
"custom_agent:allocate_tenant": ["channel_admin"],
|
||||
"custom_agent:create": ["user"],
|
||||
"custom_agent:manage": ["user"],
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据库迁移
|
||||
|
||||
### 8.1 新增表
|
||||
|
||||
```sql
|
||||
-- 平台 Agent 配额表
|
||||
CREATE TABLE platform_agent_quotas (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
target_id UUID NOT NULL,
|
||||
target_type VARCHAR(20) NOT NULL,
|
||||
template_name VARCHAR(100) NOT NULL,
|
||||
pod_quota INTEGER NOT NULL DEFAULT 0,
|
||||
pod_used INTEGER DEFAULT 0,
|
||||
allocated_by UUID REFERENCES users(id),
|
||||
allocated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(target_id, target_type, template_name)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_platform_agent_quota_target ON platform_agent_quotas(target_id, target_type);
|
||||
CREATE INDEX idx_platform_agent_quota_template ON platform_agent_quotas(template_name);
|
||||
|
||||
-- Agent 计费记录表
|
||||
CREATE TABLE agent_billing_records (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id),
|
||||
channel_id UUID REFERENCES channels(id),
|
||||
agent_name VARCHAR(100) NOT NULL,
|
||||
agent_type VARCHAR(20) NOT NULL,
|
||||
template_name VARCHAR(100) NOT NULL,
|
||||
duration_seconds INTEGER NOT NULL,
|
||||
cpu_seconds FLOAT DEFAULT 0,
|
||||
memory_gb_seconds FLOAT DEFAULT 0,
|
||||
request_count INTEGER DEFAULT 0,
|
||||
cost NUMERIC(12, 4) NOT NULL,
|
||||
currency VARCHAR(10) DEFAULT 'EU',
|
||||
period_start TIMESTAMP NOT NULL,
|
||||
period_end TIMESTAMP NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_agent_billing_user ON agent_billing_records(user_id);
|
||||
CREATE INDEX idx_agent_billing_channel ON agent_billing_records(channel_id);
|
||||
CREATE INDEX idx_agent_billing_period ON agent_billing_records(period_start, period_end);
|
||||
```
|
||||
|
||||
### 8.2 修改现有表
|
||||
|
||||
```sql
|
||||
-- 在 users 表添加平台 Agent 相关字段(如果需要)
|
||||
-- 注意:平台 Agent 配额通过 platform_agent_quotas 表管理
|
||||
|
||||
-- 在 agents 表确保有必要的字段
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS owner_channel_id UUID REFERENCES channels(id);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. API 变更汇总
|
||||
|
||||
### 9.1 新增 API
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | /api/admin/platform-agents/templates | 获取平台Agent模板列表 |
|
||||
| PUT | /api/admin/platform-agents/templates/{name}/config | 设置平台Agent配置 |
|
||||
| POST | /api/admin/channels/{id}/platform-agents | 分配平台Agent给渠道 |
|
||||
| GET | /api/admin/platform-agents/allocations | 查看平台Agent分配情况 |
|
||||
| GET | /api/channel/platform-agents | 查看渠道的平台Agent配额 |
|
||||
| POST | /api/channel/tenants/{id}/platform-agents | 分配平台Agent给租户 |
|
||||
| GET | /api/user/platform-agents | 查看可用的平台Agent |
|
||||
| POST | /api/user/platform-agents/{template}/use | 使用平台Agent |
|
||||
| DELETE | /api/user/platform-agents/{name} | 停止平台Agent |
|
||||
| GET | /api/user/platform-agents/{name}/status | 查看平台Agent状态 |
|
||||
| GET | /api/user/platform-agents/quota | 查看平台Agent配额 |
|
||||
|
||||
### 9.2 修改 API
|
||||
|
||||
| 方法 | 路径 | 变更说明 |
|
||||
|------|------|----------|
|
||||
| POST | /api/user/custom-agents | 增加配额检查,调用Agent Manager |
|
||||
| DELETE | /api/user/custom-agents/{name} | 释放配额,调用Agent Manager |
|
||||
| GET | /api/admin/dashboard/stats | 增加平台Agent统计 |
|
||||
| GET | /api/admin/resources/agents | 区分平台/自定义Agent |
|
||||
|
||||
### 9.3 废弃 API
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | /api/user/agents/deploy | 改用 /api/user/platform-agents/{template}/use |
|
||||
|
||||
---
|
||||
|
||||
## 10. 实施计划
|
||||
|
||||
### 阶段一:数据模型和迁移
|
||||
|
||||
- [ ] 创建 `PlatformAgentQuota` 模型
|
||||
- [ ] 创建 `AgentBillingRecord` 模型
|
||||
- [ ] 创建数据库迁移脚本
|
||||
- [ ] 执行迁移
|
||||
|
||||
### 阶段二:Agent Manager 客户端重构
|
||||
|
||||
- [ ] 重构 `agent_manager_client.py`
|
||||
- [ ] 添加平台Agent API支持
|
||||
- [ ] 添加自定义Agent API支持
|
||||
- [ ] 添加单元测试
|
||||
|
||||
### 阶段三:管理员功能
|
||||
|
||||
- [ ] 实现平台Agent模板管理API
|
||||
- [ ] 实现平台Agent分配给渠道API
|
||||
- [ ] 实现自定义Agent资源分配给渠道API
|
||||
- [ ] 更新管理员Dashboard统计
|
||||
|
||||
### 阶段四:渠道功能
|
||||
|
||||
- [ ] 实现渠道查看平台Agent配额API
|
||||
- [ ] 实现渠道分配平台Agent给租户API
|
||||
- [ ] 实现渠道分配自定义Agent资源给租户API
|
||||
- [ ] 更新渠道Dashboard
|
||||
|
||||
### 阶段五:租户功能
|
||||
|
||||
- [ ] 实现租户查看可用平台Agent API
|
||||
- [ ] 实现租户使用平台Agent API
|
||||
- [ ] 重构租户创建自定义Agent API
|
||||
- [ ] 实现配额查询API
|
||||
|
||||
### 阶段六:计费集成
|
||||
|
||||
- [ ] 实现Agent计费记录
|
||||
- [ ] 集成计费到Agent使用流程
|
||||
- [ ] 实现计费统计API
|
||||
|
||||
### 阶段七:测试和文档
|
||||
|
||||
- [ ] 单元测试
|
||||
- [ ] 集成测试
|
||||
- [ ] API文档更新
|
||||
- [ ] 前端对接测试
|
||||
|
||||
---
|
||||
|
||||
## 11. 注意事项
|
||||
|
||||
1. **向后兼容**:保留现有API,新增API使用新路径
|
||||
2. **配额一致性**:确保配额检查和更新的原子性
|
||||
3. **错误处理**:Agent Manager调用失败时的回滚处理
|
||||
4. **日志记录**:所有配额变更需要审计日志
|
||||
5. **性能考虑**:配额检查需要高效,避免频繁数据库查询
|
||||
|
||||
---
|
||||
|
||||
## 12. 版本历史
|
||||
|
||||
| 版本 | 日期 | 说明 |
|
||||
|------|------|------|
|
||||
| v1.0 | 2026-01-04 | 初始版本 |
|
||||
Reference in New Issue
Block a user