Preparação para entrevista
SmellAcopladores

Vazamento de Formato do Provedor

Provider Format Leak

Vazamento de Formato do Provedor (Provider Format Leak) é um smell de IA, ou seja, um sinal de problema em sistemas com LLM, do grupo Acopladores. O formato de mensagem de um provedor específico se espalhou pelo código de negócio.

Elemento
26/37
Nível
Intermediário
Leitura
4 min
Atualizado
Nesta página 7
  1. 01Como reconhecer
  2. 02Por que acontece
  3. 03Quanto custa ignorar
  4. 04Tratamento
  5. 05O que você ganha
  6. 06Quando ignorar
  7. 07É esse smell?
  8. ··Perguntas rápidas

Como reconhecer

Uma automação de back-office concilia pagamentos e emite notas. O time quer testar outro modelo, de outro provedor, numa das etapas. Uma busca no código mostra o tamanho do problema (anonimizado):

$ grep -rl "tool_use\|stop_reason\|content\[0\]" src/ | wc -l
31

src/billing/reconcile.py:   if resp.stop_reason == "tool_use":
src/billing/reconcile.py:       block = resp.content[0]
src/invoices/emit.py:       args = msg.content[1].input["cnpj"]
src/reports/daily.py:       history.append({"role": "assistant", "content": resp.content})
src/crm/sync.py:            if part["type"] == "tool_result" and part["is_error"]:
...

O formato de mensagem de um provedor específico (tipos de bloco, nomes de campo, motivos de parada) aparece em 31 arquivos de regra de negócio. Trocar o modelo de uma etapa exige mexer em todos.

No emissor de NF-e isso dói na hora: o módulo que monta o XML da nota lê resp.content[0].text, o de conciliação lê choices[0].message, e o job noturno grava o JSON cru da API no Postgres. Três jeitos de dizer “o modelo respondeu”, nenhum deles seu.

Sinais de Vazamento de Formato do Provedor:

  • Código de negócio lê campos específicos da resposta de um SDK (content[0], stop_reason, choices[0].message).
  • Ferramentas devolvem resultados no formato de bloco de um provedor.
  • Históricos de conversa são guardados no banco no formato de um provedor.
  • Testes dependem do formato da resposta bruta.
  • Trocar de modelo ou provedor é estimado em semanas.
flowchart LR
  P(["1. SDK do provedor"]):::llm --> B1["2. reconcile.py"]:::tool
  P --> B2["2. emit.py"]:::tool
  P --> B3["2. sync.py"]:::tool
  P --> DB[("3. Histórico no formato do provedor")]:::store
  1. Um único SDK, com seu formato de mensagem.
  2. Cada módulo de negócio lê esse formato diretamente.
  3. Até os dados guardados ficam presos a ele.
Checagem +20 XP de primeiraO time quer testar um modelo de outro provedor só na etapa de conciliação. A estimativa é 'três semanas, 31 arquivos'. O que essa estimativa denuncia primeiro?

Por que acontece

  • Começa com um provedor só. Usar o formato do SDK direto é o mais rápido. O primeiro tutorial pega choices[0].message.content e segue. Seis meses depois, aquilo está no faturamento, no CRM e no job de NF-e.
  • Copiar exemplos da documentação. O código de exemplo lê os campos do SDK no lugar onde a resposta é usada. Você cola o exemplo dentro de emit.py em vez de atrás de um cliente.
  • Sem camada de adaptação. Ninguém criou um ponto único que converte o formato externo no formato do sistema. Cada módulo fez a sua leitura “só desta vez”.
  • O banco virou arquivo morto do SDK. Gravar o JSON da API parece ótimo para debug. Um ano de conversas fica ilegível para outro provedor, e um campo renomeado na v3 da API quebra o replay dos testes.

A armadilha: adotar uma biblioteca que fala com vários provedores e, na primeira diferença, ler o raw_response. A abstração existe no package.json e morreu no if.

