Files
planet/docs/technical/en/agents-aiprovider.md
rayd1o 9b913a3b83
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.59.0
2026-05-16 05:02:05 +08:00

12 KiB

AI Provider Guide

Overview

aiprovider is the model-adapter service for Planet.

It isolates model-vendor details from the main backend so the rest of the system can call a stable business API:

  • Caller service -> planet backend
  • planet backend -> aiprovider
  • aiprovider -> concrete model provider

The recommended default is:

  • External and cross-service callers use planet backend
  • Only infrastructure-grade internal jobs call aiprovider directly

Responsibilities

backend is responsible for:

  • authentication and authorization
  • business-level request shaping
  • stable /api/v1/ai/... endpoints
  • internal service-to-service authentication toward aiprovider
  • reading the default provider, model, and per-provider keys saved in Settings, then overriding aiprovider .env defaults through internal headers

aiprovider is responsible for:

  • model protocol adaptation
  • provider selection by .env when no backend override headers are present
  • timeout and lightweight retry
  • request tracing via X-Request-ID

This now follows an OpenClaw-like seam:

  • AI_PROVIDER identifies the vendor or logical provider
  • AI_PROVIDER_API identifies the wire adapter

That split makes MiniMax, Claude-compatible gateways, and self-hosted OpenAI-compatible services easier to model without overloading one config field.

Supported Providers

aiprovider currently supports these provider identities:

  • openai
  • anthropic
  • minimax
  • ollama

Supported request adapters:

  • openai-completions
  • anthropic-messages
  • ollama-generate

Backward-compatible aliases still accepted:

  • openai_compatible
  • anthropic_compatible
  • claude_compatible

Provider mapping:

  • vLLM, LM Studio, One API: AI_PROVIDER=openai, AI_PROVIDER_API=openai-completions
  • MiniMax: AI_PROVIDER=minimax, AI_PROVIDER_API=anthropic-messages
  • Claude-compatible gateways: AI_PROVIDER=anthropic, AI_PROVIDER_API=anthropic-messages
  • Ollama: AI_PROVIDER=ollama, AI_PROVIDER_API=ollama-generate

API Surfaces

Main backend API

Preferred stable entrypoints:

  • GET /api/v1/ai/provider/status
  • POST /api/v1/ai/situational-awareness/analyze

Authentication:

  • Authorization: Bearer <jwt>

Optional tracing header:

  • X-Request-ID: <caller-generated-id>

The backend will propagate X-Request-ID to aiprovider and return the same header in the response.

Settings API

The AI settings page uses:

  • 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

These endpoints require an authenticated user. The secrets endpoint is only used when the settings page reveals a key or token; hiding the field restores the masked preview.

The ai-prompts endpoints back the Prompts tab in AI settings. Shipped defaults come from versioned backend resources, while business code references stable task keys. The API stores only operator overrides. Resetting a prompt removes the override and falls back to the current shipped default.

Prompt Boundary

aiprovider is a pure model adapter and does not inject a global business system prompt. News localization, alert briefing, BGP briefing, location factcheck, datasource mapping, and credential guide generation each resolve their own effective prompt by task key. Alert-analysis system prompts are only sent by alert-related tasks and do not leak into other LLM calls.

AI provider internal API

Internal-only endpoints:

  • GET /v1/provider/status
  • POST /v1/analyze

Authentication:

  • X-Provider-Token: <shared-secret>

Optional tracing header:

  • X-Request-ID: <caller-generated-id>

Request Example

Call through backend

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"
    }
  }'

Call aiprovider directly

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"
    }
  }'

Response Shape

Both backend and aiprovider return the same payload shape:

{
  "provider": "minimax",
  "api": "anthropic-messages",
  "model": "MiniMax-M2.7",
  "content": "1) 态势摘要 ...",
  "content_blocks": [],
  "text_blocks": [],
  "thinking_blocks": [],
  "raw_response": {}
}

Both services also return:

  • X-Request-ID: <id>

Configuration

Runtime Configuration Flow

