Phase 3 — Gate + Skill-Scaffold

Ziel: Cost-Risiko sofort cappen, parallel das Skill-Repo anlegen damit die Notbremsen + alles Folgende als wiederverwendbare Capability dokumentiert ist.

Aufwand: ~2h

Vorbedingung: keine (laeuft parallel zu Phase 1/2 — Notbremsen brauchen keine Caller-Daten).

Nachbedingung: Budget+Action live, max_tokens in allen Callern, Skill bedrock-cost-optimize existiert mit Grundstruktur.

Teil A — Notbremsen auf av-production

3A.1 AWS Budget + Budget-Action (Hebel 2)

CloudFormation-Template fuer Budget mit Schwellen 50%/75%/100% von $80, Email-Alarm + Budget-Action bei 100% die eine IAM-Restrict-Policy auf bedrock:InvokeModel (Account-weit) haengt.

Template wandert in templates/budget-action.yaml im Skill-Repo (Teil B). Deploy:

aws cloudformation deploy \
  --stack-name bedrock-cost-gate \
  --template-file intern/capabilities/skills/bedrock-cost-optimize/templates/budget-action.yaml \
  --parameter-overrides \
      MonthlyBudgetUsd=80 \
      AlertEmail=hello@marvinkuehlmann.com \
  --capabilities CAPABILITY_NAMED_IAM \
  --profile av-production --region us-east-1

Region us-east-1 ist Pflicht fuer AWS Budgets (Global Service).

Test: trigger den 50%-Alert manuell ueber Console — Mail kommt? Wenn ja: ready.

3A.2 max_tokens-Caps + Stop-Sequences (Hebel 3)

Pro Caller den Default max_tokens setzen (siehe Hebel-Matrix in caller-inventar). Stop-Sequences wo strukturierter Output (JSON, Tool-Use).

Open-WebUI VF: LiteLLM-Sidecar-Config bzw Modelfile editieren — max_tokens: 2000 als Default pro Modell. ECS-Task neu starten.

mcp-whatsapp Brain: Brain-Lambda-Code (~/source/mcps/mcp-whatsapp/brain/) — max_tokens=300 im Bedrock-Aufruf hard-coded. CDK-Stack redeploy.

mcp-vf-hosted: Proxy-Layer durchreichen — der MCP selbst macht keine Bedrock-Calls, aber wenn doch (z.B. Routing-Logik), max_tokens=1000.

Lambda-Routinen in agents-platform: pro Lambda im Code-Pfad pruefen. Bei Cron-Routinen meist max_tokens=500 ausreichend.

icking-ai-rebuild: im FastAPI-Bedrock-Call-Helper hard-coded max_tokens=1500 als Default, overridable per Request.

3A.3 Bedrock Service-Quotas drosseln (Hebel 10)

Service Quotas Console (eu-central-1) — pro Modell die Requests per minute-Quota auf einen Wert setzen der Normal-Last + Pufferer abdeckt, aber Runaway-Loops cappt.

Beispiel: Sonnet 4.6 in eu-central-1, aktuell Default 50 RPM. Wenn Normal-Last bei 5 RPM liegt: drossle auf 15 RPM. Bei Runaway gibt’s 429-Errors statt $1000-Rechnung.

aws service-quotas list-service-quotas \
  --service-code bedrock \
  --profile av-production --region eu-central-1

Quota-Codes finden, dann request-service-quota-decrease (Increase geht direkt, Decrease via Support-Ticket — bei uns ist Default eh hoch).

Wichtiger Hinweis: Cross-Region-Inference-Profiles (eu.anthropic.claude-sonnet-4-6-...) zaehlen auf alle Backing-Regionen, also Quota in eu-central-1 und eu-west-3 (Paris) und eu-north-1 (Stockholm) checken.

Teil B — Skill-Scaffold

3B.1 Skill-Verzeichnis anlegen

intern/capabilities/skills/bedrock-cost-optimize/
├── SKILL.md
├── playbook.md
├── audit-checklist.md
├── rollout-map.md
└── templates/
    ├── budget-action.yaml             # CloudFormation, in 3A.1 verwendet
    ├── aip-cloudformation.yaml        # leer, Phase 4 fuellt
    ├── tool-description-audit.py      # Phase 2 hat manuelles Pattern, hier als Script
    └── caller-config-snippets/        # max_tokens-Defaults pro Caller-Typ
        ├── open-webui-litellm.yaml
        ├── lambda-bedrock-helper.py
        └── mcp-eigenbau-bedrock.py

