Skip to content
WellCodPublic

About

Plataforma para operar agentes de IA em produção: agentes, times multi-agente e workflows versionados com rollback, RAG com pgvector, ferramentas via MCP, guardrails e analytics de latência e custo.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

Automata

CI Publish

Plataforma para operar agentes de IA em produção. Com ela, quem não programa cria, versiona, testa e publica agentes, times multi-agente e workflows, liberando a versão nova aos poucos para uma parte das conversas. Também liga bases de conhecimento (RAG) que acompanham o GitHub, o S3, o SharePoint, o Google Drive e o Cloud Storage, ferramentas via MCP, guardrails com piso da instância e memória do usuário entre conversas. Roda suítes de teste por agente, time e workflow antes de publicar e de forma agendada, pausa o workflow para aprovação humana onde for preciso e acompanha execução, latência e custo de cada um, com orçamento mensal, conciliação com a fatura do provedor e aviso no canal do time ou por e-mail. Cada mudança que afeta produção fica numa trilha de auditoria, e o login pode vir do SSO da empresa.

O runtime é o Agno (AgentOS). O Automata é a camada de produto em volta: configuração versionada em banco próprio, validação antes de publicar, rastreamento de cada execução, segurança e painel.

Workflow com roteador por assunto e revisão humana na consolidação

Backend Python 3.12 · FastAPI · Agno 3.1.8 · PostgreSQL 17 + pgvector · Redis · Alembic
Frontend Next.js 16 · React 19 · TypeScript strict · Tailwind 4 · shadcn/ui · TanStack Query
Qualidade mypy strict · ruff · ~1.240 testes pytest (testcontainers) · 250 testes Vitest · Playwright · evals
Decisões 42 ADRs com contexto, alternativas descartadas e gatilho de reversão

Sumário


O problema

Colocar um agente de IA em produção é simples. Operar quarenta, com equipes diferentes editando prompts, é outro problema:

  • Prompt sem histórico. Alguém ajusta uma instrução às 18h, a qualidade cai e não há caminho de volta.
  • Troca de modelo quebra comportamento em silêncio. Instruções acopladas a um provider degradam ao migrar de modelo sem gerar erro.
  • Custo opaco até a fatura chegar. Sem estimativa antes de publicar, um prompt longo vezes o volume mensal estoura o orçamento.
  • Configuração e prompt divergem. O prompt cita uma ferramenta que não está habilitada. Isso não falha no deploy, falha na conversa com o cliente.
  • Dado sensível e abuso. CPF colado no chat vai para o provedor e para o log, e "ignore as instruções anteriores" funciona.

O Automata trata esses pontos como requisito de produto, não como disciplina de quem edita.


O que a plataforma faz

Agentes com versão, teste e rollback

Cada agente é uma configuração versionada: modelo, instruções em seções (persona, situação, tom, objetivo, limites), ferramentas, bases de conhecimento, guardrails e capabilities. Publicar cria uma versão imutável; rollback move um ponteiro. O modo teste roda a versão publicada ou o rascunho, sem publicar.

Uma versão nova também pode sair aos poucos. O canário manda uma parte das conversas, até 50%, para o rascunho ou outra versão publicada, sem mexer na vigente. A escolha é pela sessão, então a conversa não troca de versão no meio. A aba Versões compara as duas desde o início do canário (conversas, taxa de erro, p50 e p95, custo médio e a última suíte), e a promoção é manual (ADR-0040).

Canário em 30% das conversas com a comparação entre a vigente e o canário

O que muda produção fica registrado. A trilha de auditoria guarda cada escrita do painel e dos tokens e cada decisão de aprovação: quem fez, quando, de onde, em que agente e com que resultado, inclusive as tentativas recusadas. Publicação, rollback, canário, piso de guardrails, papel de usuário e orçamentos guardam também o antes e o depois. O conteúdo enviado nunca entra. O owner consulta na página Auditoria, com filtro por ação, período e pessoa, e no histórico da aba Versões de cada agente (ADR-0041).

Trilha de auditoria com rollbacks e o canário, com o antes e o depois de cada ação

O login pode vir do provedor de identidade da empresa. Com SSO por OIDC configurado (Entra ID, Google, Okta, Keycloak ou Clerk), a tela de login mostra "Entrar com" o provedor. A conta é criada no primeiro acesso, o papel vem do grupo e é atualizado a cada login, e o login por senha pode ficar só para o owner de emergência (ADR-0042).

Configuração de um agente com o modo teste ao lado

Antes de salvar, a API recusa o que quebraria em produção:

  • capability que o modelo não suporta (pensamento estendido em modelo sem thinking);
  • tool de servidor MCP que não existe mais;
  • base de conhecimento apagada;
  • instrução acoplada a um provider.

Enquanto se edita, o painel mostra o linter de prompt e a estimativa de custo por mensagem e por volume mensal.

Lista de agentes

Times multi-agente

Um líder com modelo e instruções próprias coordena agentes publicados. Quatro modos, mapeados para o TeamMode do Agno:

Modo Como o líder trabalha
Coordenar Divide a tarefa, delega a quem precisar e junta as respostas
Rotear Escolhe um membro e devolve a resposta dele sem reescrever (handoff)
Consultar todos A mesma tarefa vai a todos os membros, e o líder consolida
Tarefas Monta uma lista de tarefas e acompanha até concluir

A delegação é feita por tool call do próprio líder (delegate_task_to_member). A descrição de cada agente é o que o líder lê para decidir a quem passar o caso, por isso ela é obrigatória e aparece no painel como contrato. Cada membro segue a versão vigente ou fica fixado numa versão. O modo teste mostra o rastro: a quem o líder delegou e que tools o membro chamou.

Editor de time

Workflows por etapas