The backend Settings system owns the global LLM default. The runtime flow is:

  1. Frontend or application code calls a backend /api/v1/ai/... endpoint.
  2. backend reads category = external_integrations from the PostgreSQL system_settings table.
  3. payload.ai_provider.default_provider selects the active provider.
  4. payload.ai_provider.providers[provider] supplies that provider's api_key, provider_api, base_url, model, max_tokens, and anthropic_version.
  5. backend converts those values to internal headers such as X-AI-Provider, X-AI-Provider-API, X-AI-Base-URL, X-AI-API-Key, and X-AI-Model.
  6. aiprovider uses those headers to override its .env defaults before calling the real model vendor.

After the AI settings page saves a new default provider/model/key, Playground, alert briefs, datasource mapping generation, and other backend AI calls all use that same default.

Persistence Shape

AI settings are persisted in PostgreSQL, not a JSON file. The core payload shape is:

{
  "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
  }
}

Legacy single-slot settings are mapped to providers[provider] on read and are written back in the new shape on save.

Key Fallback

Each provider has its own key slot. Resolution order is:

  1. providers[provider].api_key in PostgreSQL
  2. the provider-specific variable in aiprovider/.env, such as OPENAI_API_KEY, MINIMAX_API_KEY, or ANTHROPIC_API_KEY
  3. the generic AI_API_KEY in aiprovider/.env

.env is only a fallback. After the settings page saves successfully, or after the connection test succeeds, PostgreSQL becomes the global default source.

Settings Page Behavior

  • The Provider select controls the global default provider.
  • The model select saves the default model for the selected provider.
  • The LLM API Key field shows a masked preview while hidden; keys with a - prefix keep the prefix, for example sk-********, and keys without a prefix are fully masked.
  • Clicking the eye icon fetches and displays the full plaintext value; hiding restores the masked preview.
  • Save AI Configuration saves the current form as the global default.
  • Test Connection uses the current form for a real model-chain test, then saves it as the global default only when the test succeeds.
  • Leaving a key field empty keeps the old key; it does not delete it.

Backend

Recommended backend .env:

AI_PROVIDER_SERVICE_URL=http://localhost:8010
AI_PROVIDER_SERVICE_TOKEN=change_me
AI_PROVIDER_TIMEOUT_SECONDS=60
AI_PROVIDER_RETRY_ATTEMPTS=2

Reference file:

AI Provider

Reference file:

Frontend local reference:

Common settings:

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

Optional provider-specific keys:

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-compatible example

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 CN example

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 note:

  • This follows the same Anthropic Messages request shape as the official MiniMax examples.
  • For MiniMax, aiprovider now disables thinking by default unless the caller explicitly passes a thinking object.
  • This mirrors OpenClaw's caution around MiniMax Anthropic-compatible behavior.

Anthropic-compatible example

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 example

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

Deployment Modes

Single machine

Recommended local flow:

  • backend on localhost:8000
  • aiprovider on localhost:8010
  • local model gateway on localhost:11434 or another local port

Helpers already included:

Multi-machine

Example topology:

  • app machine: backend
  • AI gateway machine: aiprovider
  • model machine: local model service or cloud proxy

In that case, this becomes service-to-service HTTP RPC:

  • caller -> backend
  • backend -> http://10.0.0.12:8010
  • aiprovider -> model endpoint

Recommended cross-machine backend config:

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

Recommended operating rules:

  • keep aiprovider on a private network
  • protect it with X-Provider-Token at minimum
  • always send X-Request-ID
  • keep callers on the backend API unless they are infrastructure jobs

Retry And Failure Behavior

backend -> aiprovider:

  • retries lightweight network / 5xx failures
  • returns 502 when the provider service is unavailable

aiprovider -> model provider:

  • retries lightweight network / 5xx failures
  • returns 502 when the model provider is unavailable

This is intentionally conservative. It avoids masking persistent errors while still absorbing short hiccups.

Operational Notes

  • ./planet.sh start now starts aiprovider automatically
  • ./planet.sh restart -a restarts only aiprovider
  • ./planet.sh log -a tails aiprovider logs
  • ./planet.sh health reports aiprovider health
  • Frontend and application services: call backend
  • Scheduled infra jobs and diagnostics: optionally call aiprovider
  • Do not let multiple business services integrate model vendors independently

That keeps provider switching centralized and avoids model-specific drift across the system.