Summitview Studio

Trocamos um LLM comercial por motor próprio — e achamos 23 documentos onde ele achava 1

A LicitaSmart lê editais públicos brasileiros e diz para a empresa em quais ela tem chance real de ganhar. A primeira versão rodava sobre a API de um LLM comercial. A gente tirou esse LLM e construiu um motor próprio — não para economizar, mas porque o modelo comercial estava jogando informação fora em silêncio. Isto é o que mudou, medido.

23–24Documentos de habilitação extraídos por edital, onde o modelo comercial achava 0–3
0 → dezenasOportunidades reais por semana, saindo de zero positivos em 3.000 matches
100%Inferência em infraestrutura própria — nenhum LLM de terceiro na esteira
−86%Custo mensal de inferência e infraestrutura

O problema que ninguém enxerga até medir

O governo brasileiro compra mais de R$ 1 trilhão por ano e publica cada licitação como PDF — muitas vezes com dezenas de anexos, cada um guardando exigências que decidem se a empresa é habilitada ou não. Empresa de porte médio não dá conta desse volume. É esse o produto: ler tudo, dar nota de aderência e dizer onde existe chance real.

A versão um usava a API de um LLM comercial para leitura e match. Funcionava, no sentido de que devolvia resposta. A falha era invisível até a gente testar direito — e vinha em duas formas.

LLM comercial

0–3

Documentos de habilitação extraídos de um edital que continha 23. Lia o documento parcialmente e descartava o resto — em silêncio, com saída confiante.

Motor próprio

23–24

O mesmo edital, lido de ponta a ponta, incluindo todos os anexos. Nada resumido fora, porque nada foi pulado antes.

A segunda falha era pior e mais difícil de perceber: nos 3.000 matches mais recentes da base, a esteira comercial tinha produzido zero positivos. Não poucos. Zero. Todo dia passavam oportunidades que o cliente poderia ter vencido — e nada na interface sugeria que havia algo errado. Um sistema que não acha nada tem exatamente a mesma cara de um mercado onde não há nada.

Por que o modelo não era o problema

O instinto é culpar a qualidade do modelo e comprar um maior. Essa leitura está errada, e é por isso que este case vale ser publicado.

O modelo comercial truncava porque a esteira em volta dele foi desenhada para triar — filtrar edital por palavra-chave, escolher os anexos "relevantes", resumir cedo para economizar token. Cada uma dessas decisões se defende no custo, e cada uma joga fora exatamente a informação que decide a habilitação. A exigência que desclassifica uma empresa raramente está no documento principal. Está no anexo sete.

Então reconstruímos em cima de quatro princípios — e foram eles, não o modelo, que produziram o resultado:

  • Ler o edital inteiro. Sem triagem por palavra-chave antes da leitura. Baixa tudo, lê tudo, e o match decide sobre o conteúdo completo.
  • Ler todos os anexos. Não os relevantes. Todos.
  • Nunca deixar um modelo produzir um número. Valores e itens vêm da API oficial de compras. Modelo de linguagem que lê preço pode alucinar preço.
  • Guardar o edital decomposto, não resumido. O ativo não é o resumo bonito — é o documento inteiro, página a página, com tabelas e itens, recuperável depois.

A arquitetura

Tudo abaixo roda em infraestrutura própria. Nenhum LLM de terceiro é chamado em nenhuma etapa.

1

Ingestão — ler tudo, preservando a estrutura

Cada anexo é baixado e processado com PyMuPDF, quebrado página a página junto com as tabelas, e gravado num banco local. É a camada que define o teto de tudo que vem depois: o que não é ingerido nunca poderá ser encontrado.

2

Itens — da fonte, com zero IA

Quantidades e valores vêm direto do endpoint oficial /itens do PNCP. Determinístico, auditável e imune a alucinação. A regra é simples: modelo de linguagem lê linguagem, API fornece número.

3

Extração — map-reduce sobre o documento inteiro

Um Qwen 2.5 7B hospedado localmente lê o edital em blocos e extrai o resumo, os documentos de habilitação e os itens — map-reduce em vez de uma passada truncada, que é exatamente por que nada se perde no fim de um documento longo.

