Exploitation en production
Les valeurs par défaut sont réglées pour un client SaaS typique. Voici les réglages sur lesquels vous agirez quand le profil du trafic change — limitation de débit, politique de nouvelles tentatives, journal d’audit, sondes d’accessibilité des dépendances, intégration d'IHealthCheck, idempotence, redéfinition des modèles de prompts et interface d’administration BYOK.
Limiter le débit des appels IA
POST /richtextbox/ai et POST /richtextbox/ai/stream partagent un seau de jetons par IP, pour qu’un seul onglet emballé ne puisse pas épuiser votre quota chez le fournisseur en quelques secondes. Valeurs par défaut : 30 appels par minute et par IP.
builder.Services.AddRichTextBox(opts => { opts.AiRateLimit = 30; // calls per window opts.AiRateLimitWindow = TimeSpan.FromMinutes(1); // window length });
Définissez AiRateLimit = 0 pour le désactiver, ou remplacez-le par un limiteur reposant sur Redis :
builder.Services.AddSingleton<IRichTextBoxAiRateLimiter, RedisAiRateLimiter>(); builder.Services.AddRichTextBox();
Nouvelles tentatives HTTP en cas de défaillance passagère du fournisseur
OpenAI / Anthropic / Azure OpenAI renvoient des 429 et des 503 en charge normale. Les résolveurs intégrés relancent ces requêtes (ainsi que les 502 / 504 et les coupures de connexion) avec un backoff exponentiel et un jitter complet, plafonné à 30 secondes. L’en-tête Retry-After du fournisseur est respecté.
services.AddRichTextBoxOpenAiResolver(opts => { opts.ApiKey = builder.Configuration["OpenAI:ApiKey"]; opts.MaxRetryAttempts = 2; // 0 to disable opts.RetryBaseDelay = TimeSpan.FromMilliseconds(500); });
Clés d’idempotence
Chaque POST /richtextbox/ai, /ai/stream et /upload respecte Idempotency-Key. Les nouvelles tentatives en double rejouent le corps mis en cache tel quel — pas de double facturation, pas de fichiers orphelins. Les réponses en streaming rejouent tout le flux d’octets SSE à l’identique.
builder.Services.AddRichTextBox(opts => { opts.IdempotencyTtl = TimeSpan.FromHours(1); opts.IdempotencyPruneInterval = TimeSpan.FromMinutes(5); });
Hôtes multi-instances : enregistrez un IIdempotencyStore reposant sur Redis au lieu de celui en mémoire par défaut. Avec le TTL natif, vous pouvez désactiver le nettoyage périodique.
Journal d’audit de sécurité
Chaque refus lié à la sécurité émet un LogWarning structuré dans la catégorie RichTextBox.Audit, avec un EventId stable :
| EventId | Nom | Se déclenche quand |
|---|---|---|
| 8001 | LicenseInvalid | Un point de terminaison a refusé une requête parce que le fichier .lic était absent ou invalide. |
| 8101 | UploadMagicByteMismatch | La signature du fichier ne correspond pas à l’extension déclarée. |
| 8102 | UploadRejectedByValidator | Un IUploadValidator a renvoyé Reject. |
| 8103 | UploadInvalidExtension | Envoi refusé parce qu’il n’est pas dans la liste d’autorisation. |
| 8104 | UploadOversize | Dépassement de MaxUploadBytes. |
| 8201 | AiRequestOversize | Le corps de la requête IA a dépassé MaxRequestBytes. |
| 8202 | AiRateLimitExceeded | L’appelant a dépassé la limite de débit IA par IP. |
| 8203 | AiResolverException | Le résolveur IA a levé une exception ; journalisée avec un identifiant de corrélation. |
| 8204 | AiKeyVaultMiss | Le coffre BYOK n’a renvoyé aucune clé. |
| 8205 | AiKeyVaultHit | Le coffre BYOK a renvoyé une clé (KeyId journalisé ; jamais le secret). |
| 8206 | AiResponseFilterMatched | Un IRichTextBoxAiResponseFilter a modifié la réponse. |
Envoyer les événements d’audit vers un flux séparé
IRichTextBoxAuditSink permet aux charges de travail soumises à une réglementation (HIPAA / PCI / SOC2) d’envoyer uniquement les événements d’audit vers une destination à écriture unique — Splunk HEC, S3 avec verrouillage d’objet, une base de données dédiée à l’audit. Fourni avec JsonLinesAuditSink pour un usage hors ligne ou sur une seule instance :
builder.Services.AddRichTextBox(); builder.Services.AddJsonLinesAuditSink("/var/log/myapp/rtb-audit.jsonl");
Channel borné et un consommateur en arrière-plan ; RecordAsync ne bloque jamais. En cas de débordement de la file, des événements sont abandonnés, avec une métrique DroppedCount. Plusieurs sinks s’enregistrent naturellement — associez gratuitement JsonLines à un sink Splunk en temps réel.Sondes d’accessibilité des dépendances
Des interfaces complémentaires facultatives permettent à toute dépendance de RichTextBox d’indiquer si son service sous-jacent est joignable. Le point de terminaison /richtextbox/health présente le résultat avec l’état de la licence :
| Interface | Implémentations intégrées | Cible de la sonde |
|---|---|---|
IRichTextBoxAiResolverProbe | OpenAI, Azure OpenAI (gratuit) ; wrapper AnthropicResolverWithProbe (POST à faible nombre de jetons) | GET /v1/models / GET /openai/deployments / POST /v1/messages avec max_tokens=1 |
IIdempotencyStoreProbe | Stockage Redis / SQL personnalisé (à implémenter vous-même) | PING / SELECT 1 |
IRichTextBoxUploadStoreProbe | Stockage S3 / Azure Blob / Cloudinary personnalisé | HEAD du 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; });
Le TTL de cache de chaque sonde protège contre le martèlement par l’équilibreur de charge — un équilibreur qui interroge /health toutes les 5 secondes produirait sinon 12 sondages par minute, même lorsque les sondes coûtent de l’argent.
Intégration standard d'IHealthCheck
Pour les hôtes qui utilisent Microsoft.Extensions.Diagnostics.HealthChecks, enregistrez l’adaptateur : l’état de RichTextBox apparaît à côté de vos autres vérifications — sans chaîne de supervision parallèle.
builder.Services.AddRichTextBox(); builder.Services.AddHealthChecks() .AddRichTextBox(name: "richtextbox", failureStatus: HealthStatus.Unhealthy, tags: new[] { "ready" } ); app.MapHealthChecks("/health");
Renvoie Healthy lorsque la licence et toutes les sondes bloquantes sont valides ; Unhealthy avec une description qui identifie la dépendance défaillante. HealthCheckResult.Data reprend la charge utile JSON de /richtextbox/health.
BYOK — clés d’API par locataire
Les hôtes SaaS multilocataires facturent le trafic IA sur le compte fournisseur propre à chaque locataire via IAiKeyVault + IAiKeyVaultAdmin. Le package fournit une implémentation de référence en mémoire ; les déploiements en production s’appuient sur Azure Key Vault, Redis ou une vraie base SQL.
Consultez la page dédiée au coffre de clés BYOK pour le contrat complet, les points de terminaison REST d’administration et les implémentations de référence (Redis, Azure Key Vault, FileBackedAiKeyVault chiffré sur disque).
Registre des coûts par appel
IRichTextBoxAiCostSink émet un AiUsageRecord par appel IA — fournisseur, modèle, mode, jetons (entrée / sortie / total), latence, statut, KeyId. Transmettez-les à votre système de facturation pour refacturer les locataires :
builder.Services.AddSingleton<IRichTextBoxAiCostSink, MyBillingApiCostSink>();Pour les locataires à fort trafic, enveloppez-le dans le sink de mise en tampon : le sink interne reçoit alors un seul vidage groupé par intervalle au lieu d’un appel HTTP/SQL par requête IA. Si votre sink interne implémente aussi IRichTextBoxAiCostBatchSink, le wrapper passe par RecordBatchAsync — un seul INSERT au lieu de N.
builder.Services.AddBufferingAiCostSink<MyBillingApiCostSink>( flushInterval: TimeSpan.FromSeconds(30), maxBatchSize: 500);
Filtrage de la sortie — masquage des données personnelles, blocage de contenu
IRichTextBoxAiResponseFilter s’exécute après le résolveur, mais avant l’envoi de la réponse. Le RegexAiResponseFilter de référence couvre ~80% des besoins pratiques de masquage des données personnelles :
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]")));
Pour les réponses en streaming, le framework met les jetons en tampon côté serveur lorsque des filtres sont enregistrés (BufferStreamingForFilters = true par défaut), pour qu’une expression régulière de carte bancaire répartie sur plusieurs deltas corresponde réellement.
Redéfinition des modèles de prompts
IRichTextBoxPromptTemplateProvider permet de redéfinir les prompts système par mode qu’envoient les résolveurs intégrés. Utilisez la classe de base décoratrice PromptTemplateProviderBase pour ne redéfinir que la ou les méthodes dont vous avez besoin :
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."; }
Pour un ajustement ponctuel d’un mode sans fournisseur complet, utilisez le dictionnaire :
services.AddRichTextBoxOpenAiResolver(opts => { opts.ApiKey = "sk-..."; opts.SystemPromptOverridesByMode["proofread"] = "You are a hyper-pedantic copy-editor for legal documents."; });
Détection des injections de prompt
IRichTextBoxAiPolicy est le contrôle que consultent les points de terminaison IA avant d’invoquer le résolveur. La DefaultPromptInjectionPolicy intégrée rejette les modèles de jailbreak courants (« ignore previous instructions », « you are now DAN », etc.). Ajoutez des politiques supplémentaires pour le masquage des données personnelles ou des listes de modes autorisés par locataire.
builder.Services.AddSingleton<IRichTextBoxAiPolicy, DefaultPromptInjectionPolicy>(); builder.Services.AddSingleton<IRichTextBoxAiPolicy, MyTenantPolicy>();
Traçage distribué (OpenTelemetry)
Chaque appel IA, export DOCX et envoi de fichier émet un span via l'ActivitySource RichTextBox.AspNetCore. Abonnez-vous dans la configuration de votre tracer provider :
builder.Services.AddOpenTelemetry().WithTracing(t => t .AddSource(RichTextBoxDiagnostics.SourceName) // "RichTextBox.AspNetCore" .AddAspNetCoreInstrumentation() .AddOtlpExporter());
Validation des options au démarrage
RichTextBoxOptionsValidator + AiResolverOptionsValidator<T> s’exécutent à la première résolution d'IOptions.Value — avant que l’hôte n’accepte la première requête. Une mauvaise configuration (/ oublié, plafond d’octets négatif, heartbeat > timeout, clé d’API ou déploiement Azure manquants) lève OptionsValidationException au démarrage, pour que les déploiements échouent de façon visible.
Aucun câblage n’est nécessaire. Les validateurs s’enregistrent automatiquement via AddRichTextBox().
Documentation associée
Coffre de clés BYOK · Fournisseurs d’IA et streaming · Fournisseurs de stockage cloud pour les envois · Accessibilité