Agent Substrate, gVisor e OpenRL: arquitetura para agentes cloud native
Considere uma plataforma corporativa na qual agentes recebem tarefas, executam ferramentas e produzem resultados usados para avaliar uma nova versão de modelo. A equipe precisa responder a três perguntas diferentes: onde executar cada sessão, como conter código não confiável e como aproveitar resultados válidos no treinamento.
A tese deste artigo é separar essas responsabilidades em três camadas: ciclo de vida da execução, isolamento e pós-treinamento. Agent Substrate, gVisor e OpenRL oferecem peças relacionadas a essas camadas, mas não devem ser tratados como um único produto ou uma integração automaticamente pronta. A composição apresentada abaixo é uma proposta arquitetural, não um anúncio de interoperabilidade certificada. (ate.dev)
O recorte é complementar ao laboratório de GKE Agent Sandbox para Reinforcement Learning: aqui, o foco está nos contratos entre execução, avaliação e aprendizado, sem repetir a instalação de sandboxes ou seus manifests de rede.
Primeiro, qual OpenRL?
Neste artigo, OpenRL significa o projeto `gke-labs/open-rl`, que disponibiliza uma API de pós-treinamento hospedada na infraestrutura do operador e compatível com o cliente Tinker. Ele não é um serviço gerenciado nem assume a definição do algoritmo de aprendizado. O próprio repositório informa que não é um produto oficialmente suportado pelo Google. (github.com)
Existe também o projeto OpenRL-Lab/openrl, um framework de pesquisa em aprendizado por reforço. Apesar do nome semelhante, é outro software, com outra proposta. Identificar o repositório evita atribuir funcionalidades de um projeto ao outro. (github.com)
As capacidades descritas correspondem à documentação consultada para esta publicação de 5 de novembro de 2026. Para implantação, fixe versões e confira os requisitos da combinação escolhida; exemplos de uma branch de desenvolvimento não constituem garantia de compatibilidade.
Três tecnologias, três responsabilidades
Agent Substrate: ciclo de vida além do Pod
Agent Substrate administra actors, unidades de execução que podem ser ativadas, suspensas e retomadas. Sua arquitetura desacopla a vida desses actors da vida dos Pods workers: um conjunto de workers atende múltiplos actors, com atribuição e estado coordenados por um plano de controle especializado. A proposta é particularmente relevante para sessões intermitentes, não apenas processos continuamente ativos. (ate.dev)
Os principais recursos precisam ser distinguidos:
- Actor: instância de execução.
- ActorTemplate: definição de uma versão de actor.
- Atespace: escopo lógico para recursos e autorização.
- WorkerPool: recurso Kubernetes que administra capacidade de workers.
- SandboxConfig: recurso Kubernetes para configuração do runtime de sandbox.
Na documentação consultada, Actor e ActorTemplate pertencem à API do Substrate; não são objetos Kubernetes. WorkerPool e SandboxConfig são definidos por Custom Resource Definitions, ou CRDs. Portanto, não se deve inventar um YAML Kubernetes de ActorTemplate. (ate.dev)
O supervisor atelet coordena a execução nos nós. No backend gVisor, ateworker-gvisor traduz operações em chamadas ao runsc; um Pod worker pode hospedar vários actors, cada um com sua própria sandbox. Isso muda a unidade de investigação operacional: um Pod saudável não demonstra que todos os actors estão saudáveis. (learn.agentsubstrate.dev)
gVisor: uma fronteira de execução
O gVisor implementa um kernel de aplicação em espaço de usuário, chamado Sentry, que atende chamadas de sistema do workload e reduz sua exposição direta ao kernel do host. Não é apenas um filtro de chamadas de sistema e não equivale a um hipervisor tradicional. O runsc é o runtime usado para executar essas sandboxes. (gvisor.dev)
Essa fronteira não valida decisões de negócio. Um agente autorizado a acessar uma API ainda pode utilizá-la incorretamente. Isolamento também não substitui controle de acesso aos dados disponibilizados dentro da sandbox. Por isso, a segurança precisa combinar contenção técnica e autorização das ações. (gvisor.dev)
OpenRL: infraestrutura de treinamento atrás de uma API
No OpenRL, o cliente organiza o loop de aprendizado e utiliza serviços de treinamento e amostragem. Essa separação permite tratar infraestrutura de aceleradores e lógica experimental como responsabilidades distintas. Antes de integrar um cliente, consulte a matriz de compatibilidade: compatibilidade com Tinker não deve ser interpretada como implementação irrestrita de qualquer método ou comportamento do SDK, o kit de desenvolvimento de software. (github.com)
A consequência arquitetural é importante: executar um agente em uma sandbox não implica treinar um modelo, e treinar um modelo não exige executar o treinador dentro dessa sandbox.
Arquitetura proposta: execução e aprendizado desacoplados
Para uma plataforma corporativa, proponho dois caminhos separados:
Execução:
Cliente → API da plataforma → orquestrador → Agent Substrate
→ worker → sandbox gVisor → ferramenta autorizada
Aprendizado:
Evidências da execução → avaliador confiável → dataset aprovado
→ cliente de treinamento → OpenRL → modelo candidato
→ avaliação independente → promoção controladaO adaptador entre esses caminhos pertence à aplicação. Não se presume um conector nativo entre Agent Substrate e OpenRL.
Recomendo definir cinco contratos explícitos:
- Identidade: qual tenant, usuário e execução podem acessar cada recurso.
- Execução: imagem, versão do ambiente, orçamento, prazo e política de ferramentas.
- Resultado: saída, evidências, motivo de término e classificação de falha.
- Avaliação: versão do avaliador, recompensa e critérios de elegibilidade.
- Promoção: versão candidata, conjunto de testes e aprovação para produção.
No desenho proposto, nenhum resultado entra no treinamento apenas porque o processo terminou com código zero. O avaliador precisa conferir evidências e separar falha da infraestrutura de comportamento inadequado do agente.
Também recomendo distinguir três persistências: estado da sessão, registro durável das ações externas e checkpoint do modelo. Não trate esses artefatos como equivalentes. Ao restaurar uma sessão, a aplicação deve reconciliar efeitos externos antes de repetir operações; isso faz parte do contrato de recuperação proposto, não de uma promessa de execução exatamente uma vez.
Exemplo corporativo: agente que propõe correções de código
Problema
Imagine uma equipe que quer avaliar agentes capazes de corrigir testes de um serviço interno. O agente recebe uma cópia sanitizada do repositório, executa ferramentas e devolve um patch. Algumas execuções terminam por erro do patch; outras são interrompidas por indisponibilidade do worker.
Misturar esses resultados tornaria a avaliação pouco confiável. A proposta é manter o avaliador fora do ambiente controlado pelo agente e preservar a causa do término.
Solução e implementação
Neste cenário hipotético:
- o orquestrador associa cada tarefa a uma versão imutável do ambiente;
- a sandbox recebe somente código e ferramentas necessários;
- o agente não possui credencial para aprovar seu próprio patch;
- um avaliador separado executa testes protegidos;
- resultados aprovados passam por revisão de dados antes de alimentar o loop de treinamento;
- a promoção do modelo depende de um conjunto de avaliação independente.
Use uma chave estável de episódio e registre tentativas separadamente. Minha recomendação é preservar falhas legítimas do agente como exemplos avaliáveis, mas colocar interrupções de infraestrutura em uma fila de investigação ou reexecução. A política precisa ser explícita para não descartar silenciosamente casos difíceis.
Resultado esperado
O resultado esperado é rastreabilidade: explicar qual modelo, ambiente, tentativa e avaliador produziram cada decisão. Não há, neste exemplo, ganho de qualidade, latência ou custo medido.
YAML: validar o contrato antes de consumir resultados
O exemplo abaixo é um teste didático autocontido, não uma instalação de Substrate ou OpenRL. Ele executa código confiável, com dados sintéticos, para verificar uma regra da aplicação: falha de infraestrutura não recebe recompensa; uma execução concluída com recompensa zero continua elegível.
Não há código gerado sendo executado neste Job. Ele não demonstra isolamento gVisor nem substitui o ambiente de avaliação real.
apiVersion: v1
kind: Namespace
metadata:
name: agent-evaluation
---
apiVersion: batch/v1
kind: Job
metadata:
name: rollout-contract-check
namespace: agent-evaluation
spec:
backoffLimit: 0
activeDeadlineSeconds: 120
ttlSecondsAfterFinished: 3600
template:
metadata:
labels:
app: rollout-contract-check
spec:
automountServiceAccountToken: false
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: validate
image: python:3.12-slim
command: ["python", "-B", "-c"]
args:
- |
import json
import math
records = [
{"episode_id": "e1", "outcome": "completed", "reward": 1.0},
{"episode_id": "e2", "outcome": "completed", "reward": 0.0},
{"episode_id": "e3", "outcome": "infra_error", "reward": None},
]
seen = set()
eligible = []
for record in records:
key = record["episode_id"]
if key in seen:
raise ValueError("duplicate episode")
seen.add(key)
outcome = record["outcome"]
reward = record["reward"]
if outcome == "infra_error":
if reward is not None:
raise ValueError("infra_error must not carry reward")
continue
if outcome != "completed":
raise ValueError("unknown outcome")
if type(reward) not in (int, float) or not math.isfinite(reward):
raise ValueError("reward must be finite")
eligible.append(record)
if not eligible:
raise ValueError("no eligible episodes")
print(json.dumps({
"eligible": len(eligible),
"infra_errors": len(records) - len(eligible),
}))
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]backoffLimit: 0 evita novas tentativas automáticas após falha; activeDeadlineSeconds limita a duração; ttlSecondsAfterFinished permite limpar o Job concluído. Esses controles não oferecem processamento exatamente uma vez. Para dados reais, use deduplicação durável e exporte evidências antes da limpeza. (kubernetes.io)
O contexto de segurança usa usuário não root, remove capabilities e impede elevação de privilégio. O filesystem raiz é somente leitura. Essas medidas endurecem o container, mas não o transformam em uma sandbox gVisor. (kubernetes.io)
Os requests e limits são valores didáticos. Ajuste-os com medições do validador real; requests influenciam o agendamento, enquanto limites de CPU e memória têm mecanismos de aplicação diferentes. (kubernetes.io)
Salve como rollout-contract-check.yaml e execute:
kubectl apply -f rollout-contract-check.yaml
kubectl wait --for=condition=complete job/rollout-contract-check \
-n agent-evaluation --timeout=150s
kubectl logs -n agent-evaluation job/rollout-contract-checkA saída esperada é {"eligible": 2, "infra_errors": 1}. Os nomes dos campos são um contrato deste exemplo, não campos de uma API OpenRL.
Para produção, recomendo empacotar o validador em imagem revisada e fixada por digest, versionar o esquema e registrar também revisões do modelo, ambiente, dataset e avaliador. Use um nome de Job por execução. O exemplo não necessita de probes: sua condição de sucesso é terminar; serviços persistentes exigem outra estratégia de saúde. (kubernetes.io)
Operação próxima de produção
Disponibilidade e recuperação
Proponho separar capacidade para plano de controle, workers de execução e serviços de treinamento. Para componentes replicáveis, distribua réplicas entre zonas utilizando restrições de topologia compatíveis com a capacidade disponível. Restrições rígidas podem deixar Pods pendentes quando faltam domínios elegíveis. (kubernetes.io)
A documentação do Substrate recomenda PostgreSQL externo para produção. No desenho operacional, acrescente alta disponibilidade, backup testado e objetivos explícitos de recuperação. Dimensione o total de conexões considerando todas as réplicas e pools, não apenas uma instância da API. (ate.dev)
Minha recomendação para o plano de recuperação inclui:
- testar perda de worker durante uma tarefa;
- verificar restauração dos snapshots efetivamente utilizados;
- reconciliar efeitos externos antes de reexecutar;
- manter uma fila de resultados incompletos;
- impedir promoção de modelos quando a integridade das evidências estiver comprometida.
Para APIs persistentes, diferencie readiness, liveness e startup probes: receber tráfego, detectar travamento e permitir inicialização são problemas distintos. Evite reiniciar um serviço saudável apenas porque uma dependência remota está temporariamente indisponível. (kubernetes.io)
Segurança entre as camadas
O Substrate documenta fronteiras entre actors, gateways, plano de controle e armazenamento, incluindo políticas de saída e injeção de credenciais no gateway. A autenticação do usuário final e a decisão sobre quais actors ele pode acessar continuam sendo responsabilidade da aplicação. (ate.dev)\n Para a plataforma proposta, recomendo:
- separar identidades do orquestrador, avaliador, treinador e publicador;
- restringir RBAC, o controle de acesso baseado em papéis, para impedir que usuários de execução alterem a infraestrutura;
- limitar IAM, o gerenciamento de identidades e acessos da cloud, a recursos e operações necessários;
- manter credenciais fora de imagens, prompts e resultados;
- exigir TLS, segurança da camada de transporte, nas comunicações autenticadas;
- proteger datasets e checkpoints com criptografia, retenção e auditoria;
- exigir aprovação independente para ações destrutivas.
Um Kubernetes Secret não é criptografia por si só: configure proteção em repouso e acesso mínimo. Evite conceder permissões amplas de leitura de Secrets a componentes que apenas processam resultados. (kubernetes.io)
Para aprofundar o isolamento, consulte como avaliar isolamento de agentes em Kubernetes; para saída de rede, veja rede de sandboxes de agentes.
Capacidade, performance e FinOps
O custo de gVisor depende do workload: há overhead de memória e processamento, e operações intensivas em chamadas de sistema, rede ou filesystem precisam ser medidas no ambiente real. Não assuma uma porcentagem universal de perda ou ganho. (gvisor.dev)
Como modelo de planejamento proposto, use:
Concorrência média ≈ taxa de chegada × duração média da execução
Custo por resultado válido =
custo total do experimento / quantidade de resultados válidosA primeira expressão serve como estimativa inicial em regime estável, não como dimensionamento para picos. Acrescente margem para bursts, recuperação e manutenção. No numerador do custo, inclua CPU, aceleradores, armazenamento, transferência entre zonas, gateways, load balancers e observabilidade.
Recomendo limitar concorrência pela etapa mais restrita. Aumentar workers sem capacidade no avaliador ou treinador não é um objetivo útil. Para Spot, priorize tarefas reexecutáveis e com evidências persistidas; reserve capacidade mais previsível para componentes críticos. Compare economia com trabalho perdido, não apenas preço da máquina.
Observabilidade: medir o actor e a qualidade do resultado
O guia do Substrate diferencia superfícies de API, operações Kubernetes, execução de actors e rede. Portanto, acompanhar somente disponibilidade de Pods deixa lacunas. (ate.dev)
Para esta arquitetura, proponho três grupos de indicadores de nível de serviço, ou SLIs:
- Execução: espera em fila, latência de ativação, término dentro do prazo e falhas de infraestrutura.
- Avaliação: resultados inválidos, duplicados, evidências ausentes e divergência entre avaliadores.
- Aprendizado: tempo até checkpoint candidato, falhas de treinamento e aprovação no conjunto independente.
Defina objetivos de nível de serviço, ou SLOs, separados para esses grupos. Uma execução rápida com resultado não verificável não deve ser contada como sucesso de negócio.
Minha proposta de instrumentação usa métricas agregadas no Prometheus, dashboards no Grafana e correlação por traces OpenTelemetry. Coloque identificadores de episódio nos logs e traces, evitando um label de métrica para cada execução. A implementação deve respeitar os sinais realmente expostos pela versão instalada, em vez de presumir nomes de métricas. (ate.dev)
Desenvolvimento, upgrades e rollback
Em desenvolvimento, proponho uma instalação pequena, dados sintéticos e avaliações locais. Em produção, exija orçamento, revisão de acesso, backups restauráveis, alertas, capacidade de contingência e promoção auditável.
Versione separadamente runtime, imagem do ambiente, avaliador e modelo. Faça upgrades em um pool canário antes de ampliar o tráfego. O Substrate documenta regras específicas de version skew e rollback; não suponha que qualquer salto de versão ou downgrade seja suportado. (ate.dev)
Para o processo de entrega proposto, mantenha o modelo anterior disponível e defina critérios de reversão antes da mudança. Reverter o modelo não desfaz alterações externas já executadas por agentes; o registro de ações e o procedimento de compensação precisam fazer parte do desenho da aplicação.
Troubleshooting orientado à camada
Use primeiro os recursos Kubernetes para identificar problemas de agendamento, inicialização e término: (kubernetes.io)
kubectl get pods -A
kubectl get deployments -A
kubectl get nodes
kubectl describe job rollout-contract-check -n agent-evaluation
kubectl get pods -n agent-evaluation -l job-name=rollout-contract-check
kubectl logs -n agent-evaluation job/rollout-contract-check
kubectl get events -A --sort-by=.metadata.creationTimestampComo roteiro de investigação proposto:
| Sintoma | Possível causa | Investigação | Correção |
|---|---|---|---|
| Job pendente | Capacidade, quota ou restrição de agendamento | Eventos e descrição do Pod | Ajustar a restrição ou disponibilizar capacidade |
| Validação falha | Contrato inconsistente | Logs e registro que originou o erro | Corrigir o produtor; não mascarar a falha com retries |
| Worker saudável, actor indisponível | Problema na atribuição ou ativação | Correlacionar actor, worker e operação no Substrate | Corrigir a camada indicada, sem reiniciar tudo |
| Falhas após troca de runtime | Incompatibilidade do workload ou restauração | Reproduzir em canário com as mesmas versões | Suspender promoção e usar o caminho de recuperação suportado |
| Recompensa cai durante incidentes | Classificação incorreta de falhas | Cruzar resultados com eventos operacionais | Revisar elegibilidade e reavaliar dados afetados |
Em containers que reiniciaram, kubectl logs <pod> -n <namespace> --previous consulta a instância anterior. No Job apresentado, restartPolicy: Never significa que esse não é o caminho normal de diagnóstico. (kubernetes.io)
Quando utilizar — e quando simplificar
Minha recomendação é considerar essa composição quando houver muitas sessões, execução não confiável, necessidade de recuperação e um programa real de avaliação e pós-treinamento. Exija capacidade operacional para manter mais de um plano de controle.
Para poucas tarefas confiáveis, considere Jobs e uma fila. Para agentes que só chamam ferramentas aprovadas, avalie um serviço convencional com autorização por operação. Para melhorar comportamento sem treinamento, comece por avaliação, ferramentas e configuração. Não adicione OpenRL apenas porque existe um agente.
Se gVisor não atender aos requisitos de compatibilidade ou ao modelo de ameaça, avalie isolamento baseado em máquina virtual. O Substrate documenta classes gVisor e microVM, com diferenças de recursos e comportamento; a escolha exige testes, não uma classificação universal de superioridade. (ate.dev)
Como trade-off, APIs especializadas oferecem um contrato mais adequado às sessões, mas aumentam dependência de seus modelos de estado e recuperação. Recomendo manter resultados e evidências em formatos próprios versionados para facilitar migrações.
Resumo prático e conclusão
A decisão não é instalar três tecnologias ao mesmo tempo. É estabelecer fronteiras verificáveis entre executar, conter, avaliar e aprender.
Para uma adoção gradual, proponho:
- definir contratos e classificação de falhas;
- validar isolamento e recuperação com workloads representativos;
- medir custo por resultado válido;
- introduzir pós-treinamento somente com dados e critérios de avaliação confiáveis;
- promover alterações por canário, com reversão previamente testada.
Em Platform Engineering, isso se traduz em uma plataforma que oferece capacidades com limites claros. Em SRE, transforma execução de agentes em objetivos mensuráveis de confiabilidade. Em DevOps, conecta entrega e evolução de modelos sem confundir um processo que terminou com uma decisão segura ou um aprendizado válido.
Artigos relacionados
Quer aplicar isso no seu ambiente?
Agende uma conversa de 30 minutos sem compromisso. Eu olho o seu cenário e digo por onde começar.
Agendar uma conversaReceba os novos artigos por e-mail
Um e-mail quando sair artigo novo sobre infraestrutura, backend e IA. Sem spam, cancele quando quiser.