Files
gart/rag/schema.sql
João HenriqueandClaude Sonnet 5 e9a17c1b62 feat(rag): provisiona busca RAG do G-ART e corrige indexação que abortava em chunk grande
Cria rag/ (schema, busca híbrida densa+lexical com RRF em search.py/
search_gart.sh, SETUP.md) — o projeto já tinha admin/update_rag.py para
indexar, mas nenhuma forma de consultar o índice. Corrige admin/update_rag.py:
um chunk denso em tokens (code/fcpxml/font_metrics.py) estourava o contexto
do modelo de embedding e derrubava a transação inteira; agora só aquele
chunk é pulado. Banco rag_gart provisionado no rag-hub-db compartilhado e
primeira indexação completa rodada (304 arquivos, 1702 chunks).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 09:38:46 -04:00

87 lines
3.4 KiB
SQL

-- Schema RAG do projeto G-ART (fcp-mcp-server).
-- Idempotente: seguro rodar múltiplas vezes (CREATE ... IF NOT EXISTS).
-- Segue o padrão dos bancos irmãos (rag_doza, rag_tigre, jhonny-rag): um
-- banco por sistema dentro do container compartilhado rag-hub-db, schema
-- próprio. Banco: rag_gart. Schema: gart.
--
-- Colunas e tabelas espelham exatamente o que admin/update_rag.py grava
-- (code_chunks, file_index, indexed_files) e o que rag/search.py lê.
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE SCHEMA IF NOT EXISTS gart;
CREATE TABLE IF NOT EXISTS gart.code_chunks (
id bigserial PRIMARY KEY,
file_path text NOT NULL,
content text NOT NULL,
chunk_index int,
embedding vector(768),
content_hash text,
file_mtime double precision,
-- Faixa de linhas do trecho no arquivo original. É o que permite ao
-- agente ler só a janela relevante em vez do arquivo inteiro.
start_line int,
end_line int,
-- Nomes declarados no trecho (class/def/func...), separados por vírgula —
-- o lado lexical (pg_trgm) da busca híbrida casa contra isto.
symbols text,
-- Módulo derivado do caminho relativo (primeiro segmento, ex: code/fcpxml -> code).
module text,
-- 'window': admin/update_rag.py corta por janela de linhas, não por
-- declaração (o projeto é majoritariamente Python/Swift/Markdown/shell).
kind text,
updated_at timestamp DEFAULT now()
);
-- HNSW, não ivfflat: com poucas centenas/milhares de chunks o ivfflat
-- particiona o espaço em listas quase vazias e a busca com probes baixo
-- varre quase nada (ver rag/README.md para os números de referência).
CREATE INDEX IF NOT EXISTS code_chunks_embedding_hnsw_idx
ON gart.code_chunks USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- Acelera a reindexação incremental (busca por file_path) e a limpeza de
-- chunks de um arquivo antes de reinserir.
CREATE INDEX IF NOT EXISTS idx_code_chunks_file_path
ON gart.code_chunks (file_path);
-- Lado lexical da busca híbrida.
CREATE INDEX IF NOT EXISTS code_chunks_file_path_trgm_idx
ON gart.code_chunks USING gin (file_path gin_trgm_ops);
CREATE INDEX IF NOT EXISTS code_chunks_symbols_trgm_idx
ON gart.code_chunks USING gin (symbols gin_trgm_ops);
CREATE INDEX IF NOT EXISTS code_chunks_module_idx
ON gart.code_chunks (module);
-- Hash de conteúdo por arquivo, usado pelo indexador para pular arquivos
-- que não mudaram desde a última rodada (reindexação incremental).
CREATE TABLE IF NOT EXISTS gart.indexed_files (
file_path text PRIMARY KEY,
content_hash text NOT NULL,
updated_at timestamp DEFAULT now()
);
-- Mapa de arquivos: 1 linha por arquivo. Responde "onde fica X" e "o que
-- tem no módulo Y" sem trazer nenhum corpo de código.
CREATE TABLE IF NOT EXISTS gart.file_index (
file_path text PRIMARY KEY,
module text,
main_type text,
public_symbols text[],
summary text,
n_lines int,
content_hash text,
summary_embedding vector(768),
updated_at timestamp DEFAULT now()
);
CREATE INDEX IF NOT EXISTS file_index_module_idx
ON gart.file_index (module);
CREATE INDEX IF NOT EXISTS file_index_path_trgm_idx
ON gart.file_index USING gin (file_path gin_trgm_ops);
CREATE INDEX IF NOT EXISTS file_index_summary_hnsw_idx
ON gart.file_index USING hnsw (summary_embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);