# RAG sulla documentazione: chunk, indice e risposte con fonti

Un RAG sulla documentazione taglia i testi in chunk, li indicizza con un embedding e risponde citando il file: la qualità si decide nel taglio, non nel modello.

> Pagina: https://ui.eneawork.it/blog/ai-rag-documentazione
> Markdown: https://ui.eneawork.it/blog/ai-rag-documentazione.md

*2026-11-01*

Un RAG sulla documentazione è un indice di chunk con i loro embedding più un prompt che riceve solo i passaggi pertinenti: risponde citando il file, invece di indovinare. La qualità si decide nel taglio dei testi, prima del modello.

Il 1 novembre 2026 abbiamo diviso i 50 file markdown di docs/, 2.947.280 byte in totale, in chunk da 1.200 caratteri con 200 di sovrapposizione: escono 2.945 chunk, 995 caratteri in media, misurati con uno script Node. pgvector sul registry npm, letto lo stesso giorno, è alla versione 0.3.0: 39 file, 52.767 byte, 0 dipendenze, licenza MIT, Node 22 come minimo. pg è alla 8.23.1, con 20 file e 102.632 byte. L'endpoint /api/stats ha risposto con 102 byte in 139 ms. Il catalogo dietro conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie.

## Il chunk è l'unità di lavoro

Un chunk troppo grande porta rumore nel prompt e costa token; uno troppo piccolo perde il soggetto della frase. Il taglio a 1.200 caratteri con 200 di sovrapposizione tiene insieme un paragrafo e permette di citare il file.

## L'indice in Postgres

CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE doc_chunks ( id bigserial PRIMARY KEY, source text NOT NULL, chunk_index int NOT NULL, content text NOT NULL, embedding vector(1536) NOT NULL ); CREATE INDEX doc_chunks_embedding_idx ON doc_chunks USING hnsw (embedding vector_cosine_ops);

Lo schema sta in schema.sql e si applica con psql "$DATABASE_URL" -f schema.sql. La colonna vector(1536) ha la dimensione dell'embedding: se cambi modello cambi la colonna e ricostruisci l'indice. L'indice HNSW rende la ricerca approssimata, quindi veloce ma non esatta.

## Il taglio, in codice

const SIZE = 1200; const OVERLAP = 200; export function chunk(text: string): string[] { const out: string[] = []; for (let i = 0; i = text.length) break; } return out; }

La funzione è deterministica: lo stesso file produce gli stessi chunk, quindi puoi confrontare un indice vecchio con uno nuovo. Salva source e chunk_index a ogni riga: senza quei due campi la risposta non è verificabile.

## La risposta cita la fonte

## La limitazione

L'indice invecchia: se aggiorni un file senza ricalcolare i suoi chunk, il RAG risponde con la versione vecchia e la cita con sicurezza. Serve un'impronta del file per riga e un job che ricostruisce solo i file cambiati; nel nostro caso il job non è ancora automatico. Il taglio a caratteri, inoltre, non coincide con i confini di frase.

## Dove continuare

Per scegliere dove tenere i vettori, il confronto fra SQLite e Postgres in un progetto piccolo; il prompt che riceve i chunk è in prompt engineering per agenti; il protocollo per esporre la ricerca a un client è in che cos'è MCP. Le parti pronte per una chat con fonti sono in componenti chat, per esempio AI chat input di Jahed e chatgpt prompt input, dentro 111.985 componenti.

## FAQ

### Quanti chunk servono per un corpus piccolo?

Nel nostro caso 50 file markdown da 2.947.280 byte diventano 2.945 chunk da 1.200 caratteri con 200 di sovrapposizione, misurati il 1 novembre 2026. Sotto i 10.000 chunk un indice HNSW in Postgres basta; sopra, misura la latenza prima di aggiungere un servizio.

### Meglio pgvector o un servizio di vector database?

pgvector se i documenti stanno già in Postgres: una tabella, un indice e nessun servizio in più. Un servizio esterno conviene quando vuoi la ricerca gestita e accetti un'altra dipendenza; pgvector 0.3.0 pesa 52.767 byte con 0 dipendenze.

### Come scelgo la dimensione del chunk?

Parti da 1.200 caratteri con 200 di sovrapposizione e misura: se le risposte citano mezze frasi, alza la sovrapposizione; se il prompt costa troppo, abbassa la dimensione. Il numero giusto dipende dal testo, non dal modello.

### Il RAG elimina le allucinazioni?

No. Riduce lo spazio di invenzione perché il modello vede solo i chunk recuperati, ma può ancora unire due passaggi o ignorare la fonte. Una soglia di distanza e una risposta «non lo so» aiutano più di un prompt severo.

### Come aggiorno l'indice quando cambia un documento?

Salva un'impronta del file a ogni chunk e ricalcola solo i file la cui impronta è cambiata. Senza questo passaggio l'indice risponde con la versione vecchia e la cita come attuale.
