Design do DevTools: uso eficiente de tokens na assistência de IA

Publicado em: 30 de janeiro de 2026

Ao criar a assistência de IA para performance, o principal desafio de engenharia foi fazer o Gemini funcionar bem com rastreamentos de performance gravados no DevTools.

Os modelos de linguagem grandes (LLMs) operam em uma "janela de contexto", que se refere a um limite estrito na quantidade de informações que eles podem processar de uma só vez. Essa capacidade é medida em tokens. Para os modelos do Gemini, um token é aproximadamente um grupo de quatro caracteres.

Os rastreamentos de desempenho são arquivos JSON enormes, geralmente com vários megabytes. Enviar um rastreamento bruto esgotaria instantaneamente a janela de contexto de um modelo e não deixaria espaço para suas perguntas.

Para tornar possível a assistência de IA para Performance, precisamos arquitetar um sistema que maximizasse a quantidade de dados úteis para um LLM com uso mínimo de tokens. Neste blog, você pode conhecer as técnicas que usamos e adotá-las nos seus próprios projetos.

Adapte o contexto inicial

Depurar a performance de um site é uma tarefa complexa. Um desenvolvedor pode analisar o rastreamento completo para ter contexto, focar nas métricas principais da Web e nos períodos relacionados do rastreamento ou até mesmo analisar os detalhes e focar em eventos individuais, como cliques ou rolagens e as respectivas pilhas de chamadas.

Para ajudar no processo de depuração, a assistência de IA do DevTools precisa corresponder a essas jornadas do desenvolvedor e trabalhar apenas com os dados relevantes para dar conselhos específicos ao foco do desenvolvedor. Em vez de sempre enviar o rastreamento completo, criamos uma assistência de IA para segmentar os dados com base na sua tarefa de depuração:

Tarefa de depuração Dados inicialmente enviados para a assistência de IA
Conversar sobre um trace de performance Resumo do rastreamento: um relatório baseado em texto que inclui informações de alto nível da sessão de rastreamento e depuração. Inclui o URL da página, as condições de limitação, as principais métricas de performance (LCP, INP, CLS), uma lista de insights disponíveis e, se disponível, um resumo do CrUX.
Conversar sobre um insight de performance Resumo do rastreamento e nome do insight de performance selecionado.
Conversar sobre uma tarefa de um rastreamento Resumo do rastreamento e a árvore de chamadas serializada em que a tarefa selecionada está localizada.
Conversar sobre uma solicitação de rede Resumo do rastreamento e a chave e o carimbo de data/hora da solicitação selecionada
Gerar anotações de rastreamento A árvore de chamadas serializada em que a tarefa selecionada está localizada. A árvore serializada identifica qual tarefa está selecionada.

O resumo do rastreamento é quase sempre enviado para fornecer contexto inicial ao Gemini, o modelo de assistência de IA. Para anotações geradas com IA, ele é omitido.

Como dar ferramentas para a IA

A assistência de IA no DevTools funciona como um agente. Isso significa que ele pode consultar mais dados de forma autônoma com base no comando inicial do desenvolvedor e no contexto inicial compartilhado. Para consultar mais dados, fornecemos à assistência de IA um conjunto de funções predefinidas que ela pode chamar. Um padrão conhecido como chamada de função ou uso de ferramentas.

.

Com base nas jornadas de depuração descritas anteriormente, definimos um conjunto de funções granulares para o agente. Essas funções detalham especificidades consideradas importantes com base no contexto inicial, de maneira semelhante a como um desenvolvedor humano abordaria a depuração de desempenho. O conjunto de funções é o seguinte:

Função Descrição
getInsightDetails(name) Retorna informações detalhadas sobre um insight de performance específico (por exemplo,detalhes sobre por que o LCP foi sinalizado).
getEventByKey(key) Retorna propriedades detalhadas de um único evento específico.
getMainThreadTrackSummary(start, end) Retorna um resumo da atividade da linha de execução principal para os limites especificados, incluindo resumos de cima para baixo, de baixo para cima e de terceiros.
getNetworkTrackSummary(start, end) Retorna um resumo da atividade de rede para os limites de tempo especificados.
getDetailedCallTree(event_key) Retorna a árvore de chamadas completa de um evento específico da linha de execução principal no rastreamento de desempenho.
getFunctionCode(url, line, col) Retorna o código-fonte de uma função definida em um local específico de um recurso, anotado com dados de desempenho de tempo de execução do rastreamento de desempenho.
getResourceContent(url) Retorna o conteúdo de um recurso de texto usado pela página (por exemplo, HTML ou CSS).

