Provider 配置

wesgine 通过 Provider 接入 AI 模型。三种归属、四种策略、三种密钥来源,灵活覆盖从个人到企业的全场景。

三种 Provider 归属

归属作用域典型场景
Shared(共享)Hypervisor 级,所有 Cell 共用企业统一采购的 API
Named(具名)Hypervisor 声明,特定 Cell 绑定指定部门可用
Private BYOKCell 自带用户自己的 API Key

四种 Provider 策略

策略行为
own_only仅使用 Cell 私有 Provider
shared_only仅使用共享池
own_first优先私有,Fallback 到共享
shared_first优先共享,Fallback 到私有

自动推导

单侧池非空时自动推导:

SecretRef — 密钥管理

Provider 的 API Key 通过 SecretRef 声明,支持三种来源:

来源说明适用场景
inline明文传入,引擎 AES-256-GCM 加密存储个人部署、测试
env从环境变量读取容器部署
live运行时由应用层动态提供WES 平台、组织托管

inline 示例

{
  "name": "openai",
  "type": "openai",
  "base_url": "https://api.openai.com/v1",
  "api_key_ref": {
    "source": "inline",
    "value": "sk-..."
  },
  "models": [
    {"name": "gpt-4o", "context_window": 128000, "supports_vision": true}
  ]
}

inline 的明文经 AES-256-GCM 封套后存入 hypervisor.db,密钥文件 spec.key 独立存放(0600 权限)。

模型声明

每个 Provider 必须声明可用模型及其能力:

{
  "models": [
    {
      "name": "gpt-4o",
      "context_window": 128000,
      "max_output_tokens": 16384,
      "supports_vision": true
    },
    {
      "name": "gpt-4o-mini",
      "context_window": 128000,
      "max_output_tokens": 16384,
      "supports_vision": true
    }
  ]
}

引擎不含内置模型知识(INV-DS-01)——context_window 等参数必须由调用方声明或从 catalog 注入。

Vision 能力

Vision 是 Model 的能力而非 Provider 的能力。在 Models[].SupportsVision 上声明:

{"name": "gpt-4o", "supports_vision": true}

请求含图片但模型未声明 Vision 时,返回 ErrVisionNotSupported 硬错误(不静默剥离图片)。

配置共享 Provider

curl -X POST http://localhost:9091/admin/shared-providers \
  -H "Content-Type: application/json" \
  -d '{
    "providers": [{
      "name": "openai",
      "type": "openai",
      "base_url": "https://api.openai.com/v1",
      "api_key_ref": {"source": "inline", "value": "sk-..."},
      "models": [{"name": "gpt-4o", "context_window": 128000}]
    }]
  }'

Token 用量追踪

每次调用自动记录 Token 用量,支持多维查询:

# 按模型聚合
GET /cells/{id}/observe/token-usage?group_by=model

# 按 Agent 和天聚合
GET /cells/{id}/observe/token-usage/aggregate?agent=default&group_by=day&days=7

连通性测试

# 测试 Provider 连通性
POST /cells/{id}/providers/test
{"mode": "chat"}  # 或 "embedding" / "vision"