Quanto custa ignorar

  • Preso a um provedor. Comparar ou trocar modelos vira projeto. O eval de um modelo novo não é “apontar outra chave”: é uma refatoração.
  • Fragilidade a atualizações do SDK. Uma mudança de formato quebra vários módulos ao mesmo tempo. O changelog do provedor vira incidente interno.
  • Sem plano B. Quando o provedor fica fora do ar, não há como desviar para outro rapidamente. Veja Refém de um Provedor. Os dois smells andam juntos: aquele é não ter alternativa, este é o formato que impede a alternativa.
  • Testes difíceis. Simular respostas exige reproduzir o formato completo do provedor, com blocos, índices e flags. Um teste de conciliação não deveria saber o que é stop_reason.

OpenAI usa choices[0].message e finish_reason. Anthropic usa lista de blocos em content e stop_reason. Google tem outro envelope. Nenhum desses nomes deveria aparecer em invoices/emit.py.

Tratamento

Refatoração Escolha quando
Normalizar Retorno de Ferramenta O vazamento está na fronteira com modelos e ferramentas. Uma camada fina converte respostas e resultados para tipos do seu domínio, e só ela conhece o SDK.
Expor Ferramenta via MCP As ferramentas estão escritas no formato de um provedor. Expostas por MCP (Model Context Protocol), elas funcionam com qualquer cliente que fale o protocolo. Destino: Adaptador MCP.

O cliente único devolve tipos seus: TextTurn, ToolCall, ToolResult, Stop.completed | Stop.tool | Stop.filtered. Histórico no banco guarda esses tipos. Cada adapter (Anthropic, OpenAI, um terceiro) traduz nas bordas.

function complete(req: DomainRequest) -> DomainResponse:
    # só este módulo importa o SDK
    raw = provider.sdk.messages(to_provider(req))
    return from_provider(raw)

O resto do back-office chama complete. Trocar o modelo da conciliação é configuração mais um adapter, não 31 arquivos.

Isso não apaga recursos exclusivos. Se você usa um modo que só um provedor tem, isole esse modo num adapter específico e deixe o resto do domínio alheio. Não espalhe o campo exclusivo em cinco serviços “porque já está na resposta”.

Checagem +20 XP de primeiraUma biblioteca já abstrai três provedores. Mesmo assim, emit.py lê response.raw.stop_reason para saber se deve emitir a nota. O que você faz?

O que você ganha

  • O SDK aparece em um módulo, não em trinta.
  • Testar outro modelo numa etapa vira uma mudança de configuração.
  • Dados guardados num formato seu, que sobrevive à troca de provedor.
  • Testes que simulam respostas no formato do domínio, mais simples.

Quando ignorar

  • Um script pequeno, com um provedor e sem plano de trocar. Uma camada de adaptação é peso morto. Se o script crescer para um serviço, a camada entra no primeiro refactor.
  • Recursos exclusivos de um provedor. Se você depende de um recurso que só um provedor tem, aceite o acoplamento nesse ponto e isole-o, em vez de esconder num formato genérico que não o representa.

É esse smell?

Checagem +20 XP de primeiraO código chama o SDK em um único módulo llm_client.py, que devolve objetos do domínio (Classification, ToolCall). Os outros módulos só usam esses objetos. É Vazamento de Formato do Provedor?

Checagem +20 XP de primeiraO histórico das conversas é guardado no banco exatamente como a API devolve, com os tipos de bloco do provedor. Qual é o risco?

Checagem +20 XP de primeiraO time usa uma biblioteca que abstrai vários provedores. Mesmo assim, o código lê campos específicos de um provedor através de um raw_response. O que está acontecendo?

Checagem +20 XP de primeiraUm único módulo usa um modo exclusivo de um provedor (um tipo de ferramenta que os outros não têm), atrás de um adapter. O restante do sistema não vê o campo. É Vazamento de Formato do Provedor?

Perguntas rápidas

O que é Vazamento de Formato do Provedor?

Vazamento de Formato do Provedor (Provider Format Leak) é um smell de IA, ou seja, um sinal de problema em sistemas com LLM, do grupo Acopladores. O formato de mensagem de um provedor específico se espalhou pelo código de negócio.

Como corrigir Vazamento de Formato do Provedor?

Com Normalizar Retorno de Ferramenta e Expor Ferramenta via MCP. Cada refatoração traz o passo a passo seguro, com eval antes e depois.

Onde Vazamento de Formato do Provedor aparece na prática?

Nos cenários reais Automação de back-office com execução durável.

Para ir além

Relações

Buscar