This project implements a RAG (Retrieval-Augmented Generation) system using Go, Ollama for local language models, and Qdrant as a vector database. The architecture follows Clean Architecture principles to ensure a clear separation of responsibilities.
- Loads and splits PDF documents into smaller chunks
- Generates embeddings for each chunk using Ollama models
- Stores embeddings and text in a Qdrant vector database
- Retrieves relevant documents for a query
- Uses LLM to generate answers based on retrieved documents
- Supports streaming responses for a more interactive experience
- Renders AI internal reasoning wrapped in
<think>tags as expandable/collapsible sections to keep answers organized - Allows per-PDF collection creation for more targeted retrieval
- Provides a web interface for document ingestion, querying and visualization
- Go (version 1.18 or higher) - Download Go
- Ollama - Download Ollama
- Qdrant - Docker Qdrant
git clone https://github.com/DjonatanS/rag-ollama-qdrant-go
cd rag-ollama-qdrant-gogo mod tidyDownload and install Ollama at: https://ollama.com/download
After installation, download the necessary models:
# Model for generating embeddings (768-dimensional vector)
ollama pull nomic-embed-text
# Model for text generation (you can replace it with other supported models)
ollama pull deepseek-r1:8bThe easiest way is to run it via Docker:
docker run -d -p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage \
qdrant/qdrantCheck if it's working by accessing: http://localhost:6333/dashboard
The project follows Clean Architecture principles:
/cmd
/ragapp # Application entry point
/internal
/usecase # Use cases and interfaces (business rules)
/infra # Concrete implementations (adapters)
/llm # Adapters for language models
/loader # Adapters for document loading
/splitter # Adapters for text splitting
/vectorstore # Adapters for vector databases
/data
/pdfs # PDF files for processing
Place your PDF files in the data/pdfs folder. The application will process all PDF files found in this directory during the ingestion phase.
You can compile the application into a single binary:
go build -o ragapp cmd/ragapp/main.goThe application has two main modes: ingest and query.
This mode processes the PDF documents in the data/pdfs directory, generates embeddings, and stores them in Qdrant. Run this mode first.
Using go run:
go run cmd/ragapp/main.go ingestUsing the compiled binary:
./ragapp ingestPer-PDF collections: To create a separate collection for each PDF (useful for targeted queries):
go run cmd/ragapp/main.go ingest-per-pdfThis mode takes a question as input, retrieves relevant documents from Qdrant, and generates an answer using the LLM.
Using go run:
# Ask a specific question
go run cmd/ragapp/main.go query "Your question here?"
# Ask a default question (if no question is provided)
go run cmd/ragapp/main.go queryUsing the compiled binary:
# Ask a specific question
./ragapp query "Your question here?"
# Ask a default question (if no question is provided)
./ragapp queryThe streaming mode provides real-time token-by-token responses, similar to ChatGPT's streaming experience:
go run cmd/ragapp/main.go stream "What are the key features of Go programming language?"Using the compiled binary:
./ragapp stream "What are the key features of Go programming language?"This will display the LLM's response in real-time as it's being generated, providing a more interactive experience.
If you don't specify a mode, the application will run both ingestion and query phases:
go run cmd/ragapp/main.go "Your question here?"To see all available options:
go run cmd/ragapp/main.go helpThe main configurations are defined in the cmd/ragapp/main.go file as constants:
| Parameter | Description | Default Value |
|---|---|---|
| pdfDir | PDF directory | "data/pdfs" |
| pdfPattern | Pattern to find PDFs | "*.pdf" |
| qdrantURL | Qdrant server URL | "http://localhost:6333" |
| collectionName | Collection name in Qdrant | "my_collection" |
| embedModel | Model for embeddings | "nomic-embed-text" |
| genModel | Model for text generation | "deepseek-r1:8b" |
| vectorSize | Vector dimensions | 768 |
| chunkSize | Text chunk size | 1000 |
| chunkOverlap | Overlap between chunks | 100 |
To change these configurations, edit the cmd/ragapp/main.go file before compiling or running.
In addition to the command-line interface, this project includes a web server that provides a graphical user interface for interacting with the RAG system.
# Run the web server
go run cmd/webserver/main.go
# Or if compiled
./webserverThe server will start on port 8020 by default. You can access the web interface by visiting http://localhost:8020 in your browser.
The web interface provides several key features:
-
Document Ingestion: Upload PDF documents through a drag-and-drop interface. You can choose to create individual collections per PDF or add them to a single collection.
-
Chat Interface: Ask questions about your documents and receive generated answers based on the content.
-
Vector Visualizations: View visual representations of your document vectors using techniques like t-SNE, UMAP, or PCA to understand document relationships.
-
Collection Management: Browse and manage your vector collections.
-
Similarity Search: Find documents similar to a text query and explore related content.
The web server's configuration options (such as port, model names, and vector dimensions) can be found at the top of the cmd/webserver/main.go file. Modify these constants to customize your server settings.
-
Ingestion Phase (
ingestmode):- PDF files from
pdfDirare loaded. - Text is extracted and split into chunks (
chunkSize,chunkOverlap). - Each chunk is converted to an embedding using the Ollama
embedModel. - Embeddings and corresponding text chunks are stored in the Qdrant
collectionName.
- PDF files from
-
Query Phase (
querymode):- The input question is converted to an embedding using the
embedModel. - Qdrant is queried to find documents (chunks) with embeddings similar to the question embedding.
- The retrieved document chunks are combined with the original question to form a prompt.
- The prompt is sent to the Ollama
genModel. - The LLM generates a response based on the provided context (documents) and the question.
- The input question is converted to an embedding using the
-
Streaming Phase (
streammode):- Works like the query phase but delivers the response token by token as it's generated.
- The UI displays the response in real-time, similar to ChatGPT's streaming experience.
- Particularly useful for longer responses where you want to see progress immediately.
cmd/ragapp/main.go: Entry point, configuration, command-line argument parsing, and main flow orchestration.
internal/usecase/interfaces.go: Defines interfaces for the core operations (Loader, Splitter, Embedder, LLM, VectorStore).internal/usecase/ingestion_usecase.go: Orchestrates the document ingestion process (load -> split -> embed -> store).internal/usecase/query_usecase.go: Orchestrates the query and response generation process (embed query -> search -> generate response).
internal/infra/loader/pdf_loader.go: Implements theLoaderinterface for PDF files.internal/infra/splitter/recursive_splitter.go: Implements theSplitterinterface using recursive character splitting.internal/infra/llm/ollama_embedder.go: Implements theEmbedderinterface using an Ollama model.internal/infra/llm/ollama_llm.go: Implements theLLMinterface for text generation using an Ollama model.internal/infra/vectorstore/qdrant_adapter.go: Implements theVectorStoreinterface using Qdrant.
Feel free to create issues, send PRs, or suggest improvements to this project.
This project is licensed under the MIT license.
