Pular para o conteúdo

Arquitetura real · Pleno

Hidden Technical Debt in ML Systems (Google)

Arquitetura real em produção. Pontos centrais: dívida técnica de ML, glue code, loops de feedback e rules of ML.

15 min de leitura · Conteúdo revisado em 23 de outubro de 2026

Resposta curta

Arquitetura real em produção. Pontos centrais: dívida técnica de ML, glue code, loops de feedback e rules of ML. O artigo parte de uma observação: desenvolver e colocar sistemas de ML em produção é relativamente rápido e barato, mas mantê-los ao longo do tempo é difícil e caro.

01 · CONTEXTO

Barato de construir, caro de manter

O artigo parte de uma observação: desenvolver e colocar sistemas de ML em produção é relativamente rápido e barato, mas mantê-los ao longo do tempo é difícil e caro. Pela lente da dívida técnica, nem toda dívida é ruim, mas toda dívida precisa ser paga, e a dívida escondida é perigosa porque se acumula em silêncio.

A tese central é que sistemas de ML têm uma capacidade especial de acumular dívida, porque somam os problemas de manutenção do código tradicional a um conjunto de problemas próprios de ML. Essa dívida pode ser difícil de detectar por existir no nível do sistema, e não no do código, e os métodos típicos de quitar dívida de código não bastam para ela.

Uma versão curta do artigo foi apresentada no workshop SE4ML, em Montreal, em 2014. Já o resumo na página de pesquisa do Google diz que é notavelmente fácil acumular custos de manutenção enormes e contínuos no nível do sistema ao aplicar aprendizado de máquina.

02 · FRONTEIRAS ERODIDAS

Por que modelos corroem a separação entre componentes

É difícil impor fronteiras de abstração estritas em sistemas de ML, porque ML é necessário justamente quando o comportamento desejado não se expressa em lógica de software sem depender de dados externos. Por isso, abstrações e fronteiras tradicionais podem ser sutilmente corrompidas pelo fato de os dados influenciarem o comportamento do sistema.

Primeiro vem o entrelaçamento. Sistemas de ML misturam sinais, e nenhuma entrada é realmente independente; o artigo chama isso de princípio CACE, de Changing Anything Changes Everything. Mudar a distribuição de entrada de uma feature pode alterar a importância, os pesos ou o uso das demais.

Isolar modelos e servir ensembles é uma mitigação possível. Mas ensembles muitas vezes funcionam porque os erros dos componentes são descorrelacionados, e depender da combinação cria entrelaçamento forte: melhorar um componente pode piorar a acurácia do sistema.

Depois vêm as cascatas de correção. Pode ser tentador treinar um modelo que aprende uma pequena correção sobre outro, como forma rápida de resolver um problema ligeiramente diferente. Em cascata, isso pode criar um impasse de melhoria, em que melhorar a acurácia de um componente leva a prejuízos no nível do sistema. As mitigações citadas são aprender as correções dentro do mesmo modelo, com features que distinguem os casos, ou aceitar o custo de um modelo separado.

Por fim, os consumidores não declarados. Sem controle de acesso, alguns consumidores da previsão podem ficar não declarados e usar em silêncio a saída do modelo como entrada de outro sistema. Na engenharia de software clássica, esses problemas são chamados de dívida de visibilidade.

  1. Um sistema produz um sinal que o modelo usa como entrada.

    Diagrama da arquitetura: Consumidores que o modelo não conhece
    CPSistema produtor do sinal
    CPModelo em produçãomodelo
    CPConsumidor declarado
    DBArquivos e logs de previsão
    CPConsumidor não declarado
  2. O modelo entrega previsões a um consumidor que a equipe do modelo conhece.

    Diagrama da arquitetura: Consumidores que o modelo não conhece
    CPSistema produtor do sinal
    CPModelo em produção
    CPConsumidor declaradocontrato conhecido
    DBArquivos e logs de previsão
    CPConsumidor não declarado
  3. A previsão também fica em arquivos ou logs, e outro sistema passa a ler essa saída como entrada sem que a equipe do modelo saiba.

    Diagrama da arquitetura: Consumidores que o modelo não conhece
    CPSistema produtor do sinal
    CPModelo em produção
    CPConsumidor declarado
    DBArquivos e logs de previsãoprevisão gravada
    CPConsumidor não declaradolê sem aviso
  4. Quando o modelo muda, as outras partes da pilha provavelmente são afetadas, possivelmente de formas não pretendidas e prejudiciais.

    Diagrama da arquitetura: Consumidores que o modelo não conhece
    CPSistema produtor do sinal
    CPModelo em produção
    CPConsumidor declarado
    DBArquivos e logs de previsão
    CPConsumidor não declaradoafetado sem aviso
  5. O artigo cita restrições de acesso e acordos de nível de serviço rigorosos como forma de projetar o sistema para evitar consumidores não declarados.

    Diagrama da arquitetura: Consumidores que o modelo não conhece
    CPSistema produtor do sinal
    CPModelo em produção
    CPConsumidor declarado
    DBArquivos e logs de previsãoacesso controlado
    CPConsumidor não declarado

