← Toda a documentação
Operações em produção

Execução em produção

Os padrões são ajustados para um cliente SaaS típico. Abaixo estão os ajustes que você vai mexer quando o perfil de tráfego mudar — limitação de taxa, política de nova tentativa, log de auditoria, sondas de disponibilidade de dependências, integração com IHealthCheck, idempotência, substituição de templates de prompt e a interface de administração do BYOK.

Limitação de taxa das chamadas de IA

POST /richtextbox/ai e POST /richtextbox/ai/stream compartilham um token bucket por IP, para que uma única aba descontrolada não consuma a cota do seu provedor em segundos. Padrão: 30 chamadas por minuto por IP.

builder.Services.AddRichTextBox(opts =>
{
    opts.AiRateLimit       = 30;                          // calls per window
    opts.AiRateLimitWindow = TimeSpan.FromMinutes(1);     // window length
});

Defina AiRateLimit = 0 para desativar, ou troque por um limitador baseado em Redis:

builder.Services.AddSingleton<IRichTextBoxAiRateLimiter, RedisAiRateLimiter>();
builder.Services.AddRichTextBox();

Nova tentativa HTTP em falhas transitórias do provedor

OpenAI / Anthropic / Azure OpenAI retornam 429 e 503 sob carga normal. Os resolvers nativos repetem essas requisições (além de 502 / 504 e quedas de conexão) com backoff exponencial e full jitter, limitado a 30 segundos. O cabeçalho Retry-After do provedor é respeitado.

services.AddRichTextBoxOpenAiResolver(opts =>
{
    opts.ApiKey         = builder.Configuration["OpenAI:ApiKey"];
    opts.MaxRetryAttempts = 2;                              // 0 to disable
    opts.RetryBaseDelay   = TimeSpan.FromMilliseconds(500);
});

Chaves de idempotência

Todo POST /richtextbox/ai, /ai/stream e /upload respeita Idempotency-Key. Novas tentativas duplicadas reproduzem o corpo em cache literalmente — sem cobrança dupla, sem arquivos órfãos. Respostas em streaming reproduzem todo o fluxo de bytes SSE byte a byte.

builder.Services.AddRichTextBox(opts =>
{
    opts.IdempotencyTtl = TimeSpan.FromHours(1);
    opts.IdempotencyPruneInterval = TimeSpan.FromMinutes(5);
});

Hosts com várias instâncias: registre um IIdempotencyStore baseado em Redis no lugar do padrão em memória. Com o TTL nativo, você pode desativar a limpeza periódica.

Log de auditoria de segurança

Toda rejeição relevante para a segurança emite um LogWarning estruturado na categoria RichTextBox.Audit com um EventId estável:

EventIdNomeQuando é emitido
8001LicenseInvalidUm endpoint recusou uma requisição porque o arquivo .lic estava ausente ou era inválido.
8101UploadMagicByteMismatchA assinatura (magic bytes) não corresponde à extensão declarada.
8102UploadRejectedByValidatorUm IUploadValidator retornou Reject.
8103UploadInvalidExtensionUpload rejeitado por estar fora da lista de permitidos.
8104UploadOversizeExcedeu MaxUploadBytes.
8201AiRequestOversizeO corpo da requisição de IA excedeu MaxRequestBytes.
8202AiRateLimitExceededO chamador excedeu o limite de taxa de IA por IP.
8203AiResolverExceptionO resolver de IA lançou uma exceção; registrado com o correlation id.
8204AiKeyVaultMissO cofre BYOK não retornou nenhuma chave.
8205AiKeyVaultHitO cofre BYOK retornou uma chave (o KeyId é registrado; o segredo, nunca).
8206AiResponseFilterMatchedUm IRichTextBoxAiResponseFilter alterou a resposta.

Como encaminhar eventos de auditoria para um fluxo separado

IRichTextBoxAuditSink permite que cargas de trabalho sujeitas a regulamentação de conformidade (HIPAA / PCI / SOC2) encaminhem apenas os eventos de auditoria para um destino de gravação única — Splunk HEC, S3 com object lock, um banco de dados só de auditoria. Inclui JsonLinesAuditSink para uso offline / em instância única:

builder.Services.AddRichTextBox();
builder.Services.AddJsonLinesAuditSink("/var/log/myapp/rtb-audit.jsonl");
Comportamento. Channel limitado + drenador em segundo plano; RecordAsync nunca bloqueia. Quando a fila transborda, os eventos são descartados e contabilizados na métrica DroppedCount. Vários sinks se registram naturalmente — combine o JsonLines com um sink do Splunk em tempo real sem custo adicional.

Sondas de disponibilidade de dependências

Interfaces complementares opcionais permitem que qualquer dependência do RichTextBox informe se o serviço por trás dela está acessível. O endpoint /richtextbox/health exibe o resultado junto com o status da licença:

InterfaceImplementações nativasAlvo da sonda
IRichTextBoxAiResolverProbeOpenAI, Azure OpenAI (sem custo); wrapper AnthropicResolverWithProbe (POST com poucos tokens)GET /v1/models / GET /openai/deployments / POST /v1/messages com max_tokens=1
IIdempotencyStoreProbeStore Redis / SQL personalizado (implementado por você)PING / SELECT 1
IRichTextBoxUploadStoreProbeStore S3 / Azure Blob / Cloudinary personalizadoHEAD no 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;
});

