Files
planet/docs/technical/zh/agents-aiprovider.md
rayd1o 58671e7bc3
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled
release / images (push) Has been cancelled
release: bump version to 0.74.4
2026-09-13 10:27:00 +08:00

486 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`
- `POST /api/v1/settings/integrations/ai-provider/presets/{provider}/refresh`
- `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 时取回明文,隐藏时前端恢复为脱敏预览。
模型目录刷新由 `backend/app/services/llm_provider_catalog.py` 获取上游目录;多数供应商读取 models.devOpenCode Go 使用自己的模型接口。models.dev 条目按发布日期倒序排列,缺少日期的条目排在后面。成功结果和 `refreshed_at` 按供应商保存在 `system_settings``llm_provider_preset:<provider>` 分类中,列表接口优先返回已保存目录,未刷新过的供应商使用内置预设。刷新只更新目录,不写入 `external_integrations` 中的当前模型、协议、地址或凭证。失败返回 502 并保留上次目录;上游异常原文不返回客户端。前端重新加载目录,可选模型读取目录状态,表单草稿独立保留。
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/keyPlayground、告警摘要、数据源映射生成等所有后端 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 切换,避免模型相关差异在系统里四处扩散。