Overview

RAG Chatbot

Componente Angular <wuic-rag-chatbot> che permette di interrogare il codebase

WUIC in linguaggio naturale, con due modalita' operative: retrieval pure

(top-K snippet del codice) e RAG + LLM (risposta generata da Claude usando

i top-K come contesto). Degrada automaticamente in retrieval-only se la API

key Claude non e' configurata sul server.

Architettura

Tre layer, nessun processo esterno:

  • Layer 1 — Engine RAG .NET WuicRagEngine.dll (cartella rag-engine/),

caricato in-process da RagEngineLoader quando rag-use-dotnet-engine e'

true. Esegue con ONNX Runtime (GPU CUDA se presente, altrimenti CPU) il

retrieval ibrido BM25 + bge-m3 + reranker cross-encoder e la chiamata al

provider LLM configurato. Modelli, tokenizer e indice vengono scaricati al

primo avvio in rag-engine/artifacts/.

  • Layer 2 — RagController in KonvergenceCore (/api/Rag/Query,

/api/Rag/Chat, /api/Rag/Health, /api/Rag/Reload), autenticato via

cookie k-user; risolve i tool di metadata e applica le azioni proposte.

  • Layer 3 — Componente Angular standalone <wuic-rag-chatbot> esportato

da wuic-framework-lib.

Il server Python FastAPI rag_server.py (127.0.0.1:8765) e' lo stack

storico: resta supportato come fallback opzionale con

rag-use-dotnet-engine = "false", ma non e' incluso nei pacchetti di release.

Contesto pagina e retrieval dinamico dei metadata

Quando l'utente chatta da una pagina dell'app, il componente inietta nel prompt

un contesto pagina minimale: solo la route/pagina corrente (es. cities/list,

cities/edit, designer). NON inlinea l'elenco colonne, l'identita' SQL o i

dettagli dei lookup — inlinearli gonfiava ogni richiesta a prescindere dal prompt

e saturava il context window.

I dettagli mancanti vengono recuperati on-demand dal modello tramite il tool

non-terminale request_metadata_detail, risolto lato backend da

RagController.ResolveMetadataDetail (l'engine non ha accesso al DB metadata). Il

modello chiama il tool, riceve il risultato come tool_result e SOLO DOPO emette

il propose_* con i nomi reali. Il loop multi-turn e' gestito dall'engine (max 3

turni di retrieval).

detail supportati:

detailRitornaQuando
columnsidentita' SQL (schema/tabella + full qualifier) e l'elenco colonne reali (nome, tipo, lookup, required, pk, nome SQL)servono i nomi reali delle colonne di una route
lookup_columnsjoin_alias, value_field, text_field, related_route, related_columns[] di una colonna lookupByIDsi compone uno snippet SQL su un lookup

Convenzione alias di join (lookup): la query autogenerata WUIC joina la tabella

correlata di una colonna lookupByID con alias <column>_<entity> (es. la colonna

StateProvinceID lookup verso stateprovinces ha alias StateProvinceID_stateprovinces).

Negli snippet SQL i campi della tabella correlata si referenziano come

[<join_alias>].[<col>], es. [StateProvinceID_stateprovinces].[StateProvinceName].

Il valore esatto dell'alias va sempre ottenuto via

request_metadata_detail{detail:'lookup_columns'}, mai dedotto a mano.

Il meccanismo e' estendibile: nuovi detail (es. physical_columns, related_routes,

enum_values) si aggiungono nel resolver senza toccare il componente Angular ne'

gonfiare il contesto.

Modalita'

mode inputComportamento
auto (default)Usa chat se il backend espone Claude API key, altrimenti retrieval
chatForza RAG + LLM. Se la API key manca, il backend ritorna mode=retrieval-only con warning visibile
retrievalForza retrieval-only, salta la chiamata LLM (utile per ridurre costi)

Inputs

InputTipoDefaultDescrizione
titlestring'Assistente codebase WUIC'Etichetta header
mode'auto' | 'chat' | 'retrieval''auto'Modalita' operativa
topKnumber5Numero di chunk da retrieve dal RAG
showSourcesbooleantrueMostra/nasconde i source chip nei messaggi assistant
maxHistorynumber20Numero massimo di turn mantenuti in memoria
placeholderstring'Chiedi qualcosa...'Placeholder dell'input
modelstring'claude-haiku-4-5-20251001'Modello Claude per la modalita' chat
chatHeightstring'420px'Altezza fissa area chat
showClearButtonbooleantrueMostra bottone "Svuota cronologia"

