RAG Step 5: Enhance Your Chat with RAG

Integrate the RAG engine into your Flask chat endpoint so the AI answers questions using your knowledge base.

Step 1: Add the RAG Route

Add a new endpoint to backend/app/routes.py:

from .rag_engine import search_similar_chunks, build_rag_context, generate_rag_response
from .models import Document


@api.route("/rag-chat", methods=["POST"])
def rag_chat():
    data = request.get_json()
    user_message = data.get("message", "")

    if not user_message:
        return jsonify({"error": "Message is required"}), 400

    user_msg = Message(content=user_message, sender="user")
    db.session.add(user_msg)
    db.session.commit()

    try:
        results = search_similar_chunks(db, user_message, Document, top_k=5)
        context = build_rag_context(results)
        ai_reply = generate_rag_response(user_message, context)

        ai_msg = Message(content=ai_reply, sender="ai")
        db.session.add(ai_msg)
        db.session.commit()

        return jsonify({
            "user_message": user_msg.to_dict(),
            "ai_message": ai_msg.to_dict(),
            "evidence": [
                {"title": r["title"], "similarity": round(r["similarity"], 3)}
                for r in results
            ],
        })

    except Exception as e:
        return jsonify({"error": str(e)}), 500

The response now includes an evidence field showing which documents were used.

Step 2: Restart the Backend

Stop and restart with PostgreSQL connected:

docker compose -f advanced/docker-compose.rag.yml up --build

Step 3: Test the RAG Chat

# Ask about tutoring
curl -X POST http://localhost:5000/api/rag-chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Where can I get tutoring at Clark?"}'

Expected response:

{
  "user_message": {"content": "Where can I get tutoring at Clark?", ...},
  "ai_message": {
    "content": "Clark College offers free tutoring in business, English, math, science, and general education classes. You can also access online eTutoring through e-Chat or e-Questions."
  },
  "evidence": [
    {"title": "Tutoring Services at Clark College", "similarity": 0.843},
    {"title": "Tech Hub at Clark College", "similarity": 0.512},
    {"title": "Libraries at Clark College", "similarity": 0.487}
  ]
}

Try more questions:

# Ask about financial aid
curl -X POST http://localhost:5000/api/rag-chat \
  -H "Content-Type: application/json" \
  -d '{"message": "How can I get help paying for college?"}'

# Ask about news
curl -X POST http://localhost:5000/api/rag-chat \
  -H "Content-Type: application/json" \
  -d '{"message": "What happened at the CTE Showcase?"}'

# Ask about events
curl -X POST http://localhost:5000/api/rag-chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Tell me about the Sakura Festival"}'

Step 4: Compare With and Without RAG

RAG off (original /api/chat):

curl -X POST http://localhost:5000/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "What tutoring is available at Clark?"}'
# → Generic answer: "Most colleges offer tutoring services..."

RAG on (/api/rag-chat):

curl -X POST http://localhost:5000/api/rag-chat \
  -H "Content-Type: application/json" \
  -d '{"message": "What tutoring is available at Clark?"}'
# → Specific answer: "Clark College offers free tutoring in business, English..."

The RAG version gives an accurate, specific answer because it found the tutoring document.

Step 5: How It Works End-to-End

User: "What tutoring is available at Clark?"

1. Embed the question
   "What tutoring is available at Clark?"
   → [0.04, -0.13, 0.29, ...]                 (384-dim vector)

2. Search pgvector
   SELECT * FROM document
   ORDER BY embedding <=> :query_vec
   LIMIT 5

3. Found top 3 similar chunks:
   [0.84] "Tutoring Services at Clark College"
   [0.51] "Tech Hub at Clark College"
   [0.49] "Libraries at Clark College"

4. Inject into prompt:
   System: "Use this context to answer:\n\n
            [Tutoring Services at Clark College]
            Clark College offers free tutoring..."

5. LLM generates answer using context
   "Clark College offers free tutoring in business, English..."

6. Return to user + include evidence

Write Tests for the RAG Pipeline

Test the full flow — embedding, search, and response generation:

from app import create_app, db
from app.models import Document
from advanced.rag.rag_engine import search_similar_chunks, build_rag_context

app = create_app()
with app.app_context():
    results = search_similar_chunks(db, "free tutoring", Document, top_k=3)
    assert len(results) == 3
    assert results[0]["similarity"] > 0.5
    print(f"Top result: {results[0]['title']} (similarity: {results[0]['similarity']:.3f})")

What These Tests Cover

Test What it verifies
test_embed_text_returns_384_dimensions Embedding model produces correct vector size
test_embed_text_consistent_output Same input → same vector (deterministic)
test_chunk_text_creates_chunks Long text is split correctly
test_chunk_text_short_text Short text stays as one chunk
test_get_all_chunks_returns_list Documents are properly converted to chunks
test_build_rag_context_formats_correctly Context string is formatted for the LLM

Test Your Work (Manual)

Write a test to verify the RAG pipeline works:

from app import create_app, db
from app.models import Document
from advanced.rag.rag_engine import search_similar_chunks, build_rag_context

app = create_app()
with app.app_context():
    results = search_similar_chunks(db, "free tutoring", Document, top_k=3)
    assert len(results) == 3
    assert results[0]["similarity"] > 0.5
    print(f"Top result: {results[0]['title']} (similarity: {results[0]['similarity']:.3f})")