03 · DADOS E ANTIPADRÕES

Dependências de dados e antipadrões de sistema

Dependências de código podem ser identificadas por análise estática de compiladores e linkers. Sem ferramentas equivalentes para dados, é inapropriadamente fácil criar cadeias grandes de dependências de dados difíceis de desfazer. Ferramentas de análise estática de dependências de dados são menos comuns, mas essenciais para checar erros, localizar consumidores e impor migrações e atualizações.

Entre os riscos estão os sinais instáveis, que mudam de comportamento ao longo do tempo. Isso pode acontecer de forma implícita, quando o sinal vem de outro modelo que se atualiza, ou explícita, quando a propriedade de engenharia do sinal é separada da do modelo que o consome. Uma mitigação comum é uma cópia versionada do sinal, que tem custo próprio: possível defasagem e manutenção de várias versões do mesmo sinal.

Há também as dependências subutilizadas, sinais que trazem pouco benefício incremental de modelagem. Elas deixam o sistema desnecessariamente vulnerável a mudanças e poderiam ser removidas sem prejuízo. Um caso é a feature incluída cedo no desenvolvimento e tornada redundante por novas features sem que isso seja detectado. O artigo propõe avaliações exaustivas leave-one-feature-out, executadas com regularidade.

No nível do sistema, o artigo mostra que só uma pequena fração de um sistema real de ML é código de ML, e que a infraestrutura necessária ao redor é vasta e complexa.

  1. O código de aprendizado é um bloco pequeno do diagrama; ao redor dele fica uma infraestrutura vasta e complexa.

    Diagrama da arquitetura: O modelo é só uma parte do sistema
    DBColeta e armazenamento de dados
    CPPipeline de preparo
    DBConfiguração
    CPCódigo de aprendizadocódigo de ML
    CPServiço de previsão
    NWMonitoramento
  2. Na preparação de dados, novos sinais e novas fontes entram aos poucos; sem cuidado, o resultado vira uma selva de coletas, junções e amostragens, muitas vezes com arquivos intermediários.

    Diagrama da arquitetura: O modelo é só uma parte do sistema
    DBColeta e armazenamento de dados
    CPPipeline de preparorisco: selva de pipelines
    DBConfiguração
    CPCódigo de aprendizado
    CPServiço de previsão
    NWMonitoramento
  3. Pacotes genéricos de aprendizado pedem muito código de apoio para levar dados para dentro e para fora deles, e esse código tende a prender o sistema às peculiaridades de um pacote específico.

    Diagrama da arquitetura: O modelo é só uma parte do sistema
    DBColeta e armazenamento de dados
    CPPipeline de preparocódigo de cola
    DBConfiguração
    CPCódigo de aprendizadopacote genérico
    CPServiço de previsão
    NWMonitoramento
  4. A configuração também acumula dívida: num sistema maduro e em desenvolvimento ativo, as linhas de configuração podem superar em muito as de código tradicional, e cada linha tem potencial para erros.

    Diagrama da arquitetura: O modelo é só uma parte do sistema
    DBColeta e armazenamento de dados
    CPPipeline de preparo
    DBConfiguraçãoconfiguração
    CPCódigo de aprendizado
    CPServiço de previsão
    NWMonitoramento
  5. Testes não bastam diante de um mundo em mudança; o artigo defende monitoramento ao vivo combinado com resposta automatizada.

    Diagrama da arquitetura: O modelo é só uma parte do sistema
    DBColeta e armazenamento de dados
    CPPipeline de preparo
    DBConfiguração
    CPCódigo de aprendizado
    CPServiço de previsão
    NWMonitoramentomonitoramento ao vivo

Dos antipadrões, o primeiro é o código de cola. Pacotes genéricos costumam exigir uma quantidade enorme de código de apoio. Um sistema maduro pode ter no máximo 5% de código de ML e no mínimo 95% de código de cola, e pode sair mais barato criar uma solução nativa limpa do que reutilizar um pacote genérico. Uma estratégia importante é embrulhar pacotes caixa-preta em APIs comuns.

