ADR-0067: KI-Provider-Verbindungen — Ollama lokal, Anthropic und OpenAI optional
- Status: accepted
- Datum: 2026-10-09
- Phase: Prozessmanagement / Dokumente
- Bezug: ADR-0061, ADR-0065, ADR-0060
Kontext
ADR-0061 und ADR-0065 legen fest, dass Modelle lokal über Ollama laufen und keine Inhalte das Haus verlassen. Die Messung in ADR-0065 zeigt, dass Ollama ohne GPU für Scans zu langsam ist. Betreiber brauchen deshalb die Wahl eines gehosteten Anbieters, ohne dass dafür .env und Neustart nötig sind.
Entscheidung
- Anbieter und Agenten sind getrennt. Ein Anbieter ist ein Ort, an dem ein Modell läuft (
ollama,anthropic,openai) und hat eine Verbindung (URL, API-Schlüssel). Ein Agent ist eine Assistenten-Aufgabe und wählt seinen eigenen Anbieter und sein Modell. Beides gilt plattformweit und liegt in der Control-DB (ai_platform_settingsfür Verbindungen,ai_agentsfür Zuordnungen; Migrationen0045–0048). - Agenten-Katalog im Code (
assistant/ai_catalog.py):field_message(Feldnachricht verstehen, Aufgaben zuordnen, erledigt/Problem erkennen in einem Aufruf; einziger bisher aufgerufener Agent),document_lookup,document_classify,document_vision,daily_report(vorbereitet, noch ohne Aufrufer; in der Oberfläche als „Geplant“ markiert). Nur die Zuordnungen werden gespeichert. - Ollama bleibt Standard und lokal. Ohne gespeicherte Zuordnung läuft jeder Agent auf Ollama mit
ASSISTANT_MODEL_FAST/ASSISTANT_MODEL_REPORT(Vision: kein Standard). Ohne Ollama-URL (OLLAMA_BASE_URLoder Einstellung) arbeitet der Offline-Assistent (Schlüsselwort-Heuristik). - Gehostete Anbieter sind Opt-in. Anthropic und OpenAI sind nur wählbar, wenn ein Schlüssel hinterlegt ist; ein Agent ohne Modell oder mit unvollständigem Anbieter wird mit
422abgelehnt. Die Oberfläche warnt, dass Nachrichtentexte an den Dienst gesendet werden; der Betreiber braucht einen Auftragsverarbeitungsvertrag. Das lockert die „nur lokal“-Regel aus ADR-0061/0065 ausdrücklich und nur auf Betreiberentscheid, je Agent. - Schlüssel sind nur schreibbar. API-Schlüssel liegen Fernet-verschlüsselt (
app.core.secrets); die API liefert nur „gesetzt“ und die letzten vier Zeichen.nullbehält,""entfernt den Schlüssel. Nicht genutzte Felder (Ollama hat keinen Schlüssel, Anthropics URL ist fest) werden ignoriert. - Verfügbare Modelle.
GET /platform/ai/providers/{provider}/modelsfragt die Modellliste des Anbieters (/api/tags,/v1/models,/models) mit 10 s Timeout ab. Das ist zugleich der Verbindungstest; Fehler nennen nur den Status, nie den Schlüssel. Die Agenten-Oberfläche nutzt die Liste als Vorschlag, erzwingt sie aber nicht (neue Modelle erscheinen oft zuerst als Name in der Dokumentation). Die Modellauswahl der Agenten speist sich aus der angebotenen Modellliste je Anbieter (ai_models: Modell-ID, Name, Version, an/aus, Reihenfolge;GET /platform/ai/models,PUT /platform/ai/providers/{provider}/offered-modelsersetzt die Liste eines Anbieters). Der Verbindungsdialog (Stift) bearbeitet sie unter den Zugangsdaten als kleine Tabelle und speichert beides zusammen; das Pulssymbol bleibt der reine Verbindungstest. Die Tabelle erlaubt an-/abwählen, ändern, hinzufügen und löschen und startet bei leerer Liste mit der jeweils neuesten Version je Familie (Haiku 4.5,GPT mini 5; Ollama: jeder installierte Tag). Ohne gespeicherte Liste gelten diese Vorschläge direkt. Gespeichert wird die exakte Modell-ID; die Liste ist Komfort, kein Filter: freie Eingabe bleibt möglich. - Gemeinsames Protokoll.
OllamaProvider,AnthropicProvider(erzwungenes Toolresult) undOpenAIProvider(response_formatmit JSON-Schema) erfüllenLLMProvider.complete_structured; die Pipeline löst ihren Agenten überresolve_agentauf und kennt keinen Anbieter. - Health. Die Zeile
ai_agentsmeldet nur Agenten, die der Code aufruft, und ruft gehostete Anbieter nicht selbst auf. - Aufwand (Effort).
ai_agents.effort('',low,medium,high; leer = Standard des Anbieters) wird nur für Reasoning-Modelle gespeichert und gesendet: OpenAI GPT-5 und o-Serie alsreasoning_effort, Ollamagpt-ossalsthink. Anthropic ist ausgenommen, weil sein Denkbudget nicht mit dem erzwungenen Tool-Aufruf für das Ergebnis kombinierbar ist. Wechselt das Modell auf eines ohne Effort, verwirft der Server den Wert (supports_effortinai_catalog.py, GegenstückmodelSupportsEffortim Frontend). - Anweisungen.
ai_agents.instructions(leer = Standardtext ausagent_instructions.py) hält den Systemtext, den ein Admin je Agent anpassen kann; nur Agenten mit Standardtext (derzeitfield_message) nehmen einen an (sonst422). Ein Update ohneinstructionslässt den Text unverändert, der Standardtext oder ein leerer Wert setzt zurück. Das Ergebnisformat (FieldReport) geht als JSON-Schema separat an das Modell und bleibt unveränderlich. Läufe mit angepasstem Text tragen+custominagent_runs.prompt_version. Das Abhaken per Chat (task_closure.py) ist regelbasiert und hat keine Anweisungen. - Oberfläche. Unter Einstellungen → System → KI-Agent gibt es zwei Unterseiten als eigene Routen:
/settings/ai-agent/agentsund/settings/ai-agent/providers. Zuordnung und Verbindung werden in Dialogen bearbeitet, damit keine Seite mit allen Feldern entsteht.
Folgen
- Kostenkontrolle liegt beim Betreiber (Limits im Konsolenkonto des Anbieters).
- Die Dokument-Agenten (P14b) und der Tagesbericht brauchen keine weitere Konfiguration, wenn sie angebunden werden.
- Ein Fehlurteil bei „erledigt“ ist teurer als ein verpasstes. Reicht die Qualität nicht, lässt sich
field_messageauf ein größeres Modell stellen, ohne andere Agenten zu ändern; eine Aufteilung in Verstehen und Erledigt-Prüfung wäre ein eigener Schritt. - Mandantenweise Wahl ist nicht vorgesehen; sie wäre eine eigene Entscheidung.