4

Match — três camadas, não uma

Filtro por palavra-chave, depois embeddings multilíngues de sentença (paraphrase-multilingual-mpnet-base-v2) para similaridade semântica, e então um modelo local atuando como juiz, que devolve nota com justificativa escrita. Três camadas porque cada uma erra de um jeito diferente, e a combinação cancela esses erros.

5

Score supervisionado — treinado no nosso próprio histórico

Sobre os embeddings, um classificador de gradient boosting (XGBoost) treinado no histórico de compatibilidade acumulado pelo produto, mais um cross-encoder multilíngue com fine-tune. Avaliado com validação cruzada em AUC-PR, ROC-AUC e Precision@K — average precision porque as classes são muito desbalanceadas e acurácia simples elogiaria um modelo que diz "não" para tudo.

O que a camada semântica realmente corrigiu

Duas falhas reais do sistema antigo mostram por que busca por palavra-chave não funciona na linguagem de licitação:

  • Parou de casar o que era errado. Uma gráfica que vendia material "descartável" estava sendo casada com editais de fralda descartável. Mesma palavra, negócios sem relação.
  • Passou a casar o que era certo. Uma empresa de "locação de veículos com motorista" agora casa com edital de "transporte escolar" — nenhuma palavra em comum, mesmo serviço. Esse match vale dinheiro de verdade, e busca por palavra-chave jamais o encontraria.

A decisão que mais diz sobre como a gente constrói

Quando amarramos a notificação ao resumo — o cliente só é avisado depois que o edital foi de fato lido —, alguém propôs uma válvula de escape: se o prazo estivesse acabando e o resumo não estivesse pronto, avisar assim mesmo.

Foi recusado. O sistema não alerta sem a análise por trás, mesmo ao custo de perder um prazo. Mandar para o cliente uma oportunidade que ele não consegue avaliar não é funcionalidade, é ruído que corrói a confiança em todo alerta futuro. A escolha foi qualidade da informação acima da velocidade do aviso — a mesma escolha que motivou a reconstrução inteira.

O que este case prova para o seu projeto

A LicitaSmart é um produto de licitações, e é quase certo que você não precisa de um. O que ela demonstra é a capacidade por baixo, e essa transfere direto:

  • Ingerir dado sujo e não estruturado em volume — milhares de PDFs com estrutura inconsistente, decompostos em algo consultável.
  • Saber onde a IA entra e onde não entra. Modelo de linguagem para linguagem, API oficial para número, parser determinístico para estrutura. A maioria dos projetos de IA que fracassa erra exatamente essa fronteira.
  • ML supervisionado com avaliação honesta. AUC-PR e Precision@K em dado desbalanceado, não uma demo que fica bonita no slide.
  • Rodar inferência em infraestrutura própria. Se o seu dado não pode sair do seu ambiente — saúde, jurídico, financeiro — isso já foi construído e operado por nós, em produção, com agendamento.
  • Medir em vez de supor. A descoberta dos zero positivos veio de auditar a nossa própria saída. É esse hábito que a gente leva para o seu dado.

“A mudança que a gente percebeu não foi técnica — foi que passaram a aparecer oportunidades. Antes o sistema atravessava o dia sem achar quase nada, e a gente achava que o mercado era assim. Não era. Os editais estavam lá o tempo todo e nós é que estávamos cegos. Hoje cada match chega com nota e com o motivo escrito, então dá pra saber por que ele está ali.”

Kamille Melo Sócia da LicitaSmart

Transparência: a LicitaSmart é um produto da Summitview. Kamille Melo é sócia da LicitaSmart e tem parentesco com o fundador da Summitview. Declaramos isso abertamente porque o que importa nesta página são os números de engenharia — 23–24 documentos contra 0–3, zero positivos em 3.000 matches —, e eles são reproduzíveis independentemente da opinião de qualquer pessoa.

Tem dado que não está te dizendo nada?

É esse o trabalho. A gente audita primeiro e diz com honestidade se compensa consertar ou refazer — e você fala com quem faria, não com camada de vendas.

Falar com a gente