O segundo é a selva de pipelines. Testá-la costuma exigir testes de integração de ponta a ponta caros, e ela só pode ser evitada pensando de forma holística sobre a coleta de dados e a extração de features.

O terceiro são os caminhos de código experimentais mortos. No curto prazo, torna-se atraente experimentar métodos alternativos como ramos condicionais dentro do código de produção. Com o tempo, isso cria dívida crescente pela dificuldade de manter compatibilidade retroativa e pelo aumento exponencial de complexidade ciclomática. Um exemplo famoso citado: o sistema da Knight Capital perdeu 465 milhões de dólares em 45 minutos, aparentemente por comportamento inesperado de caminhos de código experimentais obsoletos.

Risco apontado no artigoMitigação citada
Código de colaCongela o sistema nas peculiaridades de um pacote específicoEmbrulhar pacotes caixa-preta em APIs comuns
Selva de pipelinesSelva de coletas, junções e passos de amostragem, com arquivos intermediáriosPensar de forma holística sobre coleta de dados e extração de features
Caminhos experimentais mortosDificulta manter compatibilidade retroativa e testar as interações entre caminhosReexaminar periodicamente cada ramo experimental para ver o que pode ser removido
Dependências subutilizadasDeixam o sistema desnecessariamente vulnerável a mudançasAvaliações leave-one-feature-out executadas com regularidade

04 · FEEDBACK E MUNDO EXTERNO

Laços de feedback e um mundo que muda

Sistemas de ML ativos costumam acabar influenciando o próprio comportamento se se atualizam com o tempo. Isso leva a uma forma de dívida de análise: é difícil prever o comportamento de um modelo antes de ele ser lançado. Os laços são mais difíceis de detectar e tratar se ocorrem gradualmente, como quando os modelos são atualizados com pouca frequência.

  1. Os usuários recebem as previsões do modelo atual.

    Diagrama da arquitetura: Um modelo que molda os próprios dados
    CLUsuários
    CPServiço de previsãomodelo atual
    QRegistro de interações
    CPRetreino
  2. As ações dos usuários voltam como dados de treino, e o modelo retreinado volta ao serviço: o ciclo se fecha no próprio diagrama.

    Diagrama da arquitetura: Um modelo que molda os próprios dados
    CLUsuários
    CPServiço de previsão
    QRegistro de interaçõesvira dado de treino
    CPRetreino
  3. É um laço de feedback direto: o modelo influencia diretamente a seleção dos seus próprios dados de treino futuros.

    Diagrama da arquitetura: Um modelo que molda os próprios dados
    CLUsuários
    CPServiço de previsão
    QRegistro de interaçõesdados moldados pelo modelo
    CPRetreino
  4. O artigo cita como mitigação usar alguma aleatorização ou isolar partes dos dados da influência do modelo; algoritmos de bandit não escalam necessariamente para os espaços de ação de problemas reais.

    Diagrama da arquitetura: Um modelo que molda os próprios dados
    CLUsuários
    CPServiço de previsãoaleatorização
    QRegistro de interações
    CPRetreino
  5. Já o laço oculto não aparece no diagrama: dois sistemas se influenciam indiretamente através do mundo, como um que escolhe produtos e outro que escolhe avaliações relacionadas na mesma página.

    Diagrama da arquitetura: Um modelo que molda os próprios dados
    CLUsuárioso mundo liga os sistemas
    CPServiço de previsão
    QRegistro de interações
    CPRetreino

O mundo externo também muda. A experiência mostra que ele raramente é estável, e isso gera custo contínuo de manutenção. Limiares de decisão definidos manualmente podem ficar inválidos quando o modelo se atualiza com novos dados, e atualizar manualmente muitos limiares em muitos modelos é demorado e frágil. Uma mitigação é aprender os limiares por avaliação simples em dados de validação separados.

Testes unitários e de ponta a ponta são valiosos, mas diante de um mundo em mudança não bastam como evidência de que o sistema funciona como pretendido. Depender de intervenção humana em resposta a alertas é uma estratégia, mas pode ser frágil para problemas sensíveis ao tempo.

O que o artigo propõe monitorarObservação do artigo
Viés de previsãoEm geral, a distribuição dos rótulos previstos deveria ser igual à dos rótulos observadosNão é teste abrangente, pois um modelo nulo que prevê valores médios também o satisfaz, mas é um diagnóstico surpreendentemente útil
Limites de açãoDefinir e impor limites de ação como checagem de sanidadeSe um limite for atingido, alertas automáticos devem disparar intervenção ou investigação manual
Produtores a montanteMonitorar e testar os processos a montante, com objetivo de nível de serviço que leve em conta o sistema de ML a jusantePropagar alertas a montante ao plano de controle do sistema de ML

