Construir um agente
Receber, pensar e responder — sem dar ao agente mais do que ele precisa.
Um agente externo que recebe o que o cliente escreveu, decide o que responder e devolve pela Amivu. Tudo pela API — o modelo é seu, a conversa é da Amivu.
O fluxo
webhook message.received
↓
seu agente lê o histórico (opcional) GET /v1/conversations/{id}/messages
↓
seu modelo decide
↓
POST /v1/messages ou nada, se for caso humano
Os escopos, e só eles
Crie uma chave dedicada ao agente, com o mínimo:
conversations:read— para ver o contexto.messages:read— para ler o histórico.messages:write— para responder.notes:write— opcional, para registrar por que ele decidiu o que decidiu.
Não dê `contacts:write` a um agente
Um modelo que pode editar cadastro vai editar cadastro — com um nome mal interpretado, um telefone alucinado. O agente responde; quem muda dado é código determinístico.
O código
JavaScript
app.post("/webhooks/amivu", async (req, res) => {
if (!assinaturaValida(req)) return res.status(401).end();
res.status(200).end();
const { type, data, id: eventoId } = req.body;
if (type !== "message.received") return;
// Entrega é pelo menos uma vez: sem isto, o agente responde duas vezes.
if (await jaProcessado(eventoId)) return;
await enfileirar(async () => {
const historico = await amivu(
`/v1/conversations/${data.conversation.id}/messages?limit=20`,
);
const resposta = await seuModelo({
// Mande o MÍNIMO. O agente não precisa do telefone nem do CPF para
// responder sobre um prazo de entrega.
mensagens: historico.data.map((m) => ({
papel: m.direction === "inbound" ? "cliente" : "atendimento",
texto: m.text,
})),
});
if (!resposta.deveResponder) {
// Sem certeza, quem assume é gente. Uma nota diz por quê.
await amivu(`/v1/conversations/${data.conversation.id}/notes`, {
method: "POST",
body: { body: `Agente não respondeu: ${resposta.motivo}` },
});
return;
}
await amivu("/v1/messages", {
method: "POST",
// Uma resposta por mensagem recebida — a chave é o id do evento.
headers: { "Idempotency-Key": `agente-${eventoId}` },
body: {
conversation_id: data.conversation.id,
type: "text",
text: resposta.texto,
},
});
});
});
Quatro cuidados
- Deduplique pelo
iddo evento. A entrega é pelo menos uma vez, e um agente que responde duas vezes é pior que um que não responde. - Responda o webhook em milissegundos. Chamar o modelo dentro do ciclo da requisição estoura os 10 segundos e faz a Amivu reentregar — e o agente processa de novo.
- Não deixe o agente responder o próprio agente. Só
message.receiveddispara o ciclo;message.sent, nunca. - Tenha uma saída para gente. Fora do assunto, cliente irritado, dúvida jurídica: não responda e atribua a conversa a um time.
POST /v1/conversations/{id}/assignresolve.
A Amivu já tem uma assistente
A Ami responde, sugere e aprende com o acervo da própria organização, sem integração nenhuma. Este guia é para quem quer o seu modelo, com o seu conhecimento — os dois caminhos coexistem.
Veja também Assinaturas.
Escrevemos sobre operação de atendimento, canais e IA no blog da Amivu.