Quando o processo é conhecido e precisa ser repetível e auditável, um líder decidindo na hora não serve. O workflow é um fluxo fixo montado num editor visual sobre agentes e times publicados:

  • Etapa: um agente ou time responde. Se falhar, para o fluxo ou segue, com até 3 tentativas.
  • Paralelo: de 2 a 5 ramos recebem a mesma entrada ao mesmo tempo.
  • Condição: regra sobre a mensagem do usuário ou a resposta anterior (contém, não contém, começa com, vazia), com então e senão.
  • Repetição: limite de voltas e regra de parada ("até a revisão dizer aprovado").
  • Roteador: de 2 a 5 caminhos, cada um com a sua regra. Roda o primeiro que casa ou um caminho padrão, e o resto nem chama o modelo.

Cada etapa escolhe o que recebe: a resposta da anterior, a mensagem original do usuário ou um texto montado com as saídas de etapas nomeadas ({etapa:triagem}), conferido na escrita. Com o histórico ligado, as etapas lembram as últimas trocas da mesma sessão (ADR-0038).

O modo teste lê o stream do AgentOS e mostra cada etapa ao vivo: quem respondeu, o que respondeu, se a condição deu verdadeira, em que volta está a repetição e onde falhou. As execuções mostram o consumo somado de todas as etapas.

Uma etapa pode pausar para revisão humana: confirmar antes de rodar ou aprovar a saída antes da próxima etapa. A pendência aparece na página Aprovações e no próprio modo teste, com a saída a conferir. Recusar encerra o fluxo, pula a etapa ou a refaz com o motivo da recusa no contexto, e um prazo opcional cancela o que ficou parado.

Modo teste do workflow pausado na revisão humana da consolidação, depois do roteador mandar o reembolso ao financeiro

Página Aprovações com a saída de uma etapa esperando revisão

Bases de conhecimento (RAG)

Bases com PDF, DOCX, Markdown, texto, CSV, JSON ou páginas web, enviados por arrastar e soltar, URL ou texto colado. O painel mostra o estado de cada documento (processando, trechos indexados, motivo da falha). A busca de teste mostra exatamente os trechos que o agente receberia para uma pergunta, sem rodar o agente.

Busca de teste numa base de conhecimento

Cada base escolhe como buscar: a busca simples, diversidade (MMR, para manuais longos e documentos repetidos), recência (para políticas que mudam) e, opcionalmente, HyDE, que busca com uma resposta hipotética quando a pergunta não usa as palavras do documento. Um cross-encoder (Cohere direto ou pelo Bedrock) pode ordenar os candidatos por relevância antes disso, com custo por busca. Cada documento pode ter campos próprios, como produto ou ano, e o agente filtra a busca por eles quando a conversa já diz o que procura. A busca de teste mostra lado a lado o resultado com a estratégia e sem ela, e os tokens que o HyDE gastou.

