JSON viabilizou seus microsserviços. Também está estrangulando silenciosamente sua stack de IA. Se seus embeddings, chamadas de ferramentas e logs de agentes ainda trafegam como strings legíveis, você está pagando um imposto de 2–4x em largura de banda e CPU a cada chamada. Isso é dinheiro, latência e orçamento de SLO que você não recupera.
O “Protobuf para Python, sem concessões” que apareceu no Hacker News este mês é o empurrão que faltava. O esforço protobuf-py removeu muitas armadilhas e penhascos de performance no Python. Tradução: a última boa desculpa para continuar enviando JSON dentro do seu plano de dados de IA morreu.
Como é o imposto do JSON em 2026
Embeddings
Pegue um embedding típico de 1.536 dimensões em float32 (6.144 bytes brutos). Se você serializar isso como um array JSON de números, cada valor costuma custar 8–12 bytes ASCII mais pontuação. Em um conservador 9 bytes por valor, dá ~13,8 KB por vetor. Se você base64 os floats brutos (um hack comum), base64 infla exatamente 33%: 6,0 KB viram ~8,2 KB.
Então, o mesmo vetor fica:
- 6,1 KB como binário (float32)
- 8,2 KB como base64 (binário-em-texto)
- ~13,8 KB como números JSON
Chame isso de uma penalidade de 2,3x do JSON vs binário. Multiplique por 10 milhões de embeddings por dia (nada absurdo se você roda RAG a 100 QPS): você está movendo ~77 GB de bytes desnecessários por dia. A $0.05–$0.09/GB de egresso, isso dá $3.8–$6.9K/mês queimados no ar — antes dos custos de CPU.
Chamadas de ferramentas e traces de agentes
Frameworks de agentes adoram enfiar tudo em JSON: entradas de ferramentas, saídas, artefatos intermediários. Isso é amigável para o desenvolvedor, não para a máquina. Entregue um blob JSON de 150 KB ao parser do Python e você paga dezenas a centenas de microssegundos de CPU por salto. Decodificadores Protobuf/FlatBuffers são tipicamente 3–5x mais rápidos que o parsing de JSON do Python em apps reais, e não alocam strings para cada número separado por vírgula.
Logs e métricas
Até logs ficam feios. Times transmitem logs de tokens e eventos semânticos como JSON via SSE ou WebSocket. Ótimo para um navegador. Péssimo entre serviços. É comum ver 5–10x mais bytes no fio do que o conteúdo informacional real, e tudo precisa ser parseado antes de ser útil.
Matriz de decisão: o que vai para onde
Não existe um martelo único. Use o formato no fio certo por faixa do seu plano de dados de IA. O teste: você consegue mover, decodificar e indexar o payload em menos de 100 microssegundos por 100 KB no seu nó mediano, com folga? Se não, mude o formato.
Faixa 1: Chamadas de ferramentas e ações de agentes (RPC)
- Escolha: gRPC com Protobuf.
- Por quê: Contratado, versionável, multiplexação HTTP/2, streaming, testado em stacks poliglotas. Com os bindings modernos de Python (protobuf‑py), você evita os buracos de reflexão/GC que historicamente doíam.
- Notas: Use oneof para variantes de saída de ferramentas, reserve números de campo para evolução e fique em tipos numéricos primitivos quando possível. Mantenha blobs fora de banda (armazenamento de objetos) e passe referências endereçáveis pelo conteúdo.
Faixa 2: Embeddings e vetores de features em lote (bulk)
- Escolha: Apache Arrow para memória/IPC e Arrow Flight para transporte em rede; Parquet para armazenamento.
- Por quê: Colunar, zero‑copy, amigável a SIMD. Arrow empacota uma coluna float de 1.536 dimensões em memória de forma compacta e envia sem transformar floats em texto. Flight entrega streaming com backpressure sobre gRPC sem reinventar semânticas de batch.
- Notas: Mantenha tamanhos de lote entre 64 KB e 4 MB para throughput sem head‑of‑line blocking. Prefira float16/bfloat16 onde aceitável; documente os trade‑offs de precisão.
Faixa 3: Streaming em tempo real para navegadores (borda)
- Escolha: Mantenha JSON ou JSON Lines para Server‑Sent Events no navegador. Comprima com gzip ou zstd e limite o tamanho dos eventos.
- Por quê: Navegadores gostam de texto. Não lute contra a plataforma na borda. Force todos os streams servidor‑a‑servidor para um formato binário.
- Notas: Se precisar transmitir binário ao navegador, use WebTransport ou WebSocket com ArrayBuffer. Espere problemas de compatibilidade mais amplos que com SSE.
Faixa 4: Caches e filas internas
- Escolha: Use valores binários em Redis/Valkey. Para Kafka/Pulsar, use Protobuf ou Avro com registry de esquemas.
- Por quê: Valores JSON em caches quentes explodem memória e CPU. Tópicos com schema evitam drift de consumidores e permitem evoluir campos sem reprocessamento manual.
Os números duros (e uma checagem rápida de ROI)
- Carga de trabalho: Média de 120 QPS, cada requisição grava um embedding float de 1.536 dimensões em um feature store e publica um trace de chamada de ferramenta de ~50 KB.
- Base em JSON: Embedding ~13,8 KB + trace 50 KB = ~63,8 KB/requisição. Isso é ~7,6 MB/s ou 657 GB/dia entre serviços.
- Refatoração para binário: Embedding 6,1 KB + trace 15 KB (protobuf, levemente comprimido) = ~21,1 KB/requisição. ~2,5 MB/s ou 218 GB/dia.
- Economia: ~439 GB/dia. A $0.05–$0.09/GB de egresso: $657–$1.183/mês só em egresso. As economias de CPU geralmente superam isso: a redução de parsing de JSON e de GC pela sua frota pode liberar 5–20% de CPU em serviços quentes, o que, aos preços atuais de instância, é dinheiro de verdade.
Note como isso compõe rapidamente em topologias multi‑região ou de fan‑out.
Design de esquemas: não recrie seu espaguete de JSON em Protobuf
Você não ganha trocando chaves por varints. Você ganha impondo estrutura.
- Separe blobs de metadados: Coloque grandes arrays binários (embeddings, imagens) em campos ou streams dedicados. Mantenha metadados enxutos e tipados.
- Use oneof para variantes: Resultados de ferramentas devem ser um tipo algébrico, não um objeto JSON com chaves ad‑hoc. Por exemplo, result pode ser um de: search_result, file_write, http_call.
- Versione para frente, não para trás: Adicione campos com novos números. Nunca reaproprie um número de campo. Use feature flags ou negociação de capacidades, não adivinhação.
- Escolha a precisão numérica de forma intencional: float16/bfloat16 reduz à metade a banda em relação a float32. Para cosseno e ANN, geralmente está ok. Documente onde não está.
- Defina limites: Tamanho máximo de arrays, tamanho máximo de strings. Faça cumprir na decodificação. Seu plano de dados de IA faz parte do seu perímetro de segurança.
Navegador: JSON na borda, binário por dentro
“Mas o nosso frontend em TypeScript…” Claro. Mantenha JSON na fronteira. Use gRPC‑Web ou Connect para compatibilidade com o navegador se quiser APIs fortemente tipadas; eles podem falar JSON no fio com o navegador enquanto seu servidor fala Protobuf internamente.
A regra: nada de JSON depois da camada de borda. Frontends falam JSON ou JSON Lines com a borda; todos os links entre serviços são binários. Se você precisar passar embeddings para um navegador (raro), envie como ArrayBuffer em um WebSocket ou WebTransport, não como strings base64 em JSON.
Maturidade das ferramentas em 2026: as desculpas acabaram
- Python: As camadas mais novas de protobuf‑py são mais rápidas e menos mágicas. Funcionam bem com type checkers e evitam o churn de GC que wrappers antigos causavam. Os bindings de Python do Apache Arrow estão estáveis e prontos para produção; Arrow Flight funciona com asyncio.
- TypeScript/Go/Java: Compiladores e bibliotecas gRPC de primeira classe. Workflows baseados em Buf impõem regras de breaking change de API no CI.
- FlatBuffers e Cap’n Proto: Se seu caso pede leituras in‑place e latência ultra‑baixa, considere esses. O trade‑off é uma curva de aprendizado maior e ergonomia multi‑linguagem mais áspera que Protobuf. Use para hot paths, não em todo lugar.
- Registries de schema: Registries no estilo Confluent não são só para Avro. Mantenha um repositório de arquivos .proto com regras de lint e docs geradas; trate como fonte de verdade.
Plano de migração: 30, 60, 90 dias
Dia 0–30: Meça e delimite o problema
- Instrumente payloads: Logue tamanhos no fio e tempos de parse por rota e serviço. Amostre 1–5% do tráfego se precisar. Marque com content type.
- Escolha dois pilotos: Um RPC (um endpoint de chamada de ferramenta movimentado). Um job em lote (ingestão de embeddings).
- Decida formatos: gRPC+Protobuf para o RPC; Arrow Flight para o job em lote. Combine por escrito a política de nomes de campos e de versionamento.
Dia 31–60: Construa o dual‑stack
- Gere tipos: Faça o land de arquivos .proto em um repositório compartilhado. Gere bindings de linguagem como parte do CI (ts‑proto para TS, protobuf‑py ou protoc‑gen‑mypy para Python).
- Implemente adaptadores: Para os endpoints escolhidos, produza e consuma JSON e Protobuf em paralelo. Controle por header ou caminho versionado.
- Testes de compatibilidade de wire: Crie fixtures binários canônicos e testes de ida e volta entre linguagens. Adicione uma passada de fuzz para decodificadores com limites de tamanho para capturar bombas de parsing.
- Ganchos operacionais: Emita métricas: decode_failures, decode_latency_p99, payload_ratio (json_bytes/binary_bytes) e banda por rota.
Dia 61–90: Vire a chave, depois espalhe
- Política de borda: Faça cumprir “JSON só na borda”. Bloqueie JSON em links internos com Envoy ou política do service mesh (lista de content‑type permitidos).
- Acabe com base64: Para qualquer payload binário que permaneça em transportes de texto, substitua blobs base64 por referências de armazenamento de objetos ou streams binários.
- Cronograma de rollout: Migre um hot path por semana. Espere reduções de 20–40% de banda por salto e folga visível de CPU.
- Checagem de custos: Após 30 dias, compare egresso e CPU antes/depois. Reinvista CPU liberada em SLOs de latência ou em redução de instâncias.
Guardrails operacionais
- Observabilidade: Erros de parse precisam ser incidentes de primeira classe. Alerta em qualquer pico. Mantenha histogramas por formato de tempos de decodificação e tamanhos.
- Backpressure: Use limites de stream de HTTP/2 e Flow Control no gRPC. Para Arrow Flight, limite batches in‑flight por par.
- Segurança: Trate seus desserializadores como trata seus clientes SQL: faça fuzz, limite e, se puder, mantenha fora do pool de threads de requisição.
- Retenção de dados: Mantenha payloads binários de vida curta. Persista apenas fatos de negócio. Para analytics, converta para Parquet com schema explícito e TTL.
Trade‑offs que você deve encarar
- Depurabilidade: Você perde a facilidade do “é só dar curl”. Contraponha com ferramentas de CLI para pretty‑print de Protobuf e Arrow, e inclua-as nas imagens de desenvolvimento.
- Atrito no navegador: gRPC‑Web e Connect resolvem muita coisa, mas você ainda vai manter JSON na borda externa. Tudo bem — mantenha-o lá.
- Curva de aprendizado do time: Seus engenheiros precisarão aprender evolução de schema e disciplina de numeração de campos. Vale a pena; imponha com linters e diffs no CI.
- APIs de terceiros: Alguns vendors de DB vetorial ainda fazem default para arrays JSON. Onde possível, use APIs binárias/em lote. Caso contrário, converta na borda do seu sistema, não nos caminhos quentes internos.
Casos de exceção: quando JSON é suficiente
- Endpoints pequenos e raramente chamados: JSON é perfeitamente ok para uma leitura de configurações ou uma ferramenta de admin pontual.
- APIs públicas com ecossistemas amplos de clientes: Mantenha JSON para alcance e limite explicitamente os payloads. Ofereça uma variante binária para parceiros.
- Logs com humano no loop: Se um payload só é lido por um humano no navegador, priorize legibilidade e compacte agressivamente.
Uma regra simples para institucionalizar
Binário por dentro; JSON por fora. Coloque isso num pôster. Crie uma regra no CI que bloqueie novos campos JSON em endpoints internos. Adicione um tile no dashboard que mostre sua razão de tráfego JSON‑para‑binário caindo semana a semana. E comemore a primeira vez que você deleta 20% de uma frota de serviços sem ferir um SLO.
Os mais velhos da Internet nos levaram a um mundo de texto interoperável. A próxima década de IA é sobre throughput, latência e unit economics. Isso significa contratos que você consegue evoluir e bytes que valem o que ocupam. Você não precisa reescrever o mundo — só pare de pagar um imposto desnecessário.
Principais pontos
- JSON infla embeddings e traces em 2–4x vs binário, e base64 adiciona 33% fixos de overhead. Isso é dinheiro e latência de verdade.
- Use gRPC+Protobuf para chamadas de ferramentas, Arrow/Flight para embeddings e features em lote, e valores binários em caches/filas.
- Mantenha JSON na borda do navegador; imponha binário dentro da malha. Migre faixa a faixa com endpoints dual‑stack.
- Meça tamanho de payload e latência de decodificação; mire em menos de 100 microssegundos por 100 KB no nó mediano.
- Espere 20–40% de economia de banda por salto e 5–20% de folga de CPU em serviços quentes após a migração.
- O ecossistema está pronto em 2026: protobuf‑py moderno, Arrow maduro e tooling forte para TS/Go/Java tiram as desculpas anteriores.