LLM-Provider¶
FEGH-Bericht nutzt Cloud-LLMs zur Textgenerierung. Lokale Modelle (Ollama, llama.cpp) sind technisch möglich und in der Roadmap skizziert, aktuell aber nicht implementiert.
Unterstützte Provider¶
| Provider | Standard-Modell | Streaming | Caching |
|---|---|---|---|
| Anthropic Claude | claude-sonnet-4-6 |
SSE | Prompt-Caching aktiv |
| OpenAI GPT | gpt-5.4 |
SSE | — |
Wechsel zwischen Providern jederzeit über Einstellungen → API → Provider.
Adapter-Architektur¶
Alle Provider implementieren das LLMAdapter-Interface
(lib/features/api/adapters/llm_adapter.dart):
abstract class LLMAdapter {
String get name;
String get defaultModel;
List<String> get availableModels;
Future<ReportResponse> generateReport(ReportRequest request);
Stream<String> generateReportStream(ReportRequest request);
Future<bool> validateApiKey(String key);
}
Konkrete Adapter:
- AnthropicAdapter — /v1/messages mit anthropic-version: 2023-06-01
- OpenAIAdapter — /v1/chat/completions
Beide werden als Riverpod-Singleton mit ref.keepAlive() gehalten
(siehe api_providers.dart). Das ist wichtig, damit Dio's
Connection-Pooling und HTTP-Keep-Alive funktionieren — bei jeder
Provider-Auswahl eine neue Dio-Instanz zu erzeugen wäre Verschwendung.
Anthropic¶
Modelle (Stand Mai 2026)¶
| Modell | Use-Case | Stärke | Kosten / 1 M Token |
|---|---|---|---|
claude-opus-4-7 |
Komplexe Fälle, höchste Qualität | Höchste | Hoch |
claude-sonnet-4-6 |
Standardberichte (empfohlen) | Sehr hoch | Mittel |
claude-haiku-4-5-20251001 |
Schnelle Massenberichte, Drafts | Hoch | Gering |
Request-Aufbau¶
POST https://api.anthropic.com/v1/messages
x-api-key: sk-ant-…
anthropic-version: 2023-06-01
{
"model": "claude-sonnet-4-6",
"max_tokens": 8000,
"temperature": 0.7,
"system": [
{
"type": "text",
"text": "<Berichtstyp-spezifischer Prompt>",
"cache_control": {"type": "ephemeral"} ← Prompt-Caching
}
],
"messages": [
{"role": "user", "content": "## VORBERICHT (pseudonymisiert):\n…\n\n## AKTUELLE STICHPUNKTE:\n…"}
]
}
Prompt-Caching¶
Der System-Prompt ist groß (mehrere KB Fach-Anweisungen) und ändert sich
zwischen Berichten nicht. Mit cache_control: ephemeral wird er für
5 Minuten serverseitig gecached, sodass Folgegenerierungen ~90 % der
Input-Token-Kosten sparen. Cache-Hits sind in den usage-Feldern der
Response sichtbar (cache_read_input_tokens).
Streaming¶
generateReportStream nutzt Server-Sent Events. Der Decoder ist
Multi-Byte-sicher:
final textStream = const Utf8Decoder(allowMalformed: false).bind(stream);
// statt: utf8.decode(chunk) -- bricht bei geteilten Umlauten
Aktuell wird im Produktiveinsatz Non-Streaming verwendet, weil die
usage-Felder mit Token-Verbrauch dann zuverlässig zurückkommen. Streaming
bleibt als Pfad erhalten für zukünftige UI-Modi.
OpenAI¶
Modelle (Stand Mai 2026)¶
| Modell | Use-Case |
|---|---|
gpt-5.5 |
Frontier; komplexe Fälle |
gpt-5.4 |
Standardberichte (empfohlen) |
gpt-5.4-mini |
Schneller, günstiger |
gpt-5.4-nano |
Kleinstmodelle für Routine |
o3 |
Reasoning-Modell für mehrstufige Argumentation |
gpt-4o |
Legacy-Kompatibilität |
Request-Unterschiede¶
OpenAI nimmt nicht max_tokens für die neueren Modelle, sondern
max_completion_tokens. Der Adapter unterscheidet:
if (request.model.startsWith('gpt-5') || request.model.startsWith('o3')) {
body['max_completion_tokens'] = 8000;
} else {
body['max_tokens'] = 8000;
body['temperature'] = request.temperature; // o3/gpt-5 mögen kein temperature
}
Key-Validierung¶
Anthropic-Adapter macht einen Dummy-Request {"role":"user","content":"Hi"},
weil das das einzige /v1/messages-Aufruf-Muster ist, das einen
401/403-Status sicher abprüfen kann.
OpenAI-Adapter ruft /v1/models auf — ein billiger GET, der bei gültigem
Key 200 liefert.
ReportRequest / ReportResponse¶
lib/features/api/models/report_request.dart
class ReportRequest {
final String apiKey;
final String model;
final ReportType reportType;
final String pseudonymizedNotes;
final String? pseudonymizedPreviousReport;
final String? pseudonymizedReferenceReport;
final double temperature; // Default 0.7
}
class ReportResponse {
final String text;
final int inputTokens;
final int outputTokens;
final String model;
final String? stopReason;
double get costUsd; // Modellbasierte Kostenschätzung
String get tokenDisplay; // "1.2k → 850 tokens"
String get costDisplay; // "$0.0042"
}
System-Prompts¶
lib/features/api/prompts/system_prompts.dart hält die Prompts:
ReportType |
Prompt |
|---|---|
informationsbericht |
Berlin Informationsbericht v1.01 — Format, Module, Sprache |
Custom-Prompts können in Einstellungen → System-Prompt überschrieben
werden — werden in SettingsStorage.customInfoPrompt /
customBrpPrompt persistiert und ersetzen den Default.
Kostenkontrolle¶
Jede Antwort enthält Token-Verbrauch und eine Kosten-Schätzung. Die App zeigt nach jedem Bericht:
API-Verbrauch: 2 845 → 1 612 Token
Modell: claude-sonnet-4-6 · Kosten: $0.018
Diese Werte landen auch im Audit-Log und können beim Träger als Argument für ein Budget verwendet werden.
Erwartete Größenordnungen¶
| Berichtstyp | Input | Output | Kosten Sonnet 4.6 | Kosten Opus 4.7 |
|---|---|---|---|---|
| Informationsbericht | 2 000 – 5 000 | 1 200 – 2 500 | $0.01 – 0.03 | $0.05 – 0.13 |
Realwerte hängen vom Umfang des Vorberichts und der Stichpunkte ab.
Netzwerk-Verhalten¶
| Parameter | Wert |
|---|---|
connectTimeout |
30 Sekunden |
receiveTimeout |
120 Sekunden |
| Retries | aktuell keine — Fehler werden direkt an UI propagiert |
| Verschlüsselung | TLS 1.3 (Dio Standard) |
| Proxy-Support | über System-Proxy (Dio nutzt OS-Settings) |
Provider-spezifische Risiken¶
| Risiko | Anthropic | OpenAI |
|---|---|---|
| Sitz | USA, San Francisco | USA, San Francisco |
| EU-Region verfügbar | Über AWS Bedrock (eu-central-1) | Über Azure OpenAI (eu-Regionen) |
| DPA / SCCs | Ja, mit Modul 2 + 3 | Ja, nach EU 2021/914 |
| Zero Data Retention | Standardmäßig nicht, in Enterprise verfügbar | "Enterprise" / "API Platform" mit ZDR-Opt-in |
| Training auf API-Inputs | Nein, beide haben das vertraglich ausgeschlossen | siehe Anthropic |
Für sensitive Anwendung wird empfohlen, mit dem jeweiligen Provider einen DPA mit SCCs abzuschließen und Zero-Data-Retention zu beantragen. Siehe Datenschutz für die rechtliche Argumentation.
Lokale LLM-Alternativen (geplant)¶
Siehe Roadmap. Konzept:
OllamaAdaptermit lokalemhttp://localhost:11434/api/generate- Standardmodelle:
llama3.1:70b-instruct,qwen2.5:32b-instruct - Pseudonymisierung wird dann zu einem Defense-in-Depth, weil das Modell ohnehin lokal läuft — aber sie bleibt als zweite Sicherung aktiv, falls jemand einmal versehentlich den Lokalmodell-Endpunkt auf einen Cloud-Proxy umstellt.