Skip to content

tucanoo/springboot-ai-rag-tutorial

Repository files navigation

Tucanoo Cloud — Support Assistant (Spring AI RAG sample)

A complete, working Retrieval-Augmented Generation (RAG) application in Java. It answers customer-support questions from a folder of Markdown help articles, shows the sources behind every answer, and politely says "I don't know" when the answer is not in its knowledge base.

Built with Spring Boot 4, Spring AI, OpenAI, and PostgreSQL + pgvector — no Python and no separate vector database.

📖 Full step-by-step tutorial: Spring AI in Production: Building a RAG Application with Spring Boot 4 and PostgreSQL pgvector


What it does

  • Loads a knowledge base of Markdown articles into a vector store on first start.
  • Retrieves the most relevant chunks for each question and answers using only that context.
  • Returns citations (which articles the answer came from) with every response.
  • Refuses to guess: out-of-scope questions get an honest "I don't have that information."
  • Ships a simple web chat UI (Thymeleaf + plain JavaScript) — no build step, no Node.

Tech stack

Framework Spring Boot 4.0.6
AI library Spring AI 2.0.0-M8
Vector store PostgreSQL + pgvector
Chat + embeddings OpenAI (gpt-4o-mini, text-embedding-3-small)
UI Thymeleaf + vanilla JS
Build / Java Gradle, Java 25 (Java 17+ works)

⚠️ Spring AI 2.0.0-M8 is a milestone (pre-GA) release. It is the latest version that targets Spring Boot 4. Versions are pinned in build.gradle; move to 2.0.0 GA when it ships.

Prerequisites

  1. Java 17 or newer (tested on Java 25): java -version
  2. PostgreSQL with the pgvector extension. The quickest way is the official Docker image, which already includes the extension:
    docker run --name pgvector -e POSTGRES_PASSWORD=postgres \
      -e POSTGRES_DB=spring-ai-rag -p 5432:5432 -d pgvector/pgvector:pg17
    (Using your own Postgres? Install pgvector for it and run CREATE EXTENSION vector; in the database.)
  3. An OpenAI API key with a little credit (the whole demo costs a few cents).

Setup & run

  1. Provide your OpenAI key. Copy the example env file and paste your key into it:

    cp .env.example .env
    # then edit .env and set OPENAI_API_KEY=sk-...

    .env is git-ignored, so your key is never committed.

  2. Run the app, loading the key from .env:

    set -a && source .env && set +a && ./gradlew bootRun

    On the first start it ingests the knowledge base (embeds the chunks via OpenAI and stores them in pgvector). This runs only once — restarts are fast and do not duplicate data.

  3. Open http://localhost:8080 and ask a question, e.g. "What are the API rate limits on the Pro plan?" or "How do I reset my password?"

If port 8080 is taken, run on another port: ./gradlew bootRun --args='--server.port=8081'.

How it works (in short)

  1. IngestKnowledgeBaseLoader reads src/main/resources/kb/*.md, splits each file into chunks, and stores them. Spring AI embeds each chunk automatically.
  2. Retrieve + Augment — a QuestionAnswerAdvisor on the ChatClient searches pgvector for the chunks most similar to the question and adds them to the prompt as context.
  3. Generate — the model answers using only that context. A strict system prompt keeps it honest.
  4. Cite — the retrieved documents are read back from the response metadata and shown as sources.

See the tutorial for the full explanation.

Project structure

src/main/java/com/tucanoo/supportrag/
├── config/ChatClientConfig.java     # ChatClient + QuestionAnswerAdvisor + system prompt
├── ingestion/KnowledgeBaseLoader.java # reads, chunks, embeds and stores the knowledge base
├── rag/RagService.java              # asks the question, returns the answer + sources
└── web/                             # ChatController + request/response records
src/main/resources/
├── kb/*.md                          # the knowledge base (12 sample articles)
├── templates/chat.html              # the chat page
├── static/                          # css + js
└── application.yaml                 # configuration

Configuration

Key settings in src/main/resources/application.yaml:

Property Meaning
spring.datasource.* your PostgreSQL connection
spring.ai.openai.chat.options.model the chat model
spring.ai.openai.embedding.options.model the embedding model
spring.ai.vectorstore.pgvector.dimensions must match the embedding model (1536 for text-embedding-3-small)
app.rag.top-k how many chunks to retrieve per question
app.rag.similarity-threshold ignore matches weaker than this score

Run it for free with Ollama (optional)

Prefer to run everything locally with no API key? Swap the OpenAI starter for the Ollama starter and update the models — remember to set dimensions: 768 for nomic-embed-text. The tutorial has the full steps.

Notes

  • The sample application.yaml uses postgres/postgres as the database credentials — fine for a local demo, but change them for anything real.
  • This is example code for a tutorial. It is intentionally simple; see the tutorial's "Taking it to production" section for what to harden before shipping.

About

A complete, working RAG application in Java — Spring Boot 4, Spring AI, and PostgreSQL pgvector. A customer-support assistant that answers from your own docs and cites its sources.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors