Im Produktivbetrieb
Die Standardwerte sind auf einen typischen SaaS-Kunden abgestimmt. Unten stehen die Stellschrauben, die Sie anfassen, wenn sich das Verkehrsprofil ändert – Rate Limiting, Retry-Richtlinie, Audit-Logging, Erreichbarkeitsprüfungen von Abhängigkeiten, Integration mit IHealthCheck, Idempotenz, Überschreiben von Prompt-Vorlagen und die BYOK-Verwaltung.
Rate Limiting für KI-Aufrufe
POST /richtextbox/ai und POST /richtextbox/ai/stream teilen sich einen Token-Bucket pro IP, damit ein einzelner außer Kontrolle geratener Tab Ihr Kontingent beim Anbieter nicht in Sekunden aufbraucht. Standard: 30 Aufrufe pro Minute und IP.
builder.Services.AddRichTextBox(opts => { opts.AiRateLimit = 30; // calls per window opts.AiRateLimitWindow = TimeSpan.FromMinutes(1); // window length });
Setzen Sie AiRateLimit = 0, um es abzuschalten, oder ersetzen Sie es durch einen Limiter auf Redis-Basis:
builder.Services.AddSingleton<IRichTextBoxAiRateLimiter, RedisAiRateLimiter>(); builder.Services.AddRichTextBox();
HTTP-Retry bei vorübergehenden Fehlern des Anbieters
OpenAI / Anthropic / Azure OpenAI geben unter normaler Last 429 und 503 zurück. Die eingebauten Resolver wiederholen diese Requests (plus 502 / 504 und Verbindungsabbrüche) mit exponentiellem Backoff und vollem Jitter, begrenzt auf 30 Sekunden. Der Header Retry-After des Anbieters wird beachtet.
services.AddRichTextBoxOpenAiResolver(opts => { opts.ApiKey = builder.Configuration["OpenAI:ApiKey"]; opts.MaxRetryAttempts = 2; // 0 to disable opts.RetryBaseDelay = TimeSpan.FromMilliseconds(500); });
Idempotenzschlüssel
Jedes POST /richtextbox/ai, /ai/stream und /upload beachtet Idempotency-Key. Doppelte Wiederholungen spielen den zwischengespeicherten Body unverändert ab – keine doppelte Abrechnung, keine verwaisten Dateien. Streaming-Antworten spielen den gesamten SSE-Bytestrom Byte für Byte ab.
builder.Services.AddRichTextBox(opts => { opts.IdempotencyTtl = TimeSpan.FromHours(1); opts.IdempotencyPruneInterval = TimeSpan.FromMinutes(5); });
Hosts mit mehreren Instanzen: Registrieren Sie einen IIdempotencyStore auf Redis-Basis statt des standardmäßigen In-Memory-Speichers. Durch die native TTL können Sie die periodische Bereinigung abschalten.
Audit-Logging für Sicherheit
Jede sicherheitsrelevante Ablehnung erzeugt ein strukturiertes LogWarning unter der Kategorie RichTextBox.Audit mit einer stabilen EventId:
| EventId | Name | Wird ausgelöst, wenn |
|---|---|---|
| 8001 | LicenseInvalid | Ein Endpoint einen Request abgelehnt hat, weil die .lic-Datei fehlte oder ungültig war. |
| 8101 | UploadMagicByteMismatch | Die Magic Bytes nicht zur angegebenen Dateiendung passen. |
| 8102 | UploadRejectedByValidator | Ein IUploadValidator Reject zurückgegeben hat. |
| 8103 | UploadInvalidExtension | Ein Upload abgelehnt wurde, weil er außerhalb der Allowlist liegt. |
| 8104 | UploadOversize | MaxUploadBytes überschritten wurde. |
| 8201 | AiRequestOversize | Der KI-Body MaxRequestBytes überschritten hat. |
| 8202 | AiRateLimitExceeded | Der Aufrufer das KI-Rate-Limit pro IP überschritten hat. |
| 8203 | AiResolverException | Der KI-Resolver eine Ausnahme geworfen hat; protokolliert mit Korrelations-ID. |
| 8204 | AiKeyVaultMiss | Der BYOK-Tresor keinen Schlüssel zurückgegeben hat. |
| 8205 | AiKeyVaultHit | Der BYOK-Tresor einen Schlüssel zurückgegeben hat (KeyId wird protokolliert, das Geheimnis nie). |
| 8206 | AiResponseFilterMatched | Ein IRichTextBoxAiResponseFilter die Antwort verändert hat. |
Audit-Ereignisse in einen eigenen Stream leiten
Mit IRichTextBoxAuditSink können regulierte Workloads (HIPAA / PCI / SOC2) nur die Audit-Ereignisse an ein Write-Once-Ziel leiten – Splunk HEC, S3 mit Object Lock, eine reine Audit-Datenbank. Mitgeliefert wird JsonLinesAuditSink für den Offline- bzw. Einzelinstanzbetrieb:
builder.Services.AddRichTextBox(); builder.Services.AddJsonLinesAuditSink("/var/log/myapp/rtb-audit.jsonl");
Channel + Abarbeitung im Hintergrund; RecordAsync blockiert nie. Läuft die Warteschlange über, werden Ereignisse verworfen und in der Metrik DroppedCount gezählt. Mehrere Sinks lassen sich einfach registrieren – kombinieren Sie JsonLines ohne Mehraufwand mit einem Splunk-Sink in Echtzeit.Erreichbarkeitsprüfungen für Abhängigkeiten
Über optionale Begleitschnittstellen kann jede Abhängigkeit von RichTextBox melden, ob ihr zugrunde liegender Dienst erreichbar ist. Der Endpoint /richtextbox/health zeigt das Ergebnis neben dem Lizenzstatus an:
| Schnittstelle | Eingebaute Implementierungen | Prüfziel |
|---|---|---|
IRichTextBoxAiResolverProbe | OpenAI, Azure OpenAI (kostenlos); Wrapper AnthropicResolverWithProbe (POST mit wenigen Tokens) | GET /v1/models / GET /openai/deployments / POST /v1/messages mit max_tokens=1 |
IIdempotencyStoreProbe | Eigener Redis- / SQL-Speicher (von Ihnen implementiert) | PING / SELECT 1 |
IRichTextBoxUploadStoreProbe | Eigener Speicher für S3 / Azure Blob / Cloudinary | HEAD auf den Bucket / list-objects --max-items 1 |
builder.Services.AddRichTextBox(opts => { opts.AiResolverHealthProbeEnabled = true; opts.AiResolverHealthProbeTimeout = TimeSpan.FromSeconds(3); opts.AiResolverHealthProbeCacheTtl = TimeSpan.FromSeconds(30); opts.IdempotencyStoreHealthProbeEnabled = true; opts.UploadStoreHealthProbeEnabled = true; });
Eine Cache-TTL pro Prüfung schützt vor dauerndem Abfragen durch den Load Balancer – ein Balancer, der /health alle 5 Sekunden aufruft, würde sonst 12 Prüfungen pro Minute auslösen, auch wenn Prüfungen echtes Geld kosten.
Standardintegration mit IHealthCheck
Für Hosts mit Microsoft.Extensions.Diagnostics.HealthChecks registrieren Sie den Adapter, und der Status von RichTextBox erscheint neben Ihren anderen Prüfungen – kein paralleler Überwachungsweg:
builder.Services.AddRichTextBox(); builder.Services.AddHealthChecks() .AddRichTextBox(name: "richtextbox", failureStatus: HealthStatus.Unhealthy, tags: new[] { "ready" } ); app.MapHealthChecks("/health");
Gibt Healthy zurück, wenn Lizenz und alle maßgeblichen Prüfungen bestehen, sonst Unhealthy mit einer Beschreibung der fehlgeschlagenen Abhängigkeit. HealthCheckResult.Data spiegelt die JSON-Daten von /richtextbox/health.
BYOK – API-Schlüssel pro Mandant
SaaS-Hosts mit mehreren Mandanten rechnen KI-Verkehr über IAiKeyVault + IAiKeyVaultAdmin auf das eigene Anbieterkonto jedes Mandanten ab. Das Paket enthält eine In-Memory-Referenzimplementierung; Produktivumgebungen setzen auf Azure Key Vault, Redis oder einen echten SQL-Speicher.
Den vollständigen Vertrag, die REST-Endpoints für die Verwaltung und Referenzimplementierungen (Redis, Azure Key Vault, verschlüsselt auf der Festplatte mit FileBackedAiKeyVault) finden Sie auf der eigenen Seite zum BYOK-Schlüsseltresor.
Kostenbuch pro Aufruf
IRichTextBoxAiCostSink erzeugt pro KI-Aufruf ein AiUsageRecord – Anbieter, Modell, Modus, Tokens (Eingabe / Ausgabe / gesamt), Latenz, Status, KeyId. Leiten Sie es zur Weiterberechnung an Mandanten an Ihr Abrechnungssystem weiter:
builder.Services.AddSingleton<IRichTextBoxAiCostSink, MyBillingApiCostSink>();Für Mandanten mit viel Verkehr umhüllen Sie ihn mit dem puffernden Sink, sodass der innere Sink pro Intervall ein gebündeltes Flush erhält statt eines HTTP- oder SQL-Aufrufs pro KI-Request. Implementiert Ihr innerer Sink auch IRichTextBoxAiCostBatchSink, leitet der Wrapper über RecordBatchAsync – ein INSERT statt N.
builder.Services.AddBufferingAiCostSink<MyBillingApiCostSink>( flushInterval: TimeSpan.FromSeconds(30), maxBatchSize: 500);
Filtern der Ausgabe – Schwärzen personenbezogener Daten, Blockieren von Inhalten
IRichTextBoxAiResponseFilter läuft nach dem Resolver, aber bevor die Antwort gesendet wird. Die Referenzimplementierung RegexAiResponseFilter deckt ~80% der praktischen Schwärzung personenbezogener Daten ab:
var emailMask = new Regex(@"[\w.+-]+@[\w-]+\.[\w.-]+"); var ssnMask = new Regex(@"\b\d{3}-\d{2}-\d{4}\b"); builder.Services.AddSingleton<IRichTextBoxAiResponseFilter>( new RegexAiResponseFilter( (emailMask, "[email-redacted]"), (ssnMask, "[ssn-redacted]")));
Bei Streaming-Antworten puffert das Framework die Tokens auf dem Server, wenn Filter registriert sind (Standard BufferStreamingForFilters = true), damit ein regulärer Ausdruck für Kreditkarten, der sich über mehrere Deltas erstreckt, tatsächlich greift.
Prompt-Vorlagen überschreiben
Mit IRichTextBoxPromptTemplateProvider überschreiben Sie die System-Prompts pro Modus, die die eingebauten Resolver senden. Mit der Decorator-Basisklasse PromptTemplateProviderBase überschreiben Sie nur die Methode(n), die Sie brauchen:
public sealed class FormalTonePromptProvider : PromptTemplateProviderBase { public override string BuildSystemPrompt(RichTextBoxAiRequest request, string? operatorSuffix) => base.BuildSystemPrompt(request, operatorSuffix) + "\n\nAlways reply in formal British English; avoid contractions."; }
Für einzelne Anpassungen eines Modus ohne vollständigen Provider verwenden Sie das Dictionary:
services.AddRichTextBoxOpenAiResolver(opts => { opts.ApiKey = "sk-..."; opts.SystemPromptOverridesByMode["proofread"] = "You are a hyper-pedantic copy-editor for legal documents."; });
Prüfung auf Prompt Injection
IRichTextBoxAiPolicy ist die Schranke, die die KI-Endpoints befragen, bevor sie den Resolver aufrufen. Die eingebaute DefaultPromptInjectionPolicy lehnt gängige Jailbreak-Vorlagen ab („ignore previous instructions“, „you are now DAN“ usw.). Ergänzen Sie weitere Richtlinien für das Schwärzen personenbezogener Daten oder Allowlists für Modi pro Mandant.
builder.Services.AddSingleton<IRichTextBoxAiPolicy, DefaultPromptInjectionPolicy>(); builder.Services.AddSingleton<IRichTextBoxAiPolicy, MyTenantPolicy>();
Verteiltes Tracing (OpenTelemetry)
Jeder KI-Aufruf, DOCX-Export und Upload erzeugt einen Span über die ActivitySource RichTextBox.AspNetCore. Abonnieren Sie sie in der Konfiguration Ihres Tracer-Providers:
builder.Services.AddOpenTelemetry().WithTracing(t => t .AddSource(RichTextBoxDiagnostics.SourceName) // "RichTextBox.AspNetCore" .AddAspNetCoreInstrumentation() .AddOtlpExporter());
Validierung der Optionen beim Start
RichTextBoxOptionsValidator + AiResolverOptionsValidator<T> laufen bei der ersten Auflösung von IOptions.Value – bevor der Host den ersten Request annimmt. Eine fehlerhafte Konfiguration (vergessener /, negatives Byte-Limit, Heartbeat > Timeout, fehlender API-Schlüssel, fehlendes Azure-Deployment) wirft beim Start eine OptionsValidationException, sodass Deployments deutlich fehlschlagen.
Keine Verdrahtung nötig. Die Validatoren registrieren sich automatisch über AddRichTextBox().
Ergänzende Dokumentation
BYOK-Schlüsseltresor·KI-Anbieter & Streaming·Cloud-Upload-Anbieter·Barrierefreiheit