AI Architecture
O capstone agora deixa de ser um conjunto de componentes e precisa de uma arquitetura defensável. Um SaaS de análise de documentos atende vários tenants, executa agentes, usa RAG e produz ações. O desafio é escolher onde a resposta será síncrona, onde haverá jobs, quais dados podem estar temporariamente desatualizados e como o sistema impede que uma identidade alcance recursos de outra.
A entrega será uma ADR e um diagrama com fronteiras de confiança para esse produto. Retomaremos gateway, cache, filas, idempotência e deploy como decisões conectadas. Cada escolha deve explicar contexto, alternativas, consequências e evidência necessária. Um diagrama com muitos serviços não demonstra maturidade; um desenho simples com invariantes, falhas e trade-offs explícitos permite operar e evoluir o produto.
JavaScriptAPIsAgentesIA & MLInfraestruturaAo terminar esta aula
- Arquitetura conecta contratos e fronteiras de confiança.
- Consistência e recuperação precisam de estados explícitos.
- Multi-tenancy atravessa dados, cache, quotas e observabilidade.
Antes de continuar: Laboratório: Cloud/rollback/canary
Sync vs async: onde o usuário espera e onde recebe um job
FundamentosUm fluxo síncrono mantém a requisição esperando por resultado. Ele é conveniente quando a operação é curta e o usuário precisa de resposta imediata. Um fluxo assíncrono aceita o trabalho de forma durável e devolve jobId, permitindo consulta de progresso. A troca traz complexidade de estados, recuperação e autorização do status, mas evita prender uma conexão a tarefas longas. Para o capstone, consultas simples de política podem ser síncronas; indexação de um lote de documentos pode ser assíncrona.
Streaming de tokens melhora a percepção de progresso em geração, mas não é equivalente a uma fila durável. Se a conexão cair, tokens enviados não descrevem necessariamente o estado recuperável do job. Defina checkpoints e resultado final separado do fluxo de exibição. Também diferencie uma stream de eventos persistidos de uma resposta HTTP incremental. Escolha sync ou async pela duração, previsibilidade, necessidade de recuperação e contrato de experiência, e não porque agentes “sempre devem rodar em background”.
Event-driven, queues e consistência eventual
InfraestruturaEm arquitetura orientada a eventos, componentes reagem a fatos como DocumentUploaded e IndexingCompleted. Uma queue distribui trabalho; um log de eventos pode preservar histórico e atender vários consumidores conforme sua implementação. Defina versão do evento, identificador, tenant e idempotencyKey. Eventos não são chamadas de função invisíveis: consumidores podem atrasar, repetir processamento ou receber dados em outra ordem. O produtor e consumidor precisam de contratos explícitos.
↗ Event-Driven Architecture Style↗ Redis streaming↗ Asynchronous Request-Reply Pattern
Consistência eventual admite que visões derivadas sejam atualizadas depois da fonte. Um documento pode estar salvo no banco e ainda não aparecer no índice vetorial. Exponha status pending_index em vez de informar que a busca já está atualizada. Para operações de autorização, não aceite uma projeção atrasada sem analisar o risco: revogação de acesso pode exigir verificação forte na fonte. O usuário deve saber quando o resultado ainda reflete uma versão anterior. Eventual não significa “algum dia sem prazo”; defina objetivo de atraso e sinais para detectar atraso excessivo.
↗ Event-Driven Architecture Style↗ Redis streaming↗ Asynchronous Request-Reply Pattern
Cache, resiliência e idempotência como decisões conjuntas
FundamentosCache reduz leitura e processamento, mas precisa de chave por tenant e versão de fonte. A aplicação decide quais dados aceitam TTL e quais exigem validação atual. Um cache de autorização pode tornar revogação lenta, enquanto cache de texto público versionado pode ser seguro dentro de um contrato claro. Use mecanismos de invalidação e trate indisponibilidade de cache sem sobrecarregar a fonte de forma ilimitada.
Resiliência inclui timeout, retry limitado, circuit breaker, degradação e recuperação. Esses mecanismos interagem com idempotência: repetir indexação pode ser tolerável se a versão e a chave impedirem duplicata, mas repetir envio de contrato pode não ser. O worker registra efeito e estado duráveis, como na semana 43. Um outbox liga mudança de estado à intenção de evento. A ADR deve apontar onde existe uma transação e onde existe reconciliação entre sistemas. Não use a palavra “resiliente” para substituir esse protocolo.
AI Gateway, agent workers e control plane/data plane
AgentesIA & MLInfraestruturaO data plane executa o trabalho do usuário: recebe consulta, recupera documentos, chama modelo e produz resultado. O control plane administra configurações, tenants, quotas, modelos permitidos e políticas. Separar responsabilidades ajuda a reduzir privilégios e impedir que uma consulta de usuário altere a política que a governa. Um agente de suporte não deveria ter a mesma identidade usada para criar tenants ou mudar quotas.
↗ Router - Load Balancing↗ Budgets, Rate Limits↗ Considerations for Multitenant Control Planes
O gateway no data plane aplica a política publicada pelo control plane, com versão registrada em cada execução. Agent workers consomem jobs e precisam da mesma autorização, orçamento e observabilidade que a API. Se o control plane estiver indisponível, defina por quanto tempo uma política já validada pode continuar e quais operações falham fechadas. Uma configuração em cache não pode manter para sempre um acesso revogado. O desenho deve mostrar fluxo de políticas e fluxo de dados separadamente, incluindo quem tem permissão de alterar cada um.
↗ Router - Load Balancing↗ Budgets, Rate Limits↗ Considerations for Multitenant Control Planes
Multi-tenant: isolamento e critérios de uma ADR
FundamentosMulti-tenancy permite compartilhar infraestrutura entre clientes, mas exige isolamento nos acessos, quotas, cache, filas, logs e ferramentas. Um tenantId no JSON não é autenticação; derive a identidade de uma sessão ou token validado e aplique a restrição na consulta. Considere riscos de noisy neighbor: um cliente com muitos jobs pode atrasar os demais. Particionamento, limites por tenant e escalonamento justo têm custo operacional e precisam de justificativa.
↗ Architect Multitenant Solutions on Azure↗ LLM06:2025 Excessive Agency
A ADR descreve o problema e as opções relevantes, como banco compartilhado com isolamento versus bancos separados. A decisão não precisa ser universal: o primeiro cenário reduz operação e custo, mas aumenta a importância de controles consistentes; o segundo facilita certas fronteiras e traz mais recursos para manter. Registre critérios de revisão, como volume, exigência contratual e incidente de isolamento. O diagrama deve mostrar componentes, dados, protocolos e fronteiras de confiança. Um revisor precisa identificar de onde vem a identidade, onde o efeito é autorizado e como o trabalho é recuperado.
↗ Architect Multitenant Solutions on Azure↗ LLM06:2025 Excessive Agency
Um percurso de job com política e tenant verificáveis
FundamentosExecute node architecture.cjs. O exemplo em memória separa publicação de políticas de execução, cria um job por tenant e aplica autorização ao status e à recuperação. Ele mostra a consistência eventual de pending para succeeded e a repetição idempotente do worker. Não pretende representar armazenamento durável; use a semana 43 para persistir esse contrato.
const assert=require('node:assert/strict');
const policies=new Map([['t1',{version:'p1',allowed:true}]]);
const jobs=new Map(),index=new Map();
function submit(session,docId){
const policy=policies.get(session.tenant);
if(!policy?.allowed)throw new Error('denied');
const key=JSON.stringify([session.tenant,docId]);
if(!jobs.has(key))jobs.set(key,{tenant:session.tenant,docId,state:'pending',policy:policy.version});
return key;
}
function status(session,key){
const job=jobs.get(key);
if(!job || job.tenant!==session.tenant)throw new Error('denied');
return job.state;
}
function work(key){
const job=jobs.get(key);if(job.state==='succeeded')return;
index.set(key,{tenant:job.tenant,docId:job.docId});job.state='succeeded';
}
const session={tenant:'t1'},key=submit(session,'d1');
assert.equal(status(session,key),'pending');
assert.throws(()=>status({tenant:'t2'},key),/denied/);
work(key);work(key);
assert.equal(index.size,1);assert.equal(status(session,key),'succeeded');
console.log({key,state:status(session,key),policy:jobs.get(key).policy});A chave inclui tenant e documento, e a consulta de status verifica a identidade independentemente do conhecimento da chave. Pending informa uma visão ainda não concluída, em vez de prometer busca imediata. A política p1 foi capturada, mas o worker ainda precisaria revalidar revogações de acordo com o contrato. Uma chave opaca ou difícil de adivinhar não substitui autorização.
Exercício aplicado
O upload foi salvo, a publicação em Redis falhou e a busca ainda não encontra o documento. Além disso, outro tenant conhece o jobId. Proponha um desenho que trate as duas falhas.
- Registre estado pending_index junto com a intenção de publicação.
- Use outbox e publicador com deduplicação.
- Exponha status consistente com o estágio real.
- Autorize consulta do job pela identidade.
Abrir resolução comentada
A transação grava documento e outbox, permitindo reenvio posterior sem perder a intenção. O worker usa chave idempotente e atualiza a projeção. Enquanto isso, o produto informa indexação pendente, sem afirmar disponibilidade na busca.
Conhecer jobId não concede acesso. A API verifica tenant no estado do job, e o mesmo isolamento precisa valer para índice, cache e logs. O control plane publica políticas, mas não deve ser editável pela execução do agente.
const assert=require('node:assert/strict');
const policies=new Map([['t1',{version:'p1',allowed:true}]]);
const jobs=new Map(),index=new Map();
function submit(session,docId){
const policy=policies.get(session.tenant);
if(!policy?.allowed)throw new Error('denied');
const key=JSON.stringify([session.tenant,docId]);
if(!jobs.has(key))jobs.set(key,{tenant:session.tenant,docId,state:'pending',policy:policy.version});
return key;
}
function status(session,key){
const job=jobs.get(key);
if(!job || job.tenant!==session.tenant)throw new Error('denied');
return job.state;
}
function work(key){
const job=jobs.get(key);if(job.state==='succeeded')return;
index.set(key,{tenant:job.tenant,docId:job.docId});job.state='succeeded';
}
const session={tenant:'t1'},key=submit(session,'d1');
assert.equal(status(session,key),'pending');
assert.throws(()=>status({tenant:'t2'},key),/denied/);
work(key);work(key);
assert.equal(index.size,1);assert.equal(status(session,key),'succeeded');
console.log({key,state:status(session,key),policy:jobs.get(key).policy});Como conferir seu resultado
- ADR apresenta alternativas e uma consequência negativa.
- Diagrama distingue política administrativa e dados do usuário.
- Job e cache não podem ser acessados por outra identidade.
- Commit/publicação e redelivery possuem recuperação definida.
Aplique em um problema novo
Primeiro resolva sem consultar a resposta. Explique suas decisões e guarde a evidência. A conclusão de leitura é independente desta autoavaliação.
Confira seus pré-requisitos
- Modelar sync/async e consistência eventual.
- Aplicar isolamento do tenant.
Upload confirmado, publish Redis falhou, busca não encontra texto; outro tenant conhecejobId. Proponha desenho.
Conferir raciocínio e critérios de domínio
Persistir intenção/outbox junto ao estado e reenviar com identidade estável evita perder job.
Busca atrasada pode ser estado de indexação; status distingue aceito/processando/pronto/falhou.
GetJob valida proprietário; jobId não dá autoridade. Separar control/data plane e registrar ADR.
Evidências para autoavaliação ou revisão por pares
- Entrega: Persistir intenção/outbox junto ao estado e reenviar com identidade estável evita perder job.
- Consistência: Busca atrasada pode ser estado de indexação; status distingue aceito/processando/pronto/falhou.
- Autoridade: GetJob valida proprietário; jobId não dá autoridade. Separar control/data plane e registrar ADR.
Um erro frequente
Salvar upload garante publicação na fila.
Persistir upload e publicar job são operações com janela de falha.
Teste sua compreensão
Responda com suas palavras antes de abrir o comentário. Saber explicar uma decisão é parte do domínio.
1. Streaming HTTP substitui uma fila durável?
Não.
Exibir progresso não garante aceitação ou recuperação de trabalho.
2. Consistência eventual serve para toda autorização?
Não automaticamente.
Revogação pode exigir consulta atual à fonte de identidade.
3. O que faz uma ADR ser útil?
Critérios, alternativas, consequências e condições de revisão.
Uma lista de tecnologias não mostra por que a decisão atende ao cenário.
Seu progresso fica salvo neste navegador. Concluir a leitura não substitui demonstrar o domínio nos exercícios.
Referências e aprofundamento
Documentação oficial e trabalhos originais. As referências registram o escopo e as limitações para você conferir o que sustentam.
- Asynchronous Request-Reply Pattern
Microsoft • consulta: 2026-10-06
FundamentosSeparar aceite de requisição, processamento longo e consulta de status.
Limites: Persistir status e tratar timeout/cancelamento; assíncrono não elimina falhas.
- Event-Driven Architecture Style
Microsoft • consulta: 2026-10-06
InfraestruturaProducers/consumers, pub/sub, streaming, desacoplamento, idempotência, consistência eventual e recuperação.
Limites: A complexidade pode não se justificar para request-response simples; ordenação e duplicação exigem desenho explícito.
- Redis streaming
Redis • consulta: 2026-10-06
RedisAPIsStreams, logs append-only, consumer groups, acknowledgments e distribuição entre workers.
Limites: Entrega at-least-once requer tratamento de duplicações; Redis Streams e uma fila de jobs têm semânticas diferentes.
- Cache-Aside Pattern
Microsoft • consulta: 2026-10-06
FundamentosCarregamento sob demanda, invalidação e expiração de cache.
Limites: Cache pode ficar desatualizado; não garante consistência entre origem e cópia.
- Retry pattern
Microsoft • consulta: 2026-10-06
FundamentosRetries de falhas transitórias, política de atrasos, logging e impacto em transações.
Limites: Retries de operações não idempotentes e camadas aninhadas podem duplicar efeitos e ampliar carga.
- Tasks
Celery • consulta: 2026-10-06
FundamentosTasks, workers, execução assíncrona, idempotência, acknowledgment, retries e limites de tempo.
Limites: Retry e redelivery podem repetir efeitos; desenhar tarefa idempotente e testar interrupções.
- Router - Load Balancing
LiteLLM • consulta: 2026-10-06
FundamentosBalanceamento, estratégias por uso/latência/custo, retries, cooldowns e fallbacks entre deployments.
Limites: Routing operacional não garante qualidade sem evals por classe de tarefa; fallback pode mudar comportamento e recursos.
- Budgets, Rate Limits
LiteLLM • consulta: 2026-10-06
FundamentosOrçamentos e limites de requisições/tokens por usuário, chave e equipe.
Limites: Configuração e persistência importam; não citar valores de preço como permanentes.
- Considerations for Multitenant Control Planes
Microsoft • consulta: 2026-10-06
FundamentosResponsabilidades do control plane, tenant lifecycle, configuração, recursos e separação dos data planes.
Limites: Não existe template único; proteger o plano de controle e evitar sobreposição de responsabilidades.
- Architect Multitenant Solutions on Azure
Microsoft • consulta: 2026-10-06
FundamentosArquitetura SaaS multi-tenant, organização de recursos, dados, identidade, messaging e operação.
Limites: Guia amplo de decisões; escolher e justificar isolamento e custos para o caso concreto.
- LLM06:2025 Excessive Agency
OWASP • consulta: 2026-10-06
FundamentosMinimização de ferramentas, funcionalidade, permissões, contexto do usuário, autorização e aprovação de ações de alto impacto.
Limites: Autorizações devem ser impostas no sistema de destino; uma recusa textual ou decisão do LLM não é controle de acesso.