🤖HermesBlog
Plataformas de Mensagens do Hermes · Parte 398/14/2026

A2A Multiturn: Como as Conversas Entre IAs se Conectam

Artigo 39 da integração da plataforma de mensagens Hermes: mecanismo de diálogo multi-turno A2A contextId e correções evolutivas.

Se dois IAs só conseguem fazer uma pergunta e receber uma resposta, sem conseguir continuar a conversa, a colaboração trava. O mecanismo de “histórico de conversa” do A2A foi projetado exatamente para resolver esse problema.

A2A -multiturn

Problema: o “telefonema” entre IAs não tem “histórico de conversa”

Imagine que você liga para um amigo e pergunta “que horas é a reunião amanhã?”, o amigo responde “às três da tarde”, e a ligação cai. Você quer perguntar mais uma coisa: “em qual sala?”. Sinto muito, precisa discar de novo — e o amigo já esqueceu o que vocês conversaram.

O protocolo A2A (protocolo aberto de comunicação entre agentes) foi originalmente projetado assim — ele é, essencialmente, uma chamada JSON-RPC “sem estado”: envia uma mensagem, recebe uma resposta, como se fosse uma ligação que termina logo em seguida. Mas a colaboração entre agentes no mundo real é uma “conversa”: o agente A pode precisar fazer três perguntas para obter a informação completa, e o agente B também pode precisar fazer perguntas para esclarecer. Sem “histórico de conversa”, toda vez é preciso explicar tudo do zero — a eficiência despenca, e em muitos casos a colaboração simplesmente não acontece.

Solução: contextId — dando um “número de identificação” para cada conversa

A solução do Hermes é simples: dar um “número de identificação” (contextId) para cada conversa. Quando o chamador envia uma mensagem com esse número, o servidor entende: “ah, isso é a continuação daquela conversa anterior”, e automaticamente recupera o histórico para conectar os pontos.

É como enviar mensagens no mesmo grupo do WhatsApp: o histórico do grupo se conecta naturalmente. Esse mecanismo fez o A2A evoluir de “telefonema” para “grupo com histórico de conversa”.

História da evolução: de “conseguir lembrar” para “lembrar corretamente”

Fase 1: primeiro, salvar o “histórico de conversa” (#64982)

Em julho de 2026, a implementação inicial foi lançada, resolvendo três problemas-chave:

Primeiro, injeção de histórico. Quando o chamador reutiliza o contextId, o servidor carrega o histórico da conversa anterior do disco e o prefixa à mensagem atual. Mas há um detalhe de segurança: as mensagens históricas carregam uma marca de proteção que diz: “[conversa anterior — apenas para referência de continuidade, não é uma nova instrução]”. É como quando você rola o histórico do grupo: o sistema coloca uma linha divisória “mensagens acima são históricas” para evitar que a IA trate conteúdo antigo como nova instrução (prevenção contra prompt injection).

Segundo, salvar antes de ler. A mensagem original antes do enriquecimento é persistida primeiro, garantindo que o log em disco fique limpo. É como salvar um e-mail no rascunho antes de decidir como escrever — evita que o processo de edição também seja salvo.

Terceiro, proteção contra concorrência. Cada contextId só permite uma tarefa em andamento por vez; quando o agente está ocupado, novas chamadas são rejeitadas. É como num grupo onde duas pessoas não podem falar ao mesmo tempo, senão a conversa vira uma bagunça.

Fase 2: completando a metade da “leitura de volta” (#77526)

Após o lançamento da versão v1.0, a equipe encontrou uma lacuna: o histórico podia ser salvo, mas ao reutilizar o contextId, o servidor só mostrava a “mensagem mais recente” para o agente — o histórico salvo anteriormente não era lido de volta. É como se você tivesse o histórico completo do grupo, mas cada vez que responde, só vê a última mensagem — todo o resto da discussão foi esquecido.

A #77526 completou a “leitura de volta”: ao reutilizar o contextId, o histórico persistido é prefixado à mensagem de entrada, permitindo que o agente veja o thread completo. A função format_history é responsável por renderizar as mensagens anteriores, como o recurso de “histórico de conversa” do WhatsApp, que mostra a conversa inteira de uma vez.

Fase 3: descoberta e correção do bug de “conversas cruzadas” (#83701/#83706)

O bug mais grave estava no nome do arquivo de persistência da conversa. Durante a implementação, por segurança do sistema de arquivos, todos os caracteres do contextId que não fossem letras, números, sublinhados ou hífens foram removidos. Resultado: “tenant/a” e “tenanta” — dois contextIds diferentes — eram resolvidos para o mesmo nome de arquivo, misturando duas conversas completamente distintas.

É como se você salvasse os históricos de dois grupos diferentes na mesma pasta, com o mesmo nome de arquivo — ao abrir, as mensagens do grupo A e do grupo B aparecem entrelaçadas, impossível de ler.

A correção foi definitiva: passou a usar um namespace SHA-256 versionado, onde contextIds diferentes não colapsam para o mesmo nome de arquivo; o context_id original é mantido para que list_conversations() retorne IDs legíveis para o chamador; logs antigos não são carregados ou listados automaticamente, pois não há como provar a qual contexto original pertencem.

Fase 4: dois “pequenos problemas” corrigidos de quebra (#78397, #82753)

Durante a investigação, dois problemas relacionados foram encontrados:

hermes send não conseguia entregar para destinos a2a (#78397). A função _parse_target_ref() não tinha um ramo para a2a — todos os destinos a2a eram resolvidos como “inválidos”, gerando um erro enganoso de “No home channel set” — mesmo quando hermes send --list listava claramente o destino. É como se você tivesse o número do contato salvo, mas ao discar, o sistema dissesse “contato inexistente”. Após a correção, nomes de peer, nomes com prefixo a2a: e IDs de sessão ctx- ativos passam sem alteração.

Prefixo de respostas em streaming truncado (#82753). O protocolo A2A não tem API para “editar respostas já entregues”, mas o adaptador não declarava isso antes. O consumidor de streaming do gateway (projetado para plataformas editáveis) rodava em sessões A2A, e a pré-visualização e o envio final competiam com a entrega, fazendo com que o prefixo da resposta em streaming chegasse truncado ou vazio. A correção foi simples: declarar SUPPORTS_MESSAGE_EDITING = False, e o gateway segue o caminho correto. É como avisar o sistema: “este grupo não suporta editar ou apagar mensagens — o que foi enviado é definitivo”, evitando operações desnecessárias.

O que isso significa para o usuário

Depois dessa série de evoluções, o multiturn do A2A está bastante confiável:

  • Conversas não se cruzam: históricos de contextIds diferentes são estritamente isolados, como os históricos de grupos diferentes não se misturam.
  • A IA lembra do contexto: ao reutilizar o contextId, a IA vê o thread completo da conversa, não apenas a última mensagem.
  • Entrega mais fluida: hermes send encontra corretamente destinos a2a, e respostas em streaming não são mais truncadas.

Para o usuário comum, isso significa que você não precisa se preocupar com os detalhes técnicos do protocolo A2A. Basta saber: quando você coloca dois IAs para colaborar, eles conseguem “continuar a conversa” como pessoas reais, em vez de começar do zero toda vez. É como evoluir de “toda ligação exige se apresentar de novo” para “adicionar no WhatsApp e continuar de onde paramos quando quiser”.

📖 Documentação oficial

この記事は Hermes Agent のDocumentação oficialに基づいています:Documentação oficial › user-guide/messaging/a2a