Ao limitar estritamente a recuperação de dados a essas chamadas de função, garantimos que apenas informações relevantes entrem na janela de contexto em um formato bem definido, otimizando o uso de tokens.

Exemplo de uma operação de agente

Vamos conferir um exemplo prático de como a assistência de IA usa a chamada de função para recuperar mais informações. Depois de um comando inicial de "Por que esta solicitação está lenta?", A assistência de IA pode chamar as seguintes funções de forma incremental:

  1. getEventByKey: busca o detalhamento do tempo (TTFB, tempo de download) da solicitação específica selecionada pelo usuário.
  2. getMainThreadTrackSummary: verifique se a linha de execução principal estava ocupada (bloqueada) quando a solicitação deveria ter sido iniciada.
  3. getNetworkTrackSummary: analise se outros recursos estavam disputando a largura de banda ao mesmo tempo.
  4. getInsightDetails: verifique se o resumo do rastreamento já menciona um insight relacionado a essa solicitação como um gargalo.

Ao combinar os resultados dessas chamadas, a assistência de IA pode fornecer um diagnóstico e propor etapas práticas, como sugerir melhorias no código usando getFunctionCode ou otimizar o carregamento de recursos com base em getResourceContent.

No entanto, a recuperação de dados relevantes é apenas metade do desafio. Mesmo com funções que fornecem dados granulares, os dados retornados por elas podem ser muito grandes. Por exemplo, getDetailedCallTree pode retornar uma árvore com centenas de nós. No JSON padrão, isso seria muitos { e } apenas para aninhamento.

Portanto, é necessário um formato denso o suficiente para ser eficiente em termos de tokens, mas ainda estruturado o suficiente para um LLM entender e referenciar.

Serializar os dados

Vamos entender melhor como abordamos esse desafio, continuando com o exemplo da árvore de chamadas, já que elas representam a maioria dos dados em um rastreamento de performance. Para referência, os exemplos a seguir mostram uma única tarefa em uma pilha de chamadas em JSON:

{
  "id": 2,
  "name": "animate",
  "selected": true,
  "duration": 150,
  "selfTime": 20,
  "children": [3, 5, 6, 7, 10, 11, 12]
}

Um rastreamento de desempenho pode conter milhares deles, como mostrado na captura de tela a seguir. Cada pequena caixa colorida é representada usando essa estrutura de objeto.

Uma call stack em um trace de desempenho gravado no DevTools

Esse formato é bom para trabalhar de forma programática no DevTools, mas é desperdiçador para LLMs pelos seguintes motivos:

  1. Chaves redundantes:strings como "duration", "selfTime" e "children" são repetidas para cada nó na árvore de chamadas. Assim, uma árvore com 500 nós enviada a um modelo consumiria tokens para cada uma dessas chaves 500 vezes.
  2. Listas detalhadas:listar cada ID filho individualmente usando children consome um grande número de tokens, especialmente para tarefas que acionam muitos eventos downstream.

A implementação de um formato eficiente em termos de tokens para todos os dados usados com a assistência de IA para performance foi um processo gradual.

Primeira iteração

Quando começamos a trabalhar com a assistência de IA para performance, otimizamos a velocidade de entrega. Nossa abordagem de otimização de tokens foi básica. Removemos as chaves e vírgulas do JSON original, o que resultou em um formato como este:

allUrls = [...]

Node: 1 - update
Selected: false
Duration: 200
Self Time: 50
Children:
   2 - animate

Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children:
   3 - calculatePosition
   5 - applyStyles
   6 - applyStyles
   7 - calculateLayout
   10 - applyStyles
   11 - applyStyles
   12 - applyStyles

Node: 3 - calculatePosition
Selected: false
Duration: 15
Self Time: 2
URL: 0
Children:
   4 - getBoundingClientRect

