483 lines
15 KiB
Markdown
483 lines
15 KiB
Markdown
# AI Provider 指南
|
||
|
||
## 概览
|
||
|
||
`aiprovider` 是 Planet 的模型适配服务。
|
||
|
||
它把模型厂商差异隔离在主后端之外,让系统其它部分可以调用稳定的业务 API:
|
||
|
||
- 调用方服务 -> `planet backend`
|
||
- `planet backend` -> `aiprovider`
|
||
- `aiprovider` -> 具体模型提供方
|
||
|
||
推荐默认方式:
|
||
|
||
- 外部调用方和跨服务调用方统一调用 `planet backend`
|
||
- 只有基础设施级内部任务才直接调用 `aiprovider`
|
||
|
||
## 职责边界
|
||
|
||
`backend` 负责:
|
||
|
||
- 身份认证和权限控制
|
||
- 业务层请求整理
|
||
- 稳定的 `/api/v1/ai/...` 接口
|
||
- 面向 `aiprovider` 的内部服务认证
|
||
- 读取配置中心保存的默认 provider、模型和每个 provider 的 key,并通过内部请求头覆盖 `aiprovider` 的 `.env` 默认值
|
||
|
||
`aiprovider` 负责:
|
||
|
||
- 模型协议适配
|
||
- 在没有后端覆盖头时基于 `.env` 选择 provider
|
||
- 超时和轻量重试
|
||
- 通过 `X-Request-ID` 串联请求追踪
|
||
|
||
当前配置采用类似 OpenClaw 的拆分方式:
|
||
|
||
- `AI_PROVIDER` 标识厂商或逻辑 provider
|
||
- `AI_PROVIDER_API` 标识实际请求协议适配器
|
||
|
||
这个拆分能更清楚地表达 MiniMax、Claude 兼容网关、自托管 OpenAI 兼容服务等情况,避免把所有含义塞进一个配置项。
|
||
|
||
## 支持的 Provider
|
||
|
||
`aiprovider` 当前支持以下 provider 标识:
|
||
|
||
- `openai`
|
||
- `anthropic`
|
||
- `minimax`
|
||
- `ollama`
|
||
|
||
支持的请求适配器:
|
||
|
||
- `openai-completions`
|
||
- `anthropic-messages`
|
||
- `ollama-generate`
|
||
|
||
仍然兼容的历史别名:
|
||
|
||
- `openai_compatible`
|
||
- `anthropic_compatible`
|
||
- `claude_compatible`
|
||
|
||
推荐映射关系:
|
||
|
||
- `vLLM`、`LM Studio`、`One API`:`AI_PROVIDER=openai`,`AI_PROVIDER_API=openai-completions`
|
||
- `MiniMax`:`AI_PROVIDER=minimax`,`AI_PROVIDER_API=anthropic-messages`
|
||
- Claude 兼容网关:`AI_PROVIDER=anthropic`,`AI_PROVIDER_API=anthropic-messages`
|
||
- `Ollama`:`AI_PROVIDER=ollama`,`AI_PROVIDER_API=ollama-generate`
|
||
|
||
## API 面
|
||
|
||
### 主后端 API
|
||
|
||
推荐使用的稳定入口:
|
||
|
||
- `GET /api/v1/ai/provider/status`
|
||
- `POST /api/v1/ai/situational-awareness/analyze`
|
||
|
||
认证方式:
|
||
|
||
- `Authorization: Bearer <jwt>`
|
||
|
||
可选追踪头:
|
||
|
||
- `X-Request-ID: <caller-generated-id>`
|
||
|
||
后端会把 `X-Request-ID` 透传给 `aiprovider`,并在响应中返回同一个 header。
|
||
|
||
### 设置中心 API
|
||
|
||
AI 配置页使用的接口:
|
||
|
||
- `GET /api/v1/settings/integrations`
|
||
- `PUT /api/v1/settings/integrations`
|
||
- `POST /api/v1/settings/integrations/ai-provider/connect`
|
||
- `GET /api/v1/settings/integrations/ai-provider/secrets`
|
||
- `GET /api/v1/settings/integrations/ai-provider/presets`
|
||
- `GET /api/v1/settings/ai-prompts`
|
||
- `PUT /api/v1/settings/ai-prompts/{task_key}`
|
||
- `POST /api/v1/settings/ai-prompts/{task_key}/reset`
|
||
|
||
这些接口都需要用户登录。`secrets` 接口只用于配置页点击显示 key/token 时取回明文,隐藏时前端恢复为脱敏预览。
|
||
|
||
Admin 的 AI 页面按业务信息架构组织为:
|
||
|
||
- `模型供应商`
|
||
- 管理 provider、协议适配、默认模型、LLM API Key、代理地址、代理 token、模型列表刷新、设为默认和轻量连通性测试。
|
||
- `工具调用`
|
||
- 管理 WebSearch、OCR 等工具。工具内部先选 provider,再编辑该 provider 的 API、key 和高级参数。
|
||
- `提示词`
|
||
- 按 prompt 分组和 task key 编辑系统提示词 / 用户提示词;保存和重置只作用于当前 task。
|
||
- `Playground`
|
||
- 使用当前默认 provider 和 prompt 配置发起真实会话;AI 回复使用 Markdown 渲染。
|
||
|
||
保存、设为默认和连通性测试是三个独立职责:保存只持久化表单,设为默认只切换默认 provider/tool,连通性测试只验证当前草稿是否可用,不应隐式保存或切换默认项。
|
||
|
||
`ai-prompts` 接口用于运维配置页的“提示词”Tab。默认提示词来自后端随发布包携带的版本化资源,业务代码只引用稳定 task key;接口只保存运维覆盖值。重置时删除覆盖值并恢复当前发布包中的缺省提示词。
|
||
|
||
### 提示词边界
|
||
|
||
`aiprovider` 是纯模型适配器,不注入通用业务 system prompt。新闻汉化、告警研判、BGP 简报、位置 factcheck、数据源映射和凭据教程等入口各自通过 task key 解析有效提示词。告警研判 prompt 只会在告警相关 task 中作为 system prompt 传入,不会污染其它 LLM 调用。
|
||
|
||
### Agent 与工具边界
|
||
|
||
Agent 工作流属于 `backend`,不属于 `aiprovider`。后续 Earth LLM 指令、态势感知、多角色模拟、WebSearch、数据库查询、证据存储和配置提案应用都应由后端 Agent Runtime 编排;`aiprovider` 只接收后端整理好的模型请求并返回规范化响应。
|
||
|
||
如果某个 provider 支持原生 tool calling,`aiprovider` 可以透传协议字段并规范化响应块,但工具白名单、参数校验、权限策略、运行记录和写入审批仍必须留在后端。provider 不支持原生 tools 时,后端使用 JSON tool-call fallback,不应为了某个模型厂商把业务工具下沉到 `aiprovider`。
|
||
|
||
### AI Provider 内部 API
|
||
|
||
仅供内部调用的接口:
|
||
|
||
- `GET /v1/provider/status`
|
||
- `POST /v1/analyze`
|
||
|
||
认证方式:
|
||
|
||
- `X-Provider-Token: <shared-secret>`
|
||
|
||
可选追踪头:
|
||
|
||
- `X-Request-ID: <caller-generated-id>`
|
||
|
||
## 请求示例
|
||
|
||
### 通过后端调用
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/api/v1/ai/situational-awareness/analyze \
|
||
-H "Authorization: Bearer <access_token>" \
|
||
-H "X-Request-ID: bgp-incident-20260407-001" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"title": "BGP异常研判",
|
||
"objective": "总结当前风险并给出处置建议",
|
||
"observations": [
|
||
"collector A 在 5 分钟内出现多次 origin 变更",
|
||
"异常集中在同一地区前缀"
|
||
],
|
||
"constraints": [
|
||
"不要编造不存在的数据",
|
||
"区分事实和推断"
|
||
],
|
||
"context": {
|
||
"source": "bgp-monitor",
|
||
"severity": "high"
|
||
}
|
||
}'
|
||
```
|
||
|
||
### 直接调用 `aiprovider`
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8010/v1/analyze \
|
||
-H "X-Provider-Token: change_me" \
|
||
-H "X-Request-ID: ai-batch-job-001" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"title": "链路波动分析",
|
||
"objective": "给出简要态势摘要和下一步建议",
|
||
"observations": [
|
||
"多个节点出现延迟上升"
|
||
],
|
||
"constraints": [
|
||
"不要假设根因已经确认"
|
||
],
|
||
"context": {
|
||
"region": "APAC"
|
||
}
|
||
}'
|
||
```
|
||
|
||
## 响应结构
|
||
|
||
后端和 `aiprovider` 返回相同的 payload 结构:
|
||
|
||
```json
|
||
{
|
||
"provider": "minimax",
|
||
"api": "anthropic-messages",
|
||
"model": "MiniMax-M2.7",
|
||
"content": "1) 态势摘要 ...",
|
||
"content_blocks": [],
|
||
"text_blocks": [],
|
||
"thinking_blocks": [],
|
||
"raw_response": {}
|
||
}
|
||
```
|
||
|
||
两个服务都会返回:
|
||
|
||
- `X-Request-ID: <id>`
|
||
|
||
## 配置
|
||
|
||
### 运行时配置链路
|
||
|
||
LLM 的全局默认配置由后端配置中心统一决定。实际调用顺序是:
|
||
|
||
1. 前端或业务代码调用 `backend` 的 `/api/v1/ai/...`。
|
||
2. `backend` 从 PostgreSQL 的 `system_settings` 表读取 `category = external_integrations`。
|
||
3. `payload.ai_provider.default_provider` 决定当前默认 provider。
|
||
4. `payload.ai_provider.providers[provider]` 提供该 provider 的 `api_key`、`provider_api`、`base_url`、`model`、`max_tokens`、`anthropic_version`。
|
||
5. `backend` 把这些值转换成 `X-AI-Provider`、`X-AI-Provider-API`、`X-AI-Base-URL`、`X-AI-API-Key`、`X-AI-Model` 等内部请求头。
|
||
6. `aiprovider` 收到头后用这些值覆盖自己的 `.env`,再调用真实模型厂商。
|
||
|
||
因此,只要 AI 设置页保存了新的默认 provider/model/key,Playground、告警摘要、数据源映射生成等所有后端 AI 调用都会使用同一个新默认配置。
|
||
|
||
#### 持久化结构
|
||
|
||
AI 配置仍保存在 PostgreSQL,不写入 JSON 文件。核心结构如下:
|
||
|
||
```json
|
||
{
|
||
"ai_provider": {
|
||
"service_url": "http://localhost:8010",
|
||
"service_token": "",
|
||
"default_provider": "openai",
|
||
"providers": {
|
||
"openai": {
|
||
"provider_api": "openai-completions",
|
||
"base_url": "https://api.openai.com/v1",
|
||
"model": "gpt-5.1",
|
||
"api_key": "<saved secret>",
|
||
"max_tokens": 4096,
|
||
"anthropic_version": "2023-06-01"
|
||
},
|
||
"minimax": {
|
||
"provider_api": "anthropic-messages",
|
||
"base_url": "https://api.minimaxi.com/anthropic",
|
||
"model": "MiniMax-M2.7",
|
||
"api_key": "<saved secret>",
|
||
"max_tokens": 1200,
|
||
"anthropic_version": "2023-06-01"
|
||
}
|
||
},
|
||
"timeout_seconds": 60,
|
||
"retry_attempts": 2
|
||
}
|
||
}
|
||
```
|
||
|
||
历史单槽配置会在读取时兼容映射到当前 provider 的 `providers[provider]`,保存后写回新结构。
|
||
|
||
#### Key fallback
|
||
|
||
每个 provider 都有自己的 key 槽。解析顺序是:
|
||
|
||
1. PostgreSQL 中 `providers[provider].api_key`
|
||
2. `aiprovider/.env` 中 preset 对应的专属变量,例如 `OPENAI_API_KEY`、`MINIMAX_API_KEY`、`ANTHROPIC_API_KEY`
|
||
3. `aiprovider/.env` 中的通用 `AI_API_KEY`
|
||
|
||
`.env` 只是兜底。配置页保存或测试连接成功后,PostgreSQL 中的配置会成为全局默认。
|
||
|
||
Admin 的密钥状态必须按 provider / tool 精确判断:
|
||
|
||
- 数据库中当前 provider/tool 有密钥时,显示为“已配置”。
|
||
- 数据库没有密钥,但 fallback provider、model 或 tool 与当前项匹配时,可以显示 fallback 的脱敏预览。
|
||
- 数据库没有密钥且 fallback 不匹配当前项时,显示为“未配置”,不能把其它 provider 的 `.env` 通用 key 当成当前项已配置。
|
||
- 脱敏规则保留 key 第一个 `-` 之前的前缀,例如 `sk-********`;明文显示只在有权限的配置页面内按需触发。
|
||
|
||
工具 key 使用同样规则。WebSearch、OCR 这类工具必须先匹配当前工具和 provider,再决定能否使用 fallback。
|
||
|
||
### 轻量连通性测试
|
||
|
||
Admin 的插头按钮走轻量连通性测试,不承担保存职责。业界常见做法是分两层:
|
||
|
||
- 快速检查 provider 目录或低成本 endpoint,确认 base URL、鉴权和当前模型是否可达。
|
||
- 只有在用户明确运行 Playground 或业务任务时才发完整模型请求。
|
||
|
||
因此,连通性测试应尽量使用低成本请求,并返回明确状态:
|
||
|
||
- `ok`: 鉴权、路由和模型目录可用。
|
||
- `warning`: 服务可达,但当前模型不在目录或能力声明不完整。
|
||
- `error`: 鉴权失败、网络失败、协议错误或模型不可用。
|
||
|
||
错误 toast 标题必须和结果一致,不能在失败时显示“连通性正常”。
|
||
|
||
### OpenCode Go 路由模型
|
||
|
||
OpenCode Go 这类订阅通道不要靠前端硬编码模型集合判断协议。推荐在 provider catalog 或后端能力发现中记录每个模型的协议能力,例如 `chat_completions`、`anthropic_messages`、`models_endpoint` 和是否需要订阅 key。前端只展示能力结果;后端负责把 provider、base URL、model 和协议适配映射为实际请求。
|
||
|
||
#### 配置页行为
|
||
|
||
- Provider 下拉框决定当前默认 provider。
|
||
- 模型下拉框保存当前 provider 的默认模型。
|
||
- LLM API Key 输入框隐藏时显示脱敏预览;有 `-` 前缀的 key 会保留前缀,例如 `sk-********`,没有前缀的 key 全量脱敏。
|
||
- 点击眼睛会从后端取回完整明文;再次隐藏会恢复脱敏预览。
|
||
- “保存 AI 配置”直接保存当前表单为全局默认配置。
|
||
- “测试连接”先用当前表单发起真实模型链路测试,成功后也会保存为全局默认配置;失败不会覆盖旧配置。
|
||
- 清空输入框并保存表示保留旧 key,不表示删除 key。
|
||
|
||
### 后端
|
||
|
||
推荐的后端 `.env`:
|
||
|
||
```env
|
||
AI_PROVIDER_SERVICE_URL=http://localhost:8010
|
||
AI_PROVIDER_SERVICE_TOKEN=change_me
|
||
AI_PROVIDER_TIMEOUT_SECONDS=60
|
||
AI_PROVIDER_RETRY_ATTEMPTS=2
|
||
```
|
||
|
||
参考文件:
|
||
|
||
- [backend/.env.example](/home/ray/dev/linkong/planet/backend/.env.example)
|
||
|
||
### AI Provider
|
||
|
||
参考文件:
|
||
|
||
- [aiprovider/.env.example](/home/ray/dev/linkong/planet/aiprovider/.env.example)
|
||
|
||
前端本地参考:
|
||
|
||
- [frontend/.env.example](/home/ray/dev/linkong/planet/frontend/.env.example)
|
||
|
||
通用配置:
|
||
|
||
```env
|
||
SERVICE_NAME=planet-ai-provider
|
||
SERVICE_VERSION=0.1.0
|
||
AI_PROVIDER_SERVICE_TOKEN=change_me
|
||
AI_TIMEOUT_SECONDS=60
|
||
AI_HTTP_RETRY_ATTEMPTS=2
|
||
```
|
||
|
||
可选 provider 专属 key:
|
||
|
||
```env
|
||
MINIMAX_API_KEY=sk-cp-xxxxx
|
||
OPENAI_API_KEY=sk-xxxxx
|
||
ANTHROPIC_API_KEY=sk-ant-xxxxx
|
||
DEEPSEEK_API_KEY=sk-xxxxx
|
||
DASHSCOPE_API_KEY=sk-xxxxx
|
||
MOONSHOT_API_KEY=sk-xxxxx
|
||
OPENROUTER_API_KEY=sk-or-xxxxx
|
||
```
|
||
|
||
### OpenAI 兼容示例
|
||
|
||
```env
|
||
AI_PROVIDER=openai
|
||
AI_PROVIDER_API=openai-completions
|
||
AI_BASE_URL=http://127.0.0.1:8001/v1
|
||
AI_API_KEY=local-key
|
||
AI_MODEL=your-local-model
|
||
```
|
||
|
||
### MiniMax 中国区示例
|
||
|
||
```env
|
||
AI_PROVIDER=minimax
|
||
AI_PROVIDER_API=anthropic-messages
|
||
AI_BASE_URL=https://api.minimaxi.com/anthropic
|
||
AI_API_KEY=sk-cp-xxxxx
|
||
AI_MODEL=MiniMax-M2.7
|
||
AI_MAX_TOKENS=1200
|
||
AI_ANTHROPIC_VERSION=2023-06-01
|
||
```
|
||
|
||
MiniMax 说明:
|
||
|
||
- 这里使用官方 MiniMax 示例中的 Anthropic Messages 请求结构。
|
||
- 对 MiniMax,`aiprovider` 默认不会开启 `thinking`,除非调用方显式传入 `thinking` 对象。
|
||
- 这个行为和 OpenClaw 对 MiniMax Anthropic 兼容接口的谨慎处理保持一致。
|
||
|
||
### Anthropic 兼容示例
|
||
|
||
```env
|
||
AI_PROVIDER=anthropic
|
||
AI_PROVIDER_API=anthropic-messages
|
||
AI_BASE_URL=https://your-claude-compatible-endpoint.example.com/anthropic
|
||
AI_API_KEY=your_api_key
|
||
AI_MODEL=your-model
|
||
AI_MAX_TOKENS=1200
|
||
AI_ANTHROPIC_VERSION=2023-06-01
|
||
```
|
||
|
||
### Ollama 示例
|
||
|
||
```env
|
||
AI_PROVIDER=ollama
|
||
AI_PROVIDER_API=ollama-generate
|
||
AI_BASE_URL=http://127.0.0.1:11434
|
||
AI_API_KEY=
|
||
AI_MODEL=qwen2.5:7b
|
||
```
|
||
|
||
## 部署模式
|
||
|
||
### 单机部署
|
||
|
||
推荐的本地流程:
|
||
|
||
- `backend` 运行在 `localhost:8000`
|
||
- `aiprovider` 运行在 `localhost:8010`
|
||
- 本地模型网关运行在 `localhost:11434` 或其它本地端口
|
||
|
||
仓库内已包含辅助入口:
|
||
|
||
- [planet.sh](/home/ray/dev/linkong/planet/planet.sh)
|
||
- [docker-compose.local-model.yml](/home/ray/dev/linkong/planet/docker-compose.local-model.yml)
|
||
|
||
### 多机部署
|
||
|
||
示例拓扑:
|
||
|
||
- 应用机器:`backend`
|
||
- AI 网关机器:`aiprovider`
|
||
- 模型机器:本地模型服务或云代理
|
||
|
||
此时链路变成服务间 HTTP RPC:
|
||
|
||
- caller -> backend
|
||
- backend -> `http://10.0.0.12:8010`
|
||
- `aiprovider` -> 模型端点
|
||
|
||
推荐的跨机器后端配置:
|
||
|
||
```env
|
||
AI_PROVIDER_SERVICE_URL=http://10.0.0.12:8010
|
||
AI_PROVIDER_SERVICE_TOKEN=change_me
|
||
AI_PROVIDER_TIMEOUT_SECONDS=60
|
||
AI_PROVIDER_RETRY_ATTEMPTS=2
|
||
```
|
||
|
||
推荐运行规则:
|
||
|
||
- 将 `aiprovider` 放在私有网络内
|
||
- 至少用 `X-Provider-Token` 保护它
|
||
- 始终发送 `X-Request-ID`
|
||
- 除基础设施任务外,调用方优先走后端 API
|
||
|
||
## 重试和失败行为
|
||
|
||
`backend -> aiprovider`:
|
||
|
||
- 对轻量网络错误和 5xx 失败进行重试
|
||
- provider 服务不可用时返回 `502`
|
||
|
||
`aiprovider -> model provider`:
|
||
|
||
- 对轻量网络错误和 5xx 失败进行重试
|
||
- 模型提供方不可用时返回 `502`
|
||
|
||
这个策略故意保持保守:它能吸收短暂抖动,但不会掩盖持续性错误。
|
||
|
||
## 运维说明
|
||
|
||
- `./planet.sh start` 会自动启动 `aiprovider`
|
||
- `./planet.sh restart -a` 只重启 `aiprovider`
|
||
- `./planet.sh log -a` 跟随查看 `aiprovider` 日志
|
||
- `./planet.sh health` 会报告 `aiprovider` 健康状态
|
||
|
||
## 推荐调用策略
|
||
|
||
- 前端和应用服务:调用 `backend`
|
||
- 定时基础设施任务和诊断任务:可选直接调用 `aiprovider`
|
||
- 不要让多个业务服务分别接入模型厂商
|
||
|
||
这样可以集中管理 provider 切换,避免模型相关差异在系统里四处扩散。
|