Merge branch 'main' into gzy

This commit is contained in:
xiaohei
2025-12-26 09:40:10 +00:00
24 changed files with 3431 additions and 3145 deletions
-879
View File
@@ -1,879 +0,0 @@
# taiji-AI-PAD API 接口文档
**版本**: v1.2.1
**更新时间**: 2025年12月22日
**最后更新**: 2025年12月22日
**基础URL**:
- Data Ingestion 服务: `http://localhost:8001`
- MCP Server 服务: `http://localhost:8002`
- API Gateway: `http://localhost:80`
---
## 📋 目录
1. [Data Ingestion 服务 API](#data-ingestion-服务-api)
2. [MCP Server 服务 API](#mcp-server-服务-api)
3. [通用响应格式](#通用响应格式)
4. [错误码说明](#错误码说明)
---
## Data Ingestion 服务 API
**基础URL**: `http://localhost:8001`
### 1. 健康检查
**GET** `/health`
检查服务健康状态。
**响应示例**:
```json
{
"status": "healthy",
"timestamp": "2025-12-22T05:04:23.211960",
"services": {
"data_ingestion": "healthy",
"redis": "healthy",
"nats": "healthy",
"rapidapi": "healthy",
"apillama": "healthy"
},
"stats": {
"total_apis": 0,
"processed_apis": 0,
"generated_tools": 20,
"cache_size": 44
}
}
```
---
### 2. 同步 RapidAPI 端点
**POST** `/rapidapi/sync`
同步 RapidAPI 端点列表。
**查询参数**:
- `category` (string, 可选): API 分类
- `limit` (int, 可选, 默认: 100): 同步数量限制
**请求示例**:
```bash
POST /rapidapi/sync?category=weather&limit=50
```
**响应示例**:
```json
{
"message": "RapidAPI端点同步已启动",
"category": "weather",
"limit": 50
}
```
---
### 3. 测试 RapidAPI 端点
**POST** `/rapidapi/test`
测试 RapidAPI 端点调用。
**请求体**:
```json
{
"endpoint": "https://rapidapi.com/api/weather/v1/current",
"method": "GET",
"params": {
"location": "Beijing"
},
"headers": {
"X-Custom-Header": "value"
}
}
```
**响应示例**:
```json
{
"success": true,
"status_code": 200,
"data": {
"temperature": 25,
"condition": "sunny"
},
"response_time": 123.45,
"headers": {
"content-type": "application/json"
}
}
```
---
### 4. 解析 OpenAPI 规范
**POST** `/openapi/parse`
解析 OpenAPI/Swagger 规范文档。
**查询参数**:
- `url` (string, 必需): OpenAPI 文档 URL
**请求示例**:
```bash
POST /openapi/parse?url=https://api.example.com/openapi.json
```
**响应示例**:
```json
{
"url": "https://api.example.com/openapi.json",
"title": "Example API",
"version": "1.0.0",
"endpoints_count": 15,
"schemas_count": 8,
"parsed_data": {
"info": {
"title": "Example API",
"version": "1.0.0"
},
"paths": {
"/users": {
"get": {
"summary": "Get users",
"responses": {
"200": {
"description": "Success"
}
}
}
}
}
},
"parsing_time": 0.234
}
```
---
### 5. APILLAMA 处理 API 文档
**POST** `/apillama/process`
使用 APILLAMA 处理 API 文档,生成结构化 Schema。
**请求体**:
```json
{
"api_doc": {
"title": "Weather API",
"description": "Get weather information",
"parameters": [
{
"name": "location",
"type": "string",
"description": "City name",
"required": true
}
]
},
"context": {
"service": "Weather service",
"version": "1.0"
},
"output_format": "json_schema"
}
```
**请求参数说明**:
- `api_doc` (string | object, 必需): API 文档,可以是字符串或对象
- `context` (object, 可选): 上下文信息
- `output_format` (string, 可选): 输出格式,可选值: `json_schema`, `pydantic`, `openapi` (默认: `json_schema`)
**响应示例**:
```json
{
"processed": true,
"output_format": "json_schema",
"schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name"
}
},
"required": ["location"]
},
"description": "Weather API for getting current weather information",
"parameters": [
{
"name": "location",
"type": "string",
"description": "City name",
"required": true
}
],
"examples": [
{
"location": "Beijing",
"temperature": 25
}
],
"processing_time": 1.234,
"confidence_score": 0.95,
"completeness_score": 0.88
}
```
---
### 6. 生成工具定义
**POST** `/tools/generate`
从 API 端点生成工具定义。
**请求体**:
```json
{
"url": "https://api.example.com/users",
"method": "GET",
"name": "get_users",
"description": "Get list of users",
"parameters": [
{
"name": "page",
"type": "integer",
"required": false
}
],
"headers": {
"Authorization": "Bearer token"
}
}
```
**响应示例**:
```json
{
"message": "工具生成任务已启动",
"endpoint": "https://api.example.com/users",
"method": "GET"
}
```
---
### 7. 获取工具列表
**GET** `/tools`
获取已生成的工具列表。
**查询参数**:
- `category` (string, 可选): 工具分类
- `limit` (int, 可选, 默认: 100): 返回数量限制
- `offset` (int, 可选, 默认: 0): 偏移量
**请求示例**:
```bash
GET /tools?category=weather&limit=20&offset=0
```
**响应示例**:
```json
[
{
"name": "get_weather",
"description": "Get weather information",
"category": "weather",
"url": "https://api.example.com/weather",
"method": "GET",
"parameters": [
{
"name": "location",
"type": "string",
"required": true
}
],
"created_at": "2025-12-22T05:00:00Z"
}
]
```
---
### 8. 获取特定工具定义
**GET** `/tools/{tool_name}`
获取特定工具的定义。
**路径参数**:
- `tool_name` (string, 必需): 工具名称
**响应示例**:
```json
{
"name": "get_weather",
"description": "Get weather information",
"category": "weather",
"url": "https://api.example.com/weather",
"method": "GET",
"parameters": [
{
"name": "location",
"type": "string",
"required": true
}
],
"created_at": "2025-12-22T05:00:00Z"
}
```
---
### 9. 删除工具
**DELETE** `/tools/{tool_name}`
删除指定的工具定义。
**路径参数**:
- `tool_name` (string, 必需): 工具名称
**响应示例**:
```json
{
"message": "工具已删除",
"tool_name": "get_weather"
}
```
---
### 10. 获取统计信息
**GET** `/stats`
获取服务统计信息。
**响应示例**:
```json
{
"total_apis": 100,
"processed_apis": 85,
"generated_tools": 20,
"failed_processes": 2,
"cache_size": 44,
"last_sync": "2025-12-22T05:00:00Z",
"categories": {
"weather": 15,
"finance": 10,
"general": 5
}
}
```
---
### 11. 清除缓存
**POST** `/cache/clear`
清除所有缓存数据。
**查询参数**:
- `pattern` (string, 可选): 缓存键模式,如 `rapidapi:*`
**请求示例**:
```bash
POST /cache/clear?pattern=rapidapi:*
```
**响应示例**:
```json
{
"message": "缓存已清除",
"cleared_keys": 150
}
```
---
### 12. Prometheus Metrics
**GET** `/metrics`
获取 Prometheus 格式的监控指标。
**响应格式**: Prometheus 文本格式
**示例**:
```
# HELP http_requests_total Total number of HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",status="200"} 1500
http_requests_total{method="POST",status="200"} 800
# HELP apillama_processing_duration_seconds APILLAMA processing duration
# TYPE apillama_processing_duration_seconds histogram
apillama_processing_duration_seconds_bucket{le="0.5"} 100
apillama_processing_duration_seconds_bucket{le="1.0"} 200
```
---
## MCP Server 服务 API
**基础URL**: `http://localhost:8002`
### 1. 健康检查
**GET** `/health`
检查 MCP Server 健康状态。
**响应示例**:
```json
{
"status": "healthy",
"timestamp": "2025-12-22T05:04:23.211960",
"services": {
"database": "healthy",
"redis": "healthy",
"nats": "healthy"
}
}
```
---
### 2. 注册 Agent
**POST** `/agents`
注册新的 Agent。
**请求体**:
```json
{
"name": "weather_agent",
"description": "Weather information agent",
"capabilities": ["weather_query", "location_search"],
"metadata": {
"version": "1.0.0",
"author": "taiji-team"
}
}
```
**响应示例**:
```json
{
"agent_id": "agent_123456",
"name": "weather_agent",
"description": "Weather information agent",
"status": "active",
"created_at": "2025-12-22T05:00:00Z",
"capabilities": ["weather_query", "location_search"],
"metadata": {
"version": "1.0.0",
"author": "taiji-team"
}
}
```
---
### 3. 获取 Agent 列表
**GET** `/agents`
获取所有注册的 Agent 列表。
**查询参数**:
- `status` (string, 可选): 过滤状态,如 `active`, `inactive`
- `limit` (int, 可选, 默认: 100): 返回数量限制
- `offset` (int, 可选, 默认: 0): 偏移量
**响应示例**:
```json
[
{
"agent_id": "agent_123456",
"name": "weather_agent",
"description": "Weather information agent",
"status": "active",
"created_at": "2025-12-22T05:00:00Z"
}
]
```
---
### 4. 获取特定 Agent
**GET** `/agents/{agent_id}`
获取特定 Agent 的详细信息。
**路径参数**:
- `agent_id` (string, 必需): Agent ID
**响应示例**:
```json
{
"agent_id": "agent_123456",
"name": "weather_agent",
"description": "Weather information agent",
"status": "active",
"created_at": "2025-12-22T05:00:00Z",
"capabilities": ["weather_query", "location_search"],
"metadata": {
"version": "1.0.0",
"author": "taiji-team"
}
}
```
---
### 5. 执行 Agent 工具
**POST** `/agents/{agent_id}/execute`
执行 Agent 的工具调用。支持三种工具类型:
- **API 工具**: 调用外部 API
- **函数工具**: 执行本地 Python 函数(新增)
- **LLM 工具**: 调用 LLM 模型
**路径参数**:
- `agent_id` (string, 必需): Agent ID
**请求体**:
```json
{
"tool_name": "math_add",
"parameters": {
"a": 10,
"b": 20
},
"context": {
"session_id": "session_123"
}
}
```
**函数工具示例**:
```json
{
"tool_name": "math_add",
"parameters": {
"a": 10,
"b": 20
}
}
```
**响应示例**:
```json
{
"success": true,
"result": 30.0,
"execution_time": 0.001,
"tool_name": "math_add"
}
```
**可用的函数工具**:
- 数学函数: `math_add`, `math_subtract`, `math_multiply`, `math_divide`, `math_power`
- 字符串函数: `string_upper`, `string_lower`, `string_length`, `string_replace`
- 日期时间: `datetime_now`
- JSON: `json_parse`, `json_stringify`
- 哈希: `hash_md5`, `hash_sha256`
- Base64: `base64_encode`, `base64_decode`
**安全特性**:
- ✅ 函数白名单验证
- ✅ 沙箱执行环境
- ✅ 超时控制(默认 5 秒)
- ✅ 参数验证和类型检查
---
### 6. 获取工具列表
**GET** `/tools`
获取所有可用工具列表。
**查询参数**:
- `category` (string, 可选): 工具分类
- `limit` (int, 可选, 默认: 100): 返回数量限制
**响应示例**:
```json
[
{
"name": "get_weather",
"description": "Get weather information",
"category": "weather",
"parameters": [
{
"name": "location",
"type": "string",
"required": true
}
]
}
]
```
---
### 7. Prometheus Metrics
**GET** `/metrics`
获取 Prometheus 格式的监控指标。
**注意**: 当前返回 TODO 消息,待实现。
---
## WebSocket API
### MCP Protocol WebSocket
**WebSocket URL**: `ws://localhost:8002/ws/{agent_id}`
**连接示例**:
```javascript
const ws = new WebSocket('ws://localhost:8002/ws/agent_123456');
```
**消息格式**:
```json
{
"type": "mcp_request",
"payload": {
"method": "tools/list",
"params": {}
}
}
```
**响应格式**:
```json
{
"type": "mcp_response",
"payload": {
"result": [...]
}
}
```
---
## 通用响应格式
### 成功响应
所有成功响应都遵循以下格式:
```json
{
"status": "success",
"data": {...},
"message": "操作成功"
}
```
### 错误响应
所有错误响应都遵循以下格式:
```json
{
"status": "error",
"error": {
"code": "ERROR_CODE",
"message": "错误描述",
"details": {...}
}
}
```
---
## 错误码说明
| HTTP 状态码 | 错误码 | 说明 |
|------------|--------|------|
| 400 | `BAD_REQUEST` | 请求参数错误 |
| 401 | `UNAUTHORIZED` | 未授权 |
| 403 | `FORBIDDEN` | 禁止访问 |
| 404 | `NOT_FOUND` | 资源不存在 |
| 500 | `INTERNAL_ERROR` | 服务器内部错误 |
| 503 | `SERVICE_UNAVAILABLE` | 服务不可用 |
---
## 认证说明
当前版本暂未实现认证机制,所有 API 均可直接访问。
**未来版本将支持**:
- API Key 认证
- JWT Token 认证
- OAuth 2.0
---
## 限流说明
当前版本暂未实现限流机制。
**未来版本将支持**:
- 基于 IP 的限流
- 基于 API Key 的限流
- 基于用户的限流
---
## 交互式 API 文档
### Swagger UI
- Data Ingestion: `http://localhost:8001/docs`
- MCP Server: `http://localhost:8002/docs`
### ReDoc
- Data Ingestion: `http://localhost:8001/redoc`
- MCP Server: `http://localhost:8002/redoc`
### OpenAPI JSON
- Data Ingestion: `http://localhost:8001/openapi.json`
- MCP Server: `http://localhost:8002/openapi.json`
---
## 前端集成示例
### JavaScript/TypeScript
```typescript
// 健康检查
const healthCheck = async () => {
const response = await fetch('http://localhost:8001/health');
const data = await response.json();
console.log(data);
};
// APILLAMA 处理
const processAPI = async (apiDoc: any) => {
const response = await fetch('http://localhost:8001/apillama/process', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
api_doc: apiDoc,
context: { service: 'example' },
output_format: 'json_schema'
})
});
const data = await response.json();
return data;
};
// 获取工具列表
const getTools = async (category?: string) => {
const url = category
? `http://localhost:8001/tools?category=${category}`
: 'http://localhost:8001/tools';
const response = await fetch(url);
const data = await response.json();
return data;
};
```
### Python
```python
import requests
# 健康检查
def health_check():
response = requests.get('http://localhost:8001/health')
return response.json()
# APILLAMA 处理
def process_api(api_doc, context=None, output_format='json_schema'):
response = requests.post(
'http://localhost:8001/apillama/process',
json={
'api_doc': api_doc,
'context': context or {},
'output_format': output_format
}
)
return response.json()
# 获取工具列表
def get_tools(category=None):
params = {'category': category} if category else {}
response = requests.get('http://localhost:8001/tools', params=params)
return response.json()
```
### cURL
```bash
# 健康检查
curl http://localhost:8001/health
# APILLAMA 处理
curl -X POST http://localhost:8001/apillama/process \
-H "Content-Type: application/json" \
-d '{
"api_doc": {"title": "Test API"},
"context": {"service": "test"},
"output_format": "json_schema"
}'
# 获取工具列表
curl http://localhost:8001/tools?category=weather
```
---
## 注意事项
1. **CORS**: 当前配置允许所有来源,生产环境需要限制
2. **认证**: 当前版本未实现认证,生产环境需要添加
3. **限流**: 当前版本未实现限流,生产环境需要添加
4. **错误处理**: 所有 API 调用都应该处理错误情况
5. **超时设置**: 建议设置合理的请求超时时间
---
**文档版本**: v1.2.1
**最后更新**: 2025年12月22日
**维护者**: taiji-AI-PAD 项目组
## 更新日志
- **v1.2.1** (2025-12-22): 添加 MCP Server 函数工具调用说明
- **v1.2.0** (2025-12-22): 初始版本,包含所有 API 端点文档
+1814 -580
View File
File diff suppressed because it is too large Load Diff
+47 -6
View File
@@ -11,10 +11,13 @@ import { Card } from "@/components/ui/card"
import { Eye, EyeOff, Shield, Globe } from "lucide-react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { useLanguage } from "@/contexts/language-context"
import { useToast } from "@/hooks/use-toast"
import { TaijiAPIClient } from "@/lib/api-client"
export default function AdminLoginPage() {
const router = useRouter()
const { language, setLanguage, t } = useLanguage()
const { toast } = useToast()
const [showPassword, setShowPassword] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const [credentials, setCredentials] = useState({
@@ -55,13 +58,51 @@ export default function AdminLoginPage() {
e.preventDefault()
setIsLoading(true)
// Simulate admin authentication
await new Promise((resolve) => setTimeout(resolve, 1500))
try {
// 清除所有旧的token(防止多用户登录时token重复)
localStorage.removeItem("auth_token")
localStorage.removeItem("channel_token")
localStorage.removeItem("admin_token")
localStorage.removeItem("refresh_token")
localStorage.removeItem("user")
localStorage.removeItem("api_key")
// Store admin auth token
localStorage.setItem("admin_token", "admin_authenticated")
router.push("/admin/dashboard")
// 调用真实的登录API
const result = await TaijiAPIClient.login(credentials.email, credentials.password, "admin")
if (result && result.success && result.data?.token) {
// 存储admin token
localStorage.setItem("admin_token", result.data.token)
if (result.data.refreshToken) {
localStorage.setItem("refresh_token", result.data.refreshToken)
}
if (result.data.user) {
localStorage.setItem("user", JSON.stringify(result.data.user))
}
toast({
title: t("登录成功", "Login successful"),
description: t("欢迎回来", "Welcome back"),
})
router.push("/admin/dashboard")
} else {
toast({
title: t("登录失败", "Login failed"),
description: (result as any)?.message || t("请检查您的邮箱和密码", "Please check your email and password"),
variant: "destructive",
})
}
} catch (error: any) {
console.error("Admin login error:", error)
toast({
title: t("登录失败", "Login failed"),
description: error.message || t("网络错误,请稍后重试", "Network error, please try again"),
variant: "destructive",
})
} finally {
setIsLoading(false)
}
}
return (
+17 -67
View File
@@ -1,6 +1,7 @@
"use client"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { DashboardLayout } from "@/components/dashboard-layout"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
@@ -9,6 +10,7 @@ import { Bot, Cpu, MemoryStick, Zap } from "lucide-react"
import { useLanguage } from "@/hooks/useLanguage"
import { TaijiAPIClient } from "@/lib/api-client"
import { useToast } from "@/hooks/use-toast"
import { isAuthenticated } from "@/lib/auth"
import {
Dialog,
DialogContent,
@@ -24,6 +26,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
export default function AgentFactoryPage() {
const { t } = useLanguage()
const { toast } = useToast()
const router = useRouter()
const [selectedAgent, setSelectedAgent] = useState<any>(null)
const [showDeployDialog, setShowDeployDialog] = useState(false)
const [loading, setLoading] = useState(true)
@@ -37,8 +40,14 @@ export default function AgentFactoryPage() {
const [stats, setStats] = useState({ cpu: 0, memory: 0 })
useEffect(() => {
// 检查认证
if (!isAuthenticated()) {
router.push("/login")
return
}
loadAgents()
}, [])
}, [router])
const loadAgents = async () => {
try {
@@ -69,69 +78,6 @@ export default function AgentFactoryPage() {
}
}
const defaultPlatformAgents = [
{
id: "weather-agent",
name: t("天气查询Agent", "Weather Query Agent"),
description: t("提供全球天气信息查询和预报服务", "Provide global weather information query and forecast service"),
capabilities: [
t("实时天气", "Real-time weather"),
t("7天预报", "7-day forecast"),
t("气象警告", "Weather alerts"),
],
status: "available",
icon: "🌤️",
},
{
id: "data-analysis-agent",
name: t("数据分析Agent", "Data Analysis Agent"),
description: t("执行数据分析、可视化和报告生成", "Perform data analysis, visualization and report generation"),
capabilities: [
t("数据清洗", "Data cleaning"),
t("统计分析", "Statistical analysis"),
t("图表生成", "Chart generation"),
],
status: "available",
icon: "📊",
},
{
id: "doc-processor-agent",
name: t("文档处理Agent", "Document Processing Agent"),
description: t("智能文档解析、提取和转换", "Intelligent document parsing, extraction and conversion"),
capabilities: [t("PDF解析", "PDF parsing"), t("文本提取", "Text extraction"), t("格式转换", "Format conversion")],
status: "available",
icon: "📄",
},
{
id: "email-agent",
name: t("邮件管理Agent", "Email Management Agent"),
description: t("自动化邮件处理和智能回复", "Automated email processing and intelligent reply"),
capabilities: [
t("邮件分类", "Email classification"),
t("自动回复", "Auto reply"),
t("内容总结", "Content summary"),
],
status: "available",
icon: "📧",
},
{
id: "api-integration-agent",
name: t("API集成Agent", "API Integration Agent"),
description: t("连接和编排第三方API服务", "Connect and orchestrate third-party API services"),
capabilities: [t("API调用", "API calls"), t("数据转换", "Data transformation"), t("错误处理", "Error handling")],
status: "available",
icon: "🔌",
},
{
id: "database-agent",
name: t("数据库操作Agent", "Database Operations Agent"),
description: t("执行数据库查询和数据管理", "Execute database queries and data management"),
capabilities: [t("SQL查询", "SQL queries"), t("数据迁移", "Data migration"), t("备份恢复", "Backup & restore") ],
status: "available",
icon: "🗄️",
},
]
const handleDeploy = (agent: any) => {
setSelectedAgent(agent)
setShowDeployDialog(true)
@@ -198,7 +144,7 @@ export default function AgentFactoryPage() {
{loading ? (
<span className="inline-block h-7 w-12 animate-pulse bg-muted rounded" />
) : (
platformAgents.length || defaultPlatformAgents.length
platformAgents.length
)}
</div>
<p className="text-xs text-muted-foreground mt-1">{t("平台原生", "Platform native")}</p>
@@ -281,9 +227,13 @@ export default function AgentFactoryPage() {
</Card>
))}
</div>
) : platformAgents.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">
{t("暂无可用Agent", "No agents available")}
</div>
) : (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{(platformAgents.length > 0 ? platformAgents : defaultPlatformAgents).map((agent) => (
{platformAgents.map((agent) => (
<Card key={agent.id} className="border-primary/20 hover:border-primary/40 transition-colors">
<CardHeader className="pb-3">
<div className="flex items-start justify-between mb-2">
@@ -297,7 +247,7 @@ export default function AgentFactoryPage() {
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground">{t("核心能力", "Core Capabilities")}:</p>
<div className="flex flex-wrap gap-1">
{agent.capabilities.map((cap: string) => (
{(agent.capabilities || []).map((cap: string) => (
<Badge key={cap} variant="outline" className="text-xs">
{cap}
</Badge>
+10 -1
View File
@@ -8,8 +8,10 @@ import { Progress } from "@/components/ui/progress"
import { ResponsiveContainer, BarChart, Bar, XAxis, YAxis, Tooltip, LineChart, Line } from "recharts"
import { useLanguage } from "@/hooks/useLanguage"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { TaijiAPIClient } from "@/lib/api-client"
import { useToast } from "@/hooks/use-toast"
import { isAuthenticated } from "@/lib/auth"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
@@ -17,6 +19,7 @@ import { Label } from "@/components/ui/label"
export default function BillingPage() {
const { t } = useLanguage()
const { toast } = useToast()
const router = useRouter()
const [loading, setLoading] = useState(true)
const [showFilterDialog, setShowFilterDialog] = useState(false)
const [showDateDialog, setShowDateDialog] = useState(false)
@@ -34,8 +37,14 @@ export default function BillingPage() {
})
useEffect(() => {
// 检查认证
if (!isAuthenticated()) {
router.push("/login")
return
}
loadBillingData()
}, [])
}, [router])
const loadBillingData = async () => {
try {
File diff suppressed because it is too large Load Diff
+49 -6
View File
@@ -10,10 +10,13 @@ import { Card } from "@/components/ui/card"
import { Building2, Globe, Eye, EyeOff } from "lucide-react"
import { useLanguage } from "@/contexts/language-context"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { useToast } from "@/hooks/use-toast"
import { TaijiAPIClient } from "@/lib/api-client"
export default function ChannelLogin() {
const router = useRouter()
const { language, setLanguage } = useLanguage()
const { language, setLanguage, t } = useLanguage()
const { toast } = useToast()
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [showPassword, setShowPassword] = useState(false)
@@ -52,11 +55,51 @@ export default function ChannelLogin() {
e.preventDefault()
setIsLoading(true)
// Simulate API call
setTimeout(() => {
localStorage.setItem("channel_token", "mock_channel_token")
router.push("/channel/dashboard")
}, 1500)
try {
// 清除所有旧的token(防止多用户登录时token重复)
localStorage.removeItem("auth_token")
localStorage.removeItem("channel_token")
localStorage.removeItem("admin_token")
localStorage.removeItem("refresh_token")
localStorage.removeItem("user")
localStorage.removeItem("api_key")
// 调用真实的登录API
const result = await TaijiAPIClient.login(email, password, "channel")
if (result && result.success && result.data?.token) {
// 存储channel token
localStorage.setItem("channel_token", result.data.token)
if (result.data.refreshToken) {
localStorage.setItem("refresh_token", result.data.refreshToken)
}
if (result.data.user) {
localStorage.setItem("user", JSON.stringify(result.data.user))
}
toast({
title: t("登录成功", "Login successful"),
description: t("欢迎回来", "Welcome back"),
})
router.push("/channel/dashboard")
} else {
toast({
title: t("登录失败", "Login failed"),
description: (result as any)?.message || t("请检查您的邮箱和密码", "Please check your email and password"),
variant: "destructive",
})
}
} catch (error: any) {
console.error("Channel login error:", error)
toast({
title: t("登录失败", "Login failed"),
description: error.message || t("网络错误,请稍后重试", "Network error, please try again"),
variant: "destructive",
})
} finally {
setIsLoading(false)
}
}
return (
+18 -9
View File
@@ -1,8 +1,10 @@
"use client"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { useLanguage } from "@/hooks/useLanguage"
import { TaijiAPIClient } from "@/lib/api-client"
import { isAuthenticated } from "@/lib/auth"
import { DashboardLayout } from "@/components/dashboard-layout"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
@@ -24,6 +26,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
export default function DataToolsPage() {
const { t } = useLanguage()
const router = useRouter()
const [tools, setTools] = useState<any[]>([])
const [loading, setLoading] = useState(true)
const [stats, setStats] = useState({ totalApis: 0, generatedTools: 0, activePods: 0 })
@@ -42,9 +45,15 @@ export default function DataToolsPage() {
const [selectedServiceGateway, setSelectedServiceGateway] = useState<string>("")
useEffect(() => {
// 检查认证
if (!isAuthenticated()) {
router.push("/login")
return
}
loadTools()
loadStats()
}, [])
}, [router])
const loadTools = async () => {
try {
@@ -263,7 +272,6 @@ export default function DataToolsPage() {
"Configure JSON API access by providing interface URL and query parameters",
)}
</p>
<Badge variant="secondary">{t("3个已配置", "3 configured")}</Badge>
</CardContent>
</Card>
@@ -283,7 +291,6 @@ export default function DataToolsPage() {
"Support Azure, Google, AWS storage services and various native databases",
)}
</p>
<Badge variant="secondary">{t("5个已配置", "5 configured")}</Badge>
</CardContent>
</Card>
</div>
@@ -344,11 +351,6 @@ export default function DataToolsPage() {
<Input placeholder={t("输入工具名称", "Enter tool name")} />
</div>
<div className="space-y-2">
<Label>{t("API端点", "API Endpoint")}</Label>
<Input placeholder="https://api.example.com/endpoint" />
</div>
<div className="border-t pt-4 space-y-4">
<h3 className="font-semibold flex items-center gap-2">
<Cpu className="h-4 w-4" />
@@ -514,7 +516,14 @@ export default function DataToolsPage() {
<>
<div className="space-y-2">
<Label>{t("数据接口URL", "Data Interface URL")}</Label>
<Input placeholder="https://api.example.com/data" />
<Input
placeholder="https://api.example.com/data"
disabled
className="bg-muted cursor-not-allowed"
/>
<p className="text-xs text-muted-foreground">
{t("端点URL由系统自动配置,不支持自定义", "Endpoint URL is automatically configured by the system and cannot be customized")}
</p>
</div>
<div className="space-y-2">
<Label>{t("查询参数", "Query Parameters")}</Label>
+20 -121
View File
@@ -1,4 +1,5 @@
"use client"
import { useRouter } from "next/navigation"
import { DashboardLayout } from "@/components/dashboard-layout"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
@@ -8,6 +9,7 @@ import { Progress } from "@/components/ui/progress"
import { useLanguage } from "@/hooks/useLanguage"
import { TaijiAPIClient } from "@/lib/api-client"
import { useToast } from "@/hooks/use-toast"
import { isAuthenticated } from "@/lib/auth"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { useState, useEffect } from "react"
import {
@@ -16,7 +18,6 @@ import {
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogFooter,
} from "@/components/ui/dialog"
import { Label } from "@/components/ui/label"
@@ -27,8 +28,7 @@ import { Textarea } from "@/components/ui/textarea"
export default function ModelGatewayPage() {
const { t } = useLanguage()
const { toast } = useToast()
const [selectedGateway, setSelectedGateway] = useState<string>("")
const [showGatewayDialog, setShowGatewayDialog] = useState(false)
const router = useRouter()
const [showApiDialog, setShowApiDialog] = useState(false)
const [apiUploadMethod, setApiUploadMethod] = useState<"file" | "url">("file")
const [jsonFile, setJsonFile] = useState<File | null>(null)
@@ -40,8 +40,14 @@ export default function ModelGatewayPage() {
const [stats, setStats] = useState({ availableGateways: 0, endpoints: 0, avgLatency: 0, requestsToday: 0 })
useEffect(() => {
// 检查认证
if (!isAuthenticated()) {
router.push("/login")
return
}
loadGatewayData()
}, [])
}, [router])
const loadGatewayData = async () => {
try {
@@ -89,59 +95,30 @@ export default function ModelGatewayPage() {
}
}
const defaultFrameworks = [
// 定义固定的网关类型(这些是系统固定的,不是假数据)
const gatewayTypes = [
{
name: "MCP",
fullName: "Model Context Protocol",
icon: Code2,
endpoints: 8,
usage: 42,
status: "active",
description: "适用于需要上下文理解的复杂对话场景",
},
{
name: "A2A",
fullName: "Agent-to-Agent Protocol",
icon: Boxes,
endpoints: 5,
usage: 28,
status: "active",
description: "适用于多Agent协同工作的场景",
},
{
name: "API",
fullName: "Standard API Gateway",
icon: Workflow,
endpoints: 6,
usage: 30,
status: "active",
description: "标准REST API,适用于简单的请求响应场景",
},
]
const frameworksToUse = frameworks.length > 0 ? frameworks : defaultFrameworks
const providersToUse = providers.length > 0 ? providers : []
const handleSelectGateway = async (gatewayType: string) => {
try {
const result = await TaijiAPIClient.selectGateway(gatewayType as "MCP" | "A2A" | "API")
if (result?.success) {
setSelectedGateway(gatewayType)
toast({
title: t("选择成功", "Success"),
description: t("服务网关已选择", "Service gateway selected"),
})
setShowGatewayDialog(false)
}
} catch (error: any) {
toast({
title: t("选择失败", "Failed"),
description: error.message || t("无法选择服务网关", "Failed to select gateway"),
variant: "destructive",
})
}
}
const handleCreateAPI = async (apiData: { name: string; method: "json" | "url"; content: string }) => {
try {
const result = await TaijiAPIClient.createGatewayAPI(apiData.name, apiData.method, apiData.content)
@@ -173,62 +150,10 @@ export default function ModelGatewayPage() {
</p>
</div>
<div className="flex gap-2">
<Button onClick={() => setShowApiDialog(true)} variant="outline" className="gap-2">
<Button onClick={() => setShowApiDialog(true)} className="gap-2">
<Plus className="h-4 w-4" />
{t("创建API", "Create API")}
</Button>
<Dialog open={showGatewayDialog} onOpenChange={setShowGatewayDialog}>
<DialogTrigger asChild>
<Button className="gap-2">
<Plus className="h-4 w-4" />
{t("选择服务网关", "Select Service Gateway")}
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle>{t("选择服务网关类型", "Select Service Gateway Type")}</DialogTitle>
<DialogDescription>
{t("选择适合您业务需求的网关服务方式", "Choose the gateway service type that fits your needs")}
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<RadioGroup value={selectedGateway} onValueChange={setSelectedGateway}>
{frameworksToUse.map((framework) => {
const Icon = framework.icon
return (
<div
key={framework.name}
className={`flex items-start space-x-3 rounded-lg border p-4 cursor-pointer transition-colors ${
selectedGateway === framework.name
? "border-primary bg-primary/5"
: "border-border hover:bg-accent"
}`}
onClick={() => handleSelectGateway(framework.name)}
>
<RadioGroupItem value={framework.name} id={framework.name} className="mt-1" />
<div className="flex-1 space-y-1">
<Label htmlFor={framework.name} className="flex items-center gap-2 cursor-pointer">
<Icon className="h-4 w-4" />
<span className="font-semibold">{framework.name}</span>
<span className="text-xs text-muted-foreground">- {framework.fullName}</span>
</Label>
<p className="text-sm text-muted-foreground">{framework.description}</p>
</div>
</div>
)
})}
</RadioGroup>
</div>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => setShowGatewayDialog(false)}>
{t("取消", "Cancel")}
</Button>
<Button onClick={() => handleSelectGateway(selectedGateway)} disabled={!selectedGateway}>
{t("确认选择", "Confirm")}
</Button>
</div>
</DialogContent>
</Dialog>
</div>
</div>
@@ -323,11 +248,11 @@ export default function ModelGatewayPage() {
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{frameworksToUse.map((framework) => {
const Icon = framework.icon
{gatewayTypes.map((gateway) => {
const Icon = gateway.icon
return (
<div
key={framework.name}
key={gateway.name}
className="flex items-center justify-between rounded-lg border border-border bg-card p-4"
>
<div className="flex items-center gap-4 flex-1">
@@ -336,22 +261,14 @@ export default function ModelGatewayPage() {
</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<h3 className="font-semibold text-lg">{framework.name}</h3>
<Badge className="bg-green-500/10 text-green-500 text-xs">{framework.status}</Badge>
<h3 className="font-semibold text-lg">{gateway.name}</h3>
<Badge className="bg-green-500/10 text-green-500 text-xs">active</Badge>
</div>
<p className="text-sm text-muted-foreground mb-1">{framework.fullName}</p>
<p className="text-xs text-muted-foreground">{framework.description}</p>
<p className="text-sm text-muted-foreground mb-1">{gateway.fullName}</p>
<p className="text-xs text-muted-foreground">{gateway.description}</p>
</div>
</div>
<div className="flex items-center gap-6">
<div className="text-right">
<div className="text-2xl font-bold">{framework.endpoints}</div>
<p className="text-xs text-muted-foreground">{t("端点", "Endpoints")}</p>
</div>
<div className="text-right">
<div className="text-2xl font-bold">{framework.usage}%</div>
<p className="text-xs text-muted-foreground">{t("使用率", "Usage")}</p>
</div>
<Button variant="outline" size="sm">
{t("查看文档", "View Docs")}
</Button>
@@ -361,24 +278,6 @@ export default function ModelGatewayPage() {
})}
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>{t("网关使用分布", "Gateway Usage Distribution")}</CardTitle>
<CardDescription>{t("各网关的请求占比", "Request distribution by gateway")}</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{frameworksToUse.map((framework) => (
<div key={framework.name}>
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">{framework.name}</span>
<span className="text-sm text-muted-foreground">{framework.usage}%</span>
</div>
<Progress value={framework.usage} className="h-2" />
</div>
))}
</CardContent>
</Card>
</TabsContent>
<TabsContent value="monitoring" className="space-y-4">
+39 -38
View File
@@ -1,6 +1,7 @@
"use client"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { DashboardLayout } from "@/components/dashboard-layout"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
@@ -9,6 +10,7 @@ import { Network, Plus, Play, Save, Trash2, ArrowRight } from "lucide-react"
import { useLanguage } from "@/hooks/useLanguage"
import { TaijiAPIClient } from "@/lib/api-client"
import { useToast } from "@/hooks/use-toast"
import { isAuthenticated } from "@/lib/auth"
import {
Dialog,
DialogContent,
@@ -23,6 +25,7 @@ import { Input } from "@/components/ui/input"
export default function OrchestrationPage() {
const { t } = useLanguage()
const { toast } = useToast()
const router = useRouter()
const [showCreateDialog, setShowCreateDialog] = useState(false)
const [workflowNodes, setWorkflowNodes] = useState<string[]>([])
const [workflowName, setWorkflowName] = useState("")
@@ -32,8 +35,14 @@ export default function OrchestrationPage() {
const [workflows, setWorkflows] = useState<any[]>([])
useEffect(() => {
// 检查认证
if (!isAuthenticated()) {
router.push("/login")
return
}
loadData()
}, [])
}, [router])
const loadData = async () => {
try {
@@ -62,20 +71,6 @@ export default function OrchestrationPage() {
}
}
const defaultAvailableAgents = [
{ id: "weather-agent", name: t("天气查询Agent", "Weather Query Agent"), icon: "🌤️" },
{ id: "data-analysis-agent", name: t("数据分析Agent", "Data Analysis Agent"), icon: "📊" },
{ id: "doc-processor-agent", name: t("文档处理Agent", "Document Processing Agent"), icon: "📄" },
{ id: "email-agent", name: t("邮件管理Agent", "Email Management Agent"), icon: "📧" },
{ id: "api-integration-agent", name: t("API集成Agent", "API Integration Agent"), icon: "🔌" },
{ id: "database-agent", name: t("数据库操作Agent", "Database Operations Agent"), icon: "🗄️" },
{ id: "custom-agent-1", name: t("我的自定义Agent 1", "My Custom Agent 1"), icon: "⚙️", custom: true },
{ id: "custom-agent-2", name: t("我的自定义Agent 2", "My Custom Agent 2"), icon: "⚙️", custom: true },
]
// 使用真实数据或默认数据
const agentsToUse = availableAgents.length > 0 ? availableAgents : defaultAvailableAgents
const addNode = (agentId: string) => {
if (workflowNodes.length < 3 && !workflowNodes.includes(agentId)) {
setWorkflowNodes([...workflowNodes, agentId])
@@ -160,7 +155,7 @@ export default function OrchestrationPage() {
{loading ? (
<span className="inline-block h-7 w-8 animate-pulse bg-muted rounded" />
) : (
agentsToUse.length
availableAgents.length
)}
</div>
<p className="text-xs text-muted-foreground mt-1">{t("平台和自定义", "Platform & Custom")}</p>
@@ -302,26 +297,32 @@ export default function OrchestrationPage() {
<div className="space-y-2">
<Label>{t("选择Agent(最多3个)", "Select Agents (max 3)")}</Label>
<div className="grid grid-cols-2 gap-2 max-h-64 overflow-y-auto p-1">
{agentsToUse.map((agent) => (
<button
key={agent.id}
onClick={() => addNode(agent.id)}
disabled={workflowNodes.length >= 3 || workflowNodes.includes(agent.id)}
className="flex items-center gap-3 p-3 rounded-lg border border-border hover:border-primary hover:bg-primary/5 disabled:opacity-50 disabled:cursor-not-allowed transition-colors text-left"
>
<span className="text-2xl">{agent.icon}</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">{agent.name}</p>
{agent.custom && (
<Badge variant="secondary" className="text-xs mt-1">
{t("自定义", "Custom")}
</Badge>
)}
</div>
</button>
))}
</div>
{availableAgents.length === 0 ? (
<div className="text-center py-8 text-muted-foreground border border-dashed rounded-lg">
{t("暂无可用Agent", "No agents available")}
</div>
) : (
<div className="grid grid-cols-2 gap-2 max-h-64 overflow-y-auto p-1">
{availableAgents.map((agent) => (
<button
key={agent.id}
onClick={() => addNode(agent.id)}
disabled={workflowNodes.length >= 3 || workflowNodes.includes(agent.id)}
className="flex items-center gap-3 p-3 rounded-lg border border-border hover:border-primary hover:bg-primary/5 disabled:opacity-50 disabled:cursor-not-allowed transition-colors text-left"
>
<span className="text-2xl">{agent.icon}</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">{agent.name}</p>
{agent.custom && (
<Badge variant="secondary" className="text-xs mt-1">
{t("自定义", "Custom")}
</Badge>
)}
</div>
</button>
))}
</div>
)}
</div>
<div className="space-y-2">
@@ -334,7 +335,7 @@ export default function OrchestrationPage() {
) : (
<div className="flex items-center justify-center gap-2">
{workflowNodes.map((nodeId, index) => {
const agent = agentsToUse.find((a) => a.id === nodeId)
const agent = availableAgents.find((a) => a.id === nodeId)
return (
<div key={index} className="flex items-center gap-2">
<div className="relative group">
@@ -377,7 +378,7 @@ export default function OrchestrationPage() {
name: workflowName,
gateway: selectedGateway as "MCP" | "A2A" | "API",
nodes: workflowNodes.map((nodeId, index) => {
const agent = agentsToUse.find((a) => a.id === nodeId)
const agent = availableAgents.find((a) => a.id === nodeId)
return {
agentId: nodeId,
agentType: agent?.type === "custom" ? "custom" : "platform",
+8 -1
View File
@@ -1,6 +1,6 @@
"use client"
import { useEffect } from "react"
import { useEffect, useState } from "react"
import { useRouter } from "next/navigation"
import { isAuthenticated } from "@/lib/auth"
import { DashboardLayout } from "@/components/dashboard-layout"
@@ -8,13 +8,20 @@ import { DashboardOverview } from "@/components/dashboard-overview"
export default function Home() {
const router = useRouter()
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
if (!isAuthenticated()) {
router.push("/login")
}
}, [router])
// 在客户端挂载前返回 null,避免 Hydration 错误
if (!mounted) {
return null
}
if (!isAuthenticated()) {
return null
}
+38 -10
View File
@@ -1,8 +1,8 @@
"use client"
import { useEffect } from "react"
import { useEffect, useState } from "react"
import { useRouter, usePathname } from "next/navigation"
import { isAuthenticated } from "@/lib/auth"
import { isAuthenticated, isAdminAuthenticated, isChannelAuthenticated } from "@/lib/auth"
interface AuthGuardProps {
children: React.ReactNode
@@ -13,15 +13,33 @@ interface AuthGuardProps {
export function AuthGuard({ children, requireAuth = true, redirectTo = "/login" }: AuthGuardProps) {
const router = useRouter()
const pathname = usePathname()
const [mounted, setMounted] = useState(false)
const [isAuth, setIsAuth] = useState(false)
// 检查是否是登录页面
const isLoginPage = pathname === "/login" || pathname === "/channel/login" || pathname === "/admin/login"
const isAdminPage = pathname.startsWith("/admin")
const isChannelPage = pathname.startsWith("/channel")
useEffect(() => {
setMounted(true)
// 根据页面类型检查对应的认证状态
let auth = false
if (isAdminPage) {
auth = isAdminAuthenticated()
} else if (isChannelPage) {
auth = isChannelAuthenticated()
} else {
auth = isAuthenticated()
}
setIsAuth(auth)
// 登录页面不需要认证
if (isLoginPage) {
// 如果已登录,重定向到首页
if (isAuthenticated()) {
// 如果已登录,重定向到对应的首页
if (auth) {
if (pathname === "/channel/login") {
router.push("/channel/dashboard")
} else if (pathname === "/admin/login") {
@@ -34,20 +52,30 @@ export function AuthGuard({ children, requireAuth = true, redirectTo = "/login"
}
// 需要认证的页面
if (requireAuth && !isAuthenticated()) {
if (requireAuth && !auth) {
// 根据路径判断重定向到哪个登录页
if (pathname.startsWith("/channel")) {
if (isChannelPage) {
router.push("/channel/login")
} else if (pathname.startsWith("/admin")) {
} else if (isAdminPage) {
router.push("/admin/login")
} else {
router.push(redirectTo)
}
}
}, [pathname, requireAuth, redirectTo, router, isLoginPage])
}, [pathname, requireAuth, redirectTo, router, isLoginPage, isAdminPage, isChannelPage])
// 在客户端挂载前,返回一个占位符以避免 Hydration 错误
if (!mounted) {
// 登录页面在挂载前直接渲染
if (isLoginPage) {
return <>{children}</>
}
// 其他页面在挂载前返回 null(等待客户端检查)
return null
}
// 如果是登录页面且已登录,不渲染内容(等待重定向)
if (isLoginPage && isAuthenticated()) {
if (isLoginPage && isAuth) {
return null
}
@@ -57,7 +85,7 @@ export function AuthGuard({ children, requireAuth = true, redirectTo = "/login"
}
// 如果需要认证但未登录,不渲染内容(等待重定向)
if (requireAuth && !isAuthenticated()) {
if (requireAuth && !isAuth) {
return null
}
+9 -3
View File
@@ -55,16 +55,22 @@ export function DashboardLayout({ children }: { children: React.ReactNode }) {
const pathname = usePathname()
const { language, setLanguage, t } = useLanguage()
const [showApiKeyDialog, setShowApiKeyDialog] = useState(false)
// 使用固定的初始值,避免服务器端和客户端不一致
const [apiKey, setApiKey] = useState("sk_live_1234567890abcdefghijklmnopqrstuvwxyz")
const [serviceEndpoint, setServiceEndpoint] = useState("https://api.taiji-ai.com/v1")
const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text)
if (typeof window !== "undefined" && navigator.clipboard) {
navigator.clipboard.writeText(text)
}
}
const regenerateApiKey = () => {
const newKey = `sk_live_${Math.random().toString(36).substring(2, 15)}${Math.random().toString(36).substring(2, 15)}`
setApiKey(newKey)
// 只在客户端执行,确保服务器端和客户端一致
if (typeof window !== "undefined") {
const newKey = `sk_live_${Math.random().toString(36).substring(2, 15)}${Math.random().toString(36).substring(2, 15)}`
setApiKey(newKey)
}
}
return (
+3 -1
View File
@@ -14,11 +14,13 @@ interface LanguageContextType {
const LanguageContext = createContext<LanguageContextType | undefined>(undefined)
export function LanguageProvider({ children }: { children: React.ReactNode }) {
// 始终从 "zh" 开始,确保服务器端和客户端初始状态一致
const [language, setLanguage] = useState<Language>("zh")
useEffect(() => {
// 只在客户端挂载后读取 localStorage
const savedLang = localStorage.getItem("language") as Language
if (savedLang) {
if (savedLang && (savedLang === "zh" || savedLang === "en")) {
setLanguage(savedLang)
}
}, [])
-175
View File
@@ -1,175 +0,0 @@
# API 客户端对接完成总结
## ✅ 已完成的工作
### 1. API 客户端完整实现 (`lib/api-client.ts`)
已根据后端 API 接口文档完整实现了所有接口方法,包括:
#### 认证模块 API (6个方法)
- ✅ `login()` - 用户登录
- ✅ `logout()` - 用户登出
- ✅ `refreshToken()` - 刷新Token
- ✅ `changePassword()` - 修改密码
- ✅ `getApiKeyInfo()` - 获取API密钥信息
- ✅ `regenerateApiKey()` - 重新生成API密钥
#### 用户侧平台 API (14个方法)
- ✅ `getUserDashboardStats()` - 获取仪表板统计
- ✅ `getUserAgentActivity()` - 获取Agent活动数据
- ✅ `selectGateway()` - 选择网关类型
- ✅ `createGatewayAPI()` - 创建网关API
- ✅ `getGatewayAPIs()` - 获取网关API列表
- ✅ `getGatewayMonitoring()` - 获取网关监控数据
- ✅ `generateTool()` - 生成工具
- ✅ `createDataTemplate()` - 创建数据模板
- ✅ `getPlatformAgents()` - 获取平台Agent列表
- ✅ `deployAgent()` - 部署Agent
- ✅ `createWorkflow()` - 创建工作流
- ✅ `getBillingBalance()` - 获取余额信息
- ✅ `rechargeBalance()` - 充值余额
- ✅ `getBillingHistory()` - 获取计费历史
#### 渠道合作伙伴 API (8个方法)
- ✅ `getChannelTenants()` - 获取租户列表
- ✅ `createChannelTenant()` - 创建租户
- ✅ `allocateTenantResources()` - 分配租户资源
- ✅ `updateTenantBilling()` - 更新租户计费设置
- ✅ `rechargeTenant()` - 为租户充值
- ✅ `setTenantCreditLimit()` - 设置租户授信额度
- ✅ `applyForResources()` - 申请资源
- ✅ `getChannelBillingStats()` - 获取渠道计费统计
#### 超级管理员 API (10个方法)
- ✅ `getAdminDashboardStats()` - 获取平台统计
- ✅ `getAdminChannels()` - 获取渠道列表
- ✅ `createAdminChannel()` - 创建渠道
- ✅ `manageChannelResources()` - 统一管理渠道资源
- ✅ `getAdminApplications()` - 获取所有申请
- ✅ `reviewApplication()` - 审批申请
- ✅ `getAdminModelProviders()` - 获取所有模型供应商
- ✅ `getAdminAgentResources()` - 获取所有Agent资源
- ✅ `getAdminAgentMonitoring()` - 监控Agent健康状态
- ✅ `getAdminBillingOverview()` - 获取三维度计费统计
#### 供应商管理 API (6个方法)
- ✅ `getModelProviders()` - 获取模型供应商列表
- ✅ `createModelProvider()` - 创建模型供应商
- ✅ `getProviderDetails()` - 获取供应商详情
- ✅ `updateProvider()` - 更新供应商配置
- ✅ `deleteProvider()` - 删除供应商
- ✅ `testProviderConnection()` - 测试供应商连接
#### Data Ingestion 服务 API (12个方法)
- ✅ `getHealth()` - 健康检查
- ✅ `syncRapidAPI()` - 同步RapidAPI
- ✅ `testRapidAPI()` - 测试RapidAPI端点
- ✅ `parseOpenAPI()` - 解析OpenAPI规范
- ✅ `processAPILLAMA()` - APILLAMA处理API文档
- ✅ `generateTool()` - 生成工具定义
- ✅ `getTools()` - 获取工具列表
- ✅ `getTool()` - 获取特定工具定义
- ✅ `deleteTool()` - 删除工具
- ✅ `getStats()` - 获取统计信息
- ✅ `clearCache()` - 清除缓存
- ✅ `getMetrics()` - 获取Prometheus Metrics
#### MCP Server 服务 API (11个方法)
- ✅ `getMCPHealth()` - MCP Server健康检查
- ✅ `registerAgent()` - 注册Agent
- ✅ `getAgents()` - 获取Agent列表
- ✅ `getAgent()` - 获取特定Agent
- ✅ `executeAgentTool()` - 执行Agent工具
- ✅ `getMCPTools()` - 获取工具列表
- ✅ `getMCPMetrics()` - 获取MCP Prometheus Metrics
- ✅ `getMonitoringMetrics()` - 获取系统性能指标
- ✅ `getMonitoringStats()` - 获取服务统计信息
- ✅ `getMonitoringTrends()` - 获取性能趋势数据
- ✅ `getMonitoringAlerts()` - 获取系统告警
- ✅ `getMonitoringDashboard()` - 获取监控仪表盘聚合
#### WebSocket API (1个方法)
- ✅ `createAgentWebSocket()` - 创建Agent WebSocket连接
### 2. 核心功能实现
#### 认证 Token 管理
- ✅ 自动保存 Token 到 localStorage
- ✅ 自动在请求头中添加 Authorization
- ✅ 支持 JWT Token 和 API Key 双认证
- ✅ 自动处理 Token 刷新
#### 错误处理
- ✅ 统一的错误处理机制
- ✅ 类型安全的响应处理
- ✅ 友好的错误提示
#### 类型定义
- ✅ 导出 `APIResponse` 类型供外部使用
- ✅ 完整的 TypeScript 类型支持
### 3. 登录页面集成
- ✅ 更新登录页面使用新的 API 客户端
- ✅ 添加错误处理和用户提示
- ✅ 集成 toast 通知
### 4. 文档
- ✅ 创建 API 集成说明文档 (`docs/API_INTEGRATION.md`)
- ✅ 包含所有 API 方法的使用示例
- ✅ 包含错误处理、认证管理等说明
## 📋 使用示例
### 基本使用
```typescript
import { TaijiAPIClient } from "@/lib/api-client"
// 登录
const result = await TaijiAPIClient.login("user@example.com", "password", "user")
// 获取仪表板统计
const stats = await TaijiAPIClient.getUserDashboardStats()
// 部署Agent
await TaijiAPIClient.deployAgent({
agentId: "agent-uuid",
instances: 3,
model: "gpt-4o-mini",
gateway: "MCP"
})
```
## 🔧 配置
在 `.env.local` 文件中配置 API 端点:
```bash
NEXT_PUBLIC_DATA_INGESTION_URL=http://localhost:8001
NEXT_PUBLIC_MCP_SERVER_URL=http://localhost:8000
NEXT_PUBLIC_API_GATEWAY_URL=http://localhost:80
```
## 📝 注意事项
1. **环境变量**: 确保设置了正确的 API 端点 URL
2. **CORS**: 开发环境需要后端配置 CORS
3. **错误处理**: 所有 API 调用都应该有错误处理
4. **Token 管理**: Token 自动管理,无需手动处理
5. **类型安全**: 使用 TypeScript 类型检查
## 🚀 下一步
1. 在各个页面组件中集成 API 调用
2. 替换现有的模拟数据为真实 API 调用
3. 添加加载状态和错误处理
4. 实现数据缓存和优化
## 📚 相关文档
- API 集成说明: `docs/API_INTEGRATION.md`
- 后端 API 文档: `/tools/taiji-AI-PAD/Docs/前后端调试说明/API接口文档.md`
- 后端需求文档: `docs/backend-api-requirements.md`
-295
View File
@@ -1,295 +0,0 @@
# API 集成说明
本文档说明如何在前端项目中使用后端 API 接口。
## 环境配置
在项目根目录创建 `.env.local` 文件(或使用 `.env.example` 作为模板):
```bash
NEXT_PUBLIC_DATA_INGESTION_URL=http://localhost:8001
NEXT_PUBLIC_MCP_SERVER_URL=http://localhost:8000
NEXT_PUBLIC_API_GATEWAY_URL=http://localhost:80
```
## API 客户端使用
### 导入 API 客户端
```typescript
import { TaijiAPIClient } from "@/lib/api-client"
```
### 认证相关
#### 登录
```typescript
try {
const result = await TaijiAPIClient.login("user@example.com", "password", "user")
if (result.success) {
// Token 已自动保存到 localStorage
console.log("登录成功", result.data.user)
}
} catch (error) {
console.error("登录失败", error)
}
```
#### 登出
```typescript
await TaijiAPIClient.logout()
// Token 已自动清除
```
#### 刷新 Token
```typescript
await TaijiAPIClient.refreshToken()
```
### 用户侧平台 API
#### 获取仪表板统计
```typescript
const stats = await TaijiAPIClient.getUserDashboardStats()
console.log(stats.data.activeAgents)
```
#### 部署 Agent
```typescript
const result = await TaijiAPIClient.deployAgent({
agentId: "agent-uuid",
instances: 3,
model: "gpt-4o-mini",
gateway: "MCP"
})
```
#### 创建工作流
```typescript
const workflow = await TaijiAPIClient.createWorkflow({
name: "订单处理流程",
gateway: "MCP",
nodes: [
{
agentId: "agent-1",
agentType: "platform",
agentName: "订单验证Agent",
order: 1
}
]
})
```
#### 获取计费历史
```typescript
const history = await TaijiAPIClient.getBillingHistory({
startTime: "2025-01-01T00:00:00Z",
endTime: "2025-01-31T23:59:59Z",
page: 1,
pageSize: 20
})
```
### 渠道合作伙伴 API
#### 获取租户列表
```typescript
const tenants = await TaijiAPIClient.getChannelTenants()
```
#### 创建租户
```typescript
const tenant = await TaijiAPIClient.createChannelTenant({
name: "企业客户A",
email: "contact@company-a.com",
password: "securepass123",
subscriptionTier: "enterprise"
})
```
#### 分配租户资源
```typescript
await TaijiAPIClient.allocateTenantResources("tenant-id", {
agents: [
{ agentId: "agent-1", quantity: 10 }
],
models: [
{ modelName: "gpt-4", rpm: 10000, tpm: 500000 }
],
customAgentResources: {
cpu: 2.0,
memory: 4.0
}
})
```
### 超级管理员 API
#### 获取平台统计
```typescript
const stats = await TaijiAPIClient.getAdminDashboardStats()
```
#### 创建渠道
```typescript
const channel = await TaijiAPIClient.createAdminChannel({
name: "合作渠道A",
email: "partner@channel-a.com",
password: "channelpass123",
commissionRate: 10.0
})
```
#### 审批申请
```typescript
await TaijiAPIClient.reviewApplication("application-id", true, "审批通过")
```
### 供应商管理 API
#### 获取模型供应商列表
```typescript
const providers = await TaijiAPIClient.getModelProviders()
```
#### 创建模型供应商
```typescript
const provider = await TaijiAPIClient.createModelProvider({
name: "OpenAI",
provider: "openai",
apiUrl: "https://api.openai.com/v1",
apiKey: "sk-xxxxx",
supportedModels: ["gpt-4", "gpt-4o-mini"],
rpm: 3500,
tpm: 90000
})
```
### Data Ingestion 服务 API
#### 获取健康状态
```typescript
const health = await TaijiAPIClient.getHealth()
```
#### 同步 RapidAPI
```typescript
await TaijiAPIClient.syncRapidAPI("weather", 100)
```
#### 处理 APILLAMA
```typescript
const result = await TaijiAPIClient.processAPILLAMA(
{ title: "Weather API", description: "Get weather" },
{ service: "Weather service" },
"json_schema"
)
```
#### 获取工具列表
```typescript
const tools = await TaijiAPIClient.getTools("weather", 100, 0)
```
### MCP Server API
#### 注册 Agent
```typescript
const agent = await TaijiAPIClient.registerAgent({
name: "weather-agent",
description: "Weather information agent",
capabilities: ["weather_query"]
})
```
#### 获取 Agent 列表
```typescript
const agents = await TaijiAPIClient.getAgents(0, 100)
```
#### 执行 Agent 工具
```typescript
const result = await TaijiAPIClient.executeAgentTool("agent-id", {
method: "tools/call",
params: {
tool: { name: "math_add", function_name: "math_add" },
arguments: { a: 10, b: 20 }
}
})
```
### WebSocket 连接
```typescript
const ws = TaijiAPIClient.createAgentWebSocket("agent-id")
ws.onopen = () => {
console.log("WebSocket connected")
ws.send(JSON.stringify({
type: "mcp_request",
payload: {
method: "tools/list",
params: {}
}
}))
}
ws.onmessage = (event) => {
const data = JSON.parse(event.data)
console.log("Received:", data)
}
```
## 错误处理
所有 API 方法都会抛出错误,建议使用 try-catch 处理:
```typescript
try {
const result = await TaijiAPIClient.getUserDashboardStats()
// 处理成功结果
} catch (error: any) {
console.error("API Error:", error.message)
// 显示错误提示给用户
}
```
## 认证 Token 管理
API 客户端会自动管理认证 Token:
- **登录时**: Token 自动保存到 `localStorage`
- **请求时**: Token 自动添加到请求头 `Authorization: Bearer <token>`
- **登出时**: Token 自动清除
如果需要手动获取 Token:
```typescript
const token = localStorage.getItem("auth_token")
```
## API Key 认证
除了 JWT Token,还支持 API Key 认证:
```typescript
// 设置 API Key
localStorage.setItem("api_key", "sk-xxxxx")
// API 客户端会自动使用 API Key
const result = await TaijiAPIClient.getUserDashboardStats()
```
## 注意事项
1. **环境变量**: 确保设置了正确的 API 端点 URL
2. **CORS**: 开发环境需要后端配置 CORS 允许前端域名
3. **错误处理**: 所有 API 调用都应该有错误处理
4. **Token 过期**: 如果 Token 过期,需要重新登录或刷新 Token
5. **类型安全**: API 客户端使用 TypeScript,建议启用类型检查
## 相关文档
- 后端 API 接口文档: `/tools/taiji-AI-PAD/Docs/前后端调试说明/API接口文档.md`
- 后端需求文档: `/tools/taiji-pad-v0/docs/backend-api-requirements.md`
+219
View File
@@ -0,0 +1,219 @@
# Taiji AI PAD 前端 API 接口状态文档
**更新时间**: 2025年1月
**前端项目**: taiji-pad-v0
**后端服务**:
- MCP Server: `http://localhost:8002`
- Data Ingestion: `http://localhost:8001`
---
## 📊 总体状态
| 模块 | 接口数量 | 状态 |
|------|----------|------|
| 认证模块 | 6 | ✅ 全部已实现 |
| 用户侧平台 | 14 | ✅ 全部已实现 |
| 渠道合作伙伴 | 8 | ✅ 全部已实现 |
| 超级管理员 | 12 | ✅ 全部已实现 |
| 供应商管理 | 6 | ✅ 全部已实现 |
| Data Ingestion | 12 | ✅ 全部已实现 |
| MCP Server 核心 | 7 | ✅ 全部已实现 |
| 监控 API | 5 | ✅ 全部已实现 |
| WebSocket | 1 | ✅ 已实现 |
| **总计** | **71** | **✅ 全部已实现** |
---
## ✅ API 接口清单
### 1. 认证模块 API (`/api/auth`)
| 接口 | 方法 | 路径 | 状态 | 说明 |
|------|------|------|------|------|
| 用户登录 | POST | `/api/auth/login` | ✅ | 支持多角色登录 |
| 用户登出 | POST | `/api/auth/logout` | ✅ | 清除token |
| 刷新Token | POST | `/api/auth/refresh` | ✅ | 刷新访问令牌 |
| 修改密码 | PUT | `/api/auth/password` | ✅ | 修改用户密码 |
| 获取API密钥信息 | GET | `/api/auth/keys/info` | ✅ | 获取当前用户API密钥 |
| 重新生成API密钥 | POST | `/api/auth/keys/regenerate` | ✅ | 重新生成API密钥 |
---
### 2. 用户侧平台 API (`/api/user`)
| 接口 | 方法 | 路径 | 状态 | 说明 |
|------|------|------|------|------|
| 获取仪表板统计 | GET | `/api/user/dashboard/stats` | ✅ | 概览数据 |
| 获取Agent活动数据 | GET | `/api/user/agents/activity` | ✅ | 支持7d/30d/90d周期 |
| 选择网关类型 | POST | `/api/user/gateway/select` | ✅ | MCP/A2A/API |
| 创建网关API | POST | `/api/user/gateway/api/create` | ✅ | 创建自定义API |
| 获取网关API列表 | GET | `/api/user/gateway/apis` | ✅ | 列表查询 |
| 获取网关监控数据 | GET | `/api/user/gateway/monitoring` | ✅ | 监控信息 |
| 生成工具 | POST | `/api/user/tools/generate` | ✅ | 工具生成 |
| 创建数据模板 | POST | `/api/user/data-templates/create` | ✅ | JSON API/云存储 |
| 获取平台Agent列表 | GET | `/api/user/agents/platform` | ✅ | 平台Agent |
| 部署Agent | POST | `/api/user/agents/deploy` | ✅ | Agent部署 |
| 创建工作流 | POST | `/api/user/workflows/create` | ✅ | 最多3节点 |
| 获取余额信息 | GET | `/api/user/billing/balance` | ✅ | 余额查询 |
| 充值余额 | POST | `/api/user/billing/recharge` | ✅ | 支付宝/微信/卡 |
| 获取计费历史 | GET | `/api/user/billing/history` | ✅ | 支持导出 |
---
### 3. 渠道合作伙伴 API (`/api/channel`)
| 接口 | 方法 | 路径 | 状态 | 说明 |
|------|------|------|------|------|
| 获取租户列表 | GET | `/api/channel/tenants` | ✅ | 渠道下租户 |
| 创建租户 | POST | `/api/channel/tenants/create` | ✅ | 创建新租户 |
| 分配租户资源 | PUT | `/api/channel/tenants/{id}/resources` | ✅ | Agent/模型资源 |
| 更新租户计费设置 | PUT | `/api/channel/tenants/{id}/billing` | ✅ | 订阅级别/折扣 |
| 为租户充值 | POST | `/api/channel/tenants/{id}/recharge` | ✅ | 充值操作 |
| 设置租户授信额度 | PUT | `/api/channel/tenants/{id}/credit` | ✅ | 授信额度 |
| 申请资源 | POST | `/api/channel/resources/apply` | ✅ | 模型/Agent申请 |
| 获取渠道计费统计 | GET | `/api/channel/billing/stats` | ✅ | 支持导出 |
---
### 4. 超级管理员 API (`/api/admin`)
| 接口 | 方法 | 路径 | 状态 | 说明 |
|------|------|------|------|------|
| 获取平台统计 | GET | `/api/admin/dashboard/stats` | ✅ | 平台总览 |
| 创建管理员 | POST | `/api/admin/admins/create` | ✅ | 计费/运营管理员 |
| 获取渠道列表 | GET | `/api/admin/channels` | ✅ | 所有渠道 |
| 创建渠道 | POST | `/api/admin/channels/create` | ✅ | 新建渠道 |
| 管理渠道资源 | PUT | `/api/admin/channels/{id}/resources` | ✅ | 统一资源管理 |
| 获取所有申请 | GET | `/api/admin/channels/applications` | ✅ | 申请列表 |
| 审批申请 | PUT | `/api/admin/channels/applications/{id}/review` | ✅ | 批准/拒绝 |
| 获取模型供应商 | GET | `/api/admin/resources/models` | ✅ | 模型供应商列表 |
| 获取Agent资源 | GET | `/api/admin/resources/agents` | ✅ | Agent资源列表 |
| 删除Agent资源 | DELETE | `/api/admin/resources/agents/{id}` | ✅ | 删除Agent |
| 监控Agent健康 | GET | `/api/admin/monitoring/agents` | ✅ | Agent监控 |
| 获取计费概览 | GET | `/api/admin/billing/overview` | ✅ | 三维度计费 |
---
### 5. 供应商管理 API (`/api/providers`)
| 接口 | 方法 | 路径 | 状态 | 说明 |
|------|------|------|------|------|
| 获取模型供应商列表 | GET | `/api/providers/models` | ✅ | 供应商列表 |
| 创建模型供应商 | POST | `/api/providers/models/create` | ✅ | 新建供应商 |
| 获取供应商详情 | GET | `/api/providers/models/{id}` | ✅ | 详情查询 |
| 更新供应商配置 | PUT | `/api/providers/models/{id}` | ✅ | 更新配置 |
| 删除供应商 | DELETE | `/api/providers/models/{id}` | ✅ | 删除供应商 |
| 测试供应商连接 | POST | `/api/providers/models/{id}/test` | ✅ | 连接测试 |
---
### 6. Data Ingestion 服务 API (`:8001`)
| 接口 | 方法 | 路径 | 状态 | 说明 |
|------|------|------|------|------|
| 健康检查 | GET | `/health` | ✅ | 服务状态 |
| 同步RapidAPI | POST | `/rapidapi/sync` | ✅ | 后台同步 |
| 测试RapidAPI | POST | `/rapidapi/test` | ✅ | 端点测试 |
| 解析OpenAPI | POST | `/openapi/parse` | ✅ | OpenAPI解析 |
| APILLAMA处理 | POST | `/apillama/process` | ✅ | API文档处理 |
| 生成工具定义 | POST | `/tools/generate` | ✅ | 工具生成 |
| 获取工具列表 | GET | `/tools` | ✅ | 工具查询 |
| 获取工具定义 | GET | `/tools/{name}` | ✅ | 工具详情 |
| 删除工具 | DELETE | `/tools/{name}` | ✅ | 工具删除 |
| 获取统计信息 | GET | `/stats` | ✅ | 统计数据 |
| 清除缓存 | POST | `/cache/clear` | ✅ | 清理缓存 |
| Prometheus Metrics | GET | `/metrics` | ✅ | 监控指标 |
---
### 7. MCP Server 服务 API (`:8002`)
| 接口 | 方法 | 路径 | 状态 | 说明 |
|------|------|------|------|------|
| 健康检查 | GET | `/health` | ✅ | 服务状态 |
| 注册Agent | POST | `/agents` | ✅ | 新建Agent |
| 获取Agent列表 | GET | `/agents` | ✅ | Agent列表 |
| 获取Agent详情 | GET | `/agents/{id}` | ✅ | Agent详情 |
| 执行Agent工具 | POST | `/agents/{id}/execute` | ✅ | 工具执行 |
| 获取工具列表 | GET | `/tools` | ✅ | MCP工具列表 |
| Prometheus Metrics | GET | `/metrics` | ✅ | 监控指标 |
---
### 8. MCP 监控 API (`/api/v1/monitoring`)
| 接口 | 方法 | 路径 | 状态 | 说明 |
|------|------|------|------|------|
| 获取系统性能指标 | GET | `/api/v1/monitoring/metrics` | ✅ | CPU/内存/磁盘 |
| 获取服务统计 | GET | `/api/v1/monitoring/stats` | ✅ | 按服务聚合 |
| 获取性能趋势 | GET | `/api/v1/monitoring/trends` | ✅ | 时间区间趋势 |
| 获取系统告警 | GET | `/api/v1/monitoring/alerts` | ✅ | 告警列表 |
| 获取监控仪表盘 | GET | `/api/v1/monitoring/dashboard` | ✅ | 聚合数据 |
---
### 9. WebSocket API
| 接口 | 路径 | 状态 | 说明 |
|------|------|------|------|
| Agent WebSocket | `ws://localhost:8002/ws/{agent_id}` | ✅ | 实时通信 |
---
## 🧹 前端假数据清理记录
已删除以下硬编码的假数据,前端现在仅使用 API 返回的真实数据:
### 1. agent-factory/page.tsx
- ❌ 删除 `defaultPlatformAgents` 数组(包含6个假Agent:天气查询、数据分析、文档处理、邮件管理、API集成、数据库操作)
- ✅ 页面现在仅显示从 `/api/user/agents/platform` 获取的真实数据
- ✅ 无数据时显示空状态提示
### 2. model-gateway/page.tsx
- ❌ 删除 `defaultFrameworks` 数组中的假统计数据(endpoints: 8/5/6, usage: 42%/28%/30%)
- ✅ 保留网关类型定义(MCP/A2A/API)作为系统固定选项(非假数据)
- ✅ 移除了"网关使用分布"假图表
### 3. orchestration/page.tsx
- ❌ 删除 `defaultAvailableAgents` 数组(包含8个假Agent)
- ✅ 页面现在仅显示从 `/api/user/agents/platform` 获取的真实数据
- ✅ 无数据时显示空状态提示
### 4. data-tools/page.tsx
- ❌ 删除硬编码的 "3个已配置" 和 "5个已配置" Badge标签
---
## 🔧 角色权限映射
| 前端角色 | 后端role参数 | 登录入口 |
|----------|-------------|----------|
| 超级管理员 | `super_admin` | `/admin/login` |
| 计费管理员 | `billing_admin` | `/admin/login` |
| 运营管理员 | `operations_admin` | `/admin/login` |
| 渠道管理员 | `channel` | `/channel/login` |
| 租户用户 | `user` | `/login` |
---
## 📌 注意事项
1. **认证方式**: 所有需认证接口支持 `Authorization: Bearer <token>` 或 `X-API-Key: <api_key>`
2. **角色映射**: 前端系统权限与后端订阅级别映射
- `tenant` → `free`
- `admin` → `pro`
- `billing-admin` → `enterprise`
- `operations-admin` → `enterprise`
3. **数据空值处理**: 前端对返回数据做空值检查(如 `capabilities || []`)
4. **空状态显示**: 当 API 无返回数据时,前端显示友好的空状态提示,不再使用假数据回退
---
## 📅 更新日志
- **2025-01**: 清理前端所有假数据,确保页面仅使用 API 真实数据
- **2025-12-26**: 初始版本,整理71个已完成接口
+161
View File
@@ -0,0 +1,161 @@
# 缺失的 API 接口清单
根据前端代码和 API 文档的对比,以下接口在 API 文档中**没有提供**:
## 1. 删除 Agent 接口
**前端使用位置**: `/app/admin/dashboard/page.tsx` (资源管理标签页)
**当前实现**:
- 前端使用 `TaijiAPIClient.deleteTool(agent.id || agent.name)` 来删除 Agent
- 这个接口实际上是删除 Data Ingestion 服务中的工具,而不是删除 Agent 资源
**需要的接口**:
```
DELETE /api/admin/resources/agents/{agent_id}
```
**请求示例**:
```bash
curl -X DELETE "http://localhost:8002/api/admin/resources/agents/agent-uuid-1" \
-H "Authorization: Bearer <admin_token>"
```
**响应示例**:
```json
{
"success": true,
"message": "Agent资源已删除"
}
```
**说明**:
- 当前前端代码错误地使用了 `deleteTool` 接口来删除 Agent
- 应该提供一个专门的删除 Agent 资源的接口
- 删除应该是软删除,仅标记为不活跃
---
## 2. 删除渠道接口
**前端使用位置**: `/app/admin/dashboard/page.tsx` (渠道管理标签页)
**当前状态**:
- 前端UI中有"删除渠道"按钮,但没有实现对应的API调用
**需要的接口**:
```
DELETE /api/admin/channels/{channel_id}
```
**请求示例**:
```bash
curl -X DELETE "http://localhost:8002/api/admin/channels/channel-uuid-1" \
-H "Authorization: Bearer <admin_token>"
```
**响应示例**:
```json
{
"success": true,
"message": "渠道已删除"
}
```
**说明**:
- 删除渠道前应该检查是否有关联的租户
- 如果有租户,应该提示或阻止删除
- 删除应该是软删除,仅标记为不活跃
---
## 3. 更新渠道信息接口
**前端使用位置**: `/app/admin/dashboard/page.tsx` (渠道管理标签页)
**当前状态**:
- 前端可能有编辑渠道信息的功能,但需要确认是否有对应的API
**需要的接口**:
```
PUT /api/admin/channels/{channel_id}
```
**请求体**:
```json
{
"name": "合作渠道A(更新)",
"email": "new-email@channel-a.com",
"commissionRate": 12.0,
"status": "active"
}
```
**响应示例**:
```json
{
"success": true,
"data": {
"id": "channel-uuid-1",
"name": "合作渠道A(更新)",
"email": "new-email@channel-a.com"
},
"message": "渠道信息更新成功"
}
```
---
## 4. 更新 Agent 资源配置接口
**前端使用位置**: `/app/admin/dashboard/page.tsx` (资源管理标签页 - Agent资源配置对话框)
**当前状态**:
- 前端有配置 Agent CPU 和内存的对话框,但保存时没有调用API
**需要的接口**:
```
PUT /api/admin/resources/agents/{agent_id}/config
```
**请求体**:
```json
{
"cpu": 4.0,
"memory": 8.0,
"maxInstances": 10
}
```
**响应示例**:
```json
{
"success": true,
"message": "Agent资源配置更新成功"
}
```
---
## 总结
### 必须实现的接口(前端已使用):
1. ❌ **DELETE /api/admin/resources/agents/{agent_id}** - 删除Agent资源
- 当前前端错误地使用了 `deleteTool` 接口
### 建议实现的接口(前端UI已存在但未实现):
2. ❌ **DELETE /api/admin/channels/{channel_id}** - 删除渠道
3. ⚠️ **PUT /api/admin/channels/{channel_id}** - 更新渠道信息
4. ⚠️ **PUT /api/admin/resources/agents/{agent_id}/config** - 更新Agent资源配置
### 已实现的接口(前端已使用):
✅ 所有其他接口都已实现并在API文档中有说明
---
## 修复建议
1. **立即修复**: 实现 `DELETE /api/admin/resources/agents/{agent_id}` 接口,并更新前端代码使用正确的接口
2. **优先级高**: 实现 `DELETE /api/admin/channels/{channel_id}` 接口,完善渠道管理功能
3. **优先级中**: 实现渠道和Agent的更新接口,提升管理功能的完整性
-93
View File
@@ -1,93 +0,0 @@
# 前端菜单与API接口对照表
> 本文档自动生成,基于 `API接口文档.md` 与前端实际代码实现。
> 更新时间:2025-12-23
---
## 概览(/)
- 页面文件:app/page.tsx(渲染组件:components/dashboard-overview.tsx)
- 已接入接口:
- MCP Server 健康检查:`GET /health`(MCP Server)
- Data Ingestion 健康检查:`GET /health`(Data Ingestion)
- Agent 列表:`GET /agents`(MCP Server,参数:status、limit、offset)
- 缺失部分:
- 全局 API 调用、EU 消耗、模型提供商数量/健康等为静态,缺少统计接口。
- 建议后端能力:
- `GET /stats/global?range=24h|7d`、`GET /billing/eu/usage?range=24h|30d`、`GET /gateway/providers`、`GET /gateway/metrics`
## 数据与工具(/data-tools)
- 页面文件:app/data-tools/page.tsx
- 已接入接口:
- 工具列表:`GET /tools`(Data Ingestion,参数:category、limit、offset)
- 删除工具:`DELETE /tools/{tool_name}`(Data Ingestion)
- 统计信息:`GET /stats`(Data Ingestion)
- RapidAPI 同步:`POST /rapidapi/sync`(Data Ingestion,参数:category、limit)
- APILLAMA 处理:`POST /apillama/process`(Data Ingestion,body: api_doc, context, output_format)
- 生成工具定义:`POST /tools/generate`(Data Ingestion,body: url, method, name, description)
- 缺失部分:
- `POST /rapidapi/test`、`POST /openapi/parse`、`POST /cache/clear`、`GET /metrics`、`GET /tools/{tool_name}` 未接入。
- 建议后端能力:
- 所有接口统一 envelope 返回,删除工具返回元信息。
## 代理工厂(/agent-factory)
- 页面文件:app/agent-factory/page.tsx
- 已接入接口:
- Agent 列表:`GET /agents`(MCP Server,参数:status、limit、offset)
- 注册 Agent:`POST /agents`(MCP Server,body: name, description, capabilities, metadata)
- 执行 Agent 工具:`POST /agents/{agent_id}/execute`(MCP Server,body: tool_name, parameters, context)
- MCP 工具列表:`GET /tools`(MCP Server,参数:category、limit)
- 缺失部分:
- 暂停/删除 agent、Agent 详情页、WebSocket 交互未实现。
- 建议后端能力:
- `DELETE /agents/{agent_id}`、`POST /agents/{agent_id}/status`、`GET /agents/{agent_id}/executions`
## 模型网关(/model-gateway)
- 页面文件:app/model-gateway/page.tsx
- 已接入接口:无(全部为静态数据)
- 缺失部分:
- 所有数据均为静态。
- 建议后端能力:
- `GET /gateway/providers`、`GET /gateway/config`、`PUT /gateway/config`、`GET /gateway/metrics`
## 编排中心(/orchestration)
- 页面文件:app/orchestration/page.tsx
- 已接入接口:无(全部为静态数据)
- 缺失部分:
- 工作流列表、运行状态、NATS 吞吐、VM 池等均为静态。
- 建议后端能力:
- `GET /workflows`、`GET /workflows/{id}`、`POST /workflows/{id}/deploy`、`POST /workflows/{id}/stop`、`GET /orchestration/metrics`
## 计费与资源(/billing)
- 页面文件:app/billing/page.tsx
- 已接入接口:无(全部为静态数据)
- 缺失部分:
- EU 余额、历史消耗、成本拆分、资源配额等均为静态。
- 建议后端能力:
- `GET /billing/eu/balance`、`GET /billing/eu/history`、`GET /billing/cost/breakdown`、`GET /billing/invoices/{id}/download`
## 认证/渠道/租户/供应商管理(/admin、/channel、/login)
- 页面文件:app/admin/*、app/channel/*、app/login/page.tsx
- 已接入接口:无(全部为本地 mock 或静态)
- 缺失部分:
- 认证、渠道、租户、供应商管理等均无后端 API。
- 建议后端能力:
- `POST /auth/login`、`POST /auth/logout`、`GET/POST/PUT/DELETE /channels`、`GET/POST/PUT /tenants`、`GET/POST/PUT /providers`
---
# 前端设计缺陷与建议
1. **中英文切换问题**:部分页面(如登录、管理后台)存在中英文内容不一致、未全量覆盖、切换后内容未实时刷新等问题,建议:
- 统一使用国际化 hooks(如 useLanguage),所有文案均走 t() 方法。
- 检查所有页面的语言切换逻辑,确保切换后 UI 实时更新。
2. **页面缺少后端功能按钮**:如“查看详情”“暂停/删除 agent”“清缓存”“OpenAPI 解析”等功能无入口或无按钮,建议:
- 补充相关按钮和弹窗,未有后端接口时可先占位。
- 对于已建议的后端接口,前端可预留 UI 并注释说明。
3. **静态数据未动态化**:如概览、计费、模型网关等页面大量数据为静态,建议:
- 后端接口补齐后,前端需全部改为动态获取。
4. **API 错误处理与 envelope 兼容**:建议所有 API 调用均兼容 envelope 格式,前端统一处理 status/data/message/error。
---
> 详细接口与参数请参考 API接口文档.md。
-321
View File
@@ -1,321 +0,0 @@
# 前端菜单 ↔ API 接口对照(自动整理)
更新时间:2025-12-23
核对时间:2025-12-23(已逐项对照前端源码与 API 文档)
本文件用于回答:
- 前端每个菜单/功能使用了哪些后端接口、传了哪些参数
- 哪些菜单/功能目前没有对应后端接口(缺失项)
- 缺失项建议补充怎样的后端能力(接口、请求参数、返回结构)
> 说明
> - 仅接入了 `API接口文档.md` 中明确存在的后端接口。
> - 文档中未提供的后端能力:前端保持静态占位,并在“缺失部分”中列出。
> - Base URL 通过环境变量配置(若未配置则使用文档默认):
> - `NEXT_PUBLIC_DATA_INGESTION_URL`(默认 `http://localhost:8001`)
> - `NEXT_PUBLIC_MCP_SERVER_URL`(默认 `http://localhost:8002`)
> - `NEXT_PUBLIC_API_GATEWAY_URL`(默认 `http://localhost:80`,当前前端未使用)
---
## 接口调用稽核(2025-12-23)
### Data Ingestion 服务
| 接口 | 前端页面 / 功能 | 代码位置 |
| --- | --- | --- |
| GET /health | 概览 → 系统组件区块 | [components/dashboard-overview.tsx](components/dashboard-overview.tsx#L55-L97) |
| POST /rapidapi/sync | 数据与工具 → RapidAPI 汇聚标签 → 同步端点按钮 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L175-L193) |
| POST /rapidapi/test | 数据与工具 → RapidAPI 汇聚标签 → 端点测试器 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L198-L226) |
| POST /openapi/parse | 数据与工具 → 运维工具标签 → OpenAPI 解析器 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L223-L266) |
| POST /apillama/process | 数据与工具 → APILLAMA 处理器 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L285-L306) |
| POST /tools/generate | 数据与工具 → 生成新工具按钮 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L319-L335) |
| GET /tools | 数据与工具 → 工具注册表列表加载 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L155-L167) |
| GET /tools/{tool_name} | 数据与工具 → 工具详情对话框 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L268-L289) |
| DELETE /tools/{tool_name} | 数据与工具 → 工具注册表删除按钮 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L300-L315) |
| GET /stats | 数据与工具 → 顶部统计卡片 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L155-L167) |
| POST /cache/clear | 数据与工具 → 运维工具 → 缓存维护 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L236-L252) |
| GET /metrics | 数据与工具 → 运维工具 → 服务指标 | [app/data-tools/page.tsx](app/data-tools/page.tsx#L253-L268) |
### MCP Server 服务
| 接口 | 前端页面 / 功能 | 代码位置 |
| --- | --- | --- |
| GET /health | 概览 → 系统组件区块 | [components/dashboard-overview.tsx](components/dashboard-overview.tsx#L55-L97) |
| GET /agents | 概览 → 活跃代理统计;代理工厂 → Agent Registry 列表 | [components/dashboard-overview.tsx](components/dashboard-overview.tsx#L55-L97)<br>[app/agent-factory/page.tsx](app/agent-factory/page.tsx#L74-L104) |
| POST /agents | 代理工厂 → 创建新代理 | [app/agent-factory/page.tsx](app/agent-factory/page.tsx#L105-L121) |
| GET /agents/{agent_id} | 代理工厂 → 代理详情对话框 | [app/agent-factory/page.tsx](app/agent-factory/page.tsx#L130-L146) |
| POST /agents/{agent_id}/execute | 代理工厂 → 播放按钮执行工具 | [app/agent-factory/page.tsx](app/agent-factory/page.tsx#L116-L128) |
| GET /tools | 代理工厂 → 可用函数工具区域 | [app/agent-factory/page.tsx](app/agent-factory/page.tsx#L74-L104) |
| GET /metrics | 代理工厂 → MCP 服务指标卡片 | [app/agent-factory/page.tsx](app/agent-factory/page.tsx#L150-L170) |
| WebSocket /ws/{agent_id} | 代理工厂 → MCP WebSocket 控制台 | [app/agent-factory/page.tsx](app/agent-factory/page.tsx#L178-L228) |
---
## 概览(/)
页面文件:app/page.tsx(渲染组件:components/dashboard-overview.tsx)
### 已接入接口
1) MCP Server 健康检查
- `GET /health`
- Base:MCP Server
- 用途:在“系统组件”区块显示 MCP Server 状态(Operational/Down/Checking)
- 参数:无
2) Data Ingestion 健康检查
- `GET /health`
- Base:Data Ingestion
- 用途:在“系统组件”区块显示 RapidAPI Hub(以 Data Ingestion 服务健康作为近似)状态
- 参数:无
3) Agent 列表
- `GET /agents`
- Base:MCP Server
- 用途:将“活跃代理”数字替换为真实 active agent 数(`status=active` 计数)
- 参数:
- `status`(可选)
- `limit`(默认 100)
- `offset`(默认 0)
### 缺失部分(无后端接口 / 或前端未展示)
- “全局 API 调用”“EU 消耗”“模型提供商数量/健康”等仍为前端静态:文档未提供对应统计接口。
### 建议补充的后端能力
- 全局调用统计:
- `GET /stats/global?range=24h|7d` → 返回每分钟/每天请求量、成功率、P95
- EU 消耗统计:
- `GET /billing/eu/usage?range=24h|30d` → 返回时间序列、余额、消耗来源拆分
- 模型网关状态:
- `GET /gateway/providers`、`GET /gateway/metrics`(详见“模型网关”菜单)
---
## 数据与工具(/data-tools)
页面文件:app/data-tools/page.tsx
### 已接入接口
1) 工具列表
- `GET /tools`
- Base:Data Ingestion
- 用途:填充 Tool Registry 表格
- 参数:
- `category`(可选)
- `limit`(默认 100)
- `offset`(默认 0)
2) 删除工具
- `DELETE /tools/{tool_name}`
- Base:Data Ingestion
- 用途:表格行的“Trash”按钮
- 路径参数:
- `tool_name`:工具名称
3) 统计信息
- `GET /stats`
- Base:Data Ingestion
- 用途:顶部三张卡片:Total APIs / Generated Tools / Cache Size
- 参数:无
4) RapidAPI 同步
- `POST /rapidapi/sync`
- Base:Data Ingestion
- 用途:RapidAPI Hub 的“Sync Endpoints”按钮
- 查询参数:
- `category`(可选)
- `limit`(默认 100)
5) APILLAMA 处理
- `POST /apillama/process`
- Base:Data Ingestion
- 用途:APILLAMA Processor 的“Process Documentation”按钮
- 请求体:
- `api_doc`(string | object,必需):文本或 JSON
- `context`(object,可选)
- `output_format`(string,可选,默认 json_schema):`json_schema|pydantic|openapi`
- 页面使用字段:
- `confidence_score`
- `completeness_score`
6) 生成工具定义(最小可用)
- `POST /tools/generate`
- Base:Data Ingestion
- 用途:页面右上角“Generate New Tool”按钮(用浏览器 prompt 收集必要字段)
- 请求体(页面目前仅采集最小字段):
- `url`(必需)
- `method`(必需)
- `name`(必需)
- `description`(可选)
### 缺失部分
- 暂无(文档内 Data Ingestion 相关接口均已在页面中落地,可视化与操作入口齐备)。
### 建议补充(后端已有,但建议增强返回/错误)
- 建议所有接口统一返回 envelope:`{ status, data, message }`,并保证错误:`{ status:'error', error:{code,message,details} }`。
- `DELETE /tools/{tool_name}` 建议返回删除前工具元信息,便于前端回滚/提示。
---
## 代理工厂(/agent-factory)
页面文件:app/agent-factory/page.tsx
### 已接入接口
1) Agent 列表
- `GET /agents`
- Base:MCP Server
- 用途:Agent Registry 表格
- 参数:
- `status`(可选)
- `limit`(默认 100)
- `offset`(默认 0)
2) 注册 Agent(最小可用)
- `POST /agents`
- Base:MCP Server
- 用途:页面右上角“Create New Agent”按钮(用浏览器 prompt 收集 name/description/capabilities)
- 请求体:
- `name`(必需)
- `description`(必需/建议必需)
- `capabilities`(必需,string[])
- `metadata`(可选)
3) 执行 Agent 工具
- `POST /agents/{agent_id}/execute`
- Base:MCP Server
- 用途:表格行 Play 按钮(当前用 `datetime_now` 作为示例工具,执行结果用 alert 展示)
- 路径参数:
- `agent_id`
- 请求体:
- `tool_name`(必需)
- `parameters`(必需,object)
- `context`(可选,object)
4) MCP 工具列表
- `GET /tools`
- Base:MCP Server
- 用途:填充“Available Function Tools”网格(若接口失败则回退静态列表)
- 参数:
- `category`(可选)
- `limit`(默认 100)
5) Agent 详情
- `GET /agents/{agent_id}`
- Base:MCP Server
- 用途:点击表格中的“Eye”按钮后弹出详情对话框,展示 capabilities/metadata 等完整信息
- 路径参数:
- `agent_id`
6) MCP Server Prometheus 指标
- `GET /metrics`
- Base:MCP Server
- 用途:Agent Factory 页面新增 “MCP 服务指标” 卡片,点击按钮直接抓取 Prometheus 文本并展示
- 参数:无
7) MCP WebSocket
- `GET ws://.../ws/{agent_id}`
- Base:MCP Server
- 用途:页面“WebSocket 控制台”支持与代理交互、发送 `tools/list` 等 MCP 请求、实时查看消息流
- 路径参数:
- `agent_id`
### 缺失部分
- “Pause/Trash” 按钮对应的后端接口文档未提供(暂停/删除 agent)。
### 建议补充的后端能力
- 删除 Agent:
- `DELETE /agents/{agent_id}` → `{ status:'success', data:{agent_id, deleted:true} }`
- 启停 Agent(或状态变更):
- `POST /agents/{agent_id}/status` body `{ status:'active'|'inactive' }` → 返回最新 Agent
- 执行历史/审计:
- `GET /agents/{agent_id}/executions?limit&offset` → 返回工具调用记录、耗时、结果摘要、错误
---
## 模型网关(/model-gateway)
页面文件:app/model-gateway/page.tsx
### 缺失部分(文档未提供后端接口)
- 当前页面所有数据均为静态。
### 建议补充的后端能力
- 模型提供商列表与状态:
- `GET /gateway/providers` → `[{ name, status, latency_ms, models:[...]}]`
- 网关配置读取/更新:
- `GET /gateway/config` → `{ routing, fallbacks, timeouts, quotas }`
- `PUT /gateway/config` body 同上 → 返回更新后的 config
- 网关监控指标:
- `GET /gateway/metrics?range=24h` → `{ p50,p95,error_rate,requests_by_provider }`
---
## 编排中心(/orchestration)
页面文件:app/orchestration/page.tsx
### 缺失部分(文档未提供后端接口)
- 工作流列表、运行状态、NATS 吞吐、VM 池等均为静态。
### 建议补充的后端能力
- 工作流列表/详情:
- `GET /workflows?status&limit&offset` → `[{ id,name,status,agents,progress,created_at }]`
- `GET /workflows/{id}` → 工作流定义/图结构/参数
- 部署/启动/停止:
- `POST /workflows/{id}/deploy` body `{ version?, params? }` → `{ task_id, status }`
- `POST /workflows/{id}/stop` → `{ stopped:true }`
- 运行时指标:
- `GET /orchestration/metrics` → NATS TPS、队列深度、P95、失败率
---
## 计费与资源(/billing)
页面文件:app/billing/page.tsx
### 缺失部分(文档未提供后端接口)
- EU 余额、历史消耗、成本拆分、资源配额等均为静态。
### 建议补充的后端能力
- EU 余额:
- `GET /billing/eu/balance` → `{ balance: number, updated_at }`
- EU 历史:
- `GET /billing/eu/history?from&to&granularity=day|hour` → `[{ ts, eu }]`
- 成本拆分:
- `GET /billing/cost/breakdown?month=YYYY-MM` → `[{ category, cost, eu }]`
- 发票下载:
- `GET /billing/invoices/{id}/download` → `application/pdf`
---
## 其他页面(/admin/*、/channel/*、/login)
这些页面存在“登录/租户/渠道/供应商/计费”等业务需求,但 `API接口文档.md` 暂未提供对应后端 API:
- 认证:Admin/Channel/Login 都是本地 mock token。
- 渠道/租户管理:创建/编辑/禁用等均缺少后端。
- 供应商(模型/数据)管理:缺少 CRUD 与密钥管理接口。
### 建议补充的后端能力(最小集合)
- 认证:
- `POST /auth/login` body `{ email,password, role:'admin'|'channel'|'tenant' }` → `{ token, user }`
- `POST /auth/logout` → `{ ok:true }`
- 渠道管理:
- `GET /channels`、`POST /channels`、`PUT /channels/{id}`、`DELETE /channels/{id}`
- 租户管理:
- `GET /tenants?channel_id&status&limit&offset`、`POST /tenants`、`PUT /tenants/{id}`、`POST /tenants/{id}/suspend`
- 供应商管理:
- `GET /providers?type=model|data`、`POST /providers`、`PUT /providers/{id}`、`POST /providers/{id}/enable|disable`
---
## 代码位置(前端接入点)
- API Client:[lib/api-client.ts](lib/api-client.ts)
- 概览:[components/dashboard-overview.tsx](components/dashboard-overview.tsx)
- 数据与工具:[app/data-tools/page.tsx](app/data-tools/page.tsx)
- 代理工厂:[app/agent-factory/page.tsx](app/agent-factory/page.tsx)
+357 -17
View File
@@ -1,15 +1,21 @@
// API client for Taiji AI Platform
// Base URLs for different services
const API_BASE_URLS = {
export const API_BASE_URLS = {
dataIngestion: process.env.NEXT_PUBLIC_DATA_INGESTION_URL || "http://localhost:8001",
mcpServer: process.env.NEXT_PUBLIC_MCP_SERVER_URL || "http://localhost:8002", // MCP Server 映射到主机端口 8002
gateway: process.env.NEXT_PUBLIC_API_GATEWAY_URL || "http://localhost:80",
}
// Helper function to get auth token
// Helper function to get auth token - checks all possible token types
function getAuthToken(): string | null {
if (typeof window !== "undefined") {
return localStorage.getItem("auth_token")
// 检查所有可能的token类型
const authToken = localStorage.getItem("auth_token")
const adminToken = localStorage.getItem("admin_token")
const channelToken = localStorage.getItem("channel_token")
return authToken || adminToken || channelToken
}
return null
}
@@ -22,8 +28,8 @@ function getApiKey(): string | null {
return null
}
// Helper function to build headers
function buildHeaders(contentType = "application/json"): HeadersInit {
// Helper function to build headers and ensure authentication
function buildHeaders(contentType = "application/json", requireAuth = false): HeadersInit {
const headers: HeadersInit = {
Accept: "application/json",
}
@@ -35,6 +41,13 @@ function buildHeaders(contentType = "application/json"): HeadersInit {
const token = getAuthToken()
const apiKey = getApiKey()
// 需要认证的请求必须有token或API key
if (requireAuth && !token && !apiKey) {
throw new Error(
"认证失败:未找到有效的token或API key。请重新登录。(Authentication failed: No valid token or API key found. Please log in again.)",
)
}
if (token) {
headers.Authorization = `Bearer ${token}`
} else if (apiKey) {
@@ -44,6 +57,18 @@ function buildHeaders(contentType = "application/json"): HeadersInit {
return headers
}
// Helper function to check if user is authenticated
function requireAuth(): void {
const token = getAuthToken()
const apiKey = getApiKey()
if (!token && !apiKey) {
throw new Error(
"认证失败:未找到有效的token或API key。请重新登录。(Authentication failed: No valid token or API key found. Please log in again.)",
)
}
}
// API Response types
export interface APIResponse<T = any> {
success: boolean
@@ -93,6 +118,16 @@ export class TaijiAPIClient {
role: "user" | "channel" | "admin" | "provider" = "user",
): Promise<APIResponse<{ token: string; refreshToken?: string; user?: any }>> {
try {
// 清除所有旧的token(防止多用户登录时token重复)
if (typeof window !== "undefined") {
localStorage.removeItem("auth_token")
localStorage.removeItem("channel_token")
localStorage.removeItem("admin_token")
localStorage.removeItem("refresh_token")
localStorage.removeItem("user")
localStorage.removeItem("api_key")
}
// 检查后端服务是否可达
const isReachable = await checkBackendReachable(API_BASE_URLS.mcpServer)
if (!isReachable) {
@@ -109,7 +144,9 @@ export class TaijiAPIClient {
})
const data = await handleResponse<APIResponse<{ token: string; refreshToken?: string; user?: any }>>(response)
if (data.success && data.data?.token && typeof window !== "undefined") {
localStorage.setItem("auth_token", data.data.token)
// 根据role存储对应的token
const tokenKey = role === "channel" ? "channel_token" : role === "admin" ? "admin_token" : "auth_token"
localStorage.setItem(tokenKey, data.data.token)
if (data.data.refreshToken) {
localStorage.setItem("refresh_token", data.data.refreshToken)
}
@@ -136,23 +173,37 @@ export class TaijiAPIClient {
* 用户登出
*/
static async logout() {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/auth/logout`, {
method: "POST",
headers: buildHeaders(),
})
if (typeof window !== "undefined") {
localStorage.removeItem("auth_token")
localStorage.removeItem("refresh_token")
localStorage.removeItem("user")
localStorage.removeItem("api_key")
try {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/auth/logout`, {
method: "POST",
headers: buildHeaders(),
})
await handleResponse(response)
} catch (error) {
// 即使API调用失败,也要清除本地存储
console.error("Logout API call failed:", error)
} finally {
// 清除所有本地存储的token和用户信息
if (typeof window !== "undefined") {
localStorage.removeItem("auth_token")
localStorage.removeItem("channel_token")
localStorage.removeItem("admin_token")
localStorage.removeItem("refresh_token")
localStorage.removeItem("user")
localStorage.removeItem("api_key")
}
}
return handleResponse(response)
}
/**
* 刷新Token
*/
static async refreshToken(): Promise<APIResponse<{ token: string; refreshToken?: string }>> {
try {
requireAuth()
} catch (error) {
throw new Error("无法刷新token:用户未认证。(Cannot refresh token: user not authenticated.)")
}
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/auth/refresh`, {
method: "POST",
headers: buildHeaders(),
@@ -171,6 +222,11 @@ export class TaijiAPIClient {
* 修改密码
*/
static async changePassword(oldPassword: string, newPassword: string) {
try {
requireAuth()
} catch (error) {
throw new Error("无法修改密码:用户未认证。(Cannot change password: user not authenticated.)")
}
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/auth/password`, {
method: "PUT",
headers: buildHeaders(),
@@ -183,6 +239,11 @@ export class TaijiAPIClient {
* 获取API密钥信息
*/
static async getApiKeyInfo() {
try {
requireAuth()
} catch (error) {
throw new Error("无法获取API密钥:用户未认证。(Cannot get API key: user not authenticated.)")
}
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/auth/keys/info`, {
headers: buildHeaders(),
})
@@ -193,6 +254,11 @@ export class TaijiAPIClient {
* 重新生成API密钥
*/
static async regenerateApiKey(): Promise<APIResponse<{ apiKey: string; message?: string }>> {
try {
requireAuth()
} catch (error) {
throw new Error("无法重新生成API密钥:用户未认证。(Cannot regenerate API key: user not authenticated.)")
}
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/auth/keys/regenerate`, {
method: "POST",
headers: buildHeaders(),
@@ -426,17 +492,36 @@ export class TaijiAPIClient {
/**
* 创建租户
* 前端使用systemRole(系统权限),映射到后端的subscriptionTier
* 角色映射:tenant->free, admin->pro, billing-admin->enterprise, operations-admin->enterprise
*/
static async createChannelTenant(data: {
name: string
email: string
password: string
subscriptionTier: "free" | "pro" | "enterprise"
systemRole?: "tenant" | "admin" | "billing-admin" | "operations-admin"
subscriptionTier?: "free" | "pro" | "enterprise"
}) {
// 角色到订阅等级的映射
const roleToTierMap: Record<string, string> = {
"tenant": "free",
"admin": "pro",
"billing-admin": "enterprise",
"operations-admin": "enterprise"
}
// 构建发送到后端的数据
const apiData = {
name: data.name,
email: data.email,
password: data.password,
subscriptionTier: data.subscriptionTier || (data.systemRole ? roleToTierMap[data.systemRole] : "free")
}
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/channel/tenants/create`, {
method: "POST",
headers: buildHeaders(),
body: JSON.stringify(data),
body: JSON.stringify(apiData),
})
return handleResponse(response)
}
@@ -496,6 +581,39 @@ export class TaijiAPIClient {
return handleResponse(response)
}
/**
* 禁用租户
*/
static async disableTenant(tenantId: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/channel/tenants/${tenantId}/disable`, {
method: "PUT",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 启用租户
*/
static async enableTenant(tenantId: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/channel/tenants/${tenantId}/enable`, {
method: "PUT",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 删除租户(软删除)
*/
static async deleteTenant(tenantId: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/channel/tenants/${tenantId}`, {
method: "DELETE",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 申请资源
*/
@@ -542,6 +660,50 @@ export class TaijiAPIClient {
return handleResponse(response)
}
/**
* 获取渠道可用供应商列表
* GET /api/channel/providers
* 获取所有可用的模型供应商列表,并标注渠道是否已获得使用授权
*/
static async getChannelProviders() {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/channel/providers`, {
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 申请使用供应商
* POST /api/channel/providers/apply
*/
static async applyForProvider(data: {
providerId: string
requestedRpm?: number
requestedTpm?: number
reason: string
}) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/channel/providers/apply`, {
method: "POST",
headers: buildHeaders(),
body: JSON.stringify(data),
})
return handleResponse(response)
}
/**
* 获取供应商申请列表
* GET /api/channel/providers/applications
*/
static async getChannelProviderApplications(status?: "pending" | "approved" | "rejected") {
const url = status
? `${API_BASE_URLS.mcpServer}/api/channel/providers/applications?status=${status}`
: `${API_BASE_URLS.mcpServer}/api/channel/providers/applications`
const response = await fetch(url, {
headers: buildHeaders(),
})
return handleResponse(response)
}
// ==================== 超级管理员 API ====================
// Base URL: http://localhost:8002/api/admin
@@ -555,6 +717,44 @@ export class TaijiAPIClient {
return handleResponse(response)
}
/**
* 获取管理员列表(仅超级管理员可用)
*/
static async getAdmins() {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/admins`, {
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 创建管理员(计费管理员/运营管理员)
*/
static async createAdmin(data: {
name: string
email: string
password: string
role: "billing_admin" | "operations_admin"
}) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/admins/create`, {
method: "POST",
headers: buildHeaders(),
body: JSON.stringify(data),
})
return handleResponse(response)
}
/**
* 删除管理员(软删除)
*/
static async deleteAdmin(adminId: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/admins/${adminId}`, {
method: "DELETE",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 获取渠道列表
*/
@@ -582,6 +782,96 @@ export class TaijiAPIClient {
return handleResponse(response)
}
/**
* 更新渠道信息
*/
static async updateAdminChannel(channelId: string, data: {
name?: string
commissionRate?: number
isActive?: boolean
}) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/channels/${channelId}`, {
method: "PUT",
headers: buildHeaders(),
body: JSON.stringify(data),
})
return handleResponse(response)
}
/**
* 删除渠道(软删除)
*/
static async deleteAdminChannel(channelId: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/channels/${channelId}`, {
method: "DELETE",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 获取渠道供应商授权列表
* GET /api/admin/providers/access
*/
static async getChannelProviderAccess(params?: {
channelId?: string
providerId?: string
status?: "active" | "suspended" | "expired"
}) {
const queryParams = new URLSearchParams()
if (params?.channelId) queryParams.append("channel_id", params.channelId)
if (params?.providerId) queryParams.append("provider_id", params.providerId)
if (params?.status) queryParams.append("status", params.status)
const url = queryParams.toString()
? `${API_BASE_URLS.mcpServer}/api/admin/providers/access?${queryParams}`
: `${API_BASE_URLS.mcpServer}/api/admin/providers/access`
const response = await fetch(url, {
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 更新渠道供应商授权
* PUT /api/admin/providers/access/{access_id}
*/
static async updateChannelProviderAccess(accessId: string, params: {
status?: "active" | "suspended" | "expired"
rpmLimit?: number
tpmLimit?: number
}) {
const queryParams = new URLSearchParams()
if (params.status) queryParams.append("status", params.status)
if (params.rpmLimit) queryParams.append("rpm_limit", params.rpmLimit.toString())
if (params.tpmLimit) queryParams.append("tpm_limit", params.tpmLimit.toString())
const response = await fetch(
`${API_BASE_URLS.mcpServer}/api/admin/providers/access/${accessId}?${queryParams}`,
{
method: "PUT",
headers: buildHeaders(),
}
)
return handleResponse(response)
}
/**
* 撤销渠道供应商授权
* DELETE /api/admin/providers/access/{access_id}
*/
static async revokeChannelProviderAccess(accessId: string) {
const response = await fetch(
`${API_BASE_URLS.mcpServer}/api/admin/providers/access/${accessId}`,
{
method: "DELETE",
headers: buildHeaders(),
}
)
return handleResponse(response)
}
/**
* 统一管理渠道资源
*/
@@ -647,6 +937,36 @@ export class TaijiAPIClient {
return handleResponse(response)
}
/**
* 删除Agent资源
*/
static async deleteAgentResource(agentId: string) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/resources/agents/${agentId}`, {
method: "DELETE",
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 更新Agent资源配置
*/
static async updateAgentResourceConfig(agentId: string, data: {
name?: string
description?: string
price?: number
category?: string
frameworkTemplate?: string
isActive?: boolean
}) {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/resources/agents/${agentId}/config`, {
method: "PUT",
headers: buildHeaders(),
body: JSON.stringify(data),
})
return handleResponse(response)
}
/**
* 监控Agent健康状态
*/
@@ -684,6 +1004,26 @@ export class TaijiAPIClient {
return handleResponse(response)
}
/**
* 获取供应商统计信息
*/
static async getAdminProviderStats() {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/providers/stats`, {
headers: buildHeaders(),
})
return handleResponse(response)
}
/**
* 获取渠道后台简易统计
*/
static async getAdminChannelsBackendStats() {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/admin/channels/backend/stats`, {
headers: buildHeaders(),
})
return handleResponse(response)
}
// ==================== 供应商管理 API ====================
// Base URL: http://localhost:8002/api/providers
+20 -1
View File
@@ -2,7 +2,12 @@
export function getAuthToken(): string | null {
if (typeof window !== "undefined") {
return localStorage.getItem("auth_token")
// 检查所有可能的token类型
const authToken = localStorage.getItem("auth_token")
const adminToken = localStorage.getItem("admin_token")
const channelToken = localStorage.getItem("channel_token")
return authToken || adminToken || channelToken
}
return null
}
@@ -25,6 +30,20 @@ export function isAuthenticated(): boolean {
return getAuthToken() !== null
}
export function isAdminAuthenticated(): boolean {
if (typeof window !== "undefined") {
return localStorage.getItem("admin_token") !== null
}
return false
}
export function isChannelAuthenticated(): boolean {
if (typeof window !== "undefined") {
return localStorage.getItem("channel_token") !== null
}
return false
}
export function clearAuth(): void {
if (typeof window !== "undefined") {
localStorage.removeItem("auth_token")
-6
View File
@@ -1,6 +0,0 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
-218
View File
@@ -1,218 +0,0 @@
全球化智力互联:Agent 赋能平台全栈工程架构与实施白皮书
人工智能代理(AI Agents)正迅速从实验性的脚本演变为具备自主决策能力、工具调用能力以及多代理协同能力的生产力单元。随着模型能力的增强,企业对 Agent 的需求已不再满足于简单的聊天接口,而是要求构建一种能够整合异构数据、灵活切换底层模型、支持跨框架互操作并具备透明计费体系的工程化平台。本报告旨在详细阐述一个全栈 Agent 赋能平台的五个核心技术平面,探讨其如何通过模型上下文协议(MCP)、代理间通信协议(A2A)以及执行单元(EU)计费模型,构建一个标准化的智力资源分发与治理体系。
第一平面:全域数据接入与工具化治理
在 Agent 生态系统中,数据不仅是静态的背景知识,更是可被感知的环境和可被操作的工具。第一平面的核心目标是将零散、异构的外部 API 资源转化为 Agent 可理解、可调用的标准“工具集”。
数据接入的多样性与 RapidAPI 生态集成
平台将 RapidAPI 作为核心数据供应源,利用其超过 16,000 个 API 的庞大市场,为 Agent 提供涵盖气象、金融、物流、社交媒体等全领域的行动能力 1。传统的 REST API 接入通常面临文档不规范、参数描述模糊以及身份验证流程复杂等问题,这直接限制了大型语言模型(LLM)对工具的理解能力。为解决这一痛点,平台引入了“LLM-Ready API”转换机制。
通过集成 Nokia API Hub 的技术理念,平台能够为每个 API 端点自动生成专用的工具模式(Tool-per-endpoint Schema),并将其托管在专用的 MCP 主机上 2。这种方式允许 Agent 开发者通过单一的 Rapid 应用密钥(x-rapidapi-key)管理所有订阅的 API,极大地简化了身份验证逻辑 2。
模式提取与语义增强技术
为了使 API 端点能够被 LLM 准确调用,平台采用了基于 APILLAMA 的结构化知识提取技术。APILLAMA 利用经过微调的 Llama-3-8B-Instruct 模型,通过软提示(Soft Prompt)技术,将原始的 API 文档转换为符合 Pydantic 或 JSON Schema 规范的结构化定义 1。相比于传统的通用模型,APILLAMA 在提取端点描述和参数约束方面表现出更高的准确性,有效避免了 Agent 在参数构造时的“幻觉”现象 1。
在工程实践中,平台要求 API 的 OpenAPI 规范必须包含详尽的自然语言提示。研究表明,LLM 极度依赖操作摘要(Summary)和描述(Description)字段来理解端点的意图 3。例如,将一个简单的 submit request 摘要替换为 为客户创建新的技术支持工单,能显著提升 Agent 在动态动作映射中的识别成功率 3。
异构数据源的动态管理
除了 RapidAPI,平台还兼顾了企业内部私有数据和其他第三方 SaaS 接口。通过 FastMCP 等工具,平台能够直接加载本地的 OpenAPI (Swagger) 定义文件,并实时生成 MCP 服务器代码 4。这种动态热加载机制允许平台在不中断服务的情况下,对 API 版本进行更新或对路由映射(Route Maps)进行自定义调整 3。
下表展示了平台在数据接入平面中对不同 API 类型的处理策略:
特性
RapidAPI 集成
自定义/私有 API
传统库函数封装
接入方式
统一 API Key 代理 2
OpenAPI/Swagger 导入 4
Python 函数装饰器 (@tool) 5
元数据生成
自动映射 + 人工微调
APILLAMA 结构化提取 1
源代码注释 (Docstrings) 6
安全性
平台侧密钥托管
OAuth2/mTLS 穿透 7
沙箱化运行环境 8
计费采集
API 调用成本折算 EU
运行时资源消耗统计
内部配额管理
第二平面:模型抽象层与动态治理体系
模型 management 层是平台的“大脑指挥部”,负责处理模型能力、成本与可用性之间的复杂平衡。该平面通过统一的模型抽象接口,实现了对底层 LLM 服务商的屏蔽,支持按需实时更换模型。
统一网关与模型治理架构
平台集成了 LiteLLM 作为核心的模型代理网关。LiteLLM 充当了应用程序与超过 100 个模型 API 之间的翻译层,提供了一个 OpenAI 兼容的统一端点 9。这种架构允许开发者在不修改业务代码的前提下,通过 YAML 配置文件灵活定义模型组(Model Groups) 11。
在治理维度上,平台通过 LiteLLM Proxy 实现了复杂的路由、负载均衡和故障转移机制。当主模型服务商(如 OpenAI)发生中断或触发频率限制时,系统会自动将请求切换至备份服务商(如 Anthropic 或自建的本地模型服务) 10。这种高可用性设计对于生产级的 Agent 应用至关重要。
模型性能监控与成本归因
为了实现精确的计费和性能评估,平台在模型管理层嵌入了全链路追踪(Tracing)功能。利用 LangSmith 或 OpenTelemetry 集成,平台可以记录每一次模型调用的延迟、输入输出长度以及模型特定的元数据 13。
模型治理的关键在于“上下文窗口管理”。平台能够自动检测不同模型的上下文限制,并根据任务需求自动执行会话截断或总结逻辑,确保 Agent 不会因超出 token 限制而失败 8。此外,通过集成 OpenRouter 等第三方聚合服务,平台可以进一步降低初创团队的账户管理复杂度,实现“一票制”结算 10。
模型选择的维度对比
下表分析了平台支持的主要模型类别的适用场景:
模型类别
典型代表
核心优势
缺点
平台应用策略
通用闭源大模型
GPT-4o, Claude 3.5
推理能力极强,支持复杂工具调用 14
成本高,隐私风险
用于复杂业务编排和最终决策 17
垂直领域模型
Granite, Llama-3
特定任务(如代码编写、API 提取)效率高 1
通用性较弱
用于数据预处理和结构化信息提取 1
端侧/本地模型
Ollama, LM Studio
低延迟,数据主权隔离 12
依赖硬件,能力受限
用于轻量级反思和敏感数据脱敏
第三平面:单体 Agent 的协议化封装与自治
每一个单体 Agent 被定义为一个具有明确边界、特定技能且符合行业标准协议的功能单元。平台强调单体 Agent 内部逻辑的极简性,将复杂的编排交由用户在本地完成。
极简逻辑与原子化设计
平台定义的单体 Agent 通常只包含其角色描述(Role)、目标(Goal)和一系列被授权访问的工具(Tools) 8。这种原子化设计使得每个 Agent 能够专注于特定的专业任务,如“需求分类代理”、“账单处理代理”或“紧急情况检测代理” 17。
核心通信协议:MCP、API 与 A2A
平台的核心竞争力在于其对多种 Agent 通信协议的全面支持,确保了 Agent 能够在不同的宿主环境中自由运行。
1. 模型上下文协议 (MCP)
MCP 由 Anthropic 推出,旨在解决 Agent 与工具之间硬编码集成的难题 7。在平台中,单体 Agent 既可以作为 MCP Client 访问外部数据源,也可以被封装为 MCP Server 暴露给 IDE(如 Cursor)或其他 AI 应用 19。
传输层支持:平台支持基于 stdio 的本地快速通信和基于服务器发送事件(SSE)的远程流式传输 7。
资源与工具发现:MCP 允许宿主应用动态列出、调用和观察 Agent 暴露的所有能力,实现真正的“即插即用” 20。
2. 代理间通信协议 (A2A)
A2A 协议由 Google 引入并捐赠给 Linux 基金会,它关注于代理之间的协作和任务委派 22。
Agent Card(代理名片):平台为每个 Agent 生成一个 JSON 格式的“代理卡”,描述其技能(Skills)、端点(Endpoints)和身份验证要求 22。这使得 Agent 能够像在社交网络中一样彼此发现。
任务生命周期管理:A2A 标准化了任务(Task)的提交、轮询、订阅和结果返回流程。任务状态包括“已提交”、“运行中”、“需要输入”、“已完成”等 22。
工件(Artifacts)交换:Agent 协同产生的结果(如生成的代码文件或分析报告)通过标准化的工件格式进行传递,支持多部分(Parts)数据的流式处理 22。
本地化运行与 API 暴露
对于开发者,单体 Agent 接口提供了标准的 REST API。这种设计确保了 Agent 可以轻松集成到传统的 Web 应用中,同时也支持异步轮询和基于 SSE 的实时状态更新,以优化长耗时任务的用户体验 15。
第四平面:以 MCP 为核心的本地编排与集成平面
在 Agent 赋能平台的工程化实践中,第四平面的核心逻辑已从传统的框架绑定转向“MCP-First”集成策略。通过将平台提供的子 Agent 服务封装为标准的 MCP 服务器,用户可以在本地利用日益成熟的 MCP 生态系统进行灵活编排。
MCP 作为本地集成的“通用语言”
MCP 已成为连接 AI 模型与外部工具、数据的行业标准协议 7。平台将每个单体 Agent 及其背后的数据接口抽象为 MCP 节点,支持用户在本地环境通过 stdio(用于本地进程间通信)或 SSE(用于远程流式服务)进行无缝接入。
这种“协议优先”的设计避免了为每个开源框架编写专用插件的重复劳动。当一个 Agent 符合 MCP 规范时,它不仅能被开发者的业务逻辑调用,还能直接在 IDE(如 Cursor)、聊天客户端(如 Claude Desktop)以及各类企业级 Agent 后台中作为原生工具使用。
主流 Agent 框架对 MCP 的深度支持
目前市面上主流的 Agent 开发框架均已实现了对 MCP 的原生或适配器支持,这使得本地编排变得异常简单:
LangChain 适配方案:LangChain 通过 langchain-mcp-adapters 库,能够将 MCP 服务器定义的 Tools、Resources 和 Prompts 自动转换为 LangChain 兼容的组件。开发者只需初始化一个 MultiServerMCPClient,即可同时加载分布在不同本地路径或远程 URL 的 Agent 技能。
CrewAI 集成机制:CrewAI 在 Agent 类中直接提供了 mcps 字段。开发者只需提供 MCP 服务器的端点信息(如 SSE URL 或特定的 Stdio 启动命令),框架即可自动发现工具并注入到代理的执行上下文中。
Microsoft AutoGen 扩展:AutoGen v0.4+ 版本引入了 StdioMcpToolAdapter 和 SseMcpToolAdapter,允许将外部 MCP 协议包装为 AutoGen 代理可识别的 Action 单元,极大地增强了跨语言和跨环境的协作能力。
协议化集成的工程优势
解耦与复用:工具逻辑在 MCP 服务器端维护,编排逻辑在本地维护,双方通过 JSON-RPC 2.0 契约通信,任何一方的升级都不会导致系统崩溃。
动态发现机制:本地编排器可以在运行时通过 tools/list 请求动态发现 Agent 的新技能,无需手动更新本地代码中的工具定义。
安全隔离:用户可以在本地沙箱中运行高风险的 MCP 工具(如文件操作系统),而将复杂的逻辑计算卸载到云端平台,确保数据主权与执行安全的平衡。
下表展示了以 MCP 为核心的集成链路:
组件层级
实现方式
技术标准
能力供应方
平台 Agent 导出为 MCP Server 2
JSON-RPC 2.0 / stdio / SSE 7
连接层适配
MCPServerAdapter / MultiServerMCPClient
MCP SDK (Python/TS/Go) 43
业务逻辑层
用户本地 Python/JS 逻辑或 DSL 配置
OpenAPI 3.0 / Pydantic
宿主框架
LangGraph, CrewAI, AutoGen, Cursor
框架原生接口 + MCP Adapter
第五平面:基于执行单元 (EU) 的资源计量与计费模型
为了解决 Token 计费模型在 Agent 场景下的不确定性(如 Agent 的过度反思或重复调用导致的 Token 激增),平台引入了基于执行时间与资源消耗的**执行单元(Execution Unit, EU)**计费模式。
执行单元 (EU) 的定义与公式
执行单元(EU)是一个衡量计算、内存和网络资源消耗的综合性指标。该模型参考了 AWS Lambda、Google Cloud Run 以及 LUMI 超算中心的计费实践 26。
一个典型的 EU 计算公式如下:
$$EU = \left( \max\left( \lceil \frac{vCPU_{Allocated}}{Step_{CPU}} \rceil, \lceil \frac{Memory_{Allocated}}{Step_{Mem}} \rceil \right) \times T_{Runtime} \right) \times \gamma_{Model\_Tax}$$
其中:
$vCPU_{Allocated}$:分配给该 Agent 任务的虚拟处理器核数 28。
$Memory_{Allocated}$:分配的内存容量(例如以 2GB 为一个计费切片) 27。
$T_{Runtime}$:任务实际执行的 wall-clock 时间(通常精确到毫秒级) 26。
$\gamma_{Model\_Tax}$:模型权重因子,反映了底层调用特定高级模型(如 GPT-4o)时的额外许可溢价。
计费引擎的架构实施
计费平面的核心是实时计量引擎。该引擎通过以下步骤确保收入不流失并提供透明的客户账单:
事件采集:利用 Golang 编写的高性能计量服务,通过 NATS 消息队列监听 Agent 的启动(Start)和停止(Stop)事件 31。
配额管理:系统在任务启动前预扣除一定额度的 EU。如果账户余额低于阈值,则拒绝启动,防止欠费运行 32。
动态调优:通过 Datadog 或 Prometheus 监控函数调用的内存峰值,建议用户“右调”资源分配,以在性能与成本间取得最优解 34。
实时仪表盘:为客户提供可视化看板,展示按 Agent、按特征、按环境划分的成本明细,并利用 AI 预测未来的支出趋势 32。
EU 计费与 Token 计费的对比分析
维度
Token 计费模型
执行单元 (EU) 计费模型
透明度
较低。用户难以理解隐藏的推理链 Token 消耗 32
较高。类似于云计算实例,运行多久付多久费 34
激励方向
鼓励生成短文本。可能损害 Agent 的推理深度
鼓励代码和算法优化。更短的运行时间意味着更低的费用 35
架构适配性
仅适用于单次 API 调用
完美契合 Serverless 函数和长时运行的自治任务 38
成本管控
难以实时熔断。可能在分钟内产生巨大账单
易于实施基于时间配额的强制停机逻辑 33
工程化平台治理:安全、隔离与多租户
作为一个赋能平台,确保多租户环境下的数据隔离和系统稳定性是商业化落地的先决条件。
多层级隔离机制
平台在计算、数据和网络三个层级实施了严格的隔离策略:
计算隔离:利用微虚拟机(MicroVMs,如 Firecracker)或受限容器(gVisor)运行 Agent 逻辑。通过设置硬性的 CPU 和内存 Limit,防止“吵闹邻居”(Noisy Neighbor)效应影响其他租户 40。
数据隔离:数据库采用行级安全性(RLS)和按租户加密(Per-tenant Encryption)。所有的 SQL 查询都必须带上 TenantID 过滤器 40。
网络隔离:为敏感的 Agent 编排提供虚拟私有云(VPC)和私有子网,限制对后端数据库和凭据存储的非授权访问 42。
身份验证与权限管控 (RBAC/ABAC)
平台集成了 Pomerium 作为智能访问关口。与传统的基于 API Key 的简单验证不同,Pomerium 能够集成 Okta 等身份提供商,实施基于上下文的访问策略(例如:仅允许特定部门的成员在工作时间内调用具有财务权限的 Agent) 9。
运行时监控与审计
全方位的观测能力对于 Agent 调试至关重要。平台在每个 Agent 的运行环境中注入了 Sidecar 代理,实时采集:
性能指标:CPU 利用率、内存驻留集大小、网络延迟。
Agent 轨迹:记录所有的工具调用请求和模型推理过程,生成可交互的轨迹图(Traces) 37。
合规审计:保存完整的对话日志和任务工件,以满足 SOC 2 或 HIPAA 等合规性要求 9。
结论:构建 Agentic Web 的基础设施
本报告详述的 Agent 赋能平台,不仅是一个简单的工具集,更是一个旨在标准化未来“智力交换”的基础设施。通过第一平面对 RapidAPI 等海量资源的工具化封装,平台解决了数据获取的广度问题;通过第二平面的多模型动态切换,平台保障了大脑的可替代性与成本可控性。
在协议层面,MCP 与 A2A 的深度整合,标志着平台从封闭系统向开放生态的转变。以 MCP 为核心的第四平面设计,使得平台 Agent 能够以标准插件的形式瞬间触达全球主流开发框架和 IDE。 这种原子化设计结合本地编排的灵活性,赋予了用户构建复杂业务逻辑的主动权。而基于 EU 的计费模型,则为 Agent 这一新型生产力单元提供了最符合工程直觉的价值衡量尺度。
随着 Agent 技术的不断演进,平台未来的研究重点将转向:
自治成本优化:开发能够自主选择最经济路径(模型 + 工具组合)的元调度器。
跨代理信誉体系:基于任务完成率和资源效率,为 A2A 生态中的代理建立信任评分。
异构计算卸载:根据 Agent 的计算强度,自动在端侧设备与云端高性能集群之间动态分配任务载荷。
通过实施这五个维度的技术标准,该平台将为企业提供一个稳健、透明且易于扩展的 Agent 运行环境,助力从“模型优先”时代平稳过渡到“代理优先”时代。
引用的著作
ToolFactory: Automating Tool Generation by Leveraging LLM to Understand REST API Documentations - arXiv, 访问时间为 十二月 20, 2025, https://arxiv.org/html/2501.16945v1
Consume APIs using AI - RapidAPI, 访问时间为 十二月 20, 2025, https://docs.rapidapi.com/docs/consume-apis-using-ai
Automate AI Workflows with OpenAPI to Build LLM-Ready APIs - Gravitee, 访问时间为 十二月 20, 2025, https://www.gravitee.io/blog/ai-workflows-with-openapi-and-llm-apis
How to Connect an LLM to a REST API - FastMCP, 访问时间为 十二月 20, 2025, https://gofastmcp.com/tutorials/rest-api
Tools - CrewAI Documentation, 访问时间为 十二月 20, 2025, https://docs.crewai.com/en/concepts/tools
12 Best Technical Documentation Templates for 2025 | DocuWriter.ai, 访问时间为 十二月 20, 2025, https://www.docuwriter.ai/posts/technical-documentation-templates
What is Model Context Protocol (MCP)? A guide - Google Cloud, 访问时间为 十二月 20, 2025, https://cloud.google.com/discover/what-is-model-context-protocol
Agents - CrewAI Documentation, 访问时间为 十二月 20, 2025, https://docs.crewai.com/en/concepts/agents
LiteLLM vs. Pomerium: Key Differences and When to Use Each One, 访问时间为 十二月 20, 2025, https://www.pomerium.com/blog/litellm-vs-pomerium
LiteLLM: A Guide With Practical Examples - DataCamp, 访问时间为 十二月 20, 2025, https://www.datacamp.com/tutorial/litellm
How Model Access Works - LiteLLM, 访问时间为 十二月 20, 2025, https://docs.litellm.ai/docs/proxy/model_access_guide
Olla vs LiteLLM - Comparison Guide for LLM Infrastructure, 访问时间为 十二月 20, 2025, https://thushan.github.io/olla/compare/litellm/
Trace with AutoGen - Docs by LangChain, 访问时间为 十二月 20, 2025, https://docs.langchain.com/langsmith/trace-with-autogen
How to integrate LangGraph with AutoGen, CrewAI, and other frameworks - LangChain docs, 访问时间为 十二月 20, 2025, https://docs.langchain.com/langsmith/autogen-integration
Designing APIs for LLM Apps: Build Scalable and AI-Ready Interfaces - Gravitee, 访问时间为 十二月 20, 2025, https://www.gravitee.io/blog/designing-apis-for-llm-apps
Why are we still pretending multi-model abstraction layers work? : r/LLMDevs - Reddit, 访问时间为 十二月 20, 2025, https://www.reddit.com/r/LLMDevs/comments/1owtio8/why_are_we_still_pretending_multimodel/
How to Build a Multi-Agent System (Part 1/3): From Problem to Design, 访问时间为 十二月 20, 2025, https://www.intotheagileshop.com/post/how-to-build-a-multi-agent-system-part-1-3-from-problem-to-design
How to Build Your Own Agentic AI System Using CrewAI | Towards Data Science, 访问时间为 十二月 20, 2025, https://towardsdatascience.com/how-to-build-your-own-agentic-ai-system-using-crewai/
Model Context Protocol (MCP) | Cursor Docs, 访问时间为 十二月 20, 2025, https://cursor.com/docs/context/mcp
Build Your Own Model Context Protocol Server | by C. L. Beard | BrainScriblr | Nov, 2025, 访问时间为 十二月 20, 2025, https://medium.com/brainscriblr/build-your-own-model-context-protocol-server-0207625472d0
Tools - Model Context Protocol, 访问时间为 十二月 20, 2025, https://modelcontextprotocol.io/docs/concepts/tools
What is A2A protocol (Agent2Agent)? - IBM, 访问时间为 十二月 20, 2025, https://www.ibm.com/think/topics/agent2agent-protocol
A2A Protocol, 访问时间为 十二月 20, 2025, https://a2a-protocol.org/latest/
Why Agent2Agent Matters for Multi-Agent Systems? | by Ricardo Olivieri | IBM IT Automation and AI | Dec, 2025, 访问时间为 十二月 20, 2025, https://medium.com/ibm-watson-aiops/why-agent2agent-matters-for-multi-agent-systems-45c070fdd1b9
What is Serverless Architecture? A Practical Guide with Examples - Middleware.io, 访问时间为 十二月 20, 2025, https://middleware.io/blog/serverless-architecture/
Demystifying Serverless Costs on Public Platforms: Bridging Billing, Architecture, and OS Scheduling - arXiv, 访问时间为 十二月 20, 2025, https://arxiv.org/html/2506.01283v2
Billing policy - Documentation - LUMI, 访问时间为 十二月 20, 2025, https://docs.lumi-supercomputer.eu/runjobs/lumi_env/billing/
Can anyone explain to me in simple terms what vCPU means? I have been scratching my head over this. : r/golang - Reddit, 访问时间为 十二月 20, 2025, https://www.reddit.com/r/golang/comments/1irz945/can_anyone_explain_to_me_in_simple_terms_what/
Memory and vCPU considerations for AWS Batch on Amazon EKS, 访问时间为 十二月 20, 2025, https://docs.aws.amazon.com/batch/latest/userguide/memory-cpu-batch-eks.html
Getting to the Bottom of Serverless Billing - arXiv, 访问时间为 十二月 20, 2025, https://arxiv.org/html/2506.01283v1
How to Implement Scalable Usage-Based Billing for AI Workloads - CloudRaft, 访问时间为 十二月 20, 2025, https://www.cloudraft.io/blog/usage-based-billing-for-ai-workloads
How to Build Custom Billing Systems for AI Agents: A Complete Guide, 访问时间为 十二月 20, 2025, https://www.getmonetizely.com/articles/how-to-build-custom-billing-systems-for-ai-agents-a-complete-guide
AI Billing Showdown: 6 Billing Platforms for AI Agents | Paid.ai blog, 访问时间为 十二月 20, 2025, https://paid.ai/blog/billing/ai-billing-showdown-6-billing-platforms
Minimizing Development Costs with Serverless Architecture - IntexSoft, 访问时间为 十二月 20, 2025, https://intexsoft.com/blog/minimizing-development-costs-with-serverless-architecture/
Impact of Serverless Architecture on Software Development Costs | Zetaton, 访问时间为 十二月 20, 2025, https://www.zetaton.com/blogs/the-impact-of-serverless-architecture-on-software-development-costs
Automated Billing Software Development: A Step-by-Step Guide - Appinventiv, 访问时间为 十二月 20, 2025, https://appinventiv.com/blog/automated-billing-software-development/
AI Agent Costs on Databricks: A Complete Guide to Pricing, Optimization, and Real-World Examples, 访问时间为 十二月 20, 2025, https://community.databricks.com/t5/technical-blog/demystifying-databricks-pricing-for-ai-agents/ba-p/122281
Top 5 Things to Know Before Using Serverless Computing - CloudOptimo, 访问时间为 十二月 20, 2025, https://www.cloudoptimo.com/blog/top-5-things-to-know-before-using-serverless-computing/
Serverless Architecture: What It Is & How It Works | Datadog, 访问时间为 十二月 20, 2025, https://www.datadoghq.com/knowledge-center/serverless-architecture/
Real-Time Monitoring for Multi-Tenant Workflows | Prompts.ai, 访问时间为 十二月 20, 2025, https://www.prompts.ai/en/blog/real-time-monitoring-for-multi-tenant-workflows
Multi-Tenant Architecture: The Complete Guide for Modern SaaS and Analytics Platforms -, 访问时间为 十二月 20, 2025, https://bix-tech.com/multi-tenant-architecture-the-complete-guide-for-modern-saas-and-analytics-platforms-2/
Building Multi-Tenant n8n Workflows for Agency Clients, 访问时间为 十二月 20, 2025, https://www.wednesday.is/writing-articles/building-multi-tenant-n8n-workflows-for-agency-clients
Model Context Protocol - GitHub, 访问时间为 十二月 20, 2025, https://github.com/modelcontextprotocol