Il RAG nativo fa parte dell'intelligenza artificiale nativaintegrata nel backend Aurabase, insieme a NL2SQL: non un servizio di terze parti da assemblare su una base generale. Prerequisiti per seguire questo tutorial: un progetto Aurabase esistente, un provider LLM configurato (OpenAI o Google Gemini per gli incorporamenti, uno dei tre provider nativi per la generazione) e una chiave API del progetto.
- Una pipeline Aurabase RAG è composta da due chiamate:
ragIngest()per indicizzare un documento,rag()per interrogare e generare una risposta. Chunking, incorporamenti e ricerca vettoriale sono gestiti lato server. - Sotto il cofano, ci sono PostgreSQL e pgvector standard: una tabella
embeddingscon una colonna vettoriale per classe di dimensione (768, 1536, 3072) e un indice HNSW parziale per classe. - Il Chunking utilizza un vero e proprio tokenizer (
tiktokeno200k), con sovrapposizione configurabile e protezione anti-esplosione su documenti di grandi dimensioni. - Il contenuto recuperato viene neutralizzato prima di essere inserito nel prompt: un documento che tenta di sfuggire al proprio tag per falsificare le istruzioni del sistema viene esplicitamente disinnescato.
- Solo OpenAI e Gemini generano incorporamenti sul lato Aurabase. Anthropic/Claude non dispone di un'API di incorporamento pubblica, rimane riservata alla generazione della risposta finale.
Come funziona questa pipeline RAG
La pipeline si svolge in cinque fasi. Dopo l'acquisizione, il testo viene suddiviso, ogni blocco viene vettorizzato in batch e quindi archiviato. Dopo l'interrogazione, la domanda viene vettorizzata a sua volta, rispetto ai blocchi memorizzati dalla similarità del coseno, e gli snippet più vicini vengono inseriti nel prompt inviato al modello di generazione.
Chunking (tiktoken)→Embedding (batch)→archiviazione pgvettoriale (HNSW)→Ricerca di similarità→Generazione aumentata
Un dettaglio architettonico importante nella produzione: durante le chiamate di rete al fornitore di incorporamento o generazione non viene mantenuta alcuna connessione Postgres. La transazione DB si chiude prima della chiamata esterna e si riapre dopo, per non bloccare mai un backend PgBouncer condiviso per la latenza di rete di terze parti.
Creare il progetto
A differenza di un tipico pgvector self-hosted, non è necessario eseguire CREATE EXTENSION vector o creare tu stesso una tabella per questa pipeline. Il provisioning dello schema embeddings del progetto, con le relative colonne vettoriali e gli indici HNSW, viene eseguito automaticamente al momento della creazione del progetto.
Il fornitore di incorporamento viene configurato una volta, lato progetto (Studio → IA → Fornitori). È questo provider che determina la dimensione effettiva dei tuoi vettori, quindi la colonna utilizzata nella tabella embeddings.
Indicizza i tuoi documenti con ragIngest()
Per indicizzare un documento è sufficiente una chiamata: il testo viene diviso in pezzi, ogni pezzo viene vettorizzato, quindi archiviato nel namespace richiesto. La suddivisione utilizza un vero tokenizzatore (tiktoken, codifica o200k_base), non una semplice suddivisione per spazi, che rimane corretta sul testo senza spazi come alcune lingue asiatiche.
In HTTP non elaborato, il percorso equivalente è POST /v1/ai/{project_id}/rag/ingest, autenticato dalla chiave API del progetto.
L'acquisizione è idempotente per impostazione predefinita: un identificatore del documento viene derivato automaticamente (hash SHA-256 del contenuto o metadata.document_id se lo fornisci). La reintegrazione dello stesso contenuto sostituisce i blocchi esistenti invece di duplicarli, rendendo sicuro il processo di sincronizzazione periodica da riprodurre.
Ciò che effettivamente arriva in Postgres
Nessuna magia proprietaria qui: la tabella che riceve i tuoi vettori è una normale tabella Postgres, con una colonna vector per classe di dimensione e un indice HNSW parziale per colonna (attivo solo sulle righe che la popolano). Ecco la sua vera definizione, semplificata:
Ogni ricerca confronta i vettori con l'operatore di distanza coseno (<=>), quello preso di mira dalle classi di operatori vector_cosine_ops e halfvec_cosine_ops dell'indice. Per i dettagli sui compromessi richiamo/latenza di HNSW rispetto a IVFFlat, vedere l'articolo dedicato all'indicizzazione HNSW. Per la scelta della dimensione di incorporamento stessa, vedere il confronto 768 vs 1536 vs 3072.
Interroga e genera risposta con rag()
Lato query, rag() concatena la vettorizzazione della domanda, la ricerca per similarità nel namespace, la costruzione del prompt aumentato e la chiamata al modello di generazione, in un unico andata e ritorno di rete lato client.
La risposta riporta la risposta generata e le sue fonti, con il fornitore effettivamente utilizzato:
Il contenuto recuperato non viene mai inserito in modo grezzo nel prompt del sistema. Si tratta di dati inaffidabili (caricamento utente, pagina indicizzata): un documento che contiene, ad esempio, un tag di sezione di chiusura seguito da false istruzioni viene neutralizzato prima dell'assemblaggio, le sue parentesi angolari sostituite da parentesi quadre, il testo preservato ma la struttura disinnescata.
Se rag() non trova nulla anche se il tuo spazio dei nomi non è vuoto, la risposta contiene un avvertimento esplicito anziché un silenzio fuorviante: il tuo corpus è probabilmente indicizzato sotto un altro modello o un'altra dimensione di incorporamento. Reindicizzarlo tramite POST /v1/ai/{project_id}/rag/{namespace}/reindex.
Da LangChain e un pgvettoriale fatto a mano: cosa cambia
Se hai già creato un chatbot RAG su PostgreSQL con LangChain, qui ogni mattone manuale ha un equivalente gestito lato server, senza modificare il database sottostante.
| Suddividere il testo | RecursiveCharacterTextSplitter da impostare | ragIngest(): suddivisione integrata dei tiktoken, 512 token/64 sovrapposti per impostazione predefinita |
|---|---|---|
| Incorporamenti | Chiamata manuale a OpenAIEmbeddings, gestione dei limiti batch | Nuovo tentativo temporaneo incorporato in batch automatico |
| Memorizzazione dei vettori | tabella pgvettoriale + indice HNSW per creare e migrare autonomamente | Schema e indici forniti per progetto |
| Cerca + richiesta | PGVector.similarity_search() quindi assemblando manualmente il prompt | rag(): ricerca e generazione aumentata in una chiamata |
| Contenuto recuperato | Iniettato così come indicato nel prompt | Neutralizzazione automatica dei tag della struttura prima del montaggio |
Stai migrando un progetto esistente basato su Supabase con questo tipo di assemblaggio manuale? La logica di migrazione per il resto del backend (schema, policy RLS, SDK) è trattata nella nostra guida alla migrazione da Supabase ad Aurabase.
Impostazioni e limiti di cui essere consapevoli prima di entrare in produzione
Tre impostazioni influiscono direttamente su costo e latenza, tutte verificate nel codice del servizio aura-ai. Il numero di tentativi su una chiamata di incorporamento temporanea (errore di rete, errore del provider 429) è 3 per impostazione predefinita, con un backoff di base di 100 ms. I documenti di grandi dimensioni sono incorporati in sottolotti limitati a 2048 blocchi per impostazione predefinita, per rispettare i limiti API dei fornitori senza fallire su un singolo documento di grandi dimensioni. Un guardrail (10.000 blocchi per impostazione predefinita, configurabile) rifiuta esplicitamente l'acquisizione di un documento che produrrebbe un numero aberrante di blocchi.
Dal lato della ricerca, la dimensione dell'elenco dei candidati HNSW si adatta automaticamente a max(64, top_k × 4): più risultati richiedi, più candidati l'indice esplora per preservarne il ricordo. Un valore fisso rimane possibile tramite una variabile d'ambiente se il tuo corpus ha un profilo particolare.
Gli spazi vettoriali di modelli diversi non vengono mai confrontati tra loro: ogni ricerca rimane limitata al modello di incorporamento corrente, e il cambiamento dei modelli richiede una reindicizzazione esplicita piuttosto che un cambiamento silenzioso che spezzerebbe la coerenza dei risultati.
Limiti attuali di cui essere consapevoli
La dimensione di incorporamento deve rientrare in una delle tre classi supportate: 768, 1536 o 3072. Un provider che restituisce un'altra dimensione viene rifiutato con un errore esplicito, mai troncato o trasmesso automaticamente.
La generazione di incorporamenti è disponibile solo tramite OpenAI o Google Gemini tra i tre fornitori nativi: Anthropic/Claude non espone un'API pubblica di incorporamenti, quindi viene utilizzata solo per generare la risposta finale in questa pipeline, mai per la vettorizzazione.
L'SDK JavaScript non espone ancora gli override top_k e threshold sulla chiamata rag(): rimangono accessibili in HTTP diretto, limitati rispettivamente a [1, 50] e [0, 1], ma non da aura.ai.rag() come avviene oggi. La soglia di somiglianza predefinita (0,3) è deliberatamente permissiva; restringere il campo a un corpus denso per evitare fonti irrilevanti nel prompt.
Per andare oltre
I RAG coprono domande su contenuti non strutturati (documenti, note, ticket). Per domande sui dati relazionali, NL2SQL nativo di Aurabase traduce direttamente una domanda in SQL convalidato. Per i dettagli sui parametri HNSW e sulle classi di dimensione menzionati sopra, vedere l'articolo sull'indicizzazione HNSW e il confronto delle dimensioni di incorporamento. Il riferimento API completo rimane la documentazione RAG e pgvector e la documentazione AI Gateway.