Trocar de modelo no meio da sessão não custa nada

· 4 min de leitura

E isso é uma decisão de design, não um recurso. A maioria das ferramentas de agentes é escrita para um único fornecedor e adaptada aos outros depois. A ordem parece um detalhe de implementação. É a coisa toda.

Adaptar depois significa que as premissas do primeiro fornecedor já estão sustentando o sistema quando o segundo chega. Elas estão no armazenamento das conversas, na forma como uma chamada de ferramenta é representada, na forma como uma resposta em streaming é interpretada — e nenhum desses é um lugar onde alguém pensa em procurar um ano depois. O que você percebe é só o sintoma: trocar de provedor exige uma migração, e uma migração no meio de uma sessão significa que você não troca de provedor.

Onde a premissa se esconde

O lugar óbvio para procurar é a chamada HTTP, e o lugar óbvio está errado. Os endpoints de quaisquer dois fornecedores estão a um fim de semana de trabalho de distância. A parte cara é o que você fez com a resposta.

Pegue um detalhe. A maioria dos fornecedores identifica o resultado de uma ferramenta pelo id da chamada que o produziu. O Gemini o identifica pelo nome da função. Se o seu armazenamento de conversas guarda os resultados de ferramentas do jeito que o fornecedor A os descreveu, então dar suporte ao Gemini não é um novo cliente HTTP — é uma mudança no formato em que já está cada transcrição que você já gravou.

Esse é o problema inteiro em miniatura. Não existe adaptador que resolva, porque a informação foi descartada no momento da gravação.

Histórico neutro

A alternativa é decidir, antes de escrever o primeiro provedor, que o histórico não pertence a nenhum deles.

O OHarness armazena as transcrições das sessões em um formato definido pelo engine (packages/engine/src/core/types.ts), e não no formato de algum fornecedor. Um resultado de ferramenta carrega toolName além de toolCallId — não porque o engine precise dos dois, mas porque o Gemini precisa do nome e todos os outros precisam do id, e a forma neutra tem de poder ser convertida em qualquer um dos dois.

O formato de transmissão de um fornecedor é produzido no momento em que uma requisição sai e descartado quando a resposta é incorporada de volta. Nada persiste nele.

Então trocar de provedor no meio da sessão não converte nada. Não porque a conversão seja rápida, mas porque não existe um formato antigo a partir do qual converter.

O que isso garante, na prática

Um modelo é algo com preço, capacidade, um limite de requisições e uma semana ruim. Quando essas são decisões de outra pessoa e você tem um único modelo, elas passam a ser decisões suas. O sentido de um backend substituível não é novidade — é que o dia em que um provedor muda os termos passa a ser um dia sobre o qual você pode ter uma opinião.

Também faz o caso banal funcionar. Rascunhe com algo barato, troque para algo caro na parte difícil, desça para um modelo na sua própria máquina quando a rede estiver ruim ou o código não deva sair do prédio. Tudo isso é a mesma sessão.

A parte que não é de graça

Sendo honesto sobre a troca: o formato neutro é um compromisso. Cada capacidade que difere entre fornecedores — esforço de raciocínio, cache de prompt, chamadas de ferramentas em paralelo, suporte a imagens — tem de ser expressa como uma flag no modelo em vez de presumida a partir do provedor, porque enviar o formato errado resulta em um 400, e não em uma resposta degradada. É um custo real, pago uma vez, em um lugar onde ele fica visível.

A alternativa é pagá-lo repetidamente, às cegas, durante toda a vida do projeto.


O OHarness é um harness de agentes open source, sob licença MIT. Ele fala nativamente com Anthropic, OpenAI e Google Gemini, com qualquer endpoint compatível com OpenAI e com runtimes locais como Ollama, LM Studio e vLLM. A referência de arquitetura descreve como a separação em camadas é imposta, e não apenas pretendida, e o que é um harness de agentes cobre a ideia em torno disso.