05 · REGRAS DE ML

O guia Rules of ML: desvio entre treino e serving

O guia Rules of Machine Learning apresenta práticas de ML do Google num estilo semelhante ao de guias de estilo de programação. Duas de suas regras tratam da infraestrutura: o primeiro modelo não precisa ser sofisticado, mas surgirão muito mais problemas de infraestrutura do que o esperado; e a infraestrutura deve ser testável, com as partes de aprendizado encapsuladas para que se possa testar tudo ao redor delas.

Um risco concreto é o training-serving skew, uma diferença entre o desempenho durante o treino e durante o serving. Ele pode vir de tratamento diferente dos dados nos pipelines de treino e de serving, de mudança nos dados entre treinar e servir, ou de um laço de feedback entre modelo e algoritmo.

  1. O guia recomenda salvar o conjunto de features usado no serving e enviá-lo a um log para uso no treino.

    Diagrama da arquitetura: Treinar como se serve
    CPServiço de previsão
    QLog de features do servingfeatures do serving
    CPPipeline de treino
    DBRepositório de modelos
    NWMedição de desvio
  2. O pipeline de treino consome as features registradas pelo serviço, para treinar como se serve.

    Diagrama da arquitetura: Treinar como se serve
    CPServiço de previsão
    QLog de features do serving
    CPPipeline de treinotreina como serve
    DBRepositório de modelos
    NWMedição de desvio
  3. O modelo treinado é publicado no repositório e carregado pelo serviço, fechando o ciclo entre treino e serving.

    Diagrama da arquitetura: Treinar como se serve
    CPServiço de previsão
    QLog de features do serving
    CPPipeline de treino
    DBRepositório de modelos
    NWMedição de desvio
  4. A melhor solução, segundo o guia, é monitorar o desvio explicitamente, para que mudanças no sistema e nos dados não o introduzam sem ser notado.

    Diagrama da arquitetura: Treinar como se serve
    CPServiço de previsão
    QLog de features do serving
    CPPipeline de treino
    DBRepositório de modelos
    NWMedição de desviomede o desvio

Outras duas regras reforçam o cuidado: reutilizar código entre o pipeline de treino e o de serving sempre que possível, e lembrar que, se você une dados de uma tabela no treino e no serving, os dados da tabela podem mudar.

O guia pede ainda que se conheçam os requisitos de atualização do sistema: saber quanto o desempenho degrada com um modelo de um dia, uma semana ou um trimestre ajuda a priorizar o monitoramento. E recomenda verificações de sanidade logo antes de exportar o modelo.

06 · LIÇÕES

Como medir e pagar a dívida

O artigo reconhece que a metáfora da dívida técnica não fornece uma métrica estrita que possa ser acompanhada ao longo do tempo. Notar que o time ainda se move rápido não é, por si, evidência de dívida baixa, pois o custo total só aparece com o tempo.

Em lugar de uma métrica, o artigo propõe perguntas. Com que facilidade uma abordagem algorítmica totalmente nova pode ser testada em escala real? Qual é o fecho transitivo de todas as dependências de dados? Melhorar um modelo ou sinal degrada outros?

Pagar a dívida exige mudar a cultura: é importante criar culturas de equipe que recompensem a remoção de features, a redução de complexidade e melhorias de reprodutibilidade, estabilidade e monitoramento no mesmo grau que melhorias de acurácia. Soluções de pesquisa que dão um benefício minúsculo de acurácia ao custo de aumentos enormes de complexidade do sistema raramente são prática sábia. Configurações, por sua vez, devem passar por revisão de código completa e ser versionadas em um repositório.

Perguntas frequentes

O que é Hidden Technical Debt in ML Systems (Google)?

Arquitetura real em produção. Pontos centrais: dívida técnica de ML, glue code, loops de feedback e rules of ML.

O que o design de Hidden Technical Debt in ML Systems (Google) cobre?

Ele está organizado nestas seções: Barato de construir, caro de manter, Por que modelos corroem a separação entre componentes, Dependências de dados e antipadrões de sistema, Laços de feedback e um mundo que muda, O guia Rules of ML: desvio entre treino e serving e Como medir e pagar a dívida.

Quanto tempo leva Hidden Technical Debt in ML Systems (Google) e qual é o nível?

Leva cerca de 15 minutos para ler e tem nível Pleno.

Agora projete você mesmo

Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.