3B.2 SKILL.md Frontmatter + Trigger

---
id: skill-bedrock-cost-optimize
type: skill
name: bedrock-cost-optimize
purpose: "Bedrock-Kosten auf av-production diagnostizieren, cappen, optimieren und das Wissen in Vault-Patterns zurueckspielen."
status: active
required_mcps:
  - "[[../../mcps/aws-pricing]]"
  - "[[../../mcps/aws-api]]"
required_tools:
  - Bash
  - Read
  - Write
  - Edit
inputs:
  - "Bedrock-Caller-Slug (optional, ohne = Account-weit)"
outputs:
  - "Aktualisiertes caller-inventar.md (im jeweiligen Projekt)"
  - "AIPs + Tags live"
  - "Notbremsen live"
runs_log_in: intern/runs/<jahr>-<monat>.md
last_used: 2026-05-17
---

3B.3 Trigger-Phrasen in intern/capabilities/skills/_index.md ergaenzen

Neue Zeile in der Skills-Tabelle:

| `bedrock-cost-optimize` | „bedrock kosten audit", „warum kostet bedrock so viel", „AIP einrichten fuer X", „MCP token check", „cost-gate fuer Y", „spar bedrock" | Bedrock-Kosten diagnostizieren, Notbremsen einbauen, AIPs pro Caller anlegen, Tool-Descriptions auditieren, Compounding in Best-Practices | [[bedrock-cost-optimize/SKILL]] |

3B.4 playbook.md — die 10 Hebel mit Code

Jeder Hebel als Sektion:

  • Worum geht’s (1 Satz)
  • Wann anwenden (Trigger-Bedingung)
  • Wie tun (Commands / Code-Snippets)
  • Wie verifizieren
  • Links auf Templates

Quelle der 10 Hebel: dieses Projekt + die parallel-Session-Hebel (Caching, Routing) damit der Skill vollstaendig ist.

3B.5 audit-checklist.md — pro Caller-Typ

Was zu pruefen ist wenn ein neuer Caller dazukommt:

  • ECS-Service (Open-WebUI-aehnlich): AIP-Tag im Task-Definition? max_tokens im LiteLLM-Config?
  • Lambda-Routine: max_tokens im Code? Bedrock-Call-Helper benutzt?
  • Eigenbau-MCP mit Bedrock-Brain: Tool-Description-Audit bestanden? max_tokens gesetzt?

3B.6 rollout-map.md

Matrix die caller-inventar spiegelt aber generischer — fuer beliebige zukuenftige Caller. Sagt: „wenn dein Caller Typ X ist, brauchst du Hebel 1/3/4/5/6, NICHT 7/9”.

Definition of Done

  • CloudFormation-Stack bedrock-cost-gate deployed, Test-Alert ausgeloest
  • max_tokens in allen aktiven Callern (mind. Open-WebUI, mcp-whatsapp, daily-briefing) explizit gesetzt
  • Bedrock Service-Quotas in eu-central-1/west-3/north-1 fuer Sonnet auf Normal+Puffer eingestellt
  • Skill-Verzeichnis existiert mit SKILL.md, playbook.md, audit-checklist.md, rollout-map.md, leeren Templates
  • Eintrag in intern/capabilities/skills/_index.md ergaenzt
  • Plugin reload getestet (Skill taucht in Skill-Tool-Liste auf)

Risiken

  • max_tokens zu eng kann Antworten abschneiden — vor Production-Deploy in Open-WebUI mit Test-Chats validieren
  • Budget-Action mit IAM-Restrict ist hart — falls Alarm faelschlich triggert, ist Bedrock fuer alle Caller down. Mitigation: Restrict-Policy hat einen Escape-Tag (emergency-bypass=true) den ich manuell auf eine Role setzen kann. Implementierungs-Detail in budget-action.yaml.
  • Service-Quota-Decrease via Support-Ticket dauert 1-3 Werktage. Increase-Direction geht sofort, also auf konservativen Wert starten und ggf hochziehen.

Deploy-Status (2026-05-17)

Was deployed wurde

