150 lines
9.6 KiB
Markdown
150 lines
9.6 KiB
Markdown
# PersoEnt-Kosten-Tracking + Budget-Bremse (OpenRouter) — Verlauf & Referenzwerte
|
||
|
||
> Session 2026-08-07: Nutzer wollte Kostenübersicht für Statistik + künftige Mesh-Bremse. Es wurde festgestellt, dass **keine Kosten im Ereignis-Log erfasst** waren (zeigt 0€), obwohl OpenRouter Budget verbraucht war. Danach wurde das komplette **Bremse-System gebaut und E2E-getestet**.
|
||
|
||
## Das gebaute System (Master/VPS)
|
||
|
||
| Komponente | Pfad | Zweck |
|
||
|---|---|---|
|
||
| `mesh-cost-track.sh` | `/usr/local/bin/` | Stündlich OpenRouter-Usage aller 4 Agenten (VPS+3 Sub) via API abfragen, in Zeitreihe schreiben |
|
||
| Zeitreihe | `/srv/work/costs/costs.jsonl` | wachsende Statistik je Agent (ts, master, unraid, switch, laptop) |
|
||
| `mesh-cost-report.sh` | `/usr/local/bin/` | erzeugt HTML-Kosten-Übersicht (Dashboard-USD + pro-Agent + Bremse-Status) |
|
||
| `budget.yaml` | `/srv/work/costs/` | Deckel: `limits.agent.*`, `limits.gesamt_pro_tag`, `modelle.erlaubt/blockiert`, `bremse.kill_switch_file` |
|
||
| `mesh-cost-break.py` | `/usr/local/bin/` | vergleicht Tages-Usage vs. budgurations → schreibt `kill_switches.json` |
|
||
| `kill_switches.json` | `/srv/work/costs/` | zentral, **chmod 0666** — welcher Agent PAUSED |
|
||
| Agent-Poller-Guard | in `mesh-agent-poller.sh` | liest kill_switches per SSH; bei PAUSED → keine Task-Bearbeitung |
|
||
| Cron (stündlich) | `0 * * * *` | `mesh-cost-track.sh && python3 mesh-cost-break.py` |
|
||
| Doku-Integration | master-report.sh | `$(bash /usr/local/bin/mesh-cost-report.sh)` vor Betriebsregeln |
|
||
|
||
## 🔥 PITFALL 1: OpenRouter-Usage-Einheit ≠ Dollar
|
||
|
||
- `GET https://openrouter.ai/api/v1/auth/key` mit `Authorization: Bearer <KEY>` → `data.usage` = **OpenRouter-Credits je Key**.
|
||
- Für die Agenten (je eigener Key in `~/.hermes/.env`) ergeben sich z.B.: master 39.5, unraid 0.33, switch 0.64, laptop 0.87.
|
||
- **Summiert (≈41) DIFFERIERT vom OpenRouter-Dashboard ($20.51)** — die API-Credits sind nicht 1:1 USD, und es können verschiedene Key-Pools/Konten sein.
|
||
- **Verbindlicher Maßstab ist der Dashboard-USD-Wert** (Nutzer liest ihn in der OpenRouter-UI ab). Den als `nutzer_dashboard_usd` mit Quelle in die Zeitreihe schreiben.
|
||
|
||
## 🔥 PITFALL 2: Usage ist KUMULATIV — Tages-Delta berechnen
|
||
|
||
Ohne Korrektur wäre **jeder Agent dauerhaft PAUSED**, weil die kumulierte Gesamt-Usage (seit Key-Start) jeden Deckel sprengt. Fix im Brems-Skript: **Tages-Delta = letzter Wert minus erster Wert desselben Kalendertags**:
|
||
|
||
```python
|
||
today = last["ts"][:10]
|
||
today_rows = [r for r in rows if r["ts"][:10] == today]
|
||
first = today_rows[0] if today_rows else last
|
||
delta = max(0.0, float(last[agent]) - float(first[agent]))
|
||
```
|
||
|
||
## Bremsen (GEBAUT + E2E-getestet 2026-08-07)
|
||
|
||
Nutzerwunsch: Master überschaut Kosten pro+gesamt über ein wachsendes Mesh (mehr Agents, mehrere Server) und kann alles bremsen. Umsetzung:
|
||
|
||
1. `mesh-cost-break.py` liest letzte Usage-Zeile (Tages-Delta), vergleicht mit `budget.yaml`-Deckeln.
|
||
2. Bei Deckel-Überschreitung (je Agent ODER Gesamt) schreibt es `kill_switches.json` mit `PAUSED`-Status + Grund.
|
||
3. Jeder Sub-Agent hat im `mesh-agent-poller.sh` einen **Guard** am Anfang (vor Task-pull), der per SSH prüft: "bin ich PAUSED?" → wenn ja: `exit 0` (keine Task-Übernahme, keine weiteren Kosten).
|
||
|
||
```bash
|
||
# Guard in mesh-agent-poller.sh (nach SSH_CMD, vor Task-pull)
|
||
KILL_CHECK=$($SSH_CMD "python3 -c \"
|
||
import json
|
||
try: d=json.load(open('/srv/work/costs/kill_switches.json'))
|
||
except Exception: d={}
|
||
sw=d.get('kill_switches',{}).get('<MEINE_ID>',{})
|
||
print('PAUSED' if sw and sw.get('status')=='PAUSED' else 'OK')
|
||
\" 2>/dev/null")
|
||
if [ "$KILL_CHECK" = "PAUSED" ]; then log "⏸️ Budget-BREMSE aktiv"; exit 0; fi
|
||
```
|
||
|
||
**E2E-Test:** UnraidHermes auf PAUSED gesetzt → sein Task blieb in `offen/` (Bremse griff), Poller-Log zeigt "⏸️ Budget-BREMSE aktiv ... pausiert". Nach Reset (leere kill_switches) wieder normal. Der aktualisierte Poller-Guard muss an alle 3 Sub-Agenten verteilt werden (je passender Key-Pfad: `unraid_mesh`/`switch_mesh`/`laptop_mesh`).
|
||
|
||
## Kostenfakt (OpenRouter-Analyse 07.08, 1 Monat)
|
||
|
||
- **DeepSeek V4 Pro = 64% aller Kosten (~$26.80)** — teures Top-Modell, nicht Standard lt. Model-Allocation; der Haupt-Kostentreiber.
|
||
- Andere: V4 Flash 0731 22,5%, V3 5,9%, Nemotron 2,4%, GLM 1,5%.
|
||
- **→ Bremsen muss auf Modell-Ebene ansetzen** (teure Modelle blockieren/deckeln), nicht nur auf Agent-Tages-Summe. Aktuell `modelle.blockiert` in budget.yaml als Konfig/Log; harter Blocker (Modell gar nicht erst laden) ist offen.
|
||
|
||
## Abfrage-Snippets
|
||
|
||
### Master (lokal)
|
||
```bash
|
||
python3 << 'PYEOF'
|
||
import json,re,urllib.request
|
||
e=open('/root/.hermes/.env').read()
|
||
m=re.search(r'OPENROUTER_API_KEY=([A-Za-z0-9_\-\\.]+)',e)
|
||
req=urllib.request.Request("https://openrouter.ai/api/v1/auth/key",
|
||
headers={"Authorization":f"Bearer {m.group(1)}"})
|
||
print(json.load(urllib.request.urlopen(req,timeout=15))["data"]["usage"])
|
||
PYEOF
|
||
```
|
||
|
||
### Sub-Agent per SSH (Key bleibt lokal, nur Zahl kommt zurück)
|
||
```bash
|
||
u=$(sshpass -p 'Bp3lskt0' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=12 mehlzoerwer@<IP> '
|
||
python3 -c "
|
||
import json,re,urllib.request
|
||
e=open(\"/home/mehlzoerwer/.hermes/.env\").read()
|
||
m=re.search(r\"OPENROUTER_API_KEY=([A-Za-z0-9_.\-]+)\", e)
|
||
req=urllib.request.Request(\"https://openrouter.ai/api/v1/auth/key\", headers={\"Authorization\":\"Bearer \"+m.group(1)})
|
||
print(json.load(urllib.request.urlopen(req, timeout=15))[\"data\"].get(\"usage\",0))
|
||
"')
|
||
```
|
||
|
||
## Erweiterungen/POLISH 2026-08-08 (Team-geprüft: Unraid+Switch+Laptop)
|
||
|
||
Das System wurde im Team geschliffen (Gegenprüfung fand echte Fehler). Ergänzungen:
|
||
|
||
### 🔥 PITFALL 3: Es gibt DREI OpenRouter-Kostenquellen — verwechsle sie nicht
|
||
|
||
| Endpoint | Feld | Einheit | Zweck |
|
||
|---|---|---|---|
|
||
| `GET /api/v1/auth/key` | `usage` | OpenRouter-Credits (je Key) | pro-Key-Verteilung, **grobe Relation nur** |
|
||
| `GET /api/v1/credits` | `total_usage` | **USD, konto-weit** | **VERBINDLICH fürs Gesamtbudget** |
|
||
| `POST chat/completions` | `usage.cost` | USD (im Body) | Kosten je Antwort (Header `X-OR-Usage-Cost-USD` oft NICHT da — Body bevorzugen) |
|
||
|
||
**Merke:** `/auth/key usage` ≠ USD und summiert anders als `/credits`. Beispiel: `/auth/key`-Werte (41.3) vs `/credits total_usage` (81.45 USD) vs Dashboard ($20.51) — drei verschiedene Zahlen. Für Gesamt-Deckel IMMER `/api/v1/credits` `total_usage` (USD) nehmen; pro-Key-`usage` nur als Aktivitäts-Relation.
|
||
|
||
### Tages-Delta KORRIGIERT (tag-übergreifend statt innerhalb des Tages)
|
||
|
||
Der naiv "letzter minus erster Wert des Kalendertags" hat Lücken: Mitternachts-Lücke zwischen Tag N und N+1, Ein-Eintrag-Tag → 0, Counter-Reset → negatives Delta (falsche "Ersparnis"). **Korrekt:**
|
||
```python
|
||
# Delta für Tag = letzter Wert heute − letzter Wert VORTAG; max(0,…) gegen Reset
|
||
vorher = [d for d in daten if d < heute]
|
||
base = tvals[vorher[-1]] if vorher else cur
|
||
delta = max(0.0, cur - base)
|
||
```
|
||
Zusätzlich: **7-Tage-Kumulativ-Summe** (fängt "täglich unter Deckel, aber Monat explodiert") + **80%-Warnschwelle** vor hartem PAUSED.
|
||
|
||
### Master-exempt (Design-Entscheidung)
|
||
Der **Master (VPSHermes) wird NIE hart pausiert** — er muss sein eigenes System + den Nutzer pflegen. Bei Monats-USD-Cap-Überschreitung werden NUR Sub-Agenten PAUSED. So bleibt das Kun-den-System bedienbar, auch wenn gespart wird.
|
||
|
||
### Modell hart blockieren (nicht nur Konfig/Log)
|
||
Umsetzung des "Bremsen auf Modell-Ebene": Hermes selbst sperrt das Modell, damit es gar nicht erst geladen wird.
|
||
```bash
|
||
hermes config set model.providers.openrouter.blocked_models '["deepseek/deepseek-v4-pro"]'
|
||
```
|
||
- **Achtung Singular:** Schlüssel ist `model.providers.…` NICHT `models.` (sonst nur notiert, nicht gelesen).
|
||
- Verifikation: Modell taucht in `hermes models list` nicht mehr auf; Fallback greift aufs nächste.
|
||
- Allowlist (`allowed_models` nur günstige) ist noch strikter — blockt automatisch neue teure Modelle.
|
||
|
||
### Referenzwerte 2026-08-08
|
||
- `/credits total_usage` (konto-weiter USD-Verbrauch): **$81.53**
|
||
- Nutzer-Entscheidung: **strikt sparen** — Monats-Cap auf $80 gesetzt → Sub-Agenten aktuell PAUSED (Master aktiv).
|
||
- Nach dem Setzen von Deckeln IMMER `mesh-cost-break.py` nochmal laufen lassen + prüfen, dass Master-exempt korrekt greift (kein Alle-Pausiert-Dauerschleife).
|
||
|
||
## 🔥 FINALES NUTZER-KOSTEN-MODELL (verbindlich ab 2026-08-08/09) — ersetzt obiges Monats-Cap-Gedächtnis
|
||
|
||
**Achtung: Der Nutzer hat das Budgetmodell zuletzt klar und EINFACH gemacht. Folge NUR diesem, nicht den komplexen $-Caps oben:**
|
||
|
||
- **Harte Grenze = 1 USD pro Tag und Agent** (`limits.tageslimit_agent_usd: 1.0`).
|
||
- **Solange OpenRouter-Credits (Guthaben) vorhanden sind, wird gearbeitet.**
|
||
- **KEIN Team-weiter Monats-Stopp** — nur pro-Agent-Tageslimit + technischer Stopp, wenn das Konto-Guthaben 0 erreicht.
|
||
- Auflade-Rhythmus des Nutzers: ~20$ am 1. des Monats, evtl. noch ~20$ am 15. (nicht garantiert). Das ist nur die Auflade-Geschichte, NICHT der Brems-Heebel.
|
||
- Master (VPSHermes) bleibt immer aktiv; nur Sub-Agenten werden pausiert.
|
||
- `budget.yaml` entsprechend: `tageslimit_agent_usd: 1.0`, `tageslimit_gesamt_usd: 4.0` (4 Agents × 1$), keine `gesamt_usd_monat`-Logik.
|
||
- Guthaben-Check im break: `guthaben = total_credits - total_usage`; wenn ≤ 0 → Sub-Agenten pausieren (Master nicht).
|
||
|
||
**PITFALL Vermeidung:** Nicht wieder ein komplexes „Monats-Cap in $" / Team-Stopp-Schema einführen — der Nutzer hat das aktiv zurückgenommen („Du oder wir?"-Korrekur + „1$ pro Tag und Agent … solange Credits da, kein Monats-Stopp"). Der Fehler aus dem Tag: Tages-Delta/`gesamt_pro_tag`-Key-Bruch und Monats-Cap-Überkomplexität.
|
||
|
||
## Referenzwerte 2026-08-07 (historisch)
|
||
- OpenRouter-Dashboard-Gesamt: **$20.51**
|
||
- API-Usage je Agent: master 39.48, unraid 0.33, switch 0.64, laptop 0.87
|