O primeiro agente que a gente colocou pra valer na operação da Rooftop funcionava bem até alguém perguntar "por quê".
Ele respondia. Respondia rápido, com confiança, e às vezes com uma informação de dez meses atrás que ninguém tinha revisado. Quando eu perguntava de onde tinha vindo aquilo, o melhor que eu conseguia era um trecho recuperado do índice vetorial. Um pedaço de texto sem dono, sem data, sem contexto de quem escreveu e por quê.
Isso não é um problema de modelo. É um problema de registro.
O que estava quebrado
A gente tinha o setup padrão: documentos entram, viram embeddings, agente busca, agente responde. Funciona surpreendentemente bem numa demo e começa a rachar quando o conhecimento envelhece.
Três coisas quebravam com frequência:
Fato sem procedência. O agente afirmava que uma unidade tinha determinado prazo de repasse. Estava num PDF de 2024 que já tinha sido substituído. O índice não tinha como saber disso — pra ele, texto é texto.
Contradição silenciosa. Dois documentos diziam coisas diferentes sobre a mesma regra. O retriever trazia o que estivesse mais próximo semanticamente. Nunca o mais recente, nunca o mais confiável, só o mais parecido.
Nada auditável. Quando um cliente perguntava por que o agente tinha recomendado X, a resposta honesta era "porque o modelo achou". Isso não sobrevive a uma conversa de due diligence.
Passei um tempo tentando resolver isso com prompt. Instrução pra citar fonte, instrução pra dizer "não sei", reranking, filtro por metadado. Melhorou nas margens. O buraco continuou no mesmo lugar: o sistema não tinha um lugar onde conhecimento fosse um registro, com identidade e histórico. Tinha um saco de texto.
A virada: tratar conhecimento como lançamento contábil
A ideia do Credence veio de um lugar meio óbvio depois que você vê: contabilidade resolveu esse problema há seiscentos anos.
Num livro-razão você não sobrescreve um número. Você lança um novo registro que corrige o anterior, e os dois ficam lá. O saldo é uma projeção do histórico, não o histórico em si. Se alguém questiona o saldo, você percorre os lançamentos.
Conhecimento de agente deveria funcionar igual.
No Credence, a unidade não é um chunk. É um Claim: uma afirmação com sujeito, chave, valor, status e evidência. Ela nunca é apagada. O vocabulário é curto de propósito: Claim, Evidence, Source. Unknown não é o mesmo que absent — "não sei" e "não tem" são respostas diferentes, e misturá-las é como misturar saldo zero com conta inexistente.
A escrita no ledger é um recordClaim:
Cada evidência carrega um stance: supports, contradicts ou cited. Omitir o campo significa unstated — e stance nunca é inferido. Status verified recusa evidência que não suporte o claim; unstated ainda passa pelo guard. Quando dois claims vivos discordam no mesmo sujeito e mesma chave, isso vira um finding, não um empate silencioso.
O que isso muda na prática
A parte que eu não esperava é que a maior mudança não foi na qualidade da resposta. Foi na conversa sobre a resposta.
Antes, quando o agente errava, a discussão virava filosofia sobre modelo. Agora abre-se o ledger e vê-se qual claim foi usado, de qual source veio, com que stance e quem registrou. Nove em cada dez erros são erro de entrada, não de raciocínio. Documento velho que ninguém aposentou, planilha que alguém preencheu errado, regra que mudou no WhatsApp e nunca virou documento.
Isso não é glamouroso. É exatamente o tipo de coisa que faz um sistema durar em produção.
Segunda mudança: contradição virou sinal, não bug. Dois claims vivos no mesmo subjectEntityId + key não são fundidos. Viram finding. Alguém decide. Já pegamos regra operacional divergente entre franquias que estava lá havia meses e ninguém tinha percebido — não porque o sistema é esperto, mas porque ele se recusa a fingir consenso.
Terceira: expiração e status passaram a ser explícitos. Cotação de câmbio vale minutos. Regra contratual vale até o aditivo. Nome do responsável pela unidade vale até alguém trocar. Antes tudo tinha a mesma meia-vida, que era infinita.
O que ainda não está resolvido
Não vou vender isso como completo, porque não é.
Extração continua sendo o gargalo. Transformar um PDF de 40 páginas em claims bem formados é trabalho de modelo, e modelo erra. O ledger deixa o erro visível e reversível, o que é bem melhor do que invisível e permanente, mas não impede que ele entre.
Granularidade é decisão de projeto, não de biblioteca. prazo_repasse = 15 é um claim bom. "O contrato é favorável ao franqueado" não é — é opinião comprimida, e vira lixo no ledger. Aprendi isso escrevendo uns trezentos claims ruins primeiro.
Custo de leitura. Projetar o estado vigente a partir do histórico é mais caro que ler um vetor. Cacheamos a projeção e invalidamos por sujeito, que é o mesmo truque de sempre, com os mesmos problemas de sempre.
E o Credence não substitui busca vetorial. Ele fica na frente dela. Vetor continua ótimo pra achar o documento; o ledger é pra afirmar o fato. Confundir as duas coisas foi o erro original.
Por que publicar isso
O pacote é @credence/core 0.6.0 no registry npm.pipedocs.app. A API ainda muda — a gente usa em produção e cada semana revela uma suposição errada.
Publico porque a parte que interessa não é o código, é o enquadramento: o problema de memória de agente é mais parecido com contabilidade do que com busca. Isso me economizaria uns três meses se alguém tivesse dito na minha cara em 2025.
Se você está montando algo parecido, a pergunta que vale fazer cedo é essa: quando seu agente afirmar alguma coisa daqui a um ano, você vai conseguir explicar de onde veio? Se a resposta for não, o problema não está no modelo.