AWS Budget bedrock-cost-monthly (us-east-1) — Email-Alarme an hello@marvinkuehlmann.com bei 50% / 80% / Forecast-100% von $80. CostFilters auf Service: Amazon Bedrock + alle Anthropic/Cohere-Sub-Services. Achtung Feasibility-Finding: Sub-Service-Strings koennen vom Budget-API anders interpretiert werden als von Cost-Explorer. Verifizieren beim ersten Trigger.

Open-WebUI ECS-Task-Def neue Revision (rev:15 → rev:16) auf default-Cluster, deployed 2026-05-17 21:30 UTC+2. Container alle HEALTHY, Deployment-Circuit-Breaker greift nicht. Aenderungen:

ChangeVorherNachher
LiteLLM model_listnur claude-sonnet-4-6+ claude-haiku-4-5 (Background-Tasks, NICHT in DEFAULT_MODELS)
LiteLLM claude-sonnet-4-6.litellm_params.max_tokens(Default 4096+)2000 (Hard-Cap)
LiteLLM claude-haiku-4-5.litellm_params.max_tokens(n/a)1000
Open-WebUI TASK_MODELclaude-sonnet-4-6claude-haiku-4-5
Open-WebUI TASK_MODEL_EXTERNALclaude-sonnet-4-6claude-haiku-4-5
Open-WebUI DEFAULT_MODEL_PARAMS.max_tokens81922000
Open-WebUI DEFAULT_MODEL_PARAMS.thinking{type: enabled, budget_tokens: 4096}{type: disabled}

User-facing Default-Modell bleibt vf-sonnet (= claude-sonnet-4-6) — VF-Pilot-User merken nur Extended-Thinking aus + max_tokens-Cap, nicht den Modell-Wechsel im Background.

Rollback-Pfad: aws ecs update-service --cluster default --service open-webui-vf --task-definition OpenWebUiVfTaskDef2DC830C3:15 — 1-Min-Operation, alte Revision intakt.

Was nach Review NICHT mehr deployed wurde

  • Budget-Action mit IAM-Restrict-Policy: Security-Lens-Risiko zu hoch (False-Positive-Trigger würde Friseur-Live-WhatsApp + VF-Pilot kappen). Nur Email-Alarm aktiv. Deferred bis Allow-List-Pattern + Emergency-Bypass mit Tag-Condition pre-deploy getestet ist.
  • max_tokens-Caps in Lambdas (receptionist-brain, daily-briefing, beleg-pipeline): Adversarial-Finding sagt Bauchgefuehl-Werte koennen Tool-Use-Loops abschneiden. Erst p95-Lookup ueber 7 Tage, dann setzen.
  • Service-Quota-Decrease: Adversarial-Finding sagt LiteLLM client-side RPM-Limit ist gleicher Effekt ohne Support-Ticket — alternative Variante. Aktuell nicht akut weil Open-WebUI-Fix den 1M-Context-Trigger praktisch eliminiert (Extended-Thinking war vermutlich der Ausloeser).
  • AIPs anlegen (Phase 4) — defer bis 7 Tage Mess-Periode entschieden hat ob Plan-Reduktion oder Vollplan.

Verifizierung

  • LiteLLM-Container-Logs zeigen Set models: claude-sonnet-4-6 / claude-haiku-4-5, Liveness-Probes 200
  • Alle 3 Container HEALTHY (litellm, open-webui, cloudflared)
  • Smoke-Test User-Chat steht aus — Marvin sollte einmal kurz https://vf-chat.agenticventures.de testen

Definition of Done

  • AWS Budget mit Email-Alarmen 50/80/100% live (us-east-1, Service-Filter)
  • max_tokens in Open-WebUI ECS-Task hard-coded auf 2000 (Sonnet) und 1000 (Haiku) ueber LiteLLM-Layer
  • TASK_MODEL + TASK_MODEL_EXTERNAL auf Haiku migriert
  • Extended Thinking in Open-WebUI DEFAULT_MODEL_PARAMS deaktiviert
  • Bedrock Service-Quotas drosseln — defer (LiteLLM client-side RPM-Limit als Alternative)
  • Skill-Verzeichnis: ✅ angelegt (siehe intern/capabilities/skills/bedrock-cost-optimize/)
  • Eintrag in intern/capabilities/skills/_index.md ergaenzt
  • Plugin-Reload getestet — manueller Schritt durch Marvin
  • Smoke-Test Open-WebUI durch Marvin — pending