feat(eu-umbau): Bedrock als zweiter KI-Modellweg (Phase 1)

Zweiter Modellweg ueber AWS Bedrock (EU-Inferenzprofile Frankfurt), umschaltbar
je Lage (incidents.ai_backend) > Organisation (org_setting ai_backend) > global
(ENV AI_BACKEND, Default cli). Neue Datei agents/bedrock_client.py (Converse
API, nur eu.-Profile, Token-zu-USD-Umrechnung ueber BEDROCK_PRICING, gleiche
Fehlerkategorien wie das CLI). Routing zentral in call_claude; Aufrufe mit
WebSearch/WebFetch laufen bis zur staan-Schleife (Phase 2) weiter uebers CLI.
Migration: Spalte incidents.ai_backend. requirements: boto3.
Hinweis Promote: boto3 muss im Live-venv installiert werden.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
claude-dev
2026-07-30 19:48:52 +00:00
Ursprung 59cd97adac
Commit fc33cccd44
7 geänderte Dateien mit 331 neuen und 3 gelöschten Zeilen

Datei anzeigen

@@ -11,7 +11,7 @@ from urllib.parse import urlparse, urlunparse, quote_plus
import httpx
from agents.claude_client import UsageAccumulator, _cancel_event_var
from agents.claude_client import UsageAccumulator, _cancel_event_var, _ai_backend_var
from agents.factchecker import find_matching_claim, deduplicate_new_facts, TWOPHASE_MIN_FACTS
from source_rules import (
_detect_category,
@@ -699,6 +699,7 @@ class AgentOrchestrator:
self._cancel_events.pop(incident_id, None)
self._cancel_requested.discard(incident_id)
_cancel_event_var.set(None)
_ai_backend_var.set(None)
queue.task_done()
async def _mark_refresh_cancelled(self, incident_id: int):
@@ -828,7 +829,21 @@ class AgentOrchestrator:
from services.org_settings import (
get_org_language, language_display, get_research_language,
get_source_language_whitelist, get_translator_enabled,
get_org_setting,
)
# KI-Backend für diesen Refresh auflösen (EU-Umbau Phase 1).
# Lage gewinnt vor Organisation, die vor dem globalen Default.
# Gilt über das ContextVar für alle call_claude-Aufrufe darunter.
from config import AI_BACKEND
incident_backend = incident["ai_backend"] if "ai_backend" in incident.keys() else None
org_backend = await get_org_setting(db, tenant_id, "ai_backend", default=None) if tenant_id else None
ai_backend = (incident_backend or org_backend or AI_BACKEND or "cli").strip().lower()
if ai_backend not in ("cli", "bedrock"):
logger.warning("Unbekanntes ai_backend '%s' für Lage %s, fallback 'cli'", ai_backend, incident_id)
ai_backend = "cli"
_ai_backend_var.set(ai_backend)
if ai_backend != "cli":
logger.info("Lage %s läuft über KI-Backend '%s'", incident_id, ai_backend)
output_language_iso = await get_org_language(db, tenant_id) if tenant_id else "de"
output_language = language_display(output_language_iso)
# research_language steuert nur den WebSearch-Prompt ("suche in Sprache X").