当前系统的模型广场仅支持云端模型(由平台统一托管的AI模型),用户无法接入自己部署的本地模型。同时,平台缺乏对外开放API的能力,用户无法通过标准API协议调用平台上的模型资源。
本需求旨在:
| 术语 | 说明 |
|---|---|
| 云端模型 | 平台统一托管的AI模型,由平台管理员配置,所有用户共享 |
| 本地模型 | 用户自行部署的AI模型,仅对上传用户可见,需提供OpenAI API兼容接口 |
| 阿里云APIKey | 现有系统中用于调用阿里云百炼服务的密钥,存储在users.apikey字段 |
| 平台APIKey | 本次新增,用于调用本平台开放API的密钥,需新建表存储 |
| OpenAI API兼容 | 遵循OpenAI Chat Completions API格式的接口规范 |
需求描述:
交互设计:
┌─────────────────────────────────────────────────────────┐
│ 模型广场 │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 云端模型 ✓ │ │ 本地模型 │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ [模型卡片列表...] │
└─────────────────────────────────────────────────────────┘
需求描述:
http://localhost:8080/v1输入字段: | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | base_url | string | 是 | 本地模型API地址,需符合URL格式 | | api_key | string | 否 | 访问密钥,部分本地部署可能不需要 | | name | string | 是 | 模型显示名称,用户自定义 |
连接测试:
{base_url}/chat/completions 接口数据库设计:
models 表is_local(Boolean,默认false)区分本地/云端模型user_id(String,可空)关联上传用户(本地模型必填)base_url(String,可空)存储本地模型API地址local_api_key(String,可空)存储本地模型访问密钥(加密存储)models表新增字段: | 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | is_local | Boolean | false | 是否为本地模型 | | user_id | String(50) | NULL | 上传用户ID(本地模型必填) | | base_url | String(500) | NULL | 本地模型API地址 | | local_api_key | String(500) | NULL | 本地模型访问密钥(加密) |
需求描述:
卡片信息:
需求描述:
需求描述:
需求描述:
API Key格式:
sk-aigc-sk-aigc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx数据库设计 - 新建 platform_api_key 表:
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Integer | 主键 |
| user_id | String(50) | 用户ID,外键关联users表 |
| api_key | String(100) | API Key(哈希存储) |
| api_key_prefix | String(20) | API Key前缀(用于显示) |
| name | String(100) | 备注名称 |
| status | String(20) | 状态:active/disabled |
| last_used_at | DateTime | 最后使用时间 |
| created_at | DateTime | 创建时间 |
| updated_at | DateTime | 更新时间 |
需求描述:
/v1/chat/completions 端点Authorization: Bearer {api_key} 进行认证API端点:
POST /api/v1/chat/completions
Headers:
Authorization: Bearer sk-aigc-xxxxx
Content-Type: application/json
Request Body:
{
"model": "qwen-max", // 模型标识(models.title)
"messages": [
{"role": "user", "content": "Hello"}
],
"stream": false, // 是否流式
"temperature": 0.7, // 可选参数
"max_tokens": 2048 // 可选参数
}
Response (非流式):
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1234567890,
"model": "qwen-max",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help you?"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
}
}
需求描述:
models.is_api_enabled 字段控制模型是否支持API调用权限检查流程:
is_api_enabled 是否为true计费规则:
计费流程:
数据库设计 - 新建 api_call_log 表:
| 字段 | 类型 | 说明 |
|------|------|------|
| id | BigInteger | 主键 |
| user_id | String(50) | 用户ID |
| api_key_id | Integer | 使用的API Key ID |
| model_id | Integer | 调用的模型ID |
| model_name | String(255) | 模型名称 |
| is_local | Boolean | 是否本地模型 |
| input_tokens | Integer | 输入token数 |
| output_tokens | Integer | 输出token数 |
| bill | Decimal(12,4) | 费用(本地模型为0) |
| status | String(20) | 状态:success/failed |
| error_message | Text | 错误信息(失败时) |
| request_ip | String(50) | 请求IP |
| created_at | DateTime | 创建时间 |
需求描述:
需求描述:
需求描述:
is_api_enabled 字段需求描述:
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/models/local | 添加本地模型 |
| GET | /api/models/local | 获取当前用户的本地模型列表 |
| PUT | /api/models/local/{id} | 更新本地模型配置 |
| DELETE | /api/models/local/{id} | 删除本地模型 |
| POST | /api/models/local/test | 测试本地模型连接 |
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/platform/api-keys | 创建API Key |
| GET | /api/platform/api-keys | 获取API Key列表 |
| PUT | /api/platform/api-keys/{id} | 更新API Key(禁用/启用) |
| DELETE | /api/platform/api-keys/{id} | 删除API Key |
| GET | /api/platform/stats | 获取调用统计 |
| GET | /api/platform/call-logs | 获取调用日志 |
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/v1/chat/completions | Chat Completions API |
| GET | /api/v1/models | 获取可用模型列表 |
models表新增字段:
ALTER TABLE aigcspace.models ADD COLUMN is_local BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE aigcspace.models ADD COLUMN user_id VARCHAR(50) NULL;
ALTER TABLE aigcspace.models ADD COLUMN base_url VARCHAR(500) NULL;
ALTER TABLE aigcspace.models ADD COLUMN local_api_key VARCHAR(500) NULL;
CREATE INDEX idx_models_is_local ON aigcspace.models(is_local);
CREATE INDEX idx_models_user_id ON aigcspace.models(user_id);
platform_api_key表:
CREATE TABLE aigcspace.platform_api_key (
id SERIAL PRIMARY KEY,
user_id VARCHAR(50) NOT NULL REFERENCES aigcspace.users(id) ON DELETE CASCADE,
api_key VARCHAR(100) NOT NULL,
api_key_prefix VARCHAR(20) NOT NULL,
name VARCHAR(100),
status VARCHAR(20) NOT NULL DEFAULT 'active',
last_used_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_platform_api_key_user_id ON aigcspace.platform_api_key(user_id);
CREATE INDEX idx_platform_api_key_api_key ON aigcspace.platform_api_key(api_key);
CREATE INDEX idx_platform_api_key_status ON aigcspace.platform_api_key(status);
api_call_log表:
CREATE TABLE aigcspace.api_call_log (
id BIGSERIAL PRIMARY KEY,
user_id VARCHAR(50) NOT NULL REFERENCES aigcspace.users(id) ON DELETE CASCADE,
api_key_id INTEGER REFERENCES aigcspace.platform_api_key(id) ON DELETE SET NULL,
model_id INTEGER REFERENCES aigcspace.models(id) ON DELETE SET NULL,
model_name VARCHAR(255) NOT NULL,
is_local BOOLEAN NOT NULL DEFAULT FALSE,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
bill DECIMAL(12,4) NOT NULL DEFAULT 0,
status VARCHAR(20) NOT NULL DEFAULT 'success',
error_message TEXT,
request_ip VARCHAR(50),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_api_call_log_user_id ON aigcspace.api_call_log(user_id);
CREATE INDEX idx_api_call_log_api_key_id ON aigcspace.api_call_log(api_key_id);
CREATE INDEX idx_api_call_log_model_id ON aigcspace.api_call_log(model_id);
CREATE INDEX idx_api_call_log_created_at ON aigcspace.api_call_log(created_at);
CREATE INDEX idx_api_call_log_is_local ON aigcspace.api_call_log(is_local);
backend/app/models/model.pybackend/app/models/user.pybackend/app/models/billing.py