Pular para o conteúdo

Implantação

Como o ai-agent-eval-harness-healthtech chega à produção, descrito em nível de arquitetura. A produção roda no Google Cloud Run (uma única instância de contêiner, região us-central1) construída a partir da mesma imagem que o Dockerfile do projeto produz. A implantação é um Cloud Build a partir do fonte, sem chaves via Workload Identity Federation, condicionado ao tag-guard da CI e que preserva segredos. Os comandos exatos de operador vivem na referência privada de comandos de operador; esta página é a referência pública da forma da implantação.

O destino de produção é uma demo pública, sempre acessível, construída a partir da imagem exata que o projeto entrega. O Cloud Run, executando uma única revisão de contêiner, nos dá:

  • Um endpoint HTTPS gerenciado mapeado para um domínio personalizado para a demo ao vivo.
  • Escala a zero quando ocioso e uma única instância sob carga, de modo que o tráfego em escala de demo permanece dentro da franquia sempre gratuita do Cloud Run e o gasto real fica perto de $0 / mês.
  • Uma implantação sem chaves: o job de CI gera um token de curta duração do Google Cloud via Workload Identity Federation (OIDC); nenhuma chave de conta de serviço é armazenada.
  • Um build a partir do fonte que reconstrói a partir do Dockerfile entregue e preserva as variáveis de ambiente e os vínculos com o Secret Manager existentes no serviço.

O teto de instância única é deliberado, não uma limitação do host: o limitador de taxa, o cache de respostas e o checkpointer do human-in-the-loop pausado são todos por processo, então uma segunda instância não os compartilharia. Uma implantação multi-instância precisaria de um armazenamento compartilhado (Redis, Postgres), o que está fora do escopo da demo.

A implantação é do lado do servidor e condicionada a uma matriz de CI verde; nenhum operador publica um release de produção manualmente.

  1. Uma tag de release que corresponde a vX.Y.Z é enviada.
  2. O workflow tag-guard roda novamente a matriz de CI completa contra o commit exato marcado com a tag.
  3. O workflow deploy roda apenas depois que o tag-guard conclui, e apenas quando aquela execução concluiu com sucesso na tag. Uma matriz de CI vermelha significa que a implantação é ignorada e nada é publicado.
  4. O job de implantação faz checkout do commit exato validado, autentica-se no Google Cloud sem chaves via Workload Identity Federation (OIDC) e dispara um Cloud Build a partir do fonte que reconstrói a imagem a partir do Dockerfile entregue e implanta uma nova revisão do Cloud Run.
  5. Como a reconstrução é a partir do fonte, ela preserva as variáveis de ambiente e os vínculos com o Secret Manager que já estão no serviço. O tráfego migra apenas quando a nova revisão está saudável; uma revisão com falha mantém o tráfego na anterior saudável.

A implantação sem chaves se apoia em uma relação de confiança única com o Google Cloud, após a qual cada release flui pelo pipeline acima:

  • Workload Identity Federation. Um pool e um provider de federação são estabelecidos para o repositório, junto com uma conta de serviço de implantação de privilégio mínimo que o pool pode personificar (limitada apenas ao que uma implantação a partir do fonte do Cloud Run precisa). O provider e a identidade de implantação são referenciados a partir de variáveis de repositório não secretas; nenhuma chave de conta de serviço é criada ou armazenada.
  • Secret Manager. As credenciais dos provedores de completude -OpenAI (primário) e Anthropic (fallback e juiz de avaliação)- e os segredos de integração (embeddings/reranking gerenciados, a camada de dados da demo, a voz e a verificação de bots na borda) são guardados no Google Secret Manager e vinculados ao serviço. Como a implantação reconstrói a partir do fonte, esses vínculos persistem a cada implantação subsequente.