...

Mas essa primeira versão foi apenas uma pequena melhoria em relação ao JSON bruto. Ele ainda listava explicitamente os filhos do nó com IDs e nomes e adicionava chaves descritivas e repetidas (Node:, Selected:, Duration:, …) antes de cada linha.

Otimizar listas de nós filhos

Como uma próxima etapa para otimizar ainda mais, removemos os nomes dos filhos do nó (calculatePosition, applyStyles, … no exemplo anterior). Como a assistência de IA tem acesso a todos os nós por chamadas de função e essas informações já estão no cabeçalho do nó (Node: 3 - calculatePosition), não é necessário repetir essas informações. Isso nos permitiu reduzir o Children a uma simples lista de números inteiros:

Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children: 3, 5, 6, 7, 10, 11, 12

..

Embora isso tenha sido uma melhoria significativa em relação ao período anterior, ainda havia espaço para otimizar. No exemplo anterior, você pode notar que Children é quase sequencial, faltando apenas 4, 8 e 9.

O motivo é que, na primeira tentativa, usamos um algoritmo de pesquisa em profundidade (DFS, na sigla em inglês) para serializar dados de árvore do rastreamento de desempenho. Isso resultou em IDs não sequenciais para nós irmãos, o que exigiu que listássemos cada ID individualmente.

Percebemos que, se reindexarmos a árvore usando a pesquisa em largura (BFS, na sigla em inglês), vamos receber IDs sequenciais, o que possibilita outra otimização. Em vez de listar IDs individuais, agora podemos representar até centenas de crianças com um único intervalo compacto, como 3-9 no exemplo original.

A notação final do nó, com a lista otimizada de Children, fica assim:

allUrls = [...]

Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children: 3-9

Reduzir o número de chaves

Com as listas de nós otimizadas, passamos para as chaves redundantes. Começamos removendo todas as chaves do formato anterior, o que resultou nisso:

allUrls = [...]

2;animate;150;20;0;3-10

Embora seja eficiente em termos de tokens, ainda precisamos dar instruções ao Gemini sobre como entender esses dados. Por isso, na primeira vez que enviamos uma árvore de chamadas para o Gemini, incluímos o seguinte comando:

...
Each call frame is presented in the following format:

'id;name;duration;selfTime;urlIndex;childRange;[S]'

Key definitions:

*   id: A unique numerical identifier for the call frame.
*   name: A concise string describing the call frame (e.g., 'Evaluate Script', 'render', 'fetchData').
*   duration: The total execution time of the call frame, including its children.
*   selfTime: The time spent directly within the call frame, excluding its children's execution.
*   urlIndex: Index referencing the "All URLs" list. Empty if no specific script URL is associated.
*   childRange: Specifies the direct children of this node using their IDs. If empty ('' or 'S' at the end), the node has no children. If a single number (e.g., '4'), the node has one child with that ID. If in the format 'firstId-lastId' (e.g., '4-5'), it indicates a consecutive range of child IDs from 'firstId' to 'lastId', inclusive.
*   S: **Optional marker.** The letter 'S' appears at the end of the line **only** for the single call frame selected by the user.

....

Embora essa descrição de formato incorra em um custo de token, ele é estático e pago uma vez por toda a conversa. O custo é compensado pela economia obtida com as otimizações anteriores.

Conclusão

Otimizar o uso de tokens é uma consideração importante ao criar com IA. Ao mudar do JSON bruto para um formato personalizado especializado, reindexar árvores com pesquisa em largura e usar chamadas de função para buscar dados sob demanda, reduzimos significativamente a quantidade de tokens que a assistência de IA no Chrome DevTools consome.

Essas otimizações eram um pré-requisito para ativar a assistência de IA para rastreamentos de performance. Devido à janela de contexto limitada, ela não conseguiria processar o grande volume de dados. Mas o formato otimizado permite um agente de performance que pode manter um histórico de conversas mais longo e fornecer respostas mais precisas e contextuais sem ser sobrecarregado por ruídos.

Esperamos que essas técnicas inspirem você a analisar suas próprias estruturas de dados ao projetar para IA. Para começar a usar a IA em aplicativos da Web, acesse Aprenda IA em web.dev.