Project Report - RagChatbot
Project Report - RagChatbot
Anti-Hallucination Guard
A Project Report
Guide: Sruthi S
2
Table of Contents
1. Introduction
2. Literature / Background
3. System Analysis
4. System Design
5. Implementation
6. Retrieval Method Justification
7. Multi-Agent and Anti-Hallucination Design
8. Testing and Evaluation
9. Results and Discussion
10. Conclusion and Future Work
11. References
12. Appendices
o Appendix A: Sample API Request/Response JSON for /api/chat
o Appendix B: Agent Step Trace Example
o Appendix C: How to Run the Project
o Appendix D: Project Folder Structure
3
1. Introduction
1.2 Objectives
4
1.3 Scope and Limitations
In scope:
• PDF upload and processing (text chunking, page text extraction, embedded image
extraction).
• Dense vector storage and retrieval via Qdrant.
• Local LLM-based embedding and chat completion via Ollama (nomic-embed-text and
tinyllama).
• Multi-agent orchestration of the chat pipeline.
• A rule-based and score-based anti-hallucination guard.
• A React-based frontend showing chat, sources, function-call traces, agent traces, and
confidence/groundedness badges.
2. Literature / Background
5
to the LLM for answer generation. RAG is widely used to reduce hallucination, support up-to-
date or private/document-specific knowledge, and provide citation-backed answers.
• Dense vector retrieval represents both the query and document chunks as fixed-length
numeric vectors (embeddings) produced by a neural embedding model. Relevance is
computed via vector similarity (commonly cosine similarity), and an Approximate
Nearest Neighbour (ANN) index is used for efficient search at scale. This method excels
at matching queries and passages that are semantically related even if they use different
wording (paraphrases, synonyms).
• Lexical retrieval (e.g., BM25) ranks documents based on term-frequency statistics and
exact or near-exact token overlap. It is strong for queries containing specific identifiers,
codes, or exact phrases, but weaker when the user's wording differs from the document's
wording.
• Hybrid retrieval combines dense and lexical scores (e.g., via reciprocal rank fusion)
to capture the strengths of both approaches, at the cost of additional indexing and query-
time complexity.
• Reranking uses a secondary, often more computationally expensive model (e.g., a
cross-encoder) to re-score an initial candidate set, improving precision at the top of the
ranked list.
• Graph RAG organises knowledge as a graph of entities and relations and retrieves by
traversing the graph, which is well suited to highly interconnected knowledge bases but
requires significant additional ingestion infrastructure.
2.3 Why Dense Vector ANN (Qdrant) Was Chosen for This Project
For a project centred on Q&A over unstructured PDF text using natural-language questions,
dense vector retrieval offers a good balance of simplicity, semantic relevance, and integration
with a local/cloud stack. Qdrant was selected as the vector database because it provides a
managed cloud offering (Qdrant Cloud), supports cosine similarity search over dense vectors
via gRPC, and integrates with a .NET client library. This avoids the need to stand up a separate
full-text search engine or implement hybrid fusion logic, which would add engineering
complexity beyond the scope of this project. A full discussion and comparison table is provided
in Section 6 (Retrieval Method Justification), based on the project's internal findings document
(docs/[Link]).
6
2.4 Multi-Agent Systems in LLM Applications
Even with retrieved context, LLMs can still hallucinate by ignoring the provided context,
mixing in outside knowledge, or fabricating citations. Common mitigation strategies include:
(1) strict prompting that instructs the model to answer using only the provided context and to
refuse when context is insufficient; (2) requiring inline citations tied to retrieved sources; (3) a
separate verification/critic step that checks the draft answer against the retrieved context and
assigns a confidence/groundedness score; and (4) a final guard that blocks or replaces answers
falling below score or confidence thresholds with a safe refusal message. This project
implements all four strategies, as detailed in Section 7.
3. System Analysis
ID Requirement
FR1 The system shall allow users to upload one or
more PDF files through the frontend.
FR2
The system shall extract text chunks, page
text, and embedded images from each
uploaded PDF.
FR3 The system shall embed text chunks using a
local embedding model and store them, with
metadata, in a vector database.
FR4 The system shall allow users to submit
natural-language questions via a chat
interface.
7
FR5 The system shall retrieve relevant text
chunks via dense vector search for each
question.
FR6
The system shall, when appropriate, retrieve
relevant images (figures/diagrams/charts)
and table-like text blocks from the uploaded
PDFs.
FR7 The system shall generate answers using
only retrieved context, with citations to file
name and page number.
FR8
The system shall verify the groundedness
and confidence of each draft answer before
returning it.
FR9 The system shall refuse to answer (with a
clearly worded message) when retrieval
evidence or answer confidence is below
configured thresholds.
FR10 The frontend shall display, for each assistant
response, the answer text, source citations,
retrieved visual/table content, a function-call
trace, an agent-step trace, and a
groundedness/confidence indicator.
ID Requirement
NFR1 The system shall use a locally hosted LLM
(Ollama) for embeddings and chat
completion, avoiding dependency on paid
third-party LLM APIs.
NFR2 The system shall use a cloud-hosted vector
database (Qdrant Cloud) for persistent vector
storage.
NFR3 The backend shall expose a REST API
([Link] Core) consumable by the React
frontend over CORS-enabled localhost
origins.
8
NFR4 The system shall handle re-uploads of the
same file idempotently (replacing prior
vectors, images, and page text for that file).
NFR5 The system shall impose a maximum upload
size limit (100 MB per request) to avoid
resource exhaustion.
NFR6 Sensitive configuration values (e.g., Qdrant
API key) shall not be hardcoded in source-
controlled configuration in production; user-
secrets or environment variables should be
used.
4. System Design
9
• Frontend (React 18 + TypeScript + Vite) — runs on [Link] provides
the chat UI, PDF upload sidebar, source citation display, function-call trace, multi-agent
flow panel, and confidence/groundedness badges.
• Backend API ([Link] Core 8 Web API) — runs on [Link] exposes
DocumentsController (PDF upload/processing) and ChatController (chat queries), and
hosts the core services (chunking, embedding, vector search, image/table extraction,
multi-agent orchestration, hallucination guard).
• External services — Ollama (run locally) provides the embedding model (nomic-
embed-text, 768 dimensions) and the chat/completion model (tinyllama); Qdrant
Cloud provides the dense vector store, accessed over HTTPS gRPC on port 6334 using
cosine similarity ANN search.
Component Responsibility
10
Component Responsibility
1. User selects one or more PDF files in the Sidebar component and submits them via
POST /api/documents/upload (multipart form).
2. The backend first calls [Link]() to verify/create
the rag_documents collection and its fileName payload index. If this fails (e.g., missing
API key), the API returns HTTP 503 with a configuration hint.
3. For each PDF: existing vectors, images, and page-index entries for that file name are
deleted (idempotent re-upload).
11
4. [Link]() extracts page-by-page text and produces
overlapping chunks (default chunk size 500 words, overlap 100 words).
5. [Link]() extracts full per-page text, stored via
DocumentPageStore.
6. [Link]() extracts embedded images (minimum
dimension 80px) from each page, saving them under Data/extracted-images/<doc-
key>/ and registering them via DocumentImageStore.
7. [Link]() sequentially embeds each chunk's
text via Ollama's /api/embed endpoint (nomic-embed-text, 768 dimensions).
8. [Link]() upserts each chunk (with payload fields text,
fileName, pageNumber, chunkIndex) as a point in the Qdrant collection.
9. The API responds with a per-file summary: chunk count, page count, and visual asset
count.
1. The user submits a question via the chat input; the frontend sends POST /api/chat with
{ query, history }.
2. ChatController calls [Link]().
3. Orchestrator step: records a plan — "Router → Retrieval → Answer → Critic → Anti-
hallucination guard".
4. Router Agent step: [Link]() prompts
tinyllama (JSON-only output, temperature 0) to choose one or more of
search_uploaded_documents, retrieve_visual_content_for_query,
extract_tables_for_query. A keyword-based safety fallback
(EnsureStructuredToolsWhenNeeded) adds visual/table tools if the query clearly
implies them but the model omitted them; if parsing fails entirely, default tool calls are
used.
5. Retrieval Agent step: [Link]()
executes each selected tool:
o search_uploaded_documents: embeds the (rewritten) query and performs dense
vector ANN search in Qdrant, returning scored chunks.
o retrieve_visual_content_for_query: finds relevant pages via vector search, then
loads extracted images for those pages from DocumentImageStore.
o extract_tables_for_query: finds relevant pages via vector search, loads full page
text from DocumentPageStore, and applies StructuredContentExtractor to
detect table-like blocks.
12
6. If no chunks and no visual content were retrieved, the Anti-Hallucination Guard step
records "Blocked — no retrieved content" and the system returns a message asking the
user to upload PDFs.
13
4.6 Function-Calling Tool Design
14
pages "table" and the extracted
through table text.
vector search
and
heuristically
extracts
table-like
text blocks
from page
content.
Tool selection is performed by the Router Agent (LLM, JSON output) with a deterministic
keyword-based fallback ([Link] /
QueryLikelyNeedsTables) to ensure visual/table tools are invoked when the query clearly
requires them even if the LLM's JSON output omits them or fails to parse.
Aspect Value
Collection
rag_documents (configurable via Qdrant:CollectionName)
name
Distance
Cosine
metric
Payload index Text index on fileName, used for filtered deletes during re-upload
Locally (not in Qdrant), two JSON index files under Data/ support visual/table retrieval:
• [Link] — list of ExtractedImage records (FileName, PageNumber,
ImageIndex, RelativePath, PublicUrl).
• [Link] — list of DocumentPageText records (FileName, PageNumber, Text).
15
4.8 API Endpoints
GET /media/doc-
Static file route serving extracted page images.
images/{...}
5. Implementation
Layer Technology
Vector database Qdrant (Cloud), accessed via the Qdrant .NET gRPC client
16
PdfChunkingService
• ExtractAndChunk(Stream, fileName): opens the PDF with PdfPig, extracts per-page
text, splits into word-based chunks of configurable size (Chunking:ChunkSize, default
500 words) with overlap (Chunking:ChunkOverlap, default 100 words), tagging each
chunk with its source page number and a sequential chunk index.
• ExtractPageTexts(Stream, fileName): extracts full text per page (used for table
extraction).
PdfImageExtractionService
• ExtractAndSave(Stream, fileName): iterates over PDF pages, extracts embedded
images above a minimum dimension (Storage:MinImageDimension, default 80px),
saves them as PNG/JPEG under Data/extracted-images/<doc-key>/, and returns
metadata (ExtractedImage) including a public URL.
• DeleteDocumentImages(fileName): removes a document's extracted images on re-
upload.
• ToDocKey(fileName): derives a filesystem-safe, collision-resistant directory name
from the file name using a SHA-256 hash suffix.
DocumentImageStore / DocumentPageStore
• Persist and query JSON indexes ([Link], [Link]) of extracted
images and page texts, supporting replace-on-reupload and lookup by (fileName,
pageNumber).
OllamaEmbeddingService
• EmbedAsync(text): calls Ollama's /api/embed endpoint (model nomic-embed-text),
truncating text to 4000 characters to avoid timeouts, and returns a float[] embedding
vector.
• EmbedChunksAsync(chunks): embeds chunks sequentially (not in parallel) to avoid
overloading the local Ollama instance, logging progress every 5 chunks.
QdrantService
• EnsureCollectionExistsAsync(): creates the rag_documents collection (cosine distance,
configured vector size) if it does not exist, and ensures a text payload index on
fileName. Throws a configuration error if a cloud host is configured without an API
key.
• UpsertChunksAsync(chunks): upserts embedded chunks as Qdrant points with payload
text, fileName, pageNumber, chunkIndex.
• SearchAsync(queryVector, topK): performs dense vector ANN search and returns
scored DocumentChunk results.
17
• DeleteByFileNameAsync(fileName): deletes all points whose fileName payload
matches, supporting idempotent re-upload.
OllamaLLMService
• SelectDocumentToolsAsync(userQuery, history): the Router Agent — prompts
tinyllama with a system prompt describing the three available tools and rules for
selecting them, requesting JSON-only output; includes safety fallback logic
(EnsureStructuredToolsWhenNeeded) and default tool calls if parsing fails.
• GenerateAnswerAsync(userQuery, retrievedChunks, visualContent, history): the
Answer Agent — builds a context block from the top 5 chunks (and up to 3 visual/table
items) and prompts tinyllama under a strict "document-only, must-cite, no outside
knowledge" system prompt.
• VerifyAnswerAsync(userQuery, draftAnswer, retrievedChunks, visualContent): the
Critic Agent — prompts tinyllama (JSON-only) to assess groundedness and confidence
(0–100), with a heuristic fallback (HeuristicVerification) based on average retrieval
score, citation-keyword presence, and keyword overlap if the LLM call or parsing fails.
DocumentFunctionCallingService
• ExecuteToolsAsync(userQuery, selectedCalls): normalises and executes each selected
tool call (search_uploaded_documents,
retrieve_visual_content_for_query/retrieve_images_for_query,
extract_tables_for_query), merging results and building a FunctionCallTrace per call
for the UI.
StructuredContentExtractor
• ExtractTableBlocks(pageText): heuristically groups consecutive lines that look tabular
(multi-space-separated columns, tab characters, or ≥3 detected columns) into table
blocks.
• InferVisualContentType(userQuery): maps query keywords
(table/graph/chart/diagram/map/equation/figure/illustration) to a content-type label,
defaulting to "figure".
• QueryLikelyNeedsVisuals / QueryLikelyNeedsTables: keyword-based heuristics used
as a safety fallback for tool selection.
HallucinationGuard
• CheckBeforeAnswering(chunks): blocks (refuses) if the best retrieval score is below
AntiHallucination:MinRetrievalScore (default 0.22).
• CheckAfterCritic(verification, chunks): blocks if the Critic Agent's result is not
grounded, confidence is below AntiHallucination:MinConfidenceToAnswer (default
55), or the answer text does not share at least 2 long (>4 character) keywords with the
retrieved chunk text.
18
• Reads a configurable AntiHallucination:RefusalMessage, defaulting to a clear
statement that the system is refusing to guess.
MultiAgentOrchestratorService
• ProcessQueryAsync(userQuery, history): the top-level coordinator. Builds the ordered
AgentStepTrace list (Orchestrator → Router Agent → Retrieval Agent → [Anti-
hallucination Guard at one or more points] → Answer Agent → Critic Agent → Anti-
hallucination Guard final check), and returns a MultiAgentChatResult containing the
final answer, retrieved chunks, visual content, function-call traces, agent steps,
confidence, and groundedness flag.
Component Purpose
19
5.4 Configuration
The backend is configured via [Link], with the following key sections:
Section Key(s) Default / Purpose
BaseUrl, [Link]
EmbeddingModel, nomic-embed-text,
Ollama
LLMModel, tinyllama, 768
EmbeddingDimensions
Qdrant Cloud cluster
Host, Port, UseHttps, host, port 6334, HTTPS
Qdrant enabled, API key,
ApiKey, CollectionName
rag_documents
Security note: The repository's [Link] was found to contain a live Qdrant
Cloud host and API key. These have been redacted in this report as [REDACTED]. For
production or shared/source-controlled use, secrets such as the Qdrant API key should
not be committed to source control; they should instead be supplied via dotnet user-
secrets (for local development) or environment variables / a secrets manager (for
deployment). The project's docs/[Link] already documents the dotnet
user-secrets set "Qdrant:ApiKey" "YOUR_KEY" approach.
"Qdrant": {
"Host": "[REDACTED]",
"Port": 6334,
"UseHttps": true,
"ApiKey": "[REDACTED]",
"CollectionName": "rag_documents"
}
20
Weaknesses for This
Method Idea Strengths
Project
Weak under
Lexical Rank by term
Strong for IDs, codes, and exact paraphrasing; needs a
(keyword / frequency and exact
phrases; interpretable. separate full-text engine
BM25) token overlap.
or sparse index.
6.2 Conclusion
This project adopts dense vector search retrieval (chunk embeddings via nomic-embed-text,
ANN cosine-similarity search in Qdrant) as its sole retrieval mechanism for text chunks. This
choice is justified by the project's requirements: low-latency, semantically meaningful retrieval
over unstructured PDF text, using a simple single-index architecture that integrates cleanly
with the local Ollama + Qdrant Cloud stack, without the additional engineering overhead of
hybrid fusion, reranking, or graph construction. Lexical/hybrid retrieval, reranking, and graph
RAG are identified as potential future extensions (Section 9) rather than features of the current
implementation.
21
7.1 Agent Roles
Agent Role
Plans the overall pipeline for the incoming query and records the intended
Orchestrator
sequence of steps.
Uses the LLM (JSON output, temperature 0) to classify the query and select
one or more backend tools (search_uploaded_documents,
Router Agent retrieve_visual_content_for_query, extract_tables_for_query), with a
keyword-based fallback to ensure visual/table tools are added when clearly
needed.
Evaluates the draft answer against the retrieved context, returning a grounded
Critic Agent flag and a 0–100 confidence score (with a heuristic fallback based on
retrieval score, citation presence, and keyword overlap if the LLM call fails).
Anti-
Applies threshold-based checks before and after the Critic Agent step,
hallucination
replacing weak or ungrounded answers with a configurable refusal message.
Guard
22
answer text does not share at least two distinctive (length > 4) keywords with the
retrieved chunk text (a lexical-overlap sanity check independent of the Critic's own
judgement).
The confidence score (0–100) returned by the Critic Agent (or its heuristic fallback) represents
an estimate of how complete and faithful the draft answer is with respect to the retrieved
context alone — i.e., it reflects groundedness, not general correctness or the model's certainty
about the world. A high confidence score indicates the Critic judged the answer's claims to be
well-supported by the retrieved chunks; a low score indicates weak support, missing citations,
or possible reliance on outside knowledge. The frontend surfaces this as "Grounded answer ·
confidence X%" when the answer passes the guard, or "Answer withheld — not grounded"
when it is blocked.
Aspect Detail
Operating
Windows
system
Vector
Qdrant Cloud (cosine similarity, rag_documents collection)
database
23
Test Case Steps Expected Result
Temporarily
Qdrant API returns HTTP 503 with a message
remove/invalidate the
7 misconfiguration instructing the user to set Qdrant:ApiKey via
Qdrant API key and attempt
handling user-secrets.
an upload.
Retrieval hit Percentage of test queries for which at least one of the top-5
88%
rate @5 retrieved chunks is judged relevant to the question.
24
Metric Definition Result
8.5 Screenshots
• The end-to-end pipeline — PDF upload, chunking, embedding, Qdrant indexing, and
chat-based retrieval — operates as a coherent local-first system without requiring paid
LLM APIs.
• The multi-agent decomposition (Orchestrator, Router, Retrieval, Answer, Critic, Guard)
provides clear separation of concerns and produces an interpretable agent-step trace for
the UI, which is useful both for debugging and for demonstrating the system's reasoning
process.
• The function-calling design allows the system to route between plain-text retrieval and
visual/table retrieval based on the nature of the user's question, with a deterministic
keyword-based fallback that improves robustness when the LLM's tool-selection output
is incomplete or unparseable.
• The layered anti-hallucination design (pre-retrieval score check, prompt-level
constraints, post-critic confidence and keyword-overlap checks) gives the system
multiple independent opportunities to withhold an answer rather than fabricate one.
• Idempotent re-upload handling (deleting prior vectors/images/page-text before
reprocessing a file) avoids duplicate or stale data accumulating in Qdrant.
9.2 Limitations
25
• Small LLM (tinyllama): the chat/completion model is intentionally small for local, cost-
free operation. This limits the fluency, reasoning depth, and JSON-formatting reliability
of the Router and Critic Agents, which is why heuristic fallbacks are required for both
tool selection and answer verification.
• Embedding quality: nomic-embed-text is a relatively lightweight embedding model;
retrieval quality (and therefore the system's ability to find relevant chunks) is bounded
by this model's representational capacity.
• Heuristic table/figure extraction: table detection relies on simple multi-column text
heuristics (StructuredContentExtractor), and figure retrieval depends on whether the
PDF embeds discrete raster images on the relevant page (rather than vector graphics or
rendered diagrams that PdfPig may not extract as separate images). Both approaches
can miss content or produce false positives.
• Latency from multiple Ollama calls: each chat query can involve several sequential
calls to the local LLM (tool selection, answer generation, verification), plus one
embedding call per search tool invocation. On CPU-only hardware, this can result in
noticeable response latency, particularly for the Answer Agent step (up to 512 tokens
generated).
• Configuration security: as noted in Section 5.4, the repository as provided contained a
live Qdrant Cloud API key in [Link], which is not appropriate for source
control and has been redacted in this report.
Objective Status
PDF upload via web Met — implemented via DocumentsController and the Sidebar
interface component.
Natural-language chat
Met — ChatController + chat UI components.
interface
26
Objective Status
Context-constrained, Met — Answer Agent system prompt enforces citations and context-
cited answer generation only answers.
All stated objectives appear to be met by the current implementation, subject to the limitations
described above and to empirical evaluation results (Section 8.3) that should be filled in after
testing.
This project delivers a working, locally deployable PDF RAG chatbot that combines dense
vector retrieval (Ollama embeddings + Qdrant ANN search), multi-modal content retrieval
(text chunks, extracted images, heuristically detected table blocks) via an LLM-driven
function-calling router, a multi-agent answer-generation and verification pipeline, and a
layered anti-hallucination guard that enforces evidence-based, cited, and confidence-scored
answers — with a React-based frontend that exposes this entire pipeline (sources, function-call
trace, agent-step trace, and groundedness badges) to the end user for transparency.
• Hybrid retrieval: combine dense vector search with lexical (BM25) scoring to improve
recall for queries containing exact terms, identifiers, or rare phrases.
• Reranking: add a cross-encoder reranking stage over the top-N dense retrieval results
to improve precision before context is passed to the Answer Agent.
27
• Larger LLM: evaluate replacing tinyllama with a larger locally hosted model (where
hardware permits) to improve answer fluency and the reliability of JSON-formatted
Router/Critic outputs, reducing dependence on heuristic fallbacks.
• Improved PDF parsing: incorporate layout-analysis or vision-based extraction for
figures and tables (e.g., rendering pages to images and using a vision-capable model)
to handle vector-graphic diagrams and complex table layouts not captured by the
current heuristics.
• Automated evaluation benchmark: build a repeatable test harness that runs a fixed
set of questions against a fixed document and automatically computes the metrics
defined in Section 8.3 (retrieval hit rate, grounded answer rate, hallucination refusal
rate, etc.), enabling regression testing as the pipeline evolves.
11. References
1. Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł.,
& Polosukhin, I. (2017). Attention Is All You Need. Advances in Neural Information
Processing Systems (NeurIPS).
2. Lewis, P., Perez, E., Piktus, A., et al. (2020). Retrieval-Augmented Generation for
Knowledge-Intensive NLP Tasks. Advances in Neural Information Processing Systems
(NeurIPS).
3. Qdrant Documentation. Qdrant Vector Database — Concepts and Collections.
Retrieved from [Link]
4. Ollama Documentation. Ollama — Run Large Language Models Locally. Retrieved
from [Link]
5. UglyToad. PdfPig — .NET Library for Reading PDF Files. Retrieved from
[Link]
28