Outputs

OutputPayloadDescrizione
resultSelectedRagSourceClick su un source chip; il componente tenta anche un deep-link vscode://file/...
errorOccurred{message, details?}Errori HTTP non recuperabili
turnAddedRagChatbotTurnEmette dopo ogni turn (user o assistant) aggiunto alla history

Esempio d'uso

Standalone import nel componente parent:

  • selector HTML: <wuic-rag-chatbot mode="auto" [topK]="5" (resultSelected)="onSrc($event)"></wuic-rag-chatbot>
  • import TypeScript: import { WuicRagChatbotComponent, RagSource } from 'wuic-framework-lib';
  • aggiungere WuicRagChatbotComponent agli imports del componente standalone parent.

Per una pagina demo completa con aside debug e gestione eventi, vedi

WuicTest/wwwroot/src/app/component/rag-chatbot-demo-page/.

Auth

Tutte le chiamate HTTP partono con withCredentials: true e il bridge C#

applica gli stessi check di autenticazione degli altri controller WUIC

(cookie di sessione k-user, regola 10 di AGENTS). L'engine RAG gira in-process nel backend: non c'e' nessun servizio

aggiuntivo da esporre o proteggere.

Accesso agli endpoint dalla 1.7.13:

EndpointAccesso
/api/Rag/Query, /api/Rag/Healthsenza login
/api/Rag/Chatsessione valida (anche guest, se enableGuest e' attivo)
/api/Rag/MetadataDetailsenza login per i dettagli sui metadati; sample_records, lookup_value, db_connections, db_databases, db_tables, db_columns solo amministratori
/api/Rag/Reloadsolo amministratori

La chiave LLM configurata sul server non viene mai inviata a un provider o a un baseUrl indicati nella richiesta: chi li sovrascrive passa la propria apiKey, altrimenti la risposta e' retrieval-only.

Server MCP wuic-rag e utente wuic_assistant

Il server MCP scripts/mcp/wuic-rag-mcp.mjs (WUIC Assistant, Claude Code, Cursor) usa questi endpoint. Quando il backend risponde 401 apre una sessione con MetaService.login, con WUIC_USER / WUIC_PASSWORD letti dall'ambiente (.mcp.json) o, se mancano, da scripts/mcp/wuic-assistant.credentials.json. Il login serve a wuic_ask e, con un utente amministratore, a wuic_sample_records / wuic_lookup_value; wuic_codebase_search, wuic_route_columns, wuic_route_metadata e wuic_lookup_columns restano senza login.

  • Il wizard di primo avvio crea l'utente dedicato wuic_assistant (superadmin, separato dall'admin interattivo) con una password generata per ogni installazione, e la scrive in scripts/mcp/wuic-assistant.credentials.json con un .gitignore accanto: il file non va committato ne' copiato su altre installazioni.
  • L'estensione VS Code usa lo stesso file quando wuicAssistant.metadataAdminUser e wuicAssistant.metadataAdminPassword sono vuoti (default); valorizzale solo per credenziali diverse.
  • Aggiornamento da 1.7.12 o precedenti: la password fissa che wuic_assistant aveva fino alla 1.7.12 viene rifiutata al login. Un amministratore imposta una nuova password per wuic_assistant e la scrive nel file credenziali ({"user":"wuic_assistant","password":"..."}) o nelle impostazioni dell'estensione.

Service WuicRagService

API tipizzata sopra RagController, esportata da wuic-framework-lib.

Tre metodi principali:

  • query(text, {topK, useLora}) -> Observable<RagQueryResponse>
  • chat(text, history, {topK, model}) -> Observable<RagChatResponse>
  • health() -> Observable<RagHealthResponse>
  • reload() -> Observable<{status, ...}> (post rebuild RAG)

Varianti *Async ritornano Promise via firstValueFrom().

Tutte le interfacce RagSource, RagQueryResponse, RagChatResponse,

RagHealthResponse, RagChatTurn sono esportate.

Modello Claude

Default: claude-haiku-4-5-20251001 (veloce, italiano nativo, ~$0.001 per

query da 5 chunk). Override possibile via input [model] del componente

oppure passando options.model al metodo chat() del service.

System prompt usato server-side:

> Sei un assistente esperto del codebase WUIC. Rispondi alla domanda dell'utente

> usando ESCLUSIVAMENTE il contesto fornito. Se la risposta non e' nel contesto,

> rispondi 'Non ho trovato informazioni sufficienti nel codebase per rispondere.'

> Cita sempre i file rilevanti tra parentesi quadre nel formato

