# 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 ` 可选追踪头: - `X-Request-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 时取回明文,隐藏时前端恢复为脱敏预览。 `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: ` 可选追踪头: - `X-Request-ID: ` ## 请求示例 ### 通过后端调用 ```bash curl -X POST http://localhost:8000/api/v1/ai/situational-awareness/analyze \ -H "Authorization: Bearer " \ -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: ` ## 配置 ### 运行时配置链路 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": "", "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": "", "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 中的配置会成为全局默认。 #### 配置页行为 - 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 切换,避免模型相关差异在系统里四处扩散。