Um cliente escreve: "no dia 3, o assistente me disse que o meu contrato cobria X". Você abre o sistema e descobre que não tem como saber o que foi respondido, com qual prompt, com quais documentos recuperados nem com qual versão do modelo.
Aplicação de LLM é não determinística. Sem registro, ela é literalmente impossível de depurar — você não consegue nem reproduzir o caso. Isso não é um refinamento para a fase 2; é a primeira coisa a montar, e leva algumas horas.
A tabela
CREATE TABLE chamadas_ia (
id TEXT PRIMARY KEY,
criado_em TIMESTAMP NOT NULL, -- em UTC, com fuso explícito
usuario_id TEXT,
sessao_id TEXT, -- agrupa a conversa
fluxo TEXT NOT NULL, -- 'atendimento', 'resumo', 'classificacao'
modelo TEXT NOT NULL,
versao_prompt TEXT NOT NULL, -- 'atendimento-v7'
temperatura REAL,
entrada_hash TEXT NOT NULL, -- para agrupar repetidos
entrada_texto TEXT, -- conforme a política de retenção
saida_texto TEXT,
documentos_ids TEXT, -- o que a busca recuperou
tokens_entrada INTEGER NOT NULL,
tokens_saida INTEGER NOT NULL,
custo_brl REAL NOT NULL,
ttft_ms INTEGER,
duracao_ms INTEGER NOT NULL,
status TEXT NOT NULL, -- ok | erro | bloqueado | timeout
motivo_bloqueio TEXT,
feedback INTEGER -- +1 / -1, quando o usuário der
);
CREATE INDEX idx_chamadas_data ON chamadas_ia(criado_em);
CREATE INDEX idx_chamadas_fluxo ON chamadas_ia(fluxo, criado_em);
CREATE INDEX idx_chamadas_status ON chamadas_ia(status, criado_em);
Dez minutos para criar, e ela responde praticamente toda pergunta que vai aparecer nos próximos dois anos.
versao_prompt — sem ela, você não consegue relacionar uma piora com a mudança que a causou. Versione o prompt como código e grave a versão em cada chamada.
documentos_ids — quando a resposta estiver errada, a primeira pergunta é "o trecho certo foi recuperado?". Sem os identificadores, não há resposta.
fluxo — sem separar por fluxo, o custo total não diz nada. Com ela, você descobre em cinco minutos qual funcionalidade consome 80% da fatura.
O que NÃO guardar
Registro é dado pessoal quando contém conversa de usuário. Três decisões que evitam problema:
- Prazo de retenção definido para o texto (30, 60, 90 dias) e apagamento automático. O agregado — tokens, custo, latência, status — pode ficar para sempre, porque não identifica ninguém.
- Mascaramento na gravação: CPF, cartão, telefone e endereço substituídos por marcador antes de escrever no registro. O filtro de entrada que você já tem serve para isso.
- Nunca grave a chave de API nem o conteúdo de cofre, nem em registro de erro. É o vazamento mais comum e o mais bobo.
Bibliotecas costumam despejar a requisição inteira no traço da exceção — com prompt, dados do usuário e cabeçalho de autorização. Filtre o que vai para o registro de erro com o mesmo rigor do registro normal.
As cinco consultas que você vai rodar toda semana
Para onde vai o dinheiro
SELECT fluxo, modelo,
COUNT(*) AS chamadas,
ROUND(SUM(custo_brl), 2) AS custo,
ROUND(AVG(tokens_entrada)) AS entrada_media
FROM chamadas_ia
WHERE criado_em > datetime('now', '-7 days')
GROUP BY fluxo, modelo
ORDER BY custo DESC;
Quase sempre revela um fluxo consumindo desproporcionalmente. E, com entrada_media na tabela, você já vê se a causa é contexto inflado.
O que está falhando
SELECT status, motivo_bloqueio, COUNT(*) AS n
FROM chamadas_ia
WHERE criado_em > datetime('now', '-1 day')
GROUP BY status, motivo_bloqueio
ORDER BY n DESC;
Latência sem a mentira da média
SELECT fluxo,
COUNT(*) AS n,
ROUND(AVG(ttft_ms)) AS ttft_medio,
MAX(ttft_ms) AS ttft_pior
FROM chamadas_ia
WHERE criado_em > datetime('now', '-1 day') AND status = 'ok'
GROUP BY fluxo;
As perguntas que se repetem
SELECT entrada_hash, COUNT(*) AS n, ROUND(SUM(custo_brl), 2) AS custo
FROM chamadas_ia
WHERE criado_em > datetime('now', '-30 days')
GROUP BY entrada_hash
HAVING n > 20
ORDER BY custo DESC;
É a consulta que justifica cache: se vinte perguntas idênticas somam um custo relevante, você acabou de achar dinheiro parado.
O que o usuário reprovou
SELECT id, criado_em, versao_prompt, saida_texto
FROM chamadas_ia
WHERE feedback = -1 AND criado_em > datetime('now', '-7 days')
ORDER BY criado_em DESC;
Cada linha dessa consulta é candidata a caso no conjunto de avaliação. É o circuito que faz o sistema melhorar sozinho ao longo dos meses.
Colete o feedback — mas colete direito
Dois botões de polegar rendem pouco: a taxa de resposta fica abaixo de 2% e vem enviesada para o extremo negativo. Duas coisas que aumentam bastante o sinal:
- Pergunte só de vez em quando, em uma a cada dez conversas, em vez de sempre. A taxa de resposta sobe.
- Registre sinais implícitos, que não pedem nada do usuário: refez a mesma pergunta em seguida (sinal ruim), copiou a resposta (sinal bom), abandonou a conversa logo depois (sinal ruim), pediu para falar com atendente (sinal ruim e específico).
Os sinais implícitos têm cobertura de 100% e, na prática, são mais informativos que o polegar.
Alarmes que valem a pena
| Alarme | Limiar sugerido | Por que importa |
|---|---|---|
| Custo diário acima do normal | 2× a média de 7 dias | Ciclo de agente, abuso ou bug de contexto |
| Taxa de erro | > 2% em 15 min | Provedor instável ou falha do seu lado |
| Taxa de bloqueio | > 5% | O prompt ou o modelo regrediram |
| TTFT do percentil 95 | > 2× o normal | Fila no servidor ou contexto inflado |
| Um usuário sozinho | > 10% do custo do dia | Automação de cliente ou uso indevido |
O último merece nota: em produto com API, um único cliente integrando de forma ineficiente pode multiplicar o seu custo em um dia. Esse alarme paga o esforço de montar o registro sozinho.
O painel já mostra consumo por chave e por modelo
Custo em reais, no mesmo saldo das GPUs — e você complementa com o seu registro por fluxo para saber onde vaza.
Criar conta →A investigação, quando alguém reclama
Com a tabela acima, o roteiro é mecânico:
- Ache a chamada por usuário e data.
- Olhe
versao_prompt— era a versão atual ou uma anterior? - Olhe
documentos_ids— o trecho certo foi recuperado? Se não, o problema é a busca, não o modelo. - Se foi recuperado e a resposta ignorou, o problema é a geração — vire o caso em teste.
- Reproduza com a mesma versão de prompt e temperatura zero. Se não reproduzir, foi variação aleatória: baixe a temperatura naquele fluxo.
Cinco minutos de trabalho, em vez de uma tarde de suposição. É exatamente essa diferença que o registro compra.
Conclusão
Uma tabela e cinco consultas. É o que separa "acho que ficou pior depois da última mudança" de "a versão 7 do prompt caiu 9 pontos no fluxo de atendimento, e a causa foram estes doze casos".
Monte antes de precisar. Quando o cliente reclamar da resposta de três semanas atrás, ou o dado está lá, ou a conversa acaba em "não temos como verificar" — que é a pior frase possível.
Continue: avaliação automática · onde vaza o custo · latência