feat: add aiprovider service foundation

This commit is contained in:
linkong
2026-04-07 17:30:27 +08:00
parent 3f5505f03e
commit 9a50e72bd1
42 changed files with 1766 additions and 166 deletions

View File

@@ -7,6 +7,37 @@ This project follows the repository versioning rule:
- `feature` -> `+0.1.0`
- `bugfix` -> `+0.0.1`
## 0.23.0
Released: 2026-04-07
### Highlights
- Introduced a dedicated `aiprovider` service so the main backend now exposes stable AI business APIs while model-vendor integration lives behind an internal adapter boundary.
- Added multi-protocol model access for `openai-compatible`, `claude-compatible`, and native `ollama` local-model flows, including local startup templates and service-aware restart controls.
- Standardized Python runtime management on `uv` across backend and `aiprovider`, removing the old container-side `pip/requirements.txt` installation path.
### Added
- Added [backend/app/api/v1/ai.py](/home/ray/dev/linkong/planet/backend/app/api/v1/ai.py), exposing stable AI business endpoints for provider status and situational-awareness analysis.
- Added [backend/app/services/ai_client.py](/home/ray/dev/linkong/planet/backend/app/services/ai_client.py), introducing an internal HTTP client for `backend -> aiprovider` calls with request-id propagation and lightweight retry.
- Added [aiprovider/main.py](/home/ray/dev/linkong/planet/aiprovider/main.py), [aiprovider/provider_service.py](/home/ray/dev/linkong/planet/aiprovider/provider_service.py), and related config/schema files to stand up the dedicated adapter service.
- Added [aiprovider/.env.example](/home/ray/dev/linkong/planet/aiprovider/.env.example) and [docker-compose.local-model.yml](/home/ray/dev/linkong/planet/docker-compose.local-model.yml) as ready-to-edit local-model templates.
- Added [docs/aiprovider.md](/home/ray/dev/linkong/planet/docs/aiprovider.md), documenting architecture, configuration, single-machine and multi-machine deployment, and cross-service calling patterns.
- Added a dedicated `重启 AI Provider` control path in [Dashboard.tsx](/home/ray/dev/linkong/planet/frontend/src/pages/Dashboard/Dashboard.tsx), [system_control.py](/home/ray/dev/linkong/planet/backend/app/services/system_control.py), and [system_restart_runner.py](/home/ray/dev/linkong/planet/backend/scripts/system_restart_runner.py).
### Improved
- Improved backend-to-provider tracing by propagating `X-Request-ID` through the AI call chain and returning the same header from both backend and `aiprovider`.
- Improved resilience by adding lightweight retry handling to both `backend -> aiprovider` and `aiprovider -> model provider` HTTP calls.
- Improved operator workflow by folding `aiprovider` startup, health checks, restart support, and log viewing into [planet.sh](/home/ray/dev/linkong/planet/planet.sh).
- Improved container consistency by switching [backend/Dockerfile](/home/ray/dev/linkong/planet/backend/Dockerfile) and [aiprovider/Dockerfile](/home/ray/dev/linkong/planet/aiprovider/Dockerfile) to `uv sync` / `uv run`.
### Changed
- Changed the repository Python dependency source of truth to `pyproject.toml + uv.lock`, and removed the old `backend/requirements.txt` path.
- Changed local restart wording in the dashboard from the vague `重启服务器` label to the more specific `重启后端`, reducing ambiguity once `aiprovider` became independently restartable.
## 0.22.14
Released: 2026-04-07

290
docs/aiprovider.md Normal file
View File

@@ -0,0 +1,290 @@
# 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`
## Supported Providers
`aiprovider` currently supports:
- `openai`
- `openai_compatible`
- `anthropic`
- `anthropic_compatible`
- `claude_compatible`
- `ollama`
Provider mapping:
- `vLLM`, `LM Studio`, `One API`: `openai_compatible`
- `MiniMax`, Claude-compatible gateways: `claude_compatible`
- `Ollama`: `ollama`
## 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": "openai_compatible",
"model": "gpt-4o-mini",
"content": "1) 态势摘要 ...",
"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_compatible
AI_BASE_URL=http://127.0.0.1:8001/v1
AI_API_KEY=local-key
AI_MODEL=your-local-model
```
### Claude-compatible example
```env
AI_PROVIDER=claude_compatible
AI_BASE_URL=https://your-claude-compatible-endpoint.example.com
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_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.

View File

@@ -16,7 +16,7 @@
## Current Version
- `main` 当前主线历史推导到:`0.16.5`
- `dev` 当前开发分支历史推导到:`0.22.9`
- `dev` 当前开发分支历史推导到:`0.23.0`
## Timeline
@@ -70,6 +70,7 @@
| `0.21.5` | bugfix | `dev` | `a761dfc5` | refine Earth legend item presentation |
| `0.21.6` | bugfix | `dev` | `pending` | improve Earth legend generation, info-card interactions, and HUD messaging polish |
| `0.22.9` | bugfix | `dev` | `6bfcd053` | simplify `planet.sh` readiness messaging and only show retry counts on actual restart |
| `0.23.0` | feature | `dev` | `pending` | add dedicated `aiprovider` service, multi-protocol AI adapters, uv-only Python runtime, and AI Provider restart controls |
## Maintenance Commits Not Counted as Version Bumps