> [file.ext::SimboloOpzionale]. Rispondi in italiano salvo richiesta esplicita

> di un'altra lingua. Non inventare API o nomi di metodi: se non sono nel

> contesto, dillo esplicitamente.

Fallback automatico

Quando il backend rileva una di queste condizioni, il response include

mode: 'retrieval-only' + warning + sources:

  • rag-llm-provider / rag-llm-api-key non configurati in AppSettings
  • chiamata Claude fallita (errore HTTP, rate limit, modello sconosciuto, ecc.)
  • richiesta con provider o baseUrl propri ma senza apiKey (la chiave del server non viene usata verso provider o host scelti da chi chiama)

Il componente Angular interpreta response.mode === 'retrieval-only' e mostra

nel turn assistant un summary testuale dei top-K chunk + il banner warning,

cosi' l'utente vede comunque dei risultati utili.

Prerequisiti runtime

  • KonvergenceCore in esecuzione con rag-use-dotnet-engine = "true" (espone /api/Rag/...)
  • Cartella rag-engine/ con WuicRagEngine.dll accanto all'app (inclusa nei pacchetti di release; in dev override con rag-engine-dll-path)
  • Accesso internet al primo avvio per scaricare modelli + indice (~4,5 GB) da rag-engine-models-url
  • Login con cookie k-user di sessione valido
  • (Opzionale) GPU NVIDIA con CUDA 12.x + cuDNN 9 (rag-engine-device = auto la usa se presente)
  • (Opzionale) rag-llm-provider + rag-llm-api-key in AppSettings per la modalita' chat

Avvio (primo utilizzo)

Alla prima apertura della route rag-chatbot (o a fine first-run) il backend

avvia in background il bootstrap dell'engine: scarica modelli ONNX, tokenizer

e indice (~4,5 GB, 1-5 min a seconda della banda) in rag-engine/artifacts/,

carica il satellite e fa il warm-up (~30 s). L'utente riceve una notifica

in-app all'avvio e al termine; fino ad allora il componente mostra il banner

"Server RAG non raggiungibile" con stato RAG offline. Se il backend

viene riavviato a meta' download, il download riprende al boot successivo.

Non c'e' nessuno script da lanciare. Le uniche scelte sono in appsettings.json

(sezione AppSettings):

Snippet 1JSON
{
  "rag-use-dotnet-engine": "true",
  "rag-engine-device": "auto",
  "rag-engine-profile": "release",
  "rag-engine-models-url": "https://wuic-framework.com/rag-models",
  "rag-llm-provider": "anthropic",
  "rag-llm-api-key": "sk-ant-..."
  • rag-engine-device: auto usa la GPU NVIDIA se trovata (CUDA 12.x + cuDNN 9,

~1 s/query), altrimenti CPU (~15-25 s/query). rag-engine-cuda-path indica la

cartella delle DLL CUDA se non sono installate a livello di sistema.

  • rag-engine-eager-load: true carica il motore in background all'avvio del

backend, cosi' la prima ricerca non paga il caricamento a freddo (su CPU anche

qualche minuto); il costo e' la RAM del motore (4,5-6,5 GB) occupata anche se il

RAG non si usa. Default false: il motore si carica alla prima richiesta; nel

frattempo gli strumenti MCP wuic_codebase_search / wuic_ask aspettano fino a

60 s e poi rispondono di riprovare invece di andare in timeout.

  • rag-llm-provider / rag-llm-api-key / rag-llm-base-url /

rag-llm-default-chat-model: provider della chat (anthropic, openai,

openrouter, ollama). Senza provider il chatbot resta in retrieval-only.

Le chiavi sono hot-reload: dettaglio nella pagina AppSettings.

Fallback Python (storico)

scripts/rag-setup.ps1 crea il venv e avvia rag_server.py su

127.0.0.1:8765; si usa solo con rag-use-dotnet-engine = "false", ad

esempio per separare il carico GPU su un host dedicato. Non e' incluso nei

pacchetti di release.

Hot-reload post rebuild RAG

Dopo aver rigenerato l'indice/LoRA, basta

chiamare:

  • POST /api/Rag/Reload (via WuicRagService.reload(), solo amministratori)
  • oppure riavviare il backend (l'engine ricarica index/ al boot)

per ricaricare il nuovo indice senza downtime applicativo.

Riferimenti

  • Engine .NET: rag-engine/WuicRagEngine.dll
  • Bridge C#: /api/Rag/Query, /api/Rag/Chat, /api/Rag/Health