334 lines
7.9 KiB
Markdown
334 lines
7.9 KiB
Markdown
# 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`
|
|
|
|
`aiprovider` is responsible for:
|
|
|
|
- model protocol adaptation
|
|
- provider selection by `.env`
|
|
- 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.
|
|
|
|
### 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
|
|
|
|
```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"
|
|
}
|
|
}'
|
|
```
|
|
|
|
### Call `aiprovider` directly
|
|
|
|
```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"
|
|
}
|
|
}'
|
|
```
|
|
|
|
## Response Shape
|
|
|
|
Both backend and `aiprovider` return the same payload shape:
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
### Backend
|
|
|
|
Recommended backend `.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
|
|
```
|
|
|
|
Reference file:
|
|
|
|
- [backend/.env.example](/home/ray/dev/linkong/planet/backend/.env.example)
|
|
|
|
### AI Provider
|
|
|
|
Reference file:
|
|
|
|
- [aiprovider/.env.example](/home/ray/dev/linkong/planet/aiprovider/.env.example)
|
|
|
|
Frontend local reference:
|
|
|
|
- [frontend/.env.example](/home/ray/dev/linkong/planet/frontend/.env.example)
|
|
|
|
Common settings:
|
|
|
|
```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
|
|
AI_ANALYSIS_SYSTEM_PROMPT=你是态势感知分析助手。请基于输入的上下文、观测与约束,输出结构化、克制、可执行的分析。
|
|
```
|
|
|
|
### OpenAI-compatible example
|
|
|
|
```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 CN example
|
|
|
|
```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 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
|
|
|
|
```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 example
|
|
|
|
```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
|
|
```
|
|
|
|
## 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:
|
|
|
|
- [planet.sh](/home/ray/dev/linkong/planet/planet.sh)
|
|
- [docker-compose.local-model.yml](/home/ray/dev/linkong/planet/docker-compose.local-model.yml)
|
|
|
|
### 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:
|
|
|
|
```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
|
|
```
|
|
|
|
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
|
|
|
|
## 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.
|