13 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->aiprovideraiprovider-> concrete model provider
The recommended default is:
- External and cross-service callers use
planet backend - Only infrastructure-grade internal jobs call
aiproviderdirectly
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.envdefaults through internal headers
aiprovider is responsible for:
- model protocol adaptation
- provider selection by
.envwhen no backend override headers are present - timeout and lightweight retry
- request tracing via
X-Request-ID
This now follows an OpenClaw-like seam:
AI_PROVIDERidentifies the vendor or logical providerAI_PROVIDER_APIidentifies 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:
openaianthropicminimaxollama
Supported request adapters:
openai-completionsanthropic-messagesollama-generate
Backward-compatible aliases still accepted:
openai_compatibleanthropic_compatibleclaude_compatible
Provider mapping:
vLLM,LM Studio,One API:AI_PROVIDER=openai,AI_PROVIDER_API=openai-completionsMiniMax: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/statusPOST /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/integrationsPUT /api/v1/settings/integrationsPOST /api/v1/settings/integrations/ai-provider/connectGET /api/v1/settings/integrations/ai-provider/secretsGET /api/v1/settings/integrations/ai-provider/presetsGET /api/v1/settings/ai-promptsPUT /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.
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/statusPOST /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:
- Frontend or application code calls a
backend/api/v1/ai/...endpoint. backendreadscategory = external_integrationsfrom the PostgreSQLsystem_settingstable.payload.ai_provider.default_providerselects the active provider.payload.ai_provider.providers[provider]supplies that provider'sapi_key,provider_api,base_url,model,max_tokens, andanthropic_version.backendconverts those values to internal headers such asX-AI-Provider,X-AI-Provider-API,X-AI-Base-URL,X-AI-API-Key, andX-AI-Model.aiprovideruses those headers to override its.envdefaults 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:
providers[provider].api_keyin PostgreSQL- the provider-specific variable in
aiprovider/.env, such asOPENAI_API_KEY,MINIMAX_API_KEY, orANTHROPIC_API_KEY - the generic
AI_API_KEYinaiprovider/.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 examplesk-********, 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 Configurationsaves the current form as the global default.Test Connectionuses 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,
aiprovidernow disablesthinkingby default unless the caller explicitly passes athinkingobject. - 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:
backendonlocalhost:8000aiprovideronlocalhost:8010- local model gateway on
localhost:11434or 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
aiprovideron a private network - protect it with
X-Provider-Tokenat 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
502when the provider service is unavailable
aiprovider -> model provider:
- retries lightweight network / 5xx failures
- returns
502when the model provider is unavailable
This is intentionally conservative. It avoids masking persistent errors while still absorbing short hiccups.
Operational Notes
./planet.sh startnow startsaiproviderautomatically./planet.sh restart -arestarts onlyaiprovider./planet.sh log -atailsaiproviderlogs./planet.sh healthreportsaiproviderhealth
Recommended Calling Policy
- 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.