Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ htmlcov/
dist/
build/
.venv/
.ragforge/

# Secrets and local configuration
.env
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: install lint type test quality bench bench-live api dashboard infra-up infra-down
.PHONY: install lint type test quality bench bench-live bench-live-local api dashboard infra-up infra-down

install:
uv sync --all-groups
Expand All @@ -24,6 +24,9 @@ bench:
bench-live:
uv run python -m ragforge.evaluation.run --mode live --config configs/experiments/benchmark-v01.yaml

bench-live-local:
uv run python -m ragforge.evaluation.run --mode live --config configs/experiments/benchmark-local-v01.yaml

api:
uv run uvicorn apps.api.main:app --reload

Expand Down
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# RAGForge

*Leia isto em [Português](README.pt-BR.md).*

**Adaptive RAG benchmarking platform for Brazilian financial and regulatory documents.**

RAGForge is being built to benchmark sparse, dense, hybrid, contextual, hierarchical (RAPTOR), graph (GraphRAG) and corrective strategies - measuring answer quality, retrieval precision, latency and cost on **RegRAG-BR**, a 230-question golden dataset over CMN/BCB and CVM norms.
Expand All @@ -23,7 +25,7 @@ Most RAG comparisons are anecdotal. RAGForge treats the question "*which RAG str
| 7 | RAPTOR | Recursive summary tree (minimal impl.) | Implemented |
| 8 | GraphRAG | LightRAG adapter (local + global) | Implemented |

Cross-cutting: **Adaptive Router** (rules + few-shot, planned), **Corrective workflow** (evidence evaluator with retry / reformulation / insufficient-evidence declaration, LangGraph, planned), **governance** (answer → chunk → article citation tracing via Citation Accuracy, implemented; full audit trail beyond the metric, planned), **observability** (Langfuse metadata-only tracing implemented; OpenTelemetry planned).
Cross-cutting: **Adaptive Router** (rules + few-shot, planned), **Corrective workflow** (evidence evaluator with retry / reformulation / insufficient-evidence declaration, LangGraph, planned), **governance** (answer → chunk → article citation tracing via Citation Accuracy, plus a post-generation semantic-support audit with bounded rewrite and a tamper-evident evidence trail per run, implemented), **observability** (Langfuse metadata-only tracing implemented; OpenTelemetry planned).

## Status