O TTL de cache em cada sonda protege contra o bombardeio do balanceador de carga — um balanceador que acessa /health a cada 5 segundos geraria, caso contrário, 12 sondas por minuto, mesmo quando as sondas custam dinheiro de verdade.

Integração padrão com IHealthCheck

Em hosts que usam Microsoft.Extensions.Diagnostics.HealthChecks, registre o adaptador e o status do RichTextBox aparece junto com suas outras verificações — sem um caminho de monitoramento paralelo:

builder.Services.AddRichTextBox();
builder.Services.AddHealthChecks()
.AddRichTextBox(name: "richtextbox", failureStatus: HealthStatus.Unhealthy, tags: new[]  { "ready" } );

app.MapHealthChecks("/health");

Retorna Healthy quando a licença e todas as sondas habilitadas passam; Unhealthy, com uma descrição que identifica a dependência que falhou. HealthCheckResult.Data espelha o payload JSON de /richtextbox/health.

BYOK — chaves de API por tenant

Hosts SaaS multi-tenant cobram o tráfego de IA da conta de provedor de cada tenant por meio de IAiKeyVault + IAiKeyVaultAdmin. O pacote inclui uma implementação de referência em memória; implantações em produção usam como backend o Azure Key Vault, o Redis ou um store SQL de verdade.

Veja a página dedicada BYOK key vault para o contrato completo, os endpoints REST de administração e as implementações de referência (Redis, Azure Key Vault, FileBackedAiKeyVault criptografado em disco).

Registro de custo por chamada

IRichTextBoxAiCostSink emite um AiUsageRecord por chamada de IA — provedor, modelo, modo, tokens (entrada / saída / total), latência, status, KeyId. Encaminhe para o seu sistema de cobrança para fazer o repasse de custos por tenant:

builder.Services.AddSingleton<IRichTextBoxAiCostSink, MyBillingApiCostSink>();

Para tenants com muito tráfego, envolva-o no sink com buffer, para que o sink interno receba um único flush em lote por intervalo, em vez de uma chamada HTTP/SQL por requisição de IA. Se o seu sink interno também implementar IRichTextBoxAiCostBatchSink, o wrapper encaminha por RecordBatchAsync — um INSERT em vez de N.

builder.Services.AddBufferingAiCostSink<MyBillingApiCostSink>(
    flushInterval: TimeSpan.FromSeconds(30),
    maxBatchSize:  500);

Filtragem da saída — ocultação de PII, bloqueio de conteúdo

IRichTextBoxAiResponseFilter é executado depois do resolver, mas antes de a resposta ser enviada. O RegexAiResponseFilter de referência cobre ~80% dos casos práticos de ocultação de PII:

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]")));

Em respostas em streaming, o framework faz buffer dos tokens no servidor quando há filtros registrados (BufferStreamingForFilters = true por padrão), para que uma regex de cartão de crédito que se estende por vários deltas de fato encontre a correspondência.

Substituição de templates de prompt

IRichTextBoxPromptTemplateProvider permite substituir os prompts de sistema por modo que os resolvers nativos enviam. Use a classe base decoradora PromptTemplateProviderBase para sobrescrever apenas o(s) método(s) de que você precisa:

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.";
}

Para ajustes pontuais de um modo sem um provider completo, use o dicionário:

services.AddRichTextBoxOpenAiResolver(opts =>
{
    opts.ApiKey = "sk-...";
    opts.SystemPromptOverridesByMode["proofread"] =
        "You are a hyper-pedantic copy-editor for legal documents.";
});

Triagem de prompt injection

IRichTextBoxAiPolicy é a barreira que os endpoints de IA consultam antes de chamar o resolver. O DefaultPromptInjectionPolicy nativo rejeita templates de jailbreak prontos (“ignore previous instructions”, “you are now DAN” etc.). Adicione políticas extras para ocultação de PII ou listas de modos permitidos por tenant.

builder.Services.AddSingleton<IRichTextBoxAiPolicy, DefaultPromptInjectionPolicy>();
builder.Services.AddSingleton<IRichTextBoxAiPolicy, MyTenantPolicy>();

Rastreamento distribuído (OpenTelemetry)

Toda chamada de IA, exportação DOCX e upload emite um span por meio do ActivitySource RichTextBox.AspNetCore. Inscreva-se na configuração do seu tracer provider:

builder.Services.AddOpenTelemetry().WithTracing(t => t
.AddSource(RichTextBoxDiagnostics.SourceName)   // "RichTextBox.AspNetCore"
.AddAspNetCoreInstrumentation()
.AddOtlpExporter());

Validação das opções na inicialização

RichTextBoxOptionsValidator + AiResolverOptionsValidator<T> são executados na primeira resolução de IOptions.Value — antes de o host aceitar a primeira requisição. Uma configuração inválida (/ esquecida, limite de bytes negativo, heartbeat > timeout, chave de API ausente, deployment do Azure ausente) lança OptionsValidationException na inicialização, para que as implantações falhem de forma visível.

Nenhuma configuração necessária. Os validadores são registrados automaticamente por AddRichTextBox().

Documentação relacionada

Cofre de chaves BYOK·Provedores de IA e streaming·Provedores de upload na nuvem·Acessibilidade