Files
planet/docs/technical/en/agents-aiprovider.md
rayd1o cee1996809
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
release / images (push) Has been cancelled
ci / delivery (push) Has been cancelled
release: bump version to 0.74.5
2026-09-13 14:04:34 +08:00

20 KiB
Raw Blame History

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
  • openai-responses
  • 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
  • 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

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.

Model refresh and lightweight checks share backend/app/services/llm_model_catalog.py and query provider endpoints directly, without models.dev. Refresh uses the draft base URL, protocol and credentials, or saved configuration when no draft is supplied. Regional hosts and custom gateway paths are preserved. Missing required credentials return 400; upstream failures return safe errors and retain the previous catalog.

Successful catalogs and refreshed_at are stored under llm_provider_preset:<provider> in system_settings. Dynamic categories use the provider preset as their defaults and are validated before committing. Listing prefers saved catalogs and otherwise shows bundled suggestions. Refresh never modifies the active model, protocol, URL or credentials in external_integrations. The frontend retains the draft and previously loaded models when listing fails, with an explicit error message.

Model Catalog Endpoints

These endpoints were checked against official documentation on 2026-09-13. The table lists discovery URLs; the form still takes the generation base URL. Credentials must belong to the configured service region.

Provider Model list GET endpoint Authentication and parsing
MiniMax https://api.minimaxi.com/anthropic/v1/models; international: api.minimax.io x-api-key; data[].id; has_more/last_id pagination
OpenAI https://api.openai.com/v1/models Bearer; data[].id
Anthropic https://api.anthropic.com/v1/models x-api-key, anthropic-version; paginate with after_id
DeepSeek https://api.deepseek.com/v1/models Bearer; data[].id
Alibaba Model Studio /api/v1/models on the configured regional host Bearer; output.models[].model; page_no/page_size/output.total; filter capabilities=TG
Moonshot / Kimi https://api.moonshot.ai/v1/models; China: api.moonshot.cn Bearer; data[].id
OpenRouter https://openrouter.ai/api/v1/models Public catalog; Bearer when supplied; data[].id
OpenCode Go https://opencode.ai/zen/go/v1/models Public catalog; Bearer when supplied; data[].id
Ollama /api/tags on the configured server Local servers need no key; models[].model/name; empty means no installed models

New Model Studio endpoints for Beijing, Tokyo, Frankfurt and Virginia require the actual workspace host, such as <WorkspaceId>.cn-beijing.maas.aliyuncs.com. Singapore uses dashscope-intl.aliyuncs.com; Hong Kong uses cn-hongkong.dashscope.aliyuncs.com. Discovery changes only the path, never guesses a workspace or switches credential regions. If a legacy Beijing host no longer accepts the account, update the base URL from the provider console.

Pagination and retries have a 30-second overall deadline. Network failures and 502/503/504 allow up to two attempts; authentication failures are not retried. Models are sorted by supplied creation/release dates, preserving upstream order on ties, without arbitrary list truncation. Public catalog membership does not establish account-specific generation permission.

Admin keeps the AI page aligned with the legacy information architecture:

  • Model Providers
    • Manages provider, wire adapter, default model, LLM API key, proxy URL, proxy token, model refresh, set-as-default, and lightweight connectivity testing.
  • Tool Calling
    • Manages tools such as WebSearch and OCR. Each tool first selects a provider, then edits that provider's API, key, and advanced parameters.
  • Prompts
    • Edits system/user prompts by prompt group and task key. Save and reset only affect the current task.
  • Playground
    • Runs real conversations with the active provider and prompt configuration. AI responses are rendered as Markdown.

Save, set-as-default, and connectivity testing are separate responsibilities: save only persists the form, set-as-default only changes the active provider/tool, and connectivity testing only validates the current draft. It must not implicitly save or switch defaults.

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.

Agent And Tool Boundary

Agent workflows belong in the backend, not in aiprovider. Future Earth LLM commands, situational awareness, multi-role simulation, WebSearch, database queries, evidence storage, and configuration proposal application should be orchestrated by the backend Agent Runtime. aiprovider should receive model-ready requests from the backend and return normalized model responses.

If a provider supports native tool calling, aiprovider may pass through protocol fields and normalize response blocks, but tool whitelists, argument validation, permission policy, run records, and write approvals must stay in the backend. When a provider does not support native tools, the backend uses JSON tool-call fallback; business tools should not move into aiprovider for a provider-specific shortcut.

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.

Admin must compute key status per provider or tool:

  • If the database has a key for the current provider/tool, show configured.
  • If the database has no key but the fallback provider, model, or tool matches the current item, show the fallback masked preview.
  • If neither database nor matching fallback exists, show not configured; a generic .env key for another provider must not make this item appear configured.
  • Masking keeps the prefix before the first -, for example sk-********. Plaintext reveal is only available inside the authorized configuration page.

Tool keys follow the same rule. WebSearch and OCR must match the current tool and provider before they can use fallback credentials.

Lightweight Connectivity Testing

The Admin plug button checks proxy configuration and queries the current provider catalog. It returns success=true only when discovery succeeds and contains the selected model. A 404, authentication error, invalid response or missing model never becomes success based on bundled suggestions. The message distinguishes discovery from generation; Playground or a business task verifies actual generation. Testing never saves the draft or switches the default provider.

OpenCode Go Routing Model

OpenCode Go protocol mappings are owned by the backend catalog: MiniMax M3/M2.7/M2.5 and the verified Qwen3.6/3.7/3.8 models use Anthropic Messages; GPT-5.6 Luna, Grok 4.6 and Muse Spark Contributor use Responses; other supported models use Chat Completions. The official /models response currently supplies IDs only, so new models still require checking the documented endpoint table. Selecting a model updates its protocol in the draft, and backend mappings supersede known stale mappings. Responses uses input, max_output_tokens and store=false, and parses text and reasoning summaries. OpenCode calls carry an application User-Agent and a stable Playground conversation identifier. Generic thinking=enabled is translated to MiniMax M3s adaptive format.

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.