Expand All @@ -37,24 +39,39 @@ is actually running today versus what the design targets - see the [PR history](
| All 8 benchmarked retrieval strategies (Dense through GraphRAG) | Implemented |
| Evaluation harness + structural-coverage judgments (ADR-0002) | Implemented |
| Observability (Langfuse, metadata-only) | Implemented |
| Answer generation + Citation Accuracy + RAGAS judge (ADR-0007) | Implemented - judge uncalibrated (ADR-0007 kappa exercise pending) |
| Answer generation + Citation Accuracy | Implemented |
| Independent LLM judge - Faithfulness/Answer Relevancy + abstention (ADR-0018) | Implemented - uncalibrated (ADR-0007 kappa exercise pending) |
| Post-generation citation/semantic-support audit + bounded rewrite (ADR-0016) | Implemented - off by default (`audit.enabled: false`) |
| Auditable, tamper-evident run evidence directory (ADR-0017) | Implemented - `artifacts/runs/<run_id>/`, verified via `scripts/verify_run.py` |
| Main benchmark runner (`make bench-live`, all 8 strategies + answer quality) | Implemented - live mode only |
| Adaptive Router, Corrective workflow | Planned |
| RegRAG-BR golden set | 230 questions published (5 of 6 corpus documents curated) |
| RegRAG-BR golden set | 230 questions published: 36 validation/dev + 194 test |
| API / dashboard apps | Planned (scaffolding only) |
| `make bench` (cached, bit-for-bit replay, ADR-0004) | Planned - needs a versioned LLM call cache, not built yet |

## Quick start

```bash
uv sync --all-groups
make infra-up # Postgres+pgvector, OpenSearch (docker compose profiles)
GEMINI_API_KEY=... make bench-live # real run, all 8 strategies, real API cost
make dashboard # benchmark view + side-by-side strategy Arena
make infra-up # Postgres+pgvector, OpenSearch
GEMINI_API_KEY=... OPENAI_API_KEY=... make bench-live
make bench-live-local # same matrix, local Qwen embeddings
make dashboard # benchmark + side-by-side Arena
```

`make bench-live` calls real providers (embeddings, contextualization, RAPTOR summarization, GraphRAG entity extraction - see the strategy table above). `make bench` (deterministic, zero-cost replay from a versioned LLM cache) is the target design per [ADR-0004](docs/adr/0004-benchmark-reproducibility-policy.md), but that cache layer doesn't exist yet - only live mode is implemented.

The canonical publishable matrix uses `gemini-embedding-001`, selected by the isolated PT-BR
embedding comparison (ADR-0005). `make bench-live-local` uses
`Qwen/Qwen3-Embedding-0.6B` as ADR-0013's credential-free embedding alternative; it is a
separately identified run, not a silent fallback or a relabeling of the quality winner.

Both live commands persist per-text embeddings and completed indexes under the ignored
`.ragforge/cache/` directory. A deterministic index fingerprint includes corpus-derived text,
embedding identity, and synthetic-text producer identity; partial indexes are never marked
reusable. `--resume <run-id>` skips strategies already checkpointed. A repository lock rejects
concurrent benchmark processes before they can mutate shared indexes.

## Key design decisions

All non-obvious choices are recorded as [ADRs](docs/adr/README.md). The load-bearing ones:
Expand All @@ -65,6 +82,8 @@ All non-obvious choices are recorded as [ADRs](docs/adr/README.md). The load-bea
- [ADR-0006](docs/adr/0006-legal-structural-chunker.md) - domain-aware chunking by legal hierarchy (Art./§/inciso) with stable structural IDs.
- [ADR-0007](docs/adr/0007-llm-judge-calibration-ptbr.md) - the LLM judge is calibrated against human evaluation in PT-BR and the agreement is published.
- [ADR-0011](docs/adr/0011-structural-id-collision-in-amended-norms.md) - structural IDs that collide across amendment history/appended annexes are excluded from golden-set citations, not fixed at the chunker level.
- [ADR-0016](docs/adr/0016-post-generation-citation-audit.md) - a semantic-support verifier and at most one bounded rewrite catch unsupported claims a citation-existence check alone would miss.
- [ADR-0017](docs/adr/0017-auditable-evidence-lineage.md) - every published score traces back to a hash-chained, tamper-evident evidence directory per run - exact inputs, model identities, and retrieval candidates, not just the aggregate metric.

## Repository layout

Expand All @@ -82,7 +101,7 @@ The core is framework-free: `RetrievalStrategy` is a Protocol; LLM SDKs are bann

## Dataset - RegRAG-BR

230 questions (7 query classes) over selected CMN/BCB resolutions (4,893, risk management, Open Finance, AML) and CVM/CMN norms, with article-level relevance judgments and reference answers, published under CC-BY-4.0 with a datasheet. Norms are official acts (art. 8, I, Law 9,610/98 - not copyright-protected).
230 questions (7 query classes) over selected CMN/BCB resolutions (4,893, risk management, Open Finance, AML) and CVM/CMN norms, with article-level relevance judgments and reference answers, published under CC-BY-4.0 with a datasheet. The deterministic stratified split reserves 36 questions for router development/validation and 194 for official test metrics. Norms are official acts (art. 8, I, Law 9,610/98 - not copyright-protected).

Published (`datasets/regrag-br/judgments.json`): 230 hand-curated questions, each with a reference answer, verified against the real parsed text of 5 corpus documents (LC-105/2001, RES-CMN-4893/2021, RES-CMN-5274/2025, LEI-13709/2018-LGPD, ICVM-607/2019). A 6th corpus document, LEI-6385/1976, is not yet curated. Structural IDs known to be ambiguous in the real source text - amendment-history and appended-annex artifacts in 3 of the 5 documents - are excluded from citation; see [ADR-0011](docs/adr/0011-structural-id-collision-in-amended-norms.md).

Expand Down
121 changes: 121 additions & 0 deletions README.pt-BR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# RAGForge

*Read this in [English](README.md).*

**Plataforma adaptativa de benchmark de RAG para documentos financeiros e regulatórios brasileiros.**

O RAGForge está sendo construído para comparar estratégias sparse, dense, hybrid, contextual, hierárquica (RAPTOR), grafo (GraphRAG) e corretiva - medindo qualidade de resposta, precisão de recuperação, latência e custo sobre o **RegRAG-BR**, um golden dataset de 230 perguntas sobre normas do CMN/BCB e da CVM.

> 🚧 v0.1 em desenvolvimento. Veja [Status](#status) para o que já está implementado versus planejado.

## Por que isso existe

A maioria das comparações de RAG é anedótica. O RAGForge trata a pergunta "*qual estratégia de RAG eu deveria usar?*" como um experimento: 8 estratégias avaliadas × 7 classes de pergunta, com um roteador adaptativo pensado para ser avaliado contra um **oráculo empírico**, e todo número publicado reproduzível bit a bit a partir de um cache versionado de chamadas de LLM. Veja [Status](#status) para o que já foi construído.

## Estratégias avaliadas

| # | Estratégia | Abordagem | Status |
| --- | ---------- | ---------- | -------- |
| 1 | Dense (baseline) | pgvector, top-k fixo | Implementado |
| 2 | Sparse BM25 | OpenSearch, analisador `brazilian` | Implementado |
| 3 | Hybrid + RRF | BM25 + dense + Reciprocal Rank Fusion | Implementado |
| 4 | Reranked | Hybrid top-50 → cross-encoder → top-5 | Implementado |
| 5 | Contextual Retrieval | Contexto via LLM por chunk + prompt caching | Implementado |
| 6 | Parent-child / multi-vector | Busca em chunks pequenos, entrega a seção | Implementado |
| 7 | RAPTOR | Árvore recursiva de resumos (impl. mínima) | Implementado |
| 8 | GraphRAG | Adapter LightRAG (local + global) | Implementado |

Transversais: **Roteador Adaptativo** (regras + few-shot, planejado), **Fluxo corretivo** (avaliador de evidência com retry / reformulação / declaração de evidência insuficiente, LangGraph, planejado), **governança** (rastreamento resposta → chunk → artigo via Citation Accuracy, mais uma auditoria de suporte semântico pós-geração com reescrita limitada e uma trilha de evidência à prova de adulteração por execução, implementado), **observabilidade** (tracing do Langfuse apenas com metadados implementado; OpenTelemetry planejado).

## Status

O RAGForge está em desenvolvimento ativo (v0.1, ver a nota de checkpoint acima). Esta seção acompanha o que
está de fato rodando hoje versus o que é meta de design - veja o [histórico de PRs](../../pulls?q=is%3Apr) para como cada linha chegou lá.

| Componente | Status |
|---|---|
| Chunker estrutural jurídico (ADR-0006) | Implementado |
| Pipeline de ingestão (extração, hash de snapshot) | Implementado |
| As 8 estratégias de recuperação avaliadas (Dense até GraphRAG) | Implementado |
| Harness de avaliação + julgamentos de cobertura estrutural (ADR-0002) | Implementado |
| Observabilidade (Langfuse, apenas metadados) | Implementado |
| Geração de resposta + Citation Accuracy | Implementado |
| Judge de LLM independente - Faithfulness/Answer Relevancy + abstenção (ADR-0018) | Implementado - não calibrado (exercício de kappa da ADR-0007 pendente) |
| Auditoria de citação/suporte semântico pós-geração + reescrita limitada (ADR-0016) | Implementado - desligado por padrão (`audit.enabled: false`) |
| Diretório de evidência auditável e à prova de adulteração por execução (ADR-0017) | Implementado - `artifacts/runs/<run_id>/`, verificado via `scripts/verify_run.py` |
| Runner principal do benchmark (`make bench-live`, 8 estratégias + qualidade de resposta) | Implementado - apenas modo live |
| Roteador Adaptativo, Fluxo corretivo | Planejado |
| Golden set RegRAG-BR | 230 perguntas: 36 validation/dev + 194 test |
| Apps de API / dashboard | Planejado (apenas scaffolding) |
| `make bench` (replay determinístico, bit a bit, ADR-0004) | Planejado - precisa de um cache versionado de chamadas de LLM, ainda não construído |

## Início rápido

```bash
uv sync --all-groups
make infra-up # Postgres+pgvector, OpenSearch
GEMINI_API_KEY=... OPENAI_API_KEY=... make bench-live
make bench-live-local # mesma matriz, embeddings Qwen locais
make dashboard # benchmark + Arena lado a lado
```

`make bench-live` chama provedores reais (embeddings, contextualização, sumarização do RAPTOR, extração de entidades do GraphRAG - ver a tabela de estratégias acima). `make bench` (replay determinístico e sem custo a partir de um cache versionado de LLM) é o design-alvo segundo a [ADR-0004](docs/adr/0004-benchmark-reproducibility-policy.md), mas essa camada de cache ainda não existe - apenas o modo live está implementado.

A matriz canônica e publicável usa `gemini-embedding-001`, selecionado pela
comparação isolada de embeddings em PT-BR (ADR-0005). `make bench-live-local`
usa `Qwen/Qwen3-Embedding-0.6B` como alternativa operacional sem credenciais
de embedding prevista pela ADR-0013; é uma execução identificada separadamente,
não um fallback silencioso nem uma troca do vencedor de qualidade.

Os dois comandos live persistem embeddings por texto e índices completos no
diretório ignorado `.ragforge/cache/`. O fingerprint inclui o texto derivado do
corpus, a identidade do embedding e o produtor de texto sintético; índices
parciais nunca são marcados como reutilizáveis. `--resume <run-id>` pula
estratégias já concluídas, e um lock do repositório impede benchmarks simultâneos.

## Decisões de design relevantes

Todas as escolhas não óbvias são registradas como [ADRs](docs/adr/README.md). As mais estruturantes:

- [ADR-0002](docs/adr/0002-article-level-relevance-judgments.md) - julgamentos de relevância no **nível de artigo da norma**, para que as métricas de recuperação continuem comparáveis entre estratégias que fragmentam o texto de formas diferentes (ou nem retornam chunks).
- [ADR-0003](docs/adr/0003-empirical-router-oracle.md) - o roteador é avaliado contra um **oráculo empírico por pergunta** (melhor estratégia medida, não presumida), com uma divisão dev/test que evita vazamento de few-shot.
- [ADR-0004](docs/adr/0004-benchmark-reproducibility-policy.md) - o `make bench` reproduz a partir de um cache versionado de LLM: reprodução bit a bit, custo zero de API.
- [ADR-0006](docs/adr/0006-legal-structural-chunker.md) - chunking sensível ao domínio pela hierarquia jurídica (Art./§/inciso), com IDs estruturais estáveis.
- [ADR-0007](docs/adr/0007-llm-judge-calibration-ptbr.md) - o judge de LLM é calibrado contra avaliação humana em PT-BR e a concordância é publicada.
- [ADR-0011](docs/adr/0011-structural-id-collision-in-amended-norms.md) - IDs estruturais que colidem entre histórico de emendas/anexos anexados são excluídos das citações do golden set, não corrigidos no nível do chunker.
- [ADR-0016](docs/adr/0016-post-generation-citation-audit.md) - um verificador de suporte semântico e no máximo uma reescrita limitada capturam alegações sem suporte que uma checagem de mera existência da citação deixaria passar.
- [ADR-0017](docs/adr/0017-auditable-evidence-lineage.md) - todo score publicado é rastreável até um diretório de evidência encadeado por hash e à prova de adulteração, por execução - entradas exatas, identidades de modelo e candidatos de recuperação, não só a métrica agregada.

## Estrutura do repositório

```
apps/ # api/ (FastAPI) e dashboard/ (Streamlit: benchmark + Arena)
src/ragforge/ # domain/ (núcleo livre de framework) · ingestion/ chunking/ embeddings/
# retrieval/ reranking/ routing/ generation/ evaluation/ governance/
datasets/ # corpus/ (snapshot versionado) + regrag-br/ (golden set, CC-BY-4.0)
experiments/ # resultados versionados + cache de LLM por run-id
configs/ # configs declarativas de experimentos - todo número do README nasce aqui
docs/adr/ # architecture decision records
```

O núcleo é livre de framework: `RetrievalStrategy` é um Protocol; SDKs de LLM são banidos dos pacotes centrais por uma guarda de arquitetura no CI (`scripts/validate_architecture.py`, limites em `pyproject.toml`).

## Dataset - RegRAG-BR

230 perguntas (7 classes de consulta) sobre resoluções selecionadas do CMN/BCB (4.893, gestão de risco, Open Finance, PLD/FT) e normas da CVM/CMN, com julgamentos de relevância no nível de artigo e respostas de referência, publicadas sob CC-BY-4.0 com um datasheet. O split determinístico e estratificado reserva 36 perguntas para desenvolvimento/validação do roteador e 194 para as métricas oficiais de teste. As normas são atos oficiais (art. 8º, I, Lei 9.610/98 - não protegidos por direito autoral).

Publicado (`datasets/regrag-br/judgments.json`): 230 perguntas curadas manualmente, cada uma com uma resposta de referência, verificadas contra o texto real extraído de 5 documentos do corpus (LC-105/2001, RES-CMN-4893/2021, RES-CMN-5274/2025, LEI-13709/2018-LGPD, ICVM-607/2019). Um 6º documento do corpus, a LEI-6385/1976, ainda não foi curado. IDs estruturais conhecidos por serem ambíguos no texto-fonte real - artefatos de histórico de emendas e anexos anexados em 3 dos 5 documentos - são excluídos de citação; ver [ADR-0011](docs/adr/0011-structural-id-collision-in-amended-norms.md).

## Desenvolvimento

```bash
uv sync --all-groups
uv run pytest
uv run python scripts/quality_gate.py # ruff, mypy, pytest (≥80% do core), bandit, pip-audit, guarda de arquitetura
```

Estruturado com [claude-python-engineering-harness](https://github.com/brunovicco/claude-python-engineering-harness) ([ADR-0009](docs/adr/0009-scaffold-via-engineering-harness.md)).

## Licença

Código: MIT · Dataset (RegRAG-BR): CC-BY-4.0
56 changes: 56 additions & 0 deletions configs/experiments/benchmark-local-v01.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Provider-free embedding variant of benchmark-v01.yaml (ADR-0013).
# It keeps the same corpus, split, strategies, generator, and independent
# judge as the canonical benchmark; only the embedding backend changes.
run_id: null
corpus:
snapshot: datasets/corpus/
hash: null
dataset:
path: datasets/regrag-br/
split: test
strategies:
- dense
- sparse_bm25
- hybrid_rrf
- reranked
- contextual
- parent_child
- sac
- sac_contextual
- raptor
- graphrag
embedding:
provider: local
model: Qwen/Qwen3-Embedding-0.6B
dimensions: 1024
# CPU is the stable default on the current development machine. Override
# with cuda on a compatible NVIDIA host; device is execution metadata, not
# a different semantic embedding identity.
device: cpu
generation:
model: gemini-3.1-flash-lite
temperature: 0
judge:
provider: openai
model: gpt-5.4-mini-2026-03-17
embedding_model: text-embedding-3-small
reasoning_effort: medium
audit:
enabled: false
provider: openai
model: gpt-5.4-mini-2026-03-17
reasoning_effort: medium
retrieval:
top_k: 5
rerank_pool: 50
llm_cache:
mode: live
execution:
answer_quality_workers: 5
gemini_max_in_flight: 4
embedding_cache_dir: .ragforge/cache/embeddings
index_cache_dir: .ragforge/cache/indexes
pricing:
generation:
input_per_million_usd: null
output_per_million_usd: null
Loading