inference-aiops 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- inference_aiops-0.1.0/.gitignore +7 -0
- inference_aiops-0.1.0/CHANGELOG.md +58 -0
- inference_aiops-0.1.0/LICENSE +21 -0
- inference_aiops-0.1.0/PKG-INFO +129 -0
- inference_aiops-0.1.0/README.md +113 -0
- inference_aiops-0.1.0/RELEASE_NOTES.md +55 -0
- inference_aiops-0.1.0/SECURITY.md +79 -0
- inference_aiops-0.1.0/inference_aiops/__init__.py +9 -0
- inference_aiops-0.1.0/inference_aiops/cli/__init__.py +9 -0
- inference_aiops-0.1.0/inference_aiops/cli/_common.py +78 -0
- inference_aiops-0.1.0/inference_aiops/cli/_root.py +57 -0
- inference_aiops-0.1.0/inference_aiops/cli/doctor.py +21 -0
- inference_aiops-0.1.0/inference_aiops/cli/init.py +97 -0
- inference_aiops-0.1.0/inference_aiops/cli/metrics.py +45 -0
- inference_aiops-0.1.0/inference_aiops/cli/overview.py +16 -0
- inference_aiops-0.1.0/inference_aiops/cli/secret.py +105 -0
- inference_aiops-0.1.0/inference_aiops/cli/serve.py +90 -0
- inference_aiops-0.1.0/inference_aiops/config.py +140 -0
- inference_aiops-0.1.0/inference_aiops/connection.py +215 -0
- inference_aiops-0.1.0/inference_aiops/doctor.py +84 -0
- inference_aiops-0.1.0/inference_aiops/governance/__init__.py +40 -0
- inference_aiops-0.1.0/inference_aiops/governance/audit.py +377 -0
- inference_aiops-0.1.0/inference_aiops/governance/budget.py +225 -0
- inference_aiops-0.1.0/inference_aiops/governance/decorators.py +474 -0
- inference_aiops-0.1.0/inference_aiops/governance/paths.py +23 -0
- inference_aiops-0.1.0/inference_aiops/governance/patterns.py +378 -0
- inference_aiops-0.1.0/inference_aiops/governance/policy.py +411 -0
- inference_aiops-0.1.0/inference_aiops/governance/sanitize.py +39 -0
- inference_aiops-0.1.0/inference_aiops/governance/undo.py +218 -0
- inference_aiops-0.1.0/inference_aiops/ops/__init__.py +1 -0
- inference_aiops-0.1.0/inference_aiops/ops/_util.py +60 -0
- inference_aiops-0.1.0/inference_aiops/ops/cost.py +52 -0
- inference_aiops-0.1.0/inference_aiops/ops/deploy.py +75 -0
- inference_aiops-0.1.0/inference_aiops/ops/metrics.py +152 -0
- inference_aiops-0.1.0/inference_aiops/ops/models.py +88 -0
- inference_aiops-0.1.0/inference_aiops/ops/overview.py +38 -0
- inference_aiops-0.1.0/inference_aiops/ops/ray_cluster.py +154 -0
- inference_aiops-0.1.0/inference_aiops/ops/serve.py +154 -0
- inference_aiops-0.1.0/inference_aiops/secretstore.py +302 -0
- inference_aiops-0.1.0/mcp_server/__init__.py +1 -0
- inference_aiops-0.1.0/mcp_server/_shared.py +101 -0
- inference_aiops-0.1.0/mcp_server/server.py +35 -0
- inference_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
- inference_aiops-0.1.0/mcp_server/tools/cost.py +27 -0
- inference_aiops-0.1.0/mcp_server/tools/deploy.py +110 -0
- inference_aiops-0.1.0/mcp_server/tools/metrics.py +70 -0
- inference_aiops-0.1.0/mcp_server/tools/models.py +101 -0
- inference_aiops-0.1.0/mcp_server/tools/ray_cluster.py +104 -0
- inference_aiops-0.1.0/mcp_server/tools/serve.py +216 -0
- inference_aiops-0.1.0/pyproject.toml +59 -0
- inference_aiops-0.1.0/server.json +21 -0
- inference_aiops-0.1.0/skills/inference-aiops/SKILL.md +116 -0
- inference_aiops-0.1.0/skills/inference-aiops/references/capabilities.md +80 -0
- inference_aiops-0.1.0/skills/inference-aiops/references/cli-reference.md +56 -0
- inference_aiops-0.1.0/skills/inference-aiops/references/setup-guide.md +107 -0
- inference_aiops-0.1.0/smithery.yaml +9 -0
- inference_aiops-0.1.0/tests/test_cost.py +47 -0
- inference_aiops-0.1.0/tests/test_deploy.py +86 -0
- inference_aiops-0.1.0/tests/test_models.py +69 -0
- inference_aiops-0.1.0/tests/test_ray_cluster.py +74 -0
- inference_aiops-0.1.0/tests/test_secretstore.py +99 -0
- inference_aiops-0.1.0/tests/test_smoke.py +280 -0
- inference_aiops-0.1.0/uv.lock +962 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to inference-aiops are documented here. This project adheres
|
|
4
|
+
to [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [0.1.0] — preview
|
|
7
|
+
|
|
8
|
+
Initial preview release: governed AI-ops for GPU inference clusters (vLLM + Ray
|
|
9
|
+
Serve / Ray Jobs) with a bundled governance harness. **Mock-validated only — not
|
|
10
|
+
yet verified against a live cluster.**
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **30 MCP tools** (16 read, 14 write), every one wrapped with the bundled
|
|
15
|
+
`@governed_tool` harness (audit, policy, token/runaway budget, undo,
|
|
16
|
+
risk-tiers):
|
|
17
|
+
- **Metrics & RCA** — `request_metrics` (TTFT/TPOT/e2e latency + token
|
|
18
|
+
totals), `queue_depth` (running vs waiting backpressure), `kv_cache_stats`
|
|
19
|
+
(KV utilisation, prefix-cache hit rate, preemptions), and the flagship
|
|
20
|
+
correlators `diagnose_latency_spike` and `diagnose_low_utilization` (fold
|
|
21
|
+
queue depth + KV-cache pressure + prefix-cache locality into a ranked cause
|
|
22
|
+
plus the specific knob to turn).
|
|
23
|
+
- **Ray Serve** — reads `serve_deployment_list`, `deployment_status`,
|
|
24
|
+
`replica_list`, `autoscale_config_get`; writes `scale_replicas_up` (med,
|
|
25
|
+
undo), `scale_replicas_down` (high, dry-run, undo), `scale_to_zero` (high,
|
|
26
|
+
dry-run, undo), `autoscale_config_update` (med, undo), `drain_replica`
|
|
27
|
+
(high, dry-run, graceful — finishes in-flight requests).
|
|
28
|
+
- **Models / vLLM** — `model_list`, `model_info` (read); `lora_load` (med),
|
|
29
|
+
`lora_unload` (high, dry-run), `model_hot_swap` (high, dry-run — Sleep-Mode
|
|
30
|
+
base swap, captures the prior model).
|
|
31
|
+
- **Ray cluster / jobs / GPU** — `ray_cluster_resources` (CPU/GPU alloc),
|
|
32
|
+
`ray_dashboard_status`, `ray_job_list`, `gpu_utilization` (per-node) as
|
|
33
|
+
reads; `ray_job_cancel` (med) and `replica_restart` (high, dry-run) as writes.
|
|
34
|
+
- **Deploy lifecycle** — `model_deploy` (med), `model_undeploy` (high,
|
|
35
|
+
dry-run), `deployment_redeploy` (high, dry-run), `routing_policy_update`
|
|
36
|
+
(med, undo — prefix-aware / session-affinity routing to fix cache locality).
|
|
37
|
+
- **Cost** — `cost_per_token` (deterministic $/1M tokens from throughput ×
|
|
38
|
+
GPU $/hr).
|
|
39
|
+
- **Prometheus-native metrics** — parses vLLM's `/metrics` endpoint directly; no
|
|
40
|
+
Prometheus server required.
|
|
41
|
+
- **Optional encrypted secret store** — a bearer token is optional (many stacks
|
|
42
|
+
run open); when required it is stored encrypted in
|
|
43
|
+
`~/.inference-aiops/secrets.enc` (Fernet + scrypt), never plaintext on disk.
|
|
44
|
+
Legacy `INFERENCE_<TARGET>_TOKEN` env var honoured as a fallback.
|
|
45
|
+
- **CLI** (`inference-aiops`) — `init` wizard, `overview`, `serve`
|
|
46
|
+
(list/status/scale/scale-to-zero), `metrics` (requests/queue/diagnose),
|
|
47
|
+
`secret` management, `mcp`, and a `doctor` that probes the Ray dashboard and
|
|
48
|
+
vLLM independently.
|
|
49
|
+
- **Connection layer** over the Ray dashboard (Serve + Jobs) and the vLLM
|
|
50
|
+
services with centralised teaching error translation.
|
|
51
|
+
|
|
52
|
+
### Known limitations
|
|
53
|
+
|
|
54
|
+
- Preview / mock-only: validated against mocked vLLM `/metrics`, vLLM OpenAI
|
|
55
|
+
API, and Ray dashboard responses; needs live verification.
|
|
56
|
+
- Unverified against real hardware / topology: multi-GPU tensor-parallel /
|
|
57
|
+
pipeline-parallel deployments, real GPU thermal/throttle telemetry, and
|
|
58
|
+
multi-node drain / node-reboot orchestration.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wei <zhouwei008@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: inference-aiops
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Governed AI-ops for GPU inference clusters (vLLM + Ray Serve/Jobs): latency/utilization RCA, replica scaling, drain, model lifecycle, and destructive-op guardrails with a built-in governance harness (audit, budget, undo, risk tiers)
|
|
5
|
+
Author-email: wei <zhouwei008@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Requires-Dist: cryptography>=42.0
|
|
10
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
11
|
+
Requires-Dist: mcp[cli]<2.0,>=1.10
|
|
12
|
+
Requires-Dist: pyyaml<7.0,>=6.0
|
|
13
|
+
Requires-Dist: rich<16.0,>=13.0
|
|
14
|
+
Requires-Dist: typer<1.0,>=0.12
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
<!-- mcp-name: io.github.AIops-tools/inference-aiops -->
|
|
18
|
+
|
|
19
|
+
# Inference AIops (preview)
|
|
20
|
+
|
|
21
|
+
> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by the vLLM or Ray projects or any inference-serving vendor.** Product and trademark names belong to their owners. MIT licensed.
|
|
22
|
+
|
|
23
|
+
Governed AI-ops for **GPU inference clusters** — **vLLM** (OpenAI API + Prometheus
|
|
24
|
+
`/metrics`) and **Ray Serve / Ray Jobs** (Ray dashboard) — with a **built-in
|
|
25
|
+
governance harness**: unified audit log, policy engine, token/runaway budget
|
|
26
|
+
guard, undo-token recording, and graduated-autonomy risk tiers. It parses
|
|
27
|
+
vLLM's Prometheus `/metrics` directly (no Prometheus server required) and probes
|
|
28
|
+
the Ray dashboard independently. A bearer token is **optional** (many stacks run
|
|
29
|
+
open). **Preview — mock-validated only, not yet verified against a live cluster.**
|
|
30
|
+
|
|
31
|
+
## What it does
|
|
32
|
+
|
|
33
|
+
The flagship value is **root-cause analysis**, wrapped in guarded reads and writes:
|
|
34
|
+
|
|
35
|
+
- **`diagnose_latency_spike`** (flagship RCA) — when TTFT/TPOT/e2e latency
|
|
36
|
+
climbs, it correlates **queue depth** (running vs waiting), **KV-cache
|
|
37
|
+
pressure / preemptions**, and **prefix-cache locality** into a *ranked* cause
|
|
38
|
+
plus the **specific knob to turn** (add replicas, raise `max-num-seqs`, fix
|
|
39
|
+
routing, enlarge KV cache). Every flag is a number, not a black-box verdict.
|
|
40
|
+
- **`diagnose_low_utilization`** — the inverse: idle GPUs, over-provisioned
|
|
41
|
+
replicas, or routing that strands a cache-warm replica → what to scale down.
|
|
42
|
+
- **Prometheus-native** — reads vLLM's `/metrics` endpoint directly; no
|
|
43
|
+
Prometheus/Grafana deployment needed.
|
|
44
|
+
- **Governance-grade** — the **first governance-grade entrant** in this niche:
|
|
45
|
+
audit + budget + risk-tier approval + undo-token + prompt-injection sanitize,
|
|
46
|
+
with **dry-run + double-confirm** on the fragile prod ops (scale-down,
|
|
47
|
+
scale-to-zero, drain, redeploy, hot-swap) the community reports as dangerous.
|
|
48
|
+
- **Laptop self-test** — ~80% of the tool self-tests free: vLLM on a single GPU
|
|
49
|
+
or CPU-mock + Ray in one local container (`ray start --head`).
|
|
50
|
+
|
|
51
|
+
## Capability matrix (30 MCP tools)
|
|
52
|
+
|
|
53
|
+
| Group | Tools | Count | R/W (risk) |
|
|
54
|
+
|-------|-------|:-----:|:-----------|
|
|
55
|
+
| **Metrics & RCA** | `request_metrics`, `queue_depth`, `kv_cache_stats`, `diagnose_latency_spike`, `diagnose_low_utilization` | 5 | read |
|
|
56
|
+
| **Ray Serve (read)** | `serve_deployment_list`, `deployment_status`, `replica_list`, `autoscale_config_get` | 4 | read |
|
|
57
|
+
| **Ray Serve (write)** | `scale_replicas_up`, `scale_replicas_down`, `scale_to_zero`, `autoscale_config_update`, `drain_replica` | 5 | write (med / **high**) |
|
|
58
|
+
| **Models / vLLM** | `model_list`, `model_info`, `lora_load`, `lora_unload`, `model_hot_swap` | 5 | read + write (med / **high**) |
|
|
59
|
+
| **Ray cluster / jobs / GPU** | `ray_cluster_resources`, `ray_dashboard_status`, `ray_job_list`, `gpu_utilization`, `ray_job_cancel`, `replica_restart` | 6 | read + write (med / **high**) |
|
|
60
|
+
| **Deploy lifecycle** | `model_deploy`, `model_undeploy`, `deployment_redeploy`, `routing_policy_update` | 4 | write (med / **high**) |
|
|
61
|
+
| **Cost** | `cost_per_token` | 1 | read |
|
|
62
|
+
|
|
63
|
+
**16 read, 14 write.** High-risk writes (`scale_replicas_down`,
|
|
64
|
+
`scale_to_zero`, `drain_replica`, `lora_unload`, `model_hot_swap`,
|
|
65
|
+
`replica_restart`, `model_undeploy`, `deployment_redeploy`) all support
|
|
66
|
+
`dry_run` + double-confirm; reversible writes record an undo descriptor.
|
|
67
|
+
|
|
68
|
+
## Install
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv tool install inference-aiops # or: pipx install inference-aiops
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick start
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
inference-aiops init # wizard: host + ray_port + vllm_port + scheme
|
|
78
|
+
inference-aiops doctor # probes BOTH the Ray dashboard and vLLM independently
|
|
79
|
+
inference-aiops overview # deployments + total replicas + queue backpressure
|
|
80
|
+
inference-aiops metrics diagnose # why is inference slow? ranked RCA + the knob to turn
|
|
81
|
+
inference-aiops serve list # Ray Serve deployments + replica counts
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Run as an MCP server (stdio) for the full 30-tool surface:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
export INFERENCE_AIOPS_MASTER_PASSWORD=... # only if a bearer token is stored
|
|
88
|
+
inference-aiops mcp
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The CLI is a convenience subset (`init`, `overview`, `serve …`, `metrics …`,
|
|
92
|
+
`secret …`, `doctor`, `mcp`); the full 30 tools are exposed via the MCP server.
|
|
93
|
+
|
|
94
|
+
## Governance
|
|
95
|
+
|
|
96
|
+
Every MCP tool passes through the bundled `@governed_tool` harness:
|
|
97
|
+
|
|
98
|
+
- **Audit** — every call (params, result, status, duration, risk tier,
|
|
99
|
+
approver, rationale) logged to `~/.inference-aiops/audit.db` (relocatable via
|
|
100
|
+
`INFERENCE_AIOPS_HOME`).
|
|
101
|
+
- **Budget / runaway guard** — token and call budgets trip a circuit breaker on
|
|
102
|
+
tight poll/retry loops.
|
|
103
|
+
- **Risk tiers** — graduated autonomy; high-risk ops can require a named
|
|
104
|
+
approver (`INFERENCE_AUDIT_APPROVED_BY` / `INFERENCE_AUDIT_RATIONALE`).
|
|
105
|
+
- **Undo recording** — reversible writes (scale, autoscale-config, routing,
|
|
106
|
+
hot-swap, LoRA load) record an inverse descriptor.
|
|
107
|
+
|
|
108
|
+
## Supported scope + limitations
|
|
109
|
+
|
|
110
|
+
**Preview / mock-only.** All behaviour is validated against mocked vLLM
|
|
111
|
+
`/metrics`, vLLM OpenAI API, and Ray dashboard responses. **~80% of the tool
|
|
112
|
+
self-tests on a laptop** — vLLM on a single GPU or CPU-mock plus a local
|
|
113
|
+
one-node Ray head. Not yet verified against a live production cluster.
|
|
114
|
+
|
|
115
|
+
Unverified against real hardware / topology:
|
|
116
|
+
|
|
117
|
+
- multi-GPU **tensor-parallel / pipeline-parallel** deployments,
|
|
118
|
+
- real GPU **thermal / throttle** telemetry (utilisation is best-effort from
|
|
119
|
+
the Ray dashboard's `/api/nodes`),
|
|
120
|
+
- **multi-node drain** and node-reboot orchestration.
|
|
121
|
+
|
|
122
|
+
The fastest live check is `inference-aiops doctor`.
|
|
123
|
+
|
|
124
|
+
## Missing a capability?
|
|
125
|
+
|
|
126
|
+
This is the GPU-inference member of the AIops-tools family (governed AI-ops with
|
|
127
|
+
audit + budget + undo + risk tiers). If a vLLM or Ray capability you need is
|
|
128
|
+
missing, or your stack speaks a dialect these tools don't yet handle — open an
|
|
129
|
+
issue or a PR. Contributions welcome.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<!-- mcp-name: io.github.AIops-tools/inference-aiops -->
|
|
2
|
+
|
|
3
|
+
# Inference AIops (preview)
|
|
4
|
+
|
|
5
|
+
> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by the vLLM or Ray projects or any inference-serving vendor.** Product and trademark names belong to their owners. MIT licensed.
|
|
6
|
+
|
|
7
|
+
Governed AI-ops for **GPU inference clusters** — **vLLM** (OpenAI API + Prometheus
|
|
8
|
+
`/metrics`) and **Ray Serve / Ray Jobs** (Ray dashboard) — with a **built-in
|
|
9
|
+
governance harness**: unified audit log, policy engine, token/runaway budget
|
|
10
|
+
guard, undo-token recording, and graduated-autonomy risk tiers. It parses
|
|
11
|
+
vLLM's Prometheus `/metrics` directly (no Prometheus server required) and probes
|
|
12
|
+
the Ray dashboard independently. A bearer token is **optional** (many stacks run
|
|
13
|
+
open). **Preview — mock-validated only, not yet verified against a live cluster.**
|
|
14
|
+
|
|
15
|
+
## What it does
|
|
16
|
+
|
|
17
|
+
The flagship value is **root-cause analysis**, wrapped in guarded reads and writes:
|
|
18
|
+
|
|
19
|
+
- **`diagnose_latency_spike`** (flagship RCA) — when TTFT/TPOT/e2e latency
|
|
20
|
+
climbs, it correlates **queue depth** (running vs waiting), **KV-cache
|
|
21
|
+
pressure / preemptions**, and **prefix-cache locality** into a *ranked* cause
|
|
22
|
+
plus the **specific knob to turn** (add replicas, raise `max-num-seqs`, fix
|
|
23
|
+
routing, enlarge KV cache). Every flag is a number, not a black-box verdict.
|
|
24
|
+
- **`diagnose_low_utilization`** — the inverse: idle GPUs, over-provisioned
|
|
25
|
+
replicas, or routing that strands a cache-warm replica → what to scale down.
|
|
26
|
+
- **Prometheus-native** — reads vLLM's `/metrics` endpoint directly; no
|
|
27
|
+
Prometheus/Grafana deployment needed.
|
|
28
|
+
- **Governance-grade** — the **first governance-grade entrant** in this niche:
|
|
29
|
+
audit + budget + risk-tier approval + undo-token + prompt-injection sanitize,
|
|
30
|
+
with **dry-run + double-confirm** on the fragile prod ops (scale-down,
|
|
31
|
+
scale-to-zero, drain, redeploy, hot-swap) the community reports as dangerous.
|
|
32
|
+
- **Laptop self-test** — ~80% of the tool self-tests free: vLLM on a single GPU
|
|
33
|
+
or CPU-mock + Ray in one local container (`ray start --head`).
|
|
34
|
+
|
|
35
|
+
## Capability matrix (30 MCP tools)
|
|
36
|
+
|
|
37
|
+
| Group | Tools | Count | R/W (risk) |
|
|
38
|
+
|-------|-------|:-----:|:-----------|
|
|
39
|
+
| **Metrics & RCA** | `request_metrics`, `queue_depth`, `kv_cache_stats`, `diagnose_latency_spike`, `diagnose_low_utilization` | 5 | read |
|
|
40
|
+
| **Ray Serve (read)** | `serve_deployment_list`, `deployment_status`, `replica_list`, `autoscale_config_get` | 4 | read |
|
|
41
|
+
| **Ray Serve (write)** | `scale_replicas_up`, `scale_replicas_down`, `scale_to_zero`, `autoscale_config_update`, `drain_replica` | 5 | write (med / **high**) |
|
|
42
|
+
| **Models / vLLM** | `model_list`, `model_info`, `lora_load`, `lora_unload`, `model_hot_swap` | 5 | read + write (med / **high**) |
|
|
43
|
+
| **Ray cluster / jobs / GPU** | `ray_cluster_resources`, `ray_dashboard_status`, `ray_job_list`, `gpu_utilization`, `ray_job_cancel`, `replica_restart` | 6 | read + write (med / **high**) |
|
|
44
|
+
| **Deploy lifecycle** | `model_deploy`, `model_undeploy`, `deployment_redeploy`, `routing_policy_update` | 4 | write (med / **high**) |
|
|
45
|
+
| **Cost** | `cost_per_token` | 1 | read |
|
|
46
|
+
|
|
47
|
+
**16 read, 14 write.** High-risk writes (`scale_replicas_down`,
|
|
48
|
+
`scale_to_zero`, `drain_replica`, `lora_unload`, `model_hot_swap`,
|
|
49
|
+
`replica_restart`, `model_undeploy`, `deployment_redeploy`) all support
|
|
50
|
+
`dry_run` + double-confirm; reversible writes record an undo descriptor.
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uv tool install inference-aiops # or: pipx install inference-aiops
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Quick start
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
inference-aiops init # wizard: host + ray_port + vllm_port + scheme
|
|
62
|
+
inference-aiops doctor # probes BOTH the Ray dashboard and vLLM independently
|
|
63
|
+
inference-aiops overview # deployments + total replicas + queue backpressure
|
|
64
|
+
inference-aiops metrics diagnose # why is inference slow? ranked RCA + the knob to turn
|
|
65
|
+
inference-aiops serve list # Ray Serve deployments + replica counts
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Run as an MCP server (stdio) for the full 30-tool surface:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
export INFERENCE_AIOPS_MASTER_PASSWORD=... # only if a bearer token is stored
|
|
72
|
+
inference-aiops mcp
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The CLI is a convenience subset (`init`, `overview`, `serve …`, `metrics …`,
|
|
76
|
+
`secret …`, `doctor`, `mcp`); the full 30 tools are exposed via the MCP server.
|
|
77
|
+
|
|
78
|
+
## Governance
|
|
79
|
+
|
|
80
|
+
Every MCP tool passes through the bundled `@governed_tool` harness:
|
|
81
|
+
|
|
82
|
+
- **Audit** — every call (params, result, status, duration, risk tier,
|
|
83
|
+
approver, rationale) logged to `~/.inference-aiops/audit.db` (relocatable via
|
|
84
|
+
`INFERENCE_AIOPS_HOME`).
|
|
85
|
+
- **Budget / runaway guard** — token and call budgets trip a circuit breaker on
|
|
86
|
+
tight poll/retry loops.
|
|
87
|
+
- **Risk tiers** — graduated autonomy; high-risk ops can require a named
|
|
88
|
+
approver (`INFERENCE_AUDIT_APPROVED_BY` / `INFERENCE_AUDIT_RATIONALE`).
|
|
89
|
+
- **Undo recording** — reversible writes (scale, autoscale-config, routing,
|
|
90
|
+
hot-swap, LoRA load) record an inverse descriptor.
|
|
91
|
+
|
|
92
|
+
## Supported scope + limitations
|
|
93
|
+
|
|
94
|
+
**Preview / mock-only.** All behaviour is validated against mocked vLLM
|
|
95
|
+
`/metrics`, vLLM OpenAI API, and Ray dashboard responses. **~80% of the tool
|
|
96
|
+
self-tests on a laptop** — vLLM on a single GPU or CPU-mock plus a local
|
|
97
|
+
one-node Ray head. Not yet verified against a live production cluster.
|
|
98
|
+
|
|
99
|
+
Unverified against real hardware / topology:
|
|
100
|
+
|
|
101
|
+
- multi-GPU **tensor-parallel / pipeline-parallel** deployments,
|
|
102
|
+
- real GPU **thermal / throttle** telemetry (utilisation is best-effort from
|
|
103
|
+
the Ray dashboard's `/api/nodes`),
|
|
104
|
+
- **multi-node drain** and node-reboot orchestration.
|
|
105
|
+
|
|
106
|
+
The fastest live check is `inference-aiops doctor`.
|
|
107
|
+
|
|
108
|
+
## Missing a capability?
|
|
109
|
+
|
|
110
|
+
This is the GPU-inference member of the AIops-tools family (governed AI-ops with
|
|
111
|
+
audit + budget + undo + risk tiers). If a vLLM or Ray capability you need is
|
|
112
|
+
missing, or your stack speaks a dialect these tools don't yet handle — open an
|
|
113
|
+
issue or a PR. Contributions welcome.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Inference AIops v0.1.0 — preview
|
|
2
|
+
|
|
3
|
+
Governed AI-ops for **GPU inference clusters** — **vLLM** (OpenAI API +
|
|
4
|
+
Prometheus `/metrics`) and **Ray Serve / Ray Jobs** (Ray dashboard) — for AI
|
|
5
|
+
agents, with a built-in governance harness (audit, policy, token/runaway budget,
|
|
6
|
+
undo-token recording, graduated risk tiers) and an optional encrypted credential
|
|
7
|
+
store. Standalone — no external skill-family dependency.
|
|
8
|
+
|
|
9
|
+
> **Preview / mock-only.** All behaviour is validated against mocked vLLM
|
|
10
|
+
> `/metrics`, vLLM OpenAI API, and Ray dashboard responses; it has not been run
|
|
11
|
+
> against a live cluster. The fastest live check is `inference-aiops doctor`.
|
|
12
|
+
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
- **30 MCP tools** (16 read, 14 write), every one wrapped with `@governed_tool`.
|
|
16
|
+
- **Metrics & RCA** (read): `request_metrics` (TTFT/TPOT/e2e + token totals),
|
|
17
|
+
`queue_depth` (running vs waiting backpressure), `kv_cache_stats` (KV util,
|
|
18
|
+
prefix-cache hit rate, preemptions), and the flagship correlators
|
|
19
|
+
`diagnose_latency_spike` / `diagnose_low_utilization`.
|
|
20
|
+
- **Ray Serve**: reads (`serve_deployment_list`, `deployment_status`,
|
|
21
|
+
`replica_list`, `autoscale_config_get`) + guarded writes (`scale_replicas_up`,
|
|
22
|
+
`scale_replicas_down`, `scale_to_zero`, `autoscale_config_update`,
|
|
23
|
+
`drain_replica`).
|
|
24
|
+
- **Models / vLLM**: `model_list`, `model_info`, `lora_load`, `lora_unload`,
|
|
25
|
+
`model_hot_swap` (Sleep-Mode base swap, captures prior model).
|
|
26
|
+
- **Ray cluster / jobs / GPU**: `ray_cluster_resources`, `ray_dashboard_status`,
|
|
27
|
+
`ray_job_list`, `gpu_utilization`, `ray_job_cancel`, `replica_restart`.
|
|
28
|
+
- **Deploy lifecycle**: `model_deploy`, `model_undeploy`, `deployment_redeploy`,
|
|
29
|
+
`routing_policy_update` (prefix-aware / session-affinity routing).
|
|
30
|
+
- **Cost**: `cost_per_token` (deterministic $/1M tokens from throughput × GPU $/hr).
|
|
31
|
+
- **Prometheus-native** — parses vLLM's `/metrics` directly; no Prometheus
|
|
32
|
+
server required.
|
|
33
|
+
- **Safety on the fragile ops** — `scale_replicas_down`, `scale_to_zero`,
|
|
34
|
+
`drain_replica`, `lora_unload`, `model_hot_swap`, `replica_restart`,
|
|
35
|
+
`model_undeploy`, `deployment_redeploy` are high-risk with `dry_run` +
|
|
36
|
+
double-confirm; reversible writes record an undo descriptor.
|
|
37
|
+
- **Optional-token auth** — a bearer token is optional (many stacks run open);
|
|
38
|
+
when required it is stored **encrypted** (`~/.inference-aiops/secrets.enc`,
|
|
39
|
+
Fernet + scrypt) — never plaintext on disk.
|
|
40
|
+
- **CLI** with an `init` onboarding wizard, `secret` management, and a `doctor`
|
|
41
|
+
that probes the Ray dashboard and vLLM independently.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv tool install inference-aiops
|
|
47
|
+
inference-aiops init
|
|
48
|
+
inference-aiops doctor
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Caveats
|
|
52
|
+
|
|
53
|
+
- Preview / mock-only: validated against mocked responses; needs live verification.
|
|
54
|
+
- Unverified against real hardware: multi-GPU tensor/pipeline-parallel
|
|
55
|
+
deployments, real GPU thermal/throttle telemetry, and multi-node drain.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Disclaimer
|
|
4
|
+
|
|
5
|
+
Community-maintained open-source project. **Not affiliated with, endorsed by, or
|
|
6
|
+
sponsored by the vLLM or Ray projects.** Product and trademark names belong to
|
|
7
|
+
their owners. Source is publicly auditable under the MIT license.
|
|
8
|
+
|
|
9
|
+
## Reporting Vulnerabilities
|
|
10
|
+
|
|
11
|
+
Report privately via a GitHub Security Advisory on
|
|
12
|
+
[github.com/AIops-tools/Inference-AIops](https://github.com/AIops-tools/Inference-AIops/security/advisories)
|
|
13
|
+
or email zhouwei008@gmail.com. Please do not open public issues for security
|
|
14
|
+
reports.
|
|
15
|
+
|
|
16
|
+
## Security Design
|
|
17
|
+
|
|
18
|
+
### Credential Management
|
|
19
|
+
- A bearer token is **optional** (many on-prem inference stacks run open). When
|
|
20
|
+
used, per-target tokens live **encrypted** in `~/.inference-aiops/secrets.enc`
|
|
21
|
+
(Fernet/AES-128 + scrypt-derived key; chmod 600), never in `config.yaml` and
|
|
22
|
+
never in source. The master password is never stored — only a per-store random
|
|
23
|
+
salt and the ciphertext are on disk.
|
|
24
|
+
- A legacy plaintext env var `INFERENCE_<TARGET_NAME_UPPER>_TOKEN` is still
|
|
25
|
+
honoured as a fallback with a deprecation warning (migrate with
|
|
26
|
+
`inference-aiops secret migrate`).
|
|
27
|
+
- When present, the token is sent as an `Authorization: Bearer` header and held
|
|
28
|
+
only in memory; it is never logged or echoed. The config file holds only host,
|
|
29
|
+
Ray/vLLM ports, scheme, and TLS settings.
|
|
30
|
+
|
|
31
|
+
### Governed Operations
|
|
32
|
+
Every MCP tool runs through the bundled `@governed_tool` harness
|
|
33
|
+
(`inference_aiops.governance`):
|
|
34
|
+
- **Audit** — every call logged to a local SQLite DB under `~/.inference-aiops/`
|
|
35
|
+
(relocatable via `INFERENCE_AIOPS_HOME`), agent-attributed, secret-redacted.
|
|
36
|
+
- **Token/runaway budget** — hard ceilings (`INFERENCE_MAX_TOOL_CALLS` /
|
|
37
|
+
`INFERENCE_MAX_TOOL_SECONDS`) plus an on-by-default guard that trips a tight
|
|
38
|
+
poll/retry loop, preventing unbounded API consumption (e.g. polling a slow
|
|
39
|
+
session).
|
|
40
|
+
- **Graduated risk tiers** — `~/.inference-aiops/rules.yaml` `risk_tiers` gate
|
|
41
|
+
writes by environment/tag; the highest tiers require a recorded approver.
|
|
42
|
+
- **Undo-token recording** — reversible writes capture the BEFORE state and
|
|
43
|
+
record an inverse descriptor (e.g. a scale op → restore the prior replica
|
|
44
|
+
count, `autoscale_config_update` → restore prior bounds, `routing_policy_update`
|
|
45
|
+
→ restore the prior policy) so the change can be rolled back.
|
|
46
|
+
|
|
47
|
+
### State-Changing Operations
|
|
48
|
+
Destructive/traffic-affecting writes — `scale_replicas_down`, `scale_to_zero`,
|
|
49
|
+
`drain_replica`, `lora_unload`, `model_hot_swap`, `model_undeploy`,
|
|
50
|
+
`deployment_redeploy`, `replica_restart` — are `risk_level=high`, accept a
|
|
51
|
+
`dry_run` preview, and (under `risk_tiers`) require a recorded approver
|
|
52
|
+
(`INFERENCE_AUDIT_APPROVED_BY` + `INFERENCE_AUDIT_RATIONALE`). The CLI
|
|
53
|
+
additionally double-confirms `serve scale-to-zero` and supports `--dry-run`.
|
|
54
|
+
Reversible medium/low writes capture before-state and record an undo token.
|
|
55
|
+
|
|
56
|
+
### SSL/TLS Verification
|
|
57
|
+
`verify_ssl` is off by default (inference stacks commonly serve plain HTTP on a
|
|
58
|
+
trusted network); set `scheme: https` + `verify_ssl: true` for TLS endpoints.
|
|
59
|
+
|
|
60
|
+
### Prompt-Injection Protection
|
|
61
|
+
All server-returned text (model ids, deployment/replica names, job entrypoints,
|
|
62
|
+
Prometheus label values) is passed through a `sanitize()` truncate +
|
|
63
|
+
control-character strip before reaching the agent.
|
|
64
|
+
|
|
65
|
+
### Network Scope
|
|
66
|
+
No webhooks, no telemetry, no outbound calls beyond the configured Ray dashboard
|
|
67
|
+
and vLLM endpoints. No post-install scripts or background services.
|
|
68
|
+
|
|
69
|
+
## Static Analysis
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uvx bandit -r inference_aiops/ mcp_server/
|
|
73
|
+
uv run ruff check .
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Supported Versions
|
|
77
|
+
|
|
78
|
+
The latest released version receives security fixes. This is a preview (0.x);
|
|
79
|
+
pin a version in production.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""inference-aiops — governed Inference SCALE operations for AI agents.
|
|
2
|
+
|
|
3
|
+
Standalone and self-contained: the governance harness (audit, token budget,
|
|
4
|
+
undo-token recording, graduated risk tiers, prompt-injection sanitize) is
|
|
5
|
+
bundled under ``inference_aiops.governance`` — this package has no external
|
|
6
|
+
skill-family dependency. Preview: not yet full-coverage.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Shared helpers for inference-aiops CLI sub-modules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Annotated, Any
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
# ─── Shared Option types ───────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
TargetOption = Annotated[
|
|
18
|
+
str | None, typer.Option("--target", "-t", help="Target name from config")
|
|
19
|
+
]
|
|
20
|
+
DryRunOption = Annotated[
|
|
21
|
+
bool, typer.Option("--dry-run", help="Print the API call without executing")
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _cli_error_types() -> tuple[type[BaseException], ...]:
|
|
26
|
+
"""Exceptions translated to a one-line teaching error instead of a traceback."""
|
|
27
|
+
from inference_aiops.connection import InferenceApiError
|
|
28
|
+
|
|
29
|
+
return (InferenceApiError, KeyError, OSError, ValueError)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def cli_errors(fn: Callable) -> Callable:
|
|
33
|
+
"""Translate known exceptions into one red line + exit code 1."""
|
|
34
|
+
|
|
35
|
+
@functools.wraps(fn)
|
|
36
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
37
|
+
try:
|
|
38
|
+
return fn(*args, **kwargs)
|
|
39
|
+
except (typer.Exit, typer.Abort):
|
|
40
|
+
raise
|
|
41
|
+
except _cli_error_types() as e:
|
|
42
|
+
message = str(e)
|
|
43
|
+
if isinstance(e, KeyError):
|
|
44
|
+
message = f"Missing required key or environment variable: {message}"
|
|
45
|
+
console.print(f"[red]Error: {message}[/]")
|
|
46
|
+
raise typer.Exit(1) from e
|
|
47
|
+
|
|
48
|
+
return wrapper
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_connection(target: str | None, config_path: Path | None = None):
|
|
52
|
+
"""Return a (conn, config) tuple for the given target."""
|
|
53
|
+
from inference_aiops.config import load_config
|
|
54
|
+
from inference_aiops.connection import ConnectionManager
|
|
55
|
+
|
|
56
|
+
cfg = load_config(config_path)
|
|
57
|
+
mgr = ConnectionManager(cfg)
|
|
58
|
+
return mgr.connect(target), cfg
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def dry_run_print(*, operation: str, api_call: str, parameters: dict | None = None) -> None:
|
|
62
|
+
"""Print a dry-run preview of the API call that would be made."""
|
|
63
|
+
console.print("\n[bold magenta][DRY-RUN] No changes will be made.[/]")
|
|
64
|
+
console.print(f"[magenta] Operation: {operation}[/]")
|
|
65
|
+
console.print(f"[magenta] API Call: {api_call}[/]")
|
|
66
|
+
for k, v in (parameters or {}).items():
|
|
67
|
+
console.print(f"[magenta] Param: {k} = {v}[/]")
|
|
68
|
+
console.print("[magenta] Run without --dry-run to execute.[/]\n")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def double_confirm(action: str, resource: str) -> None:
|
|
72
|
+
"""Require two confirmations for a destructive operation."""
|
|
73
|
+
console.print(f"[bold yellow]⚠️ About to: {action} '{resource}'[/]")
|
|
74
|
+
typer.confirm(f"Confirm 1/2: {action} '{resource}'?", abort=True)
|
|
75
|
+
typer.confirm(
|
|
76
|
+
f"Confirm 2/2: really {action} '{resource}'? This may be irreversible.",
|
|
77
|
+
abort=True,
|
|
78
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Top-level Typer app: assembles sub-apps and top-level commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from inference_aiops.cli._common import cli_errors
|
|
8
|
+
from inference_aiops.cli.doctor import doctor_cmd
|
|
9
|
+
from inference_aiops.cli.init import init_cmd
|
|
10
|
+
from inference_aiops.cli.metrics import metrics_app
|
|
11
|
+
from inference_aiops.cli.overview import overview_cmd
|
|
12
|
+
from inference_aiops.cli.secret import secret_app
|
|
13
|
+
from inference_aiops.cli.serve import serve_app
|
|
14
|
+
|
|
15
|
+
app = typer.Typer(
|
|
16
|
+
name="inference-aiops",
|
|
17
|
+
help="Governed AI-ops for GPU inference (vLLM + Ray Serve): metrics/RCA, "
|
|
18
|
+
"scaling, drain, models, jobs.",
|
|
19
|
+
no_args_is_help=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
app.add_typer(serve_app, name="serve")
|
|
23
|
+
app.add_typer(metrics_app, name="metrics")
|
|
24
|
+
app.add_typer(secret_app, name="secret")
|
|
25
|
+
app.command("init")(init_cmd)
|
|
26
|
+
app.command("overview")(overview_cmd)
|
|
27
|
+
app.command("doctor")(doctor_cmd)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.command("mcp")
|
|
31
|
+
@cli_errors
|
|
32
|
+
def mcp_cmd() -> None:
|
|
33
|
+
"""Start the MCP server (stdio transport).
|
|
34
|
+
|
|
35
|
+
Single-command entry point for MCP clients (does not go through uvx/PyPI
|
|
36
|
+
resolution at launch):
|
|
37
|
+
inference-aiops mcp
|
|
38
|
+
"""
|
|
39
|
+
import sys
|
|
40
|
+
|
|
41
|
+
if sys.version_info < (3, 11):
|
|
42
|
+
typer.echo(
|
|
43
|
+
f"ERROR: inference-aiops requires Python >= 3.11 "
|
|
44
|
+
f"(got {sys.version_info.major}.{sys.version_info.minor}).\n"
|
|
45
|
+
f"Fix: uv python install 3.12 && "
|
|
46
|
+
f"uv tool install --python 3.12 --force inference-aiops",
|
|
47
|
+
err=True,
|
|
48
|
+
)
|
|
49
|
+
raise typer.Exit(2)
|
|
50
|
+
|
|
51
|
+
from mcp_server.server import main as _mcp_main
|
|
52
|
+
|
|
53
|
+
_mcp_main()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
app()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Doctor top-level command: environment and connectivity check."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from inference_aiops.cli._common import cli_errors
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@cli_errors
|
|
13
|
+
def doctor_cmd(
|
|
14
|
+
skip_auth: Annotated[
|
|
15
|
+
bool, typer.Option("--skip-auth", help="Skip connectivity check (faster)")
|
|
16
|
+
] = False,
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Check environment, config, secrets, and connectivity."""
|
|
19
|
+
from inference_aiops.doctor import run_doctor
|
|
20
|
+
|
|
21
|
+
raise typer.Exit(run_doctor(skip_auth=skip_auth))
|