O serviço lê sua configuração das configurações de ambiente do Cloud Run e dos vínculos com o Secret Manager (as configurações da aplicação mapeiam cada campo para uma variável de ambiente em maiúsculas):

  • Geração roda uma cascata de dois provedores: OpenAI gpt-4o-mini (primário) com fallback em Anthropic claude-haiku-4-5 diante de uma falha transitória do upstream (ver ADR-0002). O juiz de avaliação é a Anthropic claude-haiku-4-5.
  • Embeddings usam por padrão o embedder gerenciado da Voyage quando há uma chave da Voyage presente e recaem no BAAI/bge-small-en-v1.5 embutido caso contrário, de modo que o serviço continua funcionando sem chave de embeddings.
  • O estado da conversa usa o MemorySaver em memória por padrão (uma thread HITL pausada não sobrevive a um reinício de revisão); um checkpointer durável respaldado por Postgres é selecionado automaticamente quando uma string de conexão do Postgres é configurada.
  • As primitivas de resiliência -o limitador de taxa de janela deslizante, o cache de respostas e o fallback de provedor- são por processo, razão pela qual o serviço roda uma única instância.
  • A base de conhecimento embutida é ingerida em uma coleção Chroma vazia no primeiro boot.

O Agent Execution Graph é alimentado por um modo de streaming server-sent-events (SSE) em /chat e /chat/resume: uma requisição que aceita text/event-stream recebe eventos de execução por nó em vez de uma única resposta JSON. O design de streaming está registrado na ADR-0009.

Para que o grafo ao vivo pareça ao vivo, esses eventos precisam chegar ao navegador incrementalmente - conforme cada nó roda - em vez de serem armazenados em buffer e entregues como um único bloco no fim do turno. A aplicação descarrega cada registro conforme o stream do LangGraph o produz, mas se a borda preserva a entrega incremental é uma propriedade de implantação que é verificada contra a revisão em execução, não presumida: um gate de release confirma que os registros chegam espaçados ao longo do turno (graph_topology, depois node_started / node_completed, depois turn_completed) em vez de colapsar em um despejo pós-turno. Um release não alega um grafo de execução ao vivo a menos que o serviço em execução comprovadamente transmita incrementalmente.

O Cloud Run mantém cada revisão implantada, então o rollback é uma operação de tráfego, não uma reconstrução:

  • Reverter migrando todo o tráfego de volta para a revisão anterior saudável; é instantâneo e não precisa de uma execução de CI.
  • Avançar um build corrigido revertendo o commit ofensor na branch padrão e cortando uma nova tag vX.Y.Z, o que roda novamente o tag-guard e, em verde, reimplanta.

Uma revisão com falha nunca recebe tráfego: o Cloud Run continua atendendo a revisão anterior saudável até que a nova esteja pronta.

O Cloud Run roda o mesmo Dockerfile que o projeto entrega - a imagem é idêntica no desenvolvimento local, na CI e na produção. Ela:

  • vincula o uvicorn à $PORT (o Cloud Run injeta 8080; execuções locais e do Hugging Face usam por padrão 7860), de modo que uma imagem atende em qualquer porta que o host fornecer,
  • roda como um usuário app não-root sobre uma base python:3.12-slim com apenas ca-certificates e curl adicionados,
  • escreve apenas em /tmp e no virtualenv da aplicação, e não requer GPU.

A mesma imagem roda sem alterações em outros hosts capazes de Docker; apenas a porta e o cabeamento da plataforma diferem:

  • Hugging Face Spaces (Docker SDK, camada gratuita CPU Basic): uma demo secundária genuinamente de custo zero e sempre ativa a partir da imagem idêntica, atendendo na porta 7860 com a mesma base de conhecimento embutida.
  • Render (camada gratuita, não testado): o mesmo Dockerfile deveria rodar quando o serviço é configurado para escutar na $PORT fornecida pelo Render; este caminho é documentado mas não exercitado.
  • Docker local: a mesma imagem roda localmente para o desenvolvimento e para a verificação de sanidade antes de uma tag de release.