feat(runtime): implement single-article consolidation runtime and modularize codebase
This commit is contained in:
@@ -0,0 +1,765 @@
|
||||
# PRD — Runtime de consolidação e higienização de artigos
|
||||
|
||||
**Versão:** 1.0
|
||||
**Status:** pronto para revisão de implementação
|
||||
**Data:** 23 de agosto de 2026
|
||||
**Escopo documental:** somente runtime
|
||||
|
||||
## 1. Contexto
|
||||
|
||||
O sistema recebe, por execução, um artigo previamente extraído por Trafilatura, Newspaper4k e Readability. O objeto já contém `selected_extractor`, calculado por um processo anterior e fora deste escopo.
|
||||
|
||||
As três extrações podem concordar, divergir, omitir campos ou conter ruídos editoriais. Mesmo quando concordam, podem preservar publicidade textual, chamadas para outras matérias, elementos de navegação, textos de players, conteúdo duplicado ou pequenos defeitos de caracteres.
|
||||
|
||||
O runtime deve usar as três extrações como evidências para produzir um resultado editorial final fundamentado, sem resumir, reescrever ou inventar o artigo.
|
||||
|
||||
O processo anterior só envia artigos com conteúdo textual elegível. Conteúdos majoritariamente compostos por vídeo ou galeria são identificados e desviados antes deste runtime.
|
||||
|
||||
Todo artigo é avaliado contra um ECP obrigatório antes de produzir qualquer saída editorial.
|
||||
|
||||
## 2. Objetivo
|
||||
|
||||
Transformar um artigo extraído pelas três bibliotecas em um resultado confiável e auditável que:
|
||||
|
||||
- gere Markdown quando houver conteúdo textual editorial válido e aderente ao ECP;
|
||||
- preserve título, subtítulo, autor, data, conteúdo, links, imagens e formatação quando existirem e forem válidos;
|
||||
- remova ruídos sem alterar o sentido do texto;
|
||||
- permita pequenas correções textuais pelo LLM, sob prompt, schema, validação, eval e harness específicos;
|
||||
- registre evidências, modelos, prompts, custos, latência, decisões e falhas;
|
||||
- opere com modelos baratos e substituíveis;
|
||||
- atenda ao pico de 100 artigos por hora.
|
||||
|
||||
## 3. Princípio mestre
|
||||
|
||||
O runtime deve estar pronto para produção e atender integralmente aos requisitos definidos utilizando o menor volume de código, dependências, abstrações e componentes necessário.
|
||||
|
||||
Nenhuma solução pode adicionar complexidade sem atender diretamente a pelo menos um requisito, critério de aceitação, risco de produção ou necessidade operacional comprovada.
|
||||
|
||||
Esse princípio implica:
|
||||
|
||||
- fluxo explícito, predeterminado e com bifurcações controladas;
|
||||
- orquestração direta em Python, sem LangChain, LangGraph ou agentes autônomos;
|
||||
- nenhuma abstração genérica sem uso atual;
|
||||
- gateway de modelos apenas porque o agnosticismo é requisito confirmado;
|
||||
- nenhuma infraestrutura antecipada para self-healing;
|
||||
- nenhuma duplicação de schemas ou regras;
|
||||
- toda dependência associada a um requisito;
|
||||
- todo requisito associado a testes e critérios de aceitação.
|
||||
|
||||
## 4. Regras mandatórias
|
||||
|
||||
### 4.1 Fundamentação
|
||||
|
||||
- O LLM só pode selecionar conteúdo existente nas entradas.
|
||||
- Nenhum texto, fato, nome, URL, imagem ou parágrafo pode ser criado.
|
||||
- O conteúdo final deve ser rastreável a candidatos e blocos identificados.
|
||||
- Pequenos reparos textuais são a única exceção à reprodução literal e devem ser auditáveis.
|
||||
|
||||
### 4.2 Proibição de regex para texto
|
||||
|
||||
É proibido usar regex em qualquer processamento, classificação, higienização, inferência, validação semântica ou assertion sobre texto.
|
||||
|
||||
Também é proibido usar listas manuais de palavras-chave por idioma para decidir semanticamente se um conteúdo é publicidade, chamada externa ou conteúdo editorial.
|
||||
|
||||
Processamentos determinísticos de texto devem usar parsers, bibliotecas Unicode, tokenizadores, segmentadores, bibliotecas NLP, algoritmos de comparação ou árvores sintáticas apropriadas.
|
||||
|
||||
### 4.3 Uso obrigatório do LLM
|
||||
|
||||
Todo artigo deve passar pelo LLM de higienização, mesmo quando os três extratores concordarem integralmente.
|
||||
|
||||
A concordância entre extratores melhora a evidência, mas não substitui a higienização.
|
||||
|
||||
### 4.4 Modelos do runtime
|
||||
|
||||
- O runtime usa somente modelos baratos.
|
||||
- Deve existir modelo primário e fallback barato.
|
||||
- Provedor, modelo e parâmetros devem ser configuráveis.
|
||||
- Modelos potentes e caros não podem ser usados para recuperar um artigo individual.
|
||||
- Self-healing de prompt pertence a um subprojeto futuro.
|
||||
|
||||
## 5. Escopo
|
||||
|
||||
### 5.1 Incluído
|
||||
|
||||
- CLI Python.
|
||||
- Uma unidade de artigo por execução.
|
||||
- ECP obrigatório por execução.
|
||||
- Validação dos contratos de entrada.
|
||||
- Validação de `selected_extractor`.
|
||||
- Preparação estrutural de metadados, blocos, links e imagens.
|
||||
- Higienização extrativa por LLM.
|
||||
- Pequenos reparos textuais controlados.
|
||||
- Construção de Markdown intermediário.
|
||||
- Gate obrigatório do ECP.
|
||||
- Sentimento relativo à entidade do ECP.
|
||||
- Tags no idioma do artigo.
|
||||
- Renderização de Markdown final.
|
||||
- Manifesto JSON de resultado em toda execução processável.
|
||||
- Gateway agnóstico de modelos.
|
||||
- Fallback barato.
|
||||
- Persistência, idempotência e escrita atômica.
|
||||
- Langfuse para observabilidade.
|
||||
- Promptfoo para eval, regressão e gate de CI.
|
||||
- Testes funcionais, contratuais, de carga e falhas.
|
||||
- Métricas e logs necessários ao runtime e ao futuro self-healing.
|
||||
|
||||
### 5.2 Fora do escopo
|
||||
|
||||
- Selecionar ou recalcular o extrator principal.
|
||||
- Receber um array de artigos em uma única execução.
|
||||
- Buscar, baixar ou fazer scraping do HTML original.
|
||||
- Executar os três extratores.
|
||||
- Identificar ou classificar conteúdos majoritariamente compostos por vídeo ou galeria, responsabilidade do processo anterior.
|
||||
- Criar fatos, completar informações ou enriquecer editorialmente o artigo.
|
||||
- Traduzir conteúdo.
|
||||
- Resumir ou reescrever conteúdo.
|
||||
- Corrigir conteúdo factual.
|
||||
- Self-healing de prompt.
|
||||
- LLM-as-a-judge para self-healing.
|
||||
- Geração, promoção, canário ou rollback automático de prompts.
|
||||
- Alertas de self-healing.
|
||||
- Modelos potentes no processamento normal.
|
||||
- LangChain, LangGraph ou agentes.
|
||||
|
||||
## 6. Atores e sistemas relacionados
|
||||
|
||||
| Ator ou sistema | Responsabilidade |
|
||||
| --- | --- |
|
||||
| Orquestrador externo | Entregar um artigo e um ECP por execução e consumir o resultado |
|
||||
| Seletor de extrator anterior | Preencher `selected_extractor` antes do runtime |
|
||||
| Runtime | Validar, classificar, higienizar, aplicar ECP, enriquecer e produzir saída |
|
||||
| Provedor LLM primário | Executar chamadas baratas normais |
|
||||
| Provedor LLM fallback | Assumir falhas técnicas ou respostas inválidas do primário |
|
||||
| Classificador ECP | Classificar aderência do conteúdo à entidade |
|
||||
| Langfuse | Receber traces, generations, scores, custos e métricas |
|
||||
| Promptfoo | Executar evals e gates de CI fora do runtime de produção |
|
||||
|
||||
## 7. Unidade de processamento
|
||||
|
||||
Cada execução recebe exatamente:
|
||||
|
||||
1. um objeto correspondente a um item do array `articles` do JSON de extração;
|
||||
2. um ECP Snapshot válido e versionado;
|
||||
3. configurações versionadas do runtime, prompts e gateway de modelos.
|
||||
|
||||
O wrapper original com `articles`, contadores e metadados de lote não faz parte da entrada desta execução.
|
||||
|
||||
## 8. Contrato de entrada do artigo
|
||||
|
||||
### 8.1 Campos estruturais esperados
|
||||
|
||||
O objeto pode conter os campos observados no arquivo de referência:
|
||||
|
||||
- `crawled_url`;
|
||||
- `error_message`;
|
||||
- `extraction_status`;
|
||||
- `http_status`;
|
||||
- `input_meta`;
|
||||
- `page_title`;
|
||||
- `selected_extractor`;
|
||||
- `trafilatura`;
|
||||
- `newspaper4k`;
|
||||
- `readability`.
|
||||
|
||||
Campos desconhecidos devem ser preservados na entrada registrada, mas ignorados pelo processamento enquanto não fizerem parte de um contrato versionado.
|
||||
|
||||
### 8.2 `selected_extractor`
|
||||
|
||||
É obrigatório e deve possuir exatamente um dos valores:
|
||||
|
||||
- `trafilatura`;
|
||||
- `newspaper4k`;
|
||||
- `readability`.
|
||||
|
||||
O runtime deve verificar que o extrator selecionado existe e contém conteúdo utilizável. Ele não pode recalcular ou substituir silenciosamente a seleção.
|
||||
|
||||
Se o campo estiver ausente, inválido ou apontar para extração indisponível, a execução deve falhar com código específico antes de chamar qualquer LLM.
|
||||
|
||||
### 8.3 Campos das extrações
|
||||
|
||||
O runtime pode consumir, quando presentes:
|
||||
|
||||
**Trafilatura**
|
||||
|
||||
- `title`, `author`, `date`, `description`;
|
||||
- `text`, `markdown`;
|
||||
- `canonical_url`, `image`;
|
||||
- `language`, `sitename`, `categories`, `tags`;
|
||||
- `raw_json`, `pagetype`, `error`.
|
||||
|
||||
**Newspaper4k**
|
||||
|
||||
- `title`, `authors`, `publish_date`, `meta_description`;
|
||||
- `text`, `article_html`;
|
||||
- `canonical_link`, `top_image`, `images`;
|
||||
- `meta_data`, `meta_lang`, `meta_site_name`, `tags`, `keywords`;
|
||||
- `error`.
|
||||
|
||||
**Readability**
|
||||
|
||||
- `title`, `short_title`, `author`;
|
||||
- `cleaned_text`, `cleaned_html`;
|
||||
- `error`.
|
||||
|
||||
### 8.4 Validade editorial mínima
|
||||
|
||||
O conjunto das três extrações deve oferecer:
|
||||
|
||||
- pelo menos uma URL de origem válida;
|
||||
- pelo menos um título candidato não vazio;
|
||||
- pelo menos um conteúdo textual processável;
|
||||
- pelo menos uma extração utilizável correspondente ao `selected_extractor`.
|
||||
|
||||
## 9. Contrato do ECP
|
||||
|
||||
### 9.1 Obrigatoriedade
|
||||
|
||||
O ECP é obrigatório em toda execução. Sua ausência ou invalidade encerra a execução antes de qualquer chamada LLM.
|
||||
|
||||
### 9.2 Schema
|
||||
|
||||
O runtime deve validar o ECP contra o schema versionado mantido pelo módulo ECP. Não deve copiar ou criar um segundo schema.
|
||||
|
||||
O snapshot precisa conter as informações exigidas pelo classificador ECP, incluindo identidade, idiomas e relações necessárias a `CONTEXTUAL_INHERENT`.
|
||||
|
||||
### 9.3 Resultados possíveis
|
||||
|
||||
- `DIRECT_INHERENT`;
|
||||
- `CONTEXTUAL_INHERENT`;
|
||||
- `TANGENTIAL`;
|
||||
- `NOT_RELATED`.
|
||||
|
||||
Somente `DIRECT_INHERENT` e `CONTEXTUAL_INHERENT` permitem saída editorial.
|
||||
|
||||
## 10. Contrato de saída
|
||||
|
||||
### 10.1 Resultado JSON e manifesto
|
||||
|
||||
Toda invocação deve devolver um resultado JSON estruturado, inclusive em falha de validação. Quando o artigo for parseável e possuir identidade suficiente para fingerprint, esse resultado também deve ser persistido como manifesto. Entrada que nem sequer possa ser parseada retorna erro estruturado pela CLI e log, sem arquivo persistente obrigatório.
|
||||
|
||||
O manifesto deve conter, no mínimo:
|
||||
|
||||
- fingerprint determinístico do artigo;
|
||||
- URL de origem;
|
||||
- `selected_extractor` recebido;
|
||||
- status final;
|
||||
- decisão de gerar ou não Markdown;
|
||||
- caminho do Markdown ou valor nulo;
|
||||
- classificação ECP e confiança;
|
||||
- versões dos prompts, modelos, providers e configuração;
|
||||
- trace ID do Langfuse;
|
||||
- códigos de erro ou descarte, quando houver.
|
||||
|
||||
### 10.2 Status finais
|
||||
|
||||
| Status | Significado |
|
||||
| --- | --- |
|
||||
| `completed_text` | ECP aprovado e Markdown produzido |
|
||||
| `rejected_ecp` | ECP classificou como tangencial ou não relacionado; nenhum Markdown produzido |
|
||||
| `failed_validation` | Entrada, ECP ou contrato inválido |
|
||||
| `failed_processing` | Falha após validação sem fallback aceitável |
|
||||
|
||||
### 10.3 Arquivo Markdown
|
||||
|
||||
O arquivo deve possuir front matter YAML com:
|
||||
|
||||
**Obrigatórios**
|
||||
|
||||
- `title`;
|
||||
- `source_url`;
|
||||
- `sentiment`;
|
||||
- `tags`;
|
||||
- `ecp_qid`;
|
||||
- `ecp_canonical_name`;
|
||||
- `ecp_category`;
|
||||
- `ecp_confidence`.
|
||||
|
||||
**Opcionais, omitidos quando inexistentes**
|
||||
|
||||
- `subtitle`;
|
||||
- `author`;
|
||||
- `published_at`.
|
||||
|
||||
Após o front matter:
|
||||
|
||||
1. título como heading nível 1;
|
||||
2. subtítulo em itálico, quando houver;
|
||||
3. conteúdo editorial em ordem;
|
||||
4. links e imagens editoriais em posições fundamentadas.
|
||||
|
||||
Autor, data, sentimento, tags e classificação ECP não devem ser repetidos no corpo.
|
||||
|
||||
### 10.4 Formatação Markdown permitida
|
||||
|
||||
- headings;
|
||||
- parágrafos;
|
||||
- negrito;
|
||||
- itálico;
|
||||
- citações;
|
||||
- listas;
|
||||
- links;
|
||||
- imagens.
|
||||
|
||||
Sublinhado não precisa ser preservado. HTML inline não deve ser necessário no resultado.
|
||||
|
||||
## 11. Fluxo funcional do runtime
|
||||
|
||||
1. Ler artigo, ECP e configuração.
|
||||
2. Validar schemas e obrigatoriedades.
|
||||
3. Validar `selected_extractor` sem recalculá-lo.
|
||||
4. Calcular fingerprint e verificar idempotência.
|
||||
5. Fazer parsing estrutural de HTML, Markdown, JSON-LD, URLs e metadados.
|
||||
6. Criar candidatos identificados de metadados, blocos, links e imagens.
|
||||
7. Chamar obrigatoriamente o LLM de higienização.
|
||||
8. Validar seleção, grounding e reparos.
|
||||
9. Montar Markdown intermediário.
|
||||
10. Executar o gate ECP.
|
||||
11. Se o ECP rejeitar, não produzir Markdown.
|
||||
12. Se o ECP aprovar, chamar enriquecimento de sentimento e tags.
|
||||
13. Validar enriquecimento.
|
||||
14. Renderizar Markdown final.
|
||||
15. Persistir manifesto, Markdown e estado de forma atômica.
|
||||
16. Finalizar trace e métricas.
|
||||
|
||||
## 12. Preparação determinística
|
||||
|
||||
### 12.1 Limite
|
||||
|
||||
A preparação determinística organiza evidências. Ela não decide semanticamente quais parágrafos são editoriais ou se o texto é bom.
|
||||
|
||||
### 12.2 Técnicas permitidas
|
||||
|
||||
- DOM para HTML;
|
||||
- AST para Markdown;
|
||||
- parser JSON para JSON-LD;
|
||||
- parser de URL;
|
||||
- normalização Unicode;
|
||||
- tokenização e segmentação por biblioteca multilíngue;
|
||||
- comparação de sequências e hashes;
|
||||
- bibliotecas NLP avaliadas para a operação específica;
|
||||
- IDs, offsets e relações estruturais.
|
||||
|
||||
### 12.3 Técnicas proibidas
|
||||
|
||||
- regex sobre texto;
|
||||
- expressões regulares dentro do Promptfoo para conteúdo;
|
||||
- dicionários manuais de palavras-chave por idioma para decisões semânticas;
|
||||
- decisão de publicidade ou relevância baseada apenas em comprimento;
|
||||
- manipulação de HTML como string quando houver parser estrutural.
|
||||
|
||||
## 13. Candidatos e proveniência
|
||||
|
||||
Cada candidato deve receber ID estável dentro da execução e registrar:
|
||||
|
||||
- tipo;
|
||||
- extrator de origem;
|
||||
- campo de origem;
|
||||
- conteúdo original;
|
||||
- posição estrutural, quando existir;
|
||||
- representação parseada;
|
||||
- relação com candidatos equivalentes;
|
||||
- hash do conteúdo original.
|
||||
|
||||
Tipos mínimos:
|
||||
|
||||
- título;
|
||||
- subtítulo;
|
||||
- autor;
|
||||
- data;
|
||||
- bloco textual;
|
||||
- heading;
|
||||
- lista;
|
||||
- citação;
|
||||
- link;
|
||||
- imagem;
|
||||
|
||||
O `selected_extractor` define a base preferencial de ordem, mas não obriga o LLM a escolher todos os seus blocos.
|
||||
|
||||
### 13.1 URL de origem
|
||||
|
||||
Selecionar deterministicamente a primeira URL HTTP ou HTTPS válida, usando parser de URL e esta prioridade:
|
||||
|
||||
1. `crawled_url`;
|
||||
2. `input_meta.url`;
|
||||
3. URL canônica do `selected_extractor`;
|
||||
4. `newspaper4k.canonical_link`;
|
||||
5. `trafilatura.canonical_url`.
|
||||
|
||||
O LLM não escolhe nem corrige a URL de origem.
|
||||
|
||||
### 13.2 Fontes de metadados
|
||||
|
||||
**Título**
|
||||
|
||||
- `input_meta.titulo`;
|
||||
- `page_title`;
|
||||
- `trafilatura.title`;
|
||||
- `newspaper4k.title`;
|
||||
- `readability.title`;
|
||||
- `readability.short_title`.
|
||||
|
||||
**Subtítulo**
|
||||
|
||||
- `input_meta.subtitulo`;
|
||||
- `trafilatura.description`;
|
||||
- `newspaper4k.meta_description`.
|
||||
|
||||
**Autor**
|
||||
|
||||
- `trafilatura.author`;
|
||||
- itens de `newspaper4k.authors`;
|
||||
- `readability.author`.
|
||||
|
||||
Strings de autor não devem ser separadas por regex ou por inferência de delimitador. Listas estruturadas preservam seus itens e ordem.
|
||||
|
||||
**Data de publicação**
|
||||
|
||||
- `input_meta.quando_publicado`;
|
||||
- `trafilatura.date`;
|
||||
- `newspaper4k.publish_date`.
|
||||
|
||||
Datas são parseadas por biblioteca apropriada e normalizadas para ISO 8601. Havendo concordância de calendário entre fontes, usar o valor concordante mais preciso. Sem consenso, usar o primeiro valor válido na prioridade `newspaper4k`, `input_meta`, `trafilatura`. Sem valor válido, omitir `published_at`.
|
||||
|
||||
A data é resolvida deterministicamente e não é escolhida ou corrigida pelo LLM.
|
||||
|
||||
## 14. Higienização por LLM
|
||||
|
||||
### 14.1 Obrigatoriedade
|
||||
|
||||
Todo artigo chama o LLM de higienização, independentemente da concordância dos extratores.
|
||||
|
||||
### 14.2 Entrada
|
||||
|
||||
- candidatos de título, subtítulo, autor e data;
|
||||
- blocos editoriais candidatos com IDs;
|
||||
- links e imagens com IDs;
|
||||
- relações de equivalência entre extrações;
|
||||
- ordem base do `selected_extractor`;
|
||||
- idioma detectado por biblioteca apropriada;
|
||||
- regras do prompt;
|
||||
- schema de saída.
|
||||
|
||||
### 14.3 Saída lógica
|
||||
|
||||
- candidato de título escolhido;
|
||||
- candidato de subtítulo, quando houver;
|
||||
- candidato de autor, quando houver;
|
||||
- IDs dos blocos mantidos;
|
||||
- IDs das imagens mantidas;
|
||||
- IDs dos links mantidos;
|
||||
- reparos textuais propostos;
|
||||
- nenhuma reprodução livre do artigo completo.
|
||||
|
||||
### 14.4 Regras editoriais
|
||||
|
||||
O modelo deve:
|
||||
|
||||
- preservar o conteúdo e a ordem editorial;
|
||||
- retirar ruídos que não pertencem ao artigo;
|
||||
- preservar formatação semanticamente suportada;
|
||||
- manter links e imagens apenas quando editoriais;
|
||||
- não resumir;
|
||||
- não reescrever;
|
||||
- não reorganizar a narrativa;
|
||||
- não criar transições;
|
||||
- não completar informações;
|
||||
- não corrigir fatos;
|
||||
- não inserir conhecimento externo.
|
||||
|
||||
## 15. Pequenos reparos textuais
|
||||
|
||||
### 15.1 Permissão
|
||||
|
||||
O LLM pode corrigir pequenas falhas em título, subtítulo, autor ou blocos, desde que a correção preserve integralmente o significado.
|
||||
|
||||
Exemplos de categorias permitidas:
|
||||
|
||||
- mojibake;
|
||||
- caracteres Unicode quebrados;
|
||||
- separação ou junção claramente acidental;
|
||||
- pontuação manifestamente corrompida;
|
||||
- erro tipográfico pequeno e inequívoco.
|
||||
|
||||
### 15.2 Proibições
|
||||
|
||||
O reparo não pode:
|
||||
|
||||
- trocar uma palavra por sinônimo;
|
||||
- melhorar estilo;
|
||||
- mudar tempo verbal;
|
||||
- alterar tom;
|
||||
- corrigir informação factual;
|
||||
- mudar nomes, números, placares, datas ou citações;
|
||||
- reformular frases;
|
||||
- criar texto ausente.
|
||||
|
||||
### 15.3 Forma auditável
|
||||
|
||||
Cada reparo deve informar:
|
||||
|
||||
- ID do candidato ou bloco;
|
||||
- fragmento original exato;
|
||||
- fragmento substituto;
|
||||
- categoria do reparo;
|
||||
- justificativa curta.
|
||||
|
||||
O harness deve aplicar e validar o reparo sobre o conteúdo original. Reparos inválidos devem ser descartados, preservando o texto original, sem autorizar regeneração livre.
|
||||
|
||||
O prompt, os evals e os testes devem conter exemplos positivos e negativos específicos para essa permissão.
|
||||
|
||||
## 16. Imagens e links
|
||||
|
||||
### 16.1 Imagens editoriais
|
||||
|
||||
Podem ser preservadas quando:
|
||||
|
||||
- estiverem estruturalmente ligadas ao corpo;
|
||||
- possuírem URL de entrada válida;
|
||||
- forem selecionadas por ID;
|
||||
- tiverem posição fundamentada.
|
||||
|
||||
Alt e legenda só podem usar texto existente.
|
||||
|
||||
### 16.2 Links
|
||||
|
||||
Links só podem usar URL e texto âncora presentes na entrada. Chamadas para outras notícias, recomendações e publicidade devem ser removidas pelo LLM a partir de candidatos identificados.
|
||||
|
||||
## 17. Gate ECP
|
||||
|
||||
### 17.1 Entrada
|
||||
|
||||
O classificador ECP recebe o Markdown intermediário higienizado.
|
||||
|
||||
### 17.2 Decisão
|
||||
|
||||
- `DIRECT_INHERENT`: continua;
|
||||
- `CONTEXTUAL_INHERENT`: continua;
|
||||
- `TANGENTIAL`: nenhum Markdown;
|
||||
- `NOT_RELATED`: nenhum Markdown;
|
||||
- falha sem classificação válida: `failed_processing`.
|
||||
|
||||
Se o classificador ECP usar fallback LLM, esse fallback deve usar modelo barato certificado. A regra de não usar modelos potentes vale para todas as chamadas do runtime, inclusive dependências acionadas por ele.
|
||||
|
||||
## 18. Enriquecimento
|
||||
|
||||
Executado somente após aprovação do ECP.
|
||||
|
||||
### 18.1 Sentimento
|
||||
|
||||
- `positive`;
|
||||
- `negative`;
|
||||
- `neutral`.
|
||||
|
||||
O sentimento é sempre relativo à entidade do ECP.
|
||||
|
||||
### 18.2 Tags
|
||||
|
||||
- entre 3 e 8;
|
||||
- no idioma do artigo;
|
||||
- fundamentadas no conteúdo final;
|
||||
- sem duplicidades semânticas evidentes;
|
||||
- sem alterar o corpo.
|
||||
|
||||
Se primário e fallback falharem, não deve ser gerado Markdown.
|
||||
|
||||
## 19. Gateway e fallback de modelos
|
||||
|
||||
O runtime deve conhecer papéis, não providers fixos:
|
||||
|
||||
- `runtime_primary`;
|
||||
- `runtime_fallback`.
|
||||
|
||||
Cada configuração certificada deve registrar:
|
||||
|
||||
- provider;
|
||||
- modelo;
|
||||
- parâmetros;
|
||||
- prompt compatível;
|
||||
- schema esperado;
|
||||
- limites de timeout;
|
||||
- versão.
|
||||
|
||||
Política:
|
||||
|
||||
- erro transitório permite retry técnico limitado;
|
||||
- resposta inválida não deve entrar em loop no mesmo modelo;
|
||||
- após falha do primário, usar fallback barato;
|
||||
- após falha do fallback, aplicar fallback determinístico da etapa ou encerrar controladamente;
|
||||
- nunca escalar para modelo potente no runtime.
|
||||
|
||||
## 20. Idempotência e persistência
|
||||
|
||||
- O fingerprint deve derivar da identidade da entrada e das versões funcionais relevantes.
|
||||
- A mesma entrada com a mesma configuração não pode produzir duplicidade.
|
||||
- Markdown, manifesto e estado devem ser gravados atomicamente.
|
||||
- Uma execução interrompida deve poder ser retomada ou repetida sem corromper saída existente.
|
||||
- Mudança de prompt, modelo, ECP ou regra versionada deve produzir uma execução distinguível.
|
||||
|
||||
## 21. Observabilidade
|
||||
|
||||
Cada artigo deve possuir uma trace no Langfuse com spans estáveis para:
|
||||
|
||||
- validação;
|
||||
- preparação estrutural;
|
||||
- higienização;
|
||||
- validação de grounding e reparos;
|
||||
- ECP;
|
||||
- enriquecimento;
|
||||
- renderização;
|
||||
- persistência.
|
||||
|
||||
Cada generation deve registrar:
|
||||
|
||||
- papel lógico;
|
||||
- modelo e provider;
|
||||
- versão do prompt;
|
||||
- tokens;
|
||||
- custo;
|
||||
- latência;
|
||||
- tentativas;
|
||||
- resultado do schema;
|
||||
- fallback;
|
||||
- scores aplicáveis.
|
||||
|
||||
Falhas de observabilidade não devem invalidar um artigo já processável. Os eventos pendentes devem ser preservados para reenvio.
|
||||
|
||||
## 22. Promptfoo no runtime
|
||||
|
||||
Promptfoo é ferramenta de desenvolvimento e CI, não dependência do processamento online.
|
||||
|
||||
Deve validar:
|
||||
|
||||
- prompts de higienização e enriquecimento;
|
||||
- primário e fallback baratos;
|
||||
- idiomas presentes no corpus;
|
||||
- seleção de IDs;
|
||||
- ausência de invenção;
|
||||
- pequenos reparos permitidos e proibidos;
|
||||
- custo e latência medidos em staging.
|
||||
|
||||
Assertions textuais baseadas em regex são proibidas.
|
||||
|
||||
## 23. Requisitos funcionais
|
||||
|
||||
- **FR-001:** receber exatamente um artigo por execução.
|
||||
- **FR-002:** exigir ECP válido por execução.
|
||||
- **FR-003:** exigir e validar `selected_extractor` sem recalculá-lo.
|
||||
- **FR-004:** validar URL, título e conteúdo textual mínimo.
|
||||
- **FR-005:** calcular fingerprint determinístico.
|
||||
- **FR-006:** impedir duplicidade de saída.
|
||||
- **FR-007:** preparar candidatos com IDs e proveniência.
|
||||
- **FR-008:** não usar regex em processamento textual.
|
||||
- **FR-009:** não usar palavras-chave manuais para decisões semânticas multilíngues.
|
||||
- **FR-010:** chamar o LLM de higienização para todo artigo.
|
||||
- **FR-011:** selecionar conteúdo por IDs.
|
||||
- **FR-012:** impedir resumo, reescrita, complementação e invenção.
|
||||
- **FR-013:** permitir apenas pequenos reparos auditáveis.
|
||||
- **FR-014:** preservar o original quando um reparo for inválido.
|
||||
- **FR-015:** preservar Markdown suportado.
|
||||
- **FR-016:** selecionar links e imagens por IDs fundamentados.
|
||||
- **FR-017:** executar ECP antes de produzir Markdown.
|
||||
- **FR-018:** bloquear `TANGENTIAL` e `NOT_RELATED`.
|
||||
- **FR-019:** classificar sentimento relativo ao ECP.
|
||||
- **FR-020:** gerar de 3 a 8 tags no idioma do artigo.
|
||||
- **FR-021:** usar somente modelos baratos no runtime.
|
||||
- **FR-022:** oferecer gateway agnóstico de modelo.
|
||||
- **FR-023:** oferecer fallback barato e controlado.
|
||||
- **FR-024:** devolver resultado JSON em toda invocação e persistir manifesto quando houver fingerprint estabelecido.
|
||||
- **FR-025:** gerar Markdown apenas para conteúdo aprovado pelo ECP.
|
||||
- **FR-026:** persistir saídas atomicamente.
|
||||
- **FR-027:** registrar trace, métricas, versões, custo e latência.
|
||||
- **FR-028:** suportar reenvio de telemetria pendente.
|
||||
- **FR-029:** executar evals de CI com Promptfoo.
|
||||
|
||||
## 24. Requisitos não funcionais
|
||||
|
||||
- **NFR-001:** suportar 100 artigos por hora no perfil acordado.
|
||||
- **NFR-002:** nenhuma perda ou duplicação no teste de carga.
|
||||
- **NFR-003:** mesma entrada e mesmas versões produzem a mesma estrutura de decisão determinística.
|
||||
- **NFR-004:** toda saída textual deve ser rastreável às entradas e reparos autorizados.
|
||||
- **NFR-005:** nenhuma URL ou imagem pode ser inventada.
|
||||
- **NFR-006:** modelos e prompts devem ser versionados.
|
||||
- **NFR-007:** segredos não podem aparecer em logs ou arquivos.
|
||||
- **NFR-008:** falha do Langfuse não pode interromper o processamento.
|
||||
- **NFR-009:** dependências devem ser minimizadas e justificadas.
|
||||
- **NFR-010:** componentes não usados pelo runtime não podem ser antecipados.
|
||||
- **NFR-011:** custo e latência devem ser instrumentados desde staging.
|
||||
- **NFR-012:** limites finais de custo e latência devem ser aprovados antes do go-live a partir da baseline de staging.
|
||||
|
||||
## 25. Códigos mínimos de erro e descarte
|
||||
|
||||
- `INVALID_ARTICLE_SCHEMA`;
|
||||
- `INVALID_ECP_SCHEMA`;
|
||||
- `MISSING_SELECTED_EXTRACTOR`;
|
||||
- `INVALID_SELECTED_EXTRACTOR`;
|
||||
- `SELECTED_EXTRACTOR_UNAVAILABLE`;
|
||||
- `MISSING_SOURCE_URL`;
|
||||
- `MISSING_TITLE_CANDIDATE`;
|
||||
- `MISSING_CONTENT`;
|
||||
- `HYGIENE_FAILED`;
|
||||
- `GROUNDING_VIOLATION`;
|
||||
- `INVALID_TEXT_REPAIR`;
|
||||
- `ECP_CLASSIFICATION_FAILED`;
|
||||
- `ECP_REJECTED`;
|
||||
- `ENRICHMENT_FAILED`;
|
||||
- `PERSISTENCE_FAILED`;
|
||||
- `TELEMETRY_PENDING`.
|
||||
|
||||
## 26. Critérios de aceitação do produto
|
||||
|
||||
1. O runtime recebe um único artigo e um ECP obrigatório.
|
||||
2. `selected_extractor` é validado e nunca recalculado.
|
||||
3. Nenhum LLM é chamado quando a entrada obrigatória é inválida.
|
||||
4. Nenhum processamento textual usa regex.
|
||||
5. Nenhuma decisão semântica multilíngue depende de lista manual de palavras-chave.
|
||||
6. Todo artigo passa pelo LLM de higienização.
|
||||
7. O LLM seleciona IDs e não devolve livremente o artigo completo.
|
||||
8. Todo reparo possui origem, substituição, categoria e justificativa.
|
||||
9. Reparo inválido preserva o original.
|
||||
10. Nenhum texto, fato, URL ou imagem sem origem é publicado.
|
||||
11. Todo artigo passa pelo ECP antes de produzir Markdown.
|
||||
12. ECP tangencial ou não relacionado não produz Markdown.
|
||||
13. Markdown aprovado contém título, URL, sentimento, tags e dados ECP obrigatórios.
|
||||
14. Campos opcionais são omitidos quando inexistentes.
|
||||
15. Primário e fallback do runtime são modelos baratos e substituíveis.
|
||||
16. Nenhum modelo potente é chamado pelo runtime.
|
||||
17. Toda execução possui estado idempotente e escrita atômica.
|
||||
18. Toda execução possui trace ou telemetria pendente preservada.
|
||||
19. Promptfoo bloqueia release que viole gates críticos.
|
||||
20. O teste de carga sustenta 100 artigos por hora sem perda ou duplicação.
|
||||
21. Custo e latência são medidos em staging e seus limites são aprovados antes do go-live.
|
||||
|
||||
## 27. Métricas de sucesso
|
||||
|
||||
Os detalhes e fórmulas estão no Catálogo de Métricas e KPIs. Gates mínimos:
|
||||
|
||||
- zero texto inventado;
|
||||
- zero URL ou imagem inventada;
|
||||
- zero duplicidade;
|
||||
- pass rate end-to-end textual de pelo menos 95%;
|
||||
- 100% das execuções com trace enviado ou preservado para reenvio.
|
||||
|
||||
## 28. Dependência futura de self-healing
|
||||
|
||||
O self-healing será um subprojeto posterior, com PRD, arquitetura, ADRs, testes, métricas e runbook próprios.
|
||||
|
||||
O runtime não implementa análise de falhas de prompt, geração de candidato, LLM-as-a-judge, promoção, canário ou rollback automático de prompt.
|
||||
|
||||
Ele apenas preserva versões, falhas, traces, scores, custos e evidências necessários para que o subprojeto futuro possa consumir esses dados.
|
||||
|
||||
## 29. Definition of Done
|
||||
|
||||
O runtime estará concluído quando:
|
||||
|
||||
- todos os requisitos funcionais e não funcionais estiverem implementados;
|
||||
- todos os critérios de aceitação estiverem automatizados ou formalmente verificáveis;
|
||||
- PRD, arquitetura, ADRs, testes, métricas e runbook estiverem consistentes;
|
||||
- schemas de entrada e saída estiverem versionados;
|
||||
- prompts e modelos baratos estiverem certificados;
|
||||
- golden set e slices de idiomas, extratores e domínios passarem pelos gates;
|
||||
- a proibição de regex textual estiver verificada estaticamente e por revisão;
|
||||
- o teste de 100 artigos por hora passar sem perda ou duplicidade;
|
||||
- falhas de providers, persistência e observabilidade tiverem testes de recuperação;
|
||||
- custo e latência tiverem baseline de staging e limites aprovados;
|
||||
- operação, rollback manual e reprocessamento estiverem documentados;
|
||||
- nenhum componente de self-healing estiver ativo no runtime.
|
||||
Reference in New Issue
Block a user