A base também acompanha a origem. Um conector lê um repositório do GitHub, um bucket S3 ou do Cloud Storage, uma pasta do SharePoint ou do Google Drive, com a credencial cifrada. Padrões de nome escolhem os arquivos (politicas/**/*.md, fora **/rascunhos/**), e um webhook assinado deixa a própria origem disparar a sincronização a cada push. A sincronização compara pela versão de cada arquivo: arquivo novo entra, alterado é reindexado sem duplicar trecho, removido sai da base, e o que não mudou não é baixado nem cobra embedding. A sincronização pode rodar num intervalo, e uma URL pode ser baixada de novo todo dia ou toda semana, reindexando só se a página mudou.

Conector do GitHub com filtro por nome e webhook da origem

Conversas longas

O agente lembra a conversa: leva ao modelo os últimos turnos da mesma sessão. Em atendimento longo, a compactação resume os turnos antigos quando a conversa passa de um limite em tokens. Assim, o número do pedido dito no começo continua chegando ao modelo, e o custo por turno fica limitado. A opção fica na versão do agente, desligada por padrão, com o que o resumo não pode perder escrito em português.

Entre conversas, a memória do usuário guarda o que a pessoa contou, como o tamanho que veste ou o horário que prefere para entrega. Cada agente, ou time, só lê o que ele mesmo guardou, e só para o mesmo usuário (ADR-0035). Documento, cartão, e-mail e telefone saem mascarados antes de gravar. Conversa sem usuário identificado não gera memória, e a memória vence depois do prazo de retenção. O owner apaga tudo de um usuário num agente, para atender pedido de exclusão, e cada usuário vê e apaga as próprias.

Cada versão também controla o run: um limite de chamadas de tool corta o laço de um modelo que insiste numa tool que falha. O retry repete só a chamada ao provedor, nunca a tool que já rodou. Até dois modelos reserva entram quando o principal cai ou responde 429, desde que façam tudo o que o agente liga, e o custo sai pelo preço do modelo que respondeu. Com um JSON Schema, o agente responde em objeto no lugar de texto, e a suíte confere a resposta contra ele (ADR-0027). Quando as tools devolvem muito texto, a compressão resume os resultados com um modelo escolhido antes de eles seguirem no contexto, e o custo do resumo entra no run (ADR-0029). Um teto de custo por run encerra a conversa que passa do valor configurado, com uma mensagem no lugar da resposta, antes que um laço de tools queime o orçamento. O owner também dá a cada usuário do painel e a cada token de integração um orçamento mensal próprio, somado em todos os agentes, com aviso pelos destinos de alerta e bloqueio opcional (ADR-0031). No painel, o teto fica no controle do run, o orçamento de cada usuário e de cada token aparece com o gasto do mês nas páginas Usuários e Integrações, e a execução parada pelo teto vem marcada.

Na revisão humana do workflow, quem aprova pode editar a saída da etapa, com o diff à vista, e o texto corrigido segue para a próxima etapa sem nova chamada ao modelo. Num laço de rascunho, a pessoa decide a cada volta se segue ou pede outra, com um comentário. Cada decisão fica registrada no run, com quem decidiu, quando, o motivo e o antes e depois da edição (ADR-0028).

Memórias que um agente guardou, por usuário

Guardrails por agente

Regras de entrada e saída versionadas junto com o agente. O bloqueio acontece antes da chamada ao modelo, então não gasta token.

  • Dados pessoais: CPF e CNPJ com dígito verificador e cartão com Luhn, para que número de pedido não seja confundido com documento. Também e-mail e telefone. Cada tipo pode ser mascarado ou bloqueado. Até 10 padrões próprios por agente cobrem matrícula, contrato ou protocolo. Cada padrão tem prefixo e faixa de dígitos, sem regex livre, e vale na entrada, na memória e na resposta.
  • Injeção de prompt: detectada em português e inglês, sem diferenciar acento.
  • Outras regras: tópicos proibidos, tamanho máximo e moderação opcional da OpenAI.
  • Direitos do titular: o owner consulta tudo o que a instância guarda de uma pessoa, pelo id dela, e exporta num arquivo que fica 7 dias disponível para download. A exclusão apaga a conversa, a memória, as aprovações e os traces da pessoa, e troca o id dela por um pseudônimo no consumo e nos runs, para as métricas e o custo continuarem batendo. Tudo fica na página Titulares, e a exclusão só sai depois de o id ser digitado de novo. Um token de integração com essa opção pede pelos dados que ele mesmo gerou, e quem usa o painel pede os próprios dados (ADR-0036, ADR-0032).
  • Classificador por modelo: um modelo escolhido julga a mensagem antes do run e pega a injeção que a lista de termos não pega, a toxicidade e o pedido fora do que o agente atende, descrito em texto. Se o classificador cair, o agente segue ou bloqueia, conforme configurado, e o custo da checagem entra no agente (ADR-0030).
  • Conteúdo de terceiros: o resultado das tools, inclusive MCP e busca da base, é examinado antes de voltar ao modelo. Uma página ou um documento com instrução embutida para o assistente chega como aviso, e o run segue com a retirada registrada. Na ingestão, o documento que tem trechos com instrução embutida fica marcado na base, para quem cuida dela ver de onde a injeção vem. No painel, o classificador e o exame de tool ficam na seção de guardrails do agente e do time, o documento suspeito aparece marcado na lista da base e o run mostra quais resultados foram retirados.
  • Na resposta: dado pessoal ou termo proibido troca a resposta antes de ela sair. Um classificador por modelo pode julgar também a resposta: ofensa, assunto fora do escopo ou vazamento das instruções internas.
  • Piso da instância: o owner define o mínimo que todo agente e time segue, como mascarar CPF ou barrar injeção. O agente só pode endurecer, e o piso vale no próximo run, sem publicar de novo (ADR-0034).

Execuções barradas aparecem como bloqueadas, com a regra, separadas de falha no analytics.

Guardrails de um agente

Piso de guardrails da instância

Testes por agente antes de publicar

Cada agente, time e workflow tem uma suíte de casos: uma mensagem e o que precisa ser verdade na resposta. As checagens são texto (contém, não contém, começa com), tools que precisam ser chamadas (a busca na base certa, a tool MCP esperada), um critério avaliado por um modelo juiz, binário ou nota com limiar, e o bloqueio esperado: o caso passa quando o guardrail barra a mensagem, pela regra certa. No workflow, a suíte confere também as etapas que rodaram, que é o que pega a condição que mudou de caminho. A suíte roda contra o rascunho ou a vigente, mostra o resultado caso a caso e compara as duas versões, apontando o que passou a falhar.

Com o gate ligado, publicar exige a suíte verde no rascunho atual. Editar o rascunho invalida o resultado. Os casos ficam fora da versão: um rascunho que muda o prompt não consegue afrouxar o próprio teste.

Aba Testes de um agente com resultado por caso e comparação entre versões

A suíte também roda sem ninguém clicar. Um agendamento por agente roda a suíte na versão vigente e pega o que muda por fora do prompt: modelo do provedor, base reindexada, servidor MCP. A lista de agentes e times mostra o estado da suíte, e a execução agendada que perde um caso que passava aparece como regressão. O agendamento pode ter um webhook, que avisa o canal do time quando a suíte regride, passa a falhar ou volta a passar. Ele só dispara na mudança de estado, com assinatura HMAC e um texto pronto para Slack, Teams ou Discord. Um token de integração pode rodar e ler a suíte de agentes escolhidos, para o CI de quem consome o agente decidir pelo verdict.

Caso novo não precisa nascer do zero. No histórico de execuções, Virar caso de teste abre o formulário preenchido com a mensagem, os turnos anteriores como contexto e as tools que o run chamou. A aba da suíte também sugere casos em lote a partir das conversas recentes. Dados pessoais chegam mascarados, e o editor revisa antes de salvar. No workflow, uma checagem de texto pode olhar a saída de uma etapa do meio, e o caso pode ter turnos anteriores.

Ferramentas via MCP e confirmação humana

Catálogo de servidores MCP externos, com credenciais cifradas e teste de conexão que descobre as tools. Em cada agente, escolhe-se quais tools ele usa e quais pedem confirmação. Uma tool sensível pausa a execução até alguém aprovar ou rejeitar, no modo teste ou na página Aprovações, vendo nome e argumentos da ação.

O caminho inverso também existe: os próprios agentes e times ficam expostos via MCP server mode para Claude Desktop, Cursor e outros sistemas, com tokens de integração limitados aos agentes escolhidos e revogáveis na hora. Por REST, um sistema pode pedir o run em background: o pedido entra numa fila durável no Postgres e sobrevive a deploy e a crash. A página Fila mostra ao owner o que está esperando, rodando e falhou, e devolve à fila o job que falhou.

Analytics e rastreamento

Conversas, taxa de falha, bloqueios, latência p50 e p95, tokens e custo, com gráficos diários e uso por agente. Cada execução abre como árvore, com time, agentes, chamadas de modelo e tools, e mostra duração, entrada, saída e erro de cada nó.

O custo sai da tabela de preços de cada modelo quando o provedor só informa tokens, que é o caso da Anthropic e da OpenAI. Cada agente pode ter um orçamento mensal, com aviso num percentual e, se ligado, bloqueio dos runs seguintes quando estoura, sem chamar o modelo. Os destinos de aviso da instância recebem orçamento perto do limite ou estourado, pico de erro, mudança de estado das suítes agendadas, pedido de titular falho ou perto do prazo, run em background que falhou e diferença de custo. O destino é um webhook assinado com HMAC, pronto para Slack, Teams ou Discord, ou e-mail pelo SMTP da instância.

Com a chave admin da Anthropic ou da OpenAI, a conciliação lê de hora em hora o custo que o provedor cobrou por dia e mostra no analytics ao lado do estimado, avisando quando a diferença passa do limite.

Orçamento do mês no desempenho de um agente

Destinos de aviso da instância

Analytics

Tema claro e escuro, escolhido pelo usuário:

Analytics no tema claro


Arquitetura

flowchart LR
    subgraph Browser
        UI[Painel Next.js]
    end
    subgraph web["web/ (Next.js, server-side)"]
        BFF["Route Handlers (BFF)<br/>cookie httpOnly → Bearer<br/>CSRF por Origin"]
    end
    subgraph api["api/ (FastAPI + AgentOS)"]
        R["Rotas próprias /api/v1<br/>configs, runs, métricas,<br/>bases, MCP, usuários"]
        OS["AgentOS (Agno)<br/>/agents /teams /workflows<br/>/mcp (server mode)"]
        F["Factories por request<br/>agente · time · workflow"]
        T["RunTracking<br/>agent_run · usage_event"]
        W["Workers<br/>fila de background ·<br/>suítes agendadas ·<br/>conectores e conciliação"]
    end
    PG[("PostgreSQL 17<br/>config versionada, runs,<br/>metering, pgvector")]
    RD[("Redis<br/>rate limit · cancelamento<br/>entre réplicas")]
    LLM["Provedores<br/>Anthropic · OpenAI"]
    MCP["Servidores MCP<br/>externos"]
    EMB["Embeddings<br/>Voyage · OpenAI"]
    HOOK["Avisos<br/>webhook · e-mail"]
    IDP["Provedor de identidade<br/>OIDC (opcional)"]
    IW["Worker de ingestão<br/>(opcional)"]

    UI --> BFF --> R & OS
    R -. "login SSO" .-> IDP
    OS --> F --> T --> PG
    R --> PG
    R --> RD
    F --> LLM & MCP & EMB
    W --> F
    W --> PG
    W --> RD
    W --> HOOK
    IW --> PG & EMB
Loading

O painel nunca fala direto com a API: todo acesso passa por Route Handlers server-side, e o token fica num cookie httpOnly. A API tem dois lados. As rotas próprias, em /api/v1, gerenciam configuração, execuções, métricas, bases, servidores MCP e usuários. As rotas do AgentOS executam agentes, times e workflows; o Automata não as modifica, só registra nelas o que foi publicado. Dois laços rodam dentro da API, sem serviço à parte: o worker da fila de background, do próprio Agno, e o poller das suítes agendadas, que também sincroniza conectores, lê a conciliação e dispara os avisos. A ingestão pode sair da API para um worker separado com fila no banco (ADR-0039).


Como funciona por dentro

Configuração versionada e factory por request

agent_config guarda os ponteiros current_version_id e draft_version_id. agent_config_version guarda o payload em JSONB. Agente, time e workflow usam a mesma tabela, diferenciados por kind.

rascunho ──publicar──▶ v3 (publicada, imutável) ◀── current_version_id
                       v2 (publicada)
                       v1 (publicada)            rollback = mover o ponteiro
  • Publicar nunca faz UPDATE. Cria uma versão nova a partir do rascunho e move o ponteiro. Rollback só aceita versão publicada do mesmo config.
  • O payload tem schema_version. Formatos antigos são convertidos na leitura, por um validator do pydantic, sem migração de dados.
  • O agente não é um objeto em código. AgentFactory, TeamFactory e WorkflowFactory do Agno reconstroem tudo a cada request a partir da versão vigente: modelo, instruções, tools MCP, buscas nas bases e guardrails como pre_hooks e post_hooks. Com version_id no factory_input, a mesma factory roda um rascunho, que é como o modo teste funciona. A versão precisa pertencer ao config, senão um rascunho de B rodaria com o custo contado em A.
  • Publicar não exige restart. O AgentOS lê listas mutáveis de agentes, times e workflows a cada request. Publicar registra a factory na hora, e outros workers sincronizam por um middleware com TTL de 5 s.
  • Memória da conversa. O agente leva ao modelo os últimos 5 turnos da sessão, lidos do banco que o AgentFactory injeta. Com a compactação ligada na versão, a janela passa a ir até um limite de tokens (16 mil por padrão, contra 150 mil do Agno), e o que sobra vira um resumo feito pelo modelo do próprio agente. O consumo do resumo entra no run (ADR-0019).
  • Lifespan do AgentOS. O AgentOS fica montado dentro do app que tem /login e /health, e o Starlette não roda lifespan de app montado. O app externo entra no lifespan do AgentOS de propósito: sem isso, o servidor MCP respondia 500 e o worker da fila não subia.

Execução em background

Um run pedido com background=true vira uma linha na fila durável do Agno, no Postgres da instância (ADR-0020). Um worker por réplica reivindica a linha e roda o agente pelo mesmo factory dos runs síncronos.

  • Sobrevive a deploy. Run aceito termina ou falha com motivo. Nunca fica PENDING para sempre.
  • Uma tentativa por padrão. O agente pode ter chamado uma tool com efeito antes de cair, e rodar de novo sozinho repetiria o efeito. Só o agente marcado como idempotente no controle do run volta sozinho para a fila, até 2 vezes; os outros voltam pelo clique na página Fila (ADR-0037).
  • 15 minutos por execução e 429 acima de mil pendentes.
  • Redis opcional. Com REDIS_URL, cancelar e acompanhar o stream funcionam de qualquer réplica.

Rastreamento e consumo

Hooks de pós-execução do Agno não rodam em erro nem em cancelamento. Por isso, o mixin RunTracking envolve arun e acontinue_run, nos modos coroutine e stream, e grava em agent_run (status, duração, erro, tools pendentes, regra de bloqueio) e em usage_event (tokens, custo, período) numa transação só.

  • Status: success, error, cancelled, paused (aguardando confirmação humana) e blocked (guardrail).
  • Times: só o run do time é gravado, porque o Agno já soma nele o consumo dos membros.
  • Workflows: o TrackedWorkflow fixa o run_id antes de rodar e o publica numa ContextVar. Cada etapa grava esse id como parent_run_id, inclusive os ramos paralelos, que rodam em tasks que herdam o contexto. O consumo do workflow é a soma das etapas, e o analytics não conta nada duas vezes.

Workflows

A árvore do payload (step, parallel, condition, loop) vira Step, Parallel, Condition e Loop do Agno, montados do zero a cada request. Três decisões saíram de comportamentos do Agno (ADR-0014):

  • Uma instância nova por etapa. Com a mesma instância, ramos paralelos compartilhariam estado e conexão MCP.
  • Etapa com erro levanta StepFailed. No Agno, a etapa seguinte receberia a mensagem de erro como se fosse resposta. Com a exceção, on_error e max_retries passam a valer. Quando o fluxo para, o TrackedWorkflow converte a falha num run com status de erro, em vez do 500 que a rota devolveria.
  • Regras próprias em vez de CEL. Sem o pacote cel-python, o Agno avalia toda expressão como False em silêncio. Além disso, expressão é linguagem de programação dentro de um painel para quem não programa. Depois de um paralelo, a regra lê a resposta do último ramo, não a frase-resumo que o Agno põe no lugar.

Limites validados na escrita: 3 níveis de aninhamento, 30 etapas, nomes únicos e o fluxo não termina num paralelo. Agente com tool de confirmação humana não entra em workflow, porque o fluxo não pausa no meio.

RAG

flowchart LR
    D[PDF · DOCX · MD · CSV<br/>JSON · URL · texto] --> C["Chunking recursivo<br/>2000 caracteres, overlap de 10%"]
    C --> E["Embedder medido<br/>Voyage voyage-3.5 ou<br/>OpenAI text-embedding-3-small"]
    E --> V[("PgVector<br/>tabela kb_‹id› por base<br/>busca híbrida, português")]
    Q[Pergunta do usuário] --> A[Agente]
    A -- "tool buscar_‹slug›" --> V
    V -- "trechos + documento de origem" --> A
Loading
  • Pgvector no Postgres que já existe. Cada base tem sua tabela vetorial, com dimensão fixada pelo embedder escolhido na criação, e busca híbrida (vetor + texto) configurada para português. Nada de serviço vetorial à parte (ADR-0012).
  • Ingestão em background. O estado de cada documento fica em knowledge_content. O primeiro trecho é embedado antes do insert, para que chave inválida ou cota estourada vire mensagem de falha legível; depois do insert, os trechos são contados. Documento preso em "processando" por mais de 30 min vira falha no boot. Com INGEST_WORKER=true, a API só grava o trabalho em ingest_job e um worker separado (python -m app.knowledge.worker, serviço ingest-worker no perfil worker do compose) processa, então PDF grande e sincronização de cem arquivos não ocupam a CPU que atende os runs.
  • Uma tool por base. O agente recebe buscar_<slug>, e a descrição da base diz quando usar. A tool devolve trechos com documento e fonte, e as instruções mandam citar o documento e tratar o trecho como dado, não instrução, uma defesa contra injeção vinda de documento.
  • Corte por base. Cada base escolhe como o conteúdo vira trecho: o corte recursivo de sempre, um trecho por título de markdown, por parágrafos ou tamanho fixo, com a sobreposição ajustável. Na aba Configuração da base, a prévia mostra como um texto colado seria cortado, sem gravar nada e sem custo, e o reprocessamento reindexa a base com o corte salvo, avisando o que precisa ser reenviado. Arquivo e texto guardam o original para isso (ADR-0029).
  • Estratégia por base. O reranker do Agno entra na nossa busca: MMR, para trechos relevantes e diferentes entre si, ou recência, pela data da linha. Com reranker, a busca pede um lote maior de candidatos e reordena contra a pergunta. O HyDE, opcional, busca com uma resposta hipotética escrita por um modelo escolhido na base, com os tokens gravados no consumo do agente que buscou (ADR-0017).
  • Custo de embedding no metering. MeteredEmbedder conta tokens de ingestão e de busca, com um cache curto para não pagar duas vezes pela mesma consulta.
  • Demo sem chave. No modo replay, um embedder local determinístico indexa e busca por palavra em comum.

Corte por títulos com a prévia dos trechos na configuração da base

Evals por agente

Os casos viram Cases do runner de suíte do próprio Agno (agno.eval.suite), que roda um por vez com timeout e checa tools esperadas (ReliabilityEval), critério do juiz (AgentAsJudgeEval) e um Scorer próprio para as regras de texto (ADR-0015).

  • Mesmo agente de produção. Cada caso ganha uma instância nova, montada pela mesma factory dos runs reais a partir da versão testada: mesmas tools, bases e guardrails. A execução é em background, e cada resultado é gravado assim que o caso termina.
  • Runs de teste não são conversas. Uma ContextVar marca agent_run.eval_run_id e usage_event.eval_run_id. Esses runs ficam fora do histórico, das aprovações e das métricas; o custo continua no metering, separado como custo de testes.
  • Juiz com modelo nosso e medido. Sem modelo explícito, o Agno cairia num modelo da OpenAI. O modelo do juiz é escolhido entre os que têm saída estruturada e embrulhado num medidor que soma os tokens dele no consumo da execução. No modo demo, o juiz aparece como "não avaliado" em vez de fingir aprovação.
  • Gate sem hash. Cada rascunho salvo já é uma versão nova, então o resultado vale para aquele version_id e nenhum outro. Caso não avaliado não conta como aprovado, e rollback segue livre.
  • Agendamento com poller próprio. Um laço na API reivindica os agendamentos vencidos com SELECT … FOR UPDATE SKIP LOCKED, e duas réplicas não duplicam a execução. O scheduler do AgentOS ficou de fora: o token interno dele não cobre as rotas próprias (ADR-0016).
  • Caso com contexto. Os turnos anteriores do caso rodam no setup do Case, na mesma sessão, e só a última resposta é checada. É o que permite transformar uma conversa real em caso, com dados pessoais mascarados.
  • Aviso só na mudança. Depois de cada execução agendada, a API compara com a anterior e chama o webhook só quando a suíte regride, passa a falhar ou volta a passar. O corpo é assinado com HMAC (ADR-0018).

MCP

  • Cliente de servidores externos. Só streamable-http. Os headers de autenticação ficam cifrados com Fernet. Há proteção contra SSRF: só https, DNS resolvido e IP privado, loopback e link-local recusados, salvo hosts liberados por variável. A conexão é estrita: servidor fora do ar faz o run falhar com o motivo, em vez de o agente responder sem as tools (ADR-0010).
  • Confirmação humana. Tools marcadas viram requires_confirmation_tools no Agno. O run pausado guarda as tools pendentes em agent_run.pending_tools, aparece em Aprovações e continua pela rota de continue do AgentOS.
  • Server mode. O próprio AgentOS expõe os agentes por MCP, autenticado com JWT RS256. Tokens de integração têm jti, escopo por agente ou time, validade de até 90 dias e revogação imediata (ADR-0009).

Segurança

Área Implementação
JWT RS256 A API assina com a chave privada, que nunca sai dela. O AgentOS valida com a pública e com user_isolation. O token expira em 1 h e leva jti e kid; na troca do par, a chave anterior segue aceita até os tokens vencerem (ADR-0026).
BFF Cookie httpOnly e sameSite=lax, secure em produção. O proxy server-side converte o cookie em Authorization: Bearer e limpa a sessão no 401. Nenhum segredo vai para o bundle, e um teste no CI procura chaves no build.
CSRF Origin conferido contra Host em todo método que não é seguro.
Revogação Logout revoga o jti. Mudar papel, desativar ou trocar senha corta na hora as sessões da pessoa.
SSO Login por OIDC com authorization code e PKCE, state de uso único preso ao navegador por cookie e id_token conferido pelo JWKS do provedor (sem none nem HS*). Conta ligada pelo sujeito do provedor; por e-mail, só verificado. Papel pelo grupo, sem rebaixar o último owner, e login por senha opcional só para o owner (ADR-0042).
Auditoria Toda escrita em /api/v1 e toda decisão de aprovação gravadas com autor, IP, alvo e resultado, inclusive as recusadas, sem o corpo da requisição. Só o owner lê, e a exclusão do titular troca o id dele pelo pseudônimo também ali (ADR-0041).
Papéis e scopes owner, editor, viewer. Toda rota, própria ou do AgentOS, exige scope.
Rate limit Login limitado por e-mail e IP, por e-mail e por IP no Redis, sem deixar ninguém travar a conta de outro. X-Forwarded-For só vale vindo de proxy listado em TRUSTED_PROXIES, e o painel só repassa o IP do cabeçalho de CLIENT_IP_HEADER. Busca de teste na base limitada por usuário.
Superfície Login com e-mail inexistente também roda argon2, para a latência não revelar contas. /docs e /openapi.json só em desenvolvimento. Fora do login (senha e SSO) e do health, a única rota pública é o webhook da origem dos conectores, que só sincroniza com a assinatura HMAC do corpo e no máximo uma vez por minuto.
Headers HSTS, CSP com frame-ancestors 'none', nosniff, Referrer-Policy.
Saída Servidores MCP, webhooks, destinos de aviso e conectores de conhecimento passam pelo mesmo filtro: só https, sem host que resolva para IP interno, conferido no cadastro e a cada chamada, sem seguir redirect. URLs e segredos ficam cifrados com Fernet. A telemetria do Agno fica desligada.
Integrações Token de consumidor com escopo por recurso: roda só os agentes liberados e, se marcado, a suíte de testes deles, sem acesso a configuração.
Troca de chaves A chave JWT e a chave dos segredos aceitam uma anterior só para ler durante a troca, e um comando recifra os segredos. A página Chaves mostra ao owner os tokens de integração e os segredos que ainda dependem da chave velha. Integrações marca esses tokens. Passo a passo em docs/rotacao-de-chaves.md (ADR-0026).
Dado pessoal Memória do usuário mascarada antes de gravar, lida só pelo agente que guardou, com retenção e exclusão pelo owner e pelo próprio usuário. Credencial de conector e memórias de usuários finais são só do owner.

Qualidade e testes

Camada Ferramenta Cobertura
API pytest + testcontainers ~1.240 testes contra Postgres com pgvector real, sem mock de banco. Gate de cobertura de 70%.
Tipos mypy strict + plugin pydantic · ruff Rodam em todo PR.
Web Vitest + Testing Library 250 testes de componente e de lógica, inclusive o redutor de eventos do workflow, a suíte de testes, a revisão humana, o canário e as rotas do SSO.
E2E Playwright Login → editar agente → publicar → rollback.
Contrato openapi-typescript Os tipos do painel são gerados do OpenAPI da API, nunca escritos à mão.

Evals medem o comportamento que importa, não só se o código roda:

Eval O que mede Quando roda
Guardrails 30 mensagens com a regra que deveria barrar cada uma ou nenhuma. Um terço são casos legítimos (número de pedido, "política de reembolso") que precisam passar. Todo PR
Workflows Regras sobre respostas reais de triagem, inclusive os limites documentados (negação, flexão), condição depois de paralelo e estrutura aceita ou recusada. Todo PR
Suíte de testes Scorer de texto sobre respostas reais, montagem do Case do Agno (juiz só com modelo, nunca no modo demo), tradução do resultado do runner, veredito do gate (não avaliado trava) e comparação entre execuções. Todo PR
Evals contínuos Validação do agendamento (cron, fuso, intervalo mínimo de 1 hora), próximo horário no fuso certo, escopo por recurso dos tokens de integração, verdict que o pipeline lê e montagem da sugestão de caso (máscara, tools com erro fora). Todo PR
Avisos de regressão Transições que avisam e as que ficam em silêncio (falha seguida de falha, verde seguido de verde), assinatura HMAC conferida pelo receptor e corpo com text e content. Todo PR
Compactação Versão sem a seção fica sem compactação, limite e turnos passados ao Agno, resumo pelo modelo do agente e limites recusados. O ponta a ponta, com o resumo chegando ao modelo acima do limite, roda na suíte de runtime. Todo PR
Controle do run Com modelos falsos e o Agent de verdade: o laço de tool para no limite com resposta, o 503 se repete sem repetir a tool, o 429 cai na reserva e o custo sai pela tabela dela, o 401 não troca de modelo e a resposta estruturada chega como objeto e valida. Todo PR
Corte e compressão O manual com três seções vira três trechos com o título, o nível de título decide onde abre trecho, a seção grande é cortada com o título em cada pedaço e a base antiga mantém a recursiva com 10%. Com o Agent de verdade, o resultado de 20 mil caracteres chega ao modelo resumido e o resumo entra no custo do run. Todo PR
Guardrails por modelo Injeções indiretas em português e inglês ("nota para a IA", "envie os dados do cliente", comentário HTML) são pegas no resultado de tool e na varredura, e o conteúdo legítimo passa. O classificador bloqueia a injeção com a categoria, deixa seguir quando cai em falha aberta e bloqueia em falha fechada. Com o Agent de verdade, o resultado suspeito chega ao modelo como aviso e o run termina. Todo PR
Controle de custo Com o Agent de verdade e uma tool em laço, o teto de US$ 0,05 encerra o run passando no máximo uma chamada, o teto corta na chamada certa e o run abaixo do teto termina normal. O orçamento por quem chama barra só quem estourou com bloqueio ligado, mede sem bloquear e ignora run sem usuário. Todo PR
Reranker e filtros O lote de candidatos cresce com o cross-encoder, e a falha do provedor deixa a busca seguir sem ele. O filtro fica só com campo e valor que existem, nunca traz o manual de outro plano e, errado, não vira "nada encontrado". Todo PR
Guardrails da instância O efetivo nunca afrouxa o piso nem o agente, o piso vazio não muda nada e o classificador da saída pega o vazamento das instruções. Todo PR
Memória em time e titular O time lê a memória pelo team_id, nunca pelo agent_id, só com usuário e com a máscara dele. O resumo com modelo próprio herda o retry da versão. O pedido do titular segue a matriz de acesso por token, e o prazo vem do ambiente (15 dias por padrão). Todo PR
Operação O retry automático só vale para o agente idempotente, e falha antiga não volta no deploy. A conciliação lê centavos da Anthropic e dólares da OpenAI. O estado do e-mail nunca traz a mensagem do servidor, e sem SMTP o destino é recusado sem tentar. Todo PR
Workflow e suíte O roteador escolhe pela regra e pela ordem, e sem caminho padrão nada roda. A entrada da etapa monta o texto com as saídas certas, e a checagem olha a etapa pedida ou a resposta final. Todo PR
Conectores e ingestão Pasta do Drive com Docs e PDF vira dois documentos e editar o Docs reindexa só ele, o filtro tira da base o que saiu dele, a assinatura do webhook recusa corpo trocado e quatro workers não pegam o mesmo job. Todo PR
Canário 120 conversas com canário em 25% caem perto de 25% na versão nova, cada uma numa versão só. O líder do time segue o canário, o modo teste nunca cai nele e publicar no meio devolve tudo à vigente. Todo PR
Auditoria Uma bateria de escritas com prompt, cabeçalho de MCP, senha e token emitido não deixa nenhum deles na trilha. Rebaixar usuário guarda o antes e o depois, a aprovação recusada entra e a exclusão do titular troca o id dele pelo pseudônimo. Todo PR
SSO Provedor falso com ES256 e papel aninhado no formato do Clerk, troca de chave que busca o JWKS de novo, id_token adulterado (outra chave, aud, nonce, none, HS256, vencido) recusado e provedor na rede interna barrado. Todo PR
Recuperação O documento certo volta entre os 3 primeiros trechos. A versão literal roda em todo PR com cada estratégia de busca (simples, MMR, recência), e nenhuma pode errar. A semântica, com Voyage, roda à noite, aceita recall@3 de 80% e compara as estratégias (HyDE incluso, com chave de modelo) com a busca simples. PR e noturna
Confiabilidade Tool calls com LLM real. Noturna

CI (GitHub Actions): filtro por caminho, jobs de API, web e e2e, montagem das imagens de produção da API e do painel e um gate que falha se qualquer um falhar. Tag v* publica as imagens no GHCR e anexa o openapi.json na release.


Decisões de arquitetura

Cada decisão relevante está em docs/adr/, com contexto, alternativas descartadas e o gatilho concreto que faria reverter.

ADR Decisão
0001 Monorepo sem ferramenta de monorepo: uv e pnpm bastam
0002 Configuração em banco próprio, não no editor do framework
0003 Uma instância por cliente, e a assimetria que torna difícil desfazer
0004 Painel próprio; o Control Plane do Agno só como ferramenta interna
0005 JWT RS256 próprio; a chave de assinatura nunca sai do servidor
0006 Instruções sem termos de provider, a regra que sustenta trocar de modelo
0007 Código aberto sob AGPL-3.0 com licença comercial paralela
0008 Demo pública com respostas gravadas, sem chave de LLM
0009 REST e MCP server mode como superfície de integração
0010 Servidores MCP externos: segredo cifrado, só HTTP, falha visível
0011 Times na mesma tabela de configs, membros seguindo a versão vigente
0012 RAG com pgvector no Postgres existente e embeddings da Voyage
0013 Guardrails versionados com o agente, bloqueio sem custo de modelo
0014 Workflows por etapas com regras sem CEL e etapa com erro que para o fluxo
0015 Evals por agente no painel: casos fora da versão, runner de suíte do Agno e gate de publicação
0016 Evals contínuos: suíte por token de integração, agendamento próprio e casos de conversas reais
0017 Estratégia de recuperação por base: reranker do Agno (MMR, recência) e HyDE com modelo medido
0018 Avisos de regressão por webhook assinado nas mudanças de estado da suíte agendada
0019 Compactação de conversa por agente no payload versionado, limite de 16 mil tokens
0020 Fila durável para runs em background, 15 min por execução e uma tentativa salvo agente idempotente
0021 Custo estimado pela tabela de preços, orçamento mensal com bloqueio e destinos de aviso
0022 Suíte de testes para workflows e caso que espera bloqueio de guardrail
0023 Revisão humana numa etapa do workflow, antes de rodar ou depois da saída
0024 Conectores de conhecimento (GitHub, S3, SharePoint) e reindexação agendada
0025 Memória do usuário entre sessões, por agente, com retenção, PII mascarado e exclusão
0026 Rotação da chave JWT e da chave dos segredos sem derrubar sessões nem integrações
0027 Controle do run: limite de tools, retry do provedor com modelo reserva e saída estruturada
0028 Revisão humana completa: saída editada, revisão por volta de laço e registro das decisões
0029 Chunking por base com prévia e reprocessamento, e compressão do resultado de tool
0030 Classificador por modelo na entrada e exame do resultado de tool e dos documentos
0031 Teto de custo por run e orçamento mensal por usuário e por token de integração
0032 Direitos do titular: consulta, exportação e exclusão por usuário, e máscara com padrões próprios
0033 Reranker por cross-encoder e filtros escolhidos pelo modelo na recuperação
0034 Piso de guardrails da instância e classificador na saída
0035 Memória do usuário no time e modelo próprio para o resumo da compactação
0036 Pedido do titular por integração e pelo próprio usuário, com prazo e aviso
0037 Painel da fila, retry por agente idempotente, conciliação de custo e aviso por e-mail
0038 Roteador, entrada por etapa, histórico no workflow e casos de suíte a partir das conversas
0039 Google Drive e Cloud Storage, filtro por nome, webhook da origem e worker de ingestão
0040 Liberação gradual de versão: canário por sessão, comparação e promoção manual (Fase 45)
0041 Trilha de auditoria: escritas de /api/v1 e aprovações com quem, alvo e resultado, antes e depois nas ações de produção (Fase 46)
0042 Login por SSO via OIDC: um provedor por instância, papel pelo grupo e conta criada no primeiro login (Fase 47)

O histórico de fases, com os problemas encontrados em auditoria e o critério de aceite de cada uma, está em docs/roadmap.md.


Rodando local

Pré-requisitos: Docker Desktop, Node.js 22+, pnpm, Python 3.12+, uv e openssl.

git clone https://github.com/WellCod/automata.git
cd automata
bash scripts/bootstrap.sh   # gera chaves RSA, cria .env, instala dependências e sobe o banco

Demo sem chave de LLM

Com DEMO_REPLAY=true, o modelo é trocado por respostas gravadas em api/fixtures/ e as bases usam um embedder local. Edição, versões, modo teste, workflows e analytics funcionam sem chave nenhuma.

# API em modo replay (--build -V recria imagem e venv se as dependências mudaram)
DEMO_REPLAY=true docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build -V

# Seed: owner, 5 agentes, base de conhecimento, workflow, suíte de testes e 500 execuções em 90 dias
read -rsp "Senha do owner: " SEED_OWNER_PASSWORD; echo
docker exec \
  -e SEED_OWNER_EMAIL="admin@exemplo.com" \
  -e SEED_OWNER_PASSWORD="$SEED_OWNER_PASSWORD" \
  automata-api-1 bash -c "cd /app && .venv/bin/python scripts/seed.py full"

# Painel
pnpm --filter web dev   # http://localhost:3000

Guia completo, com o que o seed cria e como as fixtures funcionam, em DEMO.md.

Desenvolvimento

docker compose -f docker-compose.yml -f docker-compose.dev.yml up   # API em :8000, migrations no boot
pnpm --filter web dev                                                 # painel em :3000

A porta 8000 só é publicada pelo override de dev. Em produção, a API fica na rede do compose e o painel fala com ela por http://api:8000. Depois de um git pull que mexa em api/uv.lock, recrie a API com --build -V. Sem o -V, o volume anônimo do venv mantém as dependências antigas.

Testes

cd api && uv run pytest -m "not nightly"   # API, com testcontainers
cd api && uv run pytest -m nightly         # evals com LLM real (ANTHROPIC_API_KEY)
pnpm --filter web test                     # Vitest
pnpm --filter web test:e2e                 # Playwright

Estrutura do repositório

api/
  app/
    agents/       factories, rastreamento, workflows, modelos, memória do usuário, replay
    evals/        runner da suíte (agente, time e workflow), juiz, gate, agendamento, avisos e sugestão de caso
    guardrails/   regras de entrada e saída
    knowledge/    embedders, ingestão e worker, conectores e filtro, reindexação, busca com reranker, HyDE e filtros, tools
    mcp/          cliente MCP, proteção de saída (SSRF)
    routers/      rotas próprias /api/v1
    services/     regras de negócio e validação na escrita
  alembic/        56 migrations
  fixtures/       respostas gravadas do modo replay
  tests/          pytest, integração e evals
web/
  src/app/        páginas e Route Handlers (BFF)
  src/components/ editor de workflow, suíte de testes, modo teste, painéis
  src/lib/        client gerado do OpenAPI, SSE, progresso do workflow
  e2e/            Playwright
docs/
  adr/            42 Architecture Decision Records
  roadmap.md      fases, auditorias e critérios de aceite
DESIGN.md         sistema visual do painel
DEMO.md           demo local sem chave de LLM

Licença

Ver LICENSE. Justificativa em ADR-0007.

Construído sobre o Agno. Nenhum dado de produção, prompt real ou identificação de cliente consta neste repositório; os prints usam o seed de demonstração.

About

Plataforma para operar agentes de IA em produção: agentes, times multi-agente e workflows versionados com rollback, RAG com pgvector, ferramentas via MCP, guardrails e analytics de latência e custo.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Contributors

Languages