Overview
RAG Chatbot
Angular component <wuic-rag-chatbot> that allows querying the WUIC codebase
in natural language, with two operating modes: pure retrieval
(top-K code snippets) and RAG + LLM (response generated by Claude using
the top-K as context). Automatically degrades to retrieval-only if the Claude
API key is not configured on the server.
Architecture
3-layer stack, all already deployed in the project:
- Layer 1 -- Python FastAPI server
rag_server.pyon127.0.0.1:8765,
loads at boot the hybrid BM25 + bge-m3 + LoRA cross-encoder Phase C index
from c:/src/Wuic/codebase_embeddings/.
- Layer 2 -- C# bridge
RagControllerin KonvergenceCore (/api/Rag/Query,
/api/Rag/Chat, /api/Rag/Health, /api/Rag/Reload), authenticated proxy
via k-user cookie.
- Layer 3 -- Angular standalone component
<wuic-rag-chatbot>exported
from wuic-framework-lib.
See also the operational skill skills/rag-chatbot-creation/SKILL.md for the
end-to-end creation/maintenance playbook, and
skills/rag-rebuild-pipeline/SKILL.md for the index/LoRA rebuild.
Page context and dynamic metadata retrieval
When the user chats from an app page, the component injects a **minimal page
context** into the prompt: only the current route/page (e.g. cities/list,
cities/edit, designer). It does NOT inline the column list, SQL identity or
lookup details — inlining them bloated every request regardless of the prompt and
saturated the context window.
The missing details are fetched on-demand by the model via the non-terminal
tool request_metadata_detail, resolved on the backend by
RagController.ResolveMetadataDetail (the engine has no access to the metadata DB).
The model calls the tool, receives the result as a tool_result, and ONLY THEN
emits the propose_* with the real names. The multi-turn loop is handled by the
engine (max 3 retrieval turns).
Supported detail:
detail | Returns | When |
|---|---|---|
columns | SQL identity (schema/table + full qualifier) and the real column list (name, type, lookup, required, pk, SQL name) | the real column names of a route are needed |
lookup_columns | join_alias, value_field, text_field, related_route, related_columns[] of a lookupByID column | composing a SQL snippet on a lookup |
Join-alias convention (lookup): the WUIC auto-generated query joins the related
table of a lookupByID column with alias <column>_<entity> (e.g. the StateProvinceID
column looking up stateprovinces has alias StateProvinceID_stateprovinces). In SQL
snippets the related table fields are referenced as [<join_alias>].[<col>], e.g.
[StateProvinceID_stateprovinces].[StateProvinceName]. The exact alias value must
always be obtained via request_metadata_detail{detail:'lookup_columns'}, never
deduced by hand.
The mechanism is extensible: new detail kinds (e.g. physical_columns, related_routes,
enum_values) are added in the resolver without touching the Angular component or
bloating the context.
Modes
mode input | Behavior |
|---|---|
auto (default) | Uses chat if the backend exposes a Claude API key, otherwise retrieval |
chat | Forces RAG + LLM. If the API key is missing, the backend returns mode=retrieval-only with a visible warning |
retrieval | Forces retrieval-only, skips the LLM call (useful to reduce costs) |
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
title | string | 'Assistente codebase WUIC' | Header label |
mode | 'auto' | 'chat' | 'retrieval' | 'auto' | Operating mode |
topK | number | 5 | Number of chunks to retrieve from the RAG |
showSources | boolean | true | Shows/hides source chips in assistant messages |
maxHistory | number | 20 | Maximum number of turns kept in memory |
placeholder | string | 'Chiedi qualcosa...' | Input placeholder |
model | string | 'claude-haiku-4-5-20251001' | Claude model for chat mode |
chatHeight | string | '420px' | Fixed chat area height |
showClearButton | boolean | true | Shows the "Clear history" button |
Outputs
| Output | Payload | Description |
|---|---|---|
resultSelected | RagSource | Click on a source chip; the component also attempts a deep-link vscode://file/... |
errorOccurred | {message, details?} | Non-recoverable HTTP errors |
turnAdded | RagChatbotTurn | Emitted after each turn (user or assistant) added to the history |
Usage Example
Standalone import in the parent component:
- HTML selector:
<wuic-rag-chatbot mode="auto" [topK]="5" (resultSelected)="onSrc($event)"></wuic-rag-chatbot> - TypeScript import:
import { WuicRagChatbotComponent, RagSource } from 'wuic-framework-lib'; - Add
WuicRagChatbotComponentto the standalone parent component'simports.
For a complete demo page with debug aside and event handling, see
WuicTest/wwwroot/src/app/component/rag-chatbot-demo-page/.
Auth
All HTTP calls are sent with withCredentials: true and the C# bridge
applies the same authentication checks as other WUIC controllers
(session cookie k-user, rule 10 of AGENTS). Never expose the Python server
127.0.0.1:8765 directly to the browser: it must always be proxied
through C#.
WuicRagService Service
Typed API over RagController, exported from wuic-framework-lib.
Three main methods:
query(text, {topK, useLora}) -> Observable<RagQueryResponse>chat(text, history, {topK, model}) -> Observable<RagChatResponse>health() -> Observable<RagHealthResponse>reload() -> Observable<{status, ...}>(post RAG rebuild)
*Async variants return Promise via firstValueFrom().
All interfaces RagSource, RagQueryResponse, RagChatResponse,
RagHealthResponse, RagChatTurn are exported.
Claude Model
Default: claude-haiku-4-5-20251001 (fast, native Italian, ~$0.001 per
5-chunk query). Override possible via the component's [model] input
or by passing options.model to the service's chat() method.
System prompt used server-side:
> You are an expert assistant for the WUIC codebase. Answer the user's question
> using EXCLUSIVELY the provided context. If the answer is not in the context,
> reply 'I did not find enough information in the codebase to answer.'
> Always cite relevant files in square brackets in the format
> [file.ext::OptionalSymbol]. Reply in Italian unless another language is
> explicitly requested. Do not make up APIs or method names: if they are not
> in the context, say so explicitly.
Automatic Fallback
When the backend detects one of these conditions, the response includes
mode: 'retrieval-only' + warning + sources:
ANTHROPIC_API_KEYnot set on the Python server- Claude call failed (HTTP error, rate limit, unknown model, etc.)
The Angular component interprets response.mode === 'retrieval-only' and shows
in the assistant turn a textual summary of the top-K chunks + the warning banner,
so the user still sees useful results.
Runtime Prerequisites
- Python server
rag_server.pyactive on127.0.0.1:8765(see skill
rag-chatbot-creation for the NSSM setup in production)
- KonvergenceCore running (exposes
/api/Rag/...) - Login with a valid session
k-usercookie - (Optional)
ANTHROPIC_API_KEYenv var on the Python server for chat mode
Getting Started (first use)
If, when accessing the rag-chatbot route from the menu, you see the banner
"RAG server unreachable" with status RAG offline, it means the
Python server is not listening.
Prerequisites: Python 3.12 (winget install Python.Python.3.12)
Setup and startup with rag-setup.ps1
The rag-setup.ps1 script automates the venv creation and the installation
of the dependencies. It works both from the source repository and from a
deploy ZIP package (the RAG files are included in both).
# Setup (one time only) — creates venv, installs torch + dependencies
pwsh scripts/rag-setup.ps1
# For CUDA GPU (optional, faster)
pwsh scripts/rag-setup.ps1 -CudaVersion 12.1
# Start the serverThe cold start takes ~13 seconds (index + LoRA loading). Once the log
shows Uvicorn running on http://127.0.0.1:8765, reload the page in the
browser: the banner disappears and the chatbot switches to operating mode.
For production (persistent Windows service) see the skill
skills/rag-chatbot-deploy/SKILL.md.
Hot-reload After RAG Rebuild
After regenerating the index/LoRA with the rag-rebuild-pipeline skill, just
call:
POST /api/Rag/Reload(via WuicRagService.reload())- or restart the Python service
to reload the new index without application downtime.
Tests
The service and component tests are in:
projects/wuic-framework-lib/src/lib/service/wuic-rag.service.spec.ts(14 tests)projects/wuic-framework-lib/src/lib/component/rag-chatbot/rag-chatbot.component.spec.ts(18 tests)
Runnable with npm run test:unit:wuic-lib (vitest, default lib runner
post karma->vitest migration).
References
- Creation skill:
skills/rag-chatbot-creation/SKILL.md - RAG rebuild skill:
skills/rag-rebuild-pipeline/SKILL.md - Python server:
c:/src/Wuic/codebase_embeddings/rag_server.py - C# bridge:
c:/src/Wuic/KonvergenceCore/Controllers/RagController.cs - Angular service:
projects/wuic-framework-lib/src/lib/service/wuic-rag.service.ts - Component:
projects/wuic-framework-lib/src/lib/component/rag-chatbot/rag-chatbot.component.ts - Demo page:
c:/src/Wuic/WuicTest/wwwroot/src/app/component/rag-chatbot-demo-page/