A minimal web chat assistant demonstrating RAG (Retrieval-Augmented Generation) and Memory patterns using Next.js and OpenAI's GPT-4o.
- RAG Implementation: Injects relevant information from
knowledge_base.txtinto prompts - User Memory: Stores and applies user preferences (concise vs detailed responses)
- Simple Chat UI: Clean, responsive interface built with React/Next.js
- Serverless API: Next.js API routes for prompt construction and OpenAI calls
- Persistent Storage: Uses lowdb for simple JSON-based user preference storage
- Node.js 18+ and npm
- OpenAI API key (Get one here)
npm installCreate a .env file in the project root:
cp .env.example .envEdit .env and add your OpenAI API key:
OPENAI_API_KEY=sk-your-actual-openai-api-key-here
npm run devOpen http://localhost:3000 in your browser.
smart-faq-mvp/
├── pages/
│ ├── index.tsx # Main chat UI
│ ├── _app.tsx # Next.js app wrapper
│ └── api/
│ ├── chat.ts # Main chat endpoint (RAG + Memory)
│ └── clear-preference.ts # Clear user preference endpoint
├── lib/
│ ├── memory.ts # User preference storage (lowdb)
│ └── rag.ts # RAG retrieval logic
├── styles/
│ └── globals.css # Global styles
├── knowledge_base.txt # FAQ content (RAG source)
├── claude.md # Alternative Claude-style implementation
├── package.json
├── tsconfig.json
├── next.config.js
└── README.md
Try asking questions from the knowledge base:
- "What is the refund policy?"
- "What are the hardware requirements?"
- "When are the live sessions?"
- "Tell me about technical support"
Control response format:
- "I want concise answers" → Sets preference to concise
- "I prefer detailed responses" → Sets preference to detailed
The bot will remember your preference across the session!
Click the "Clear" button in the preference bar to reset your response format preference.
The system uses simple keyword-based retrieval:
- User query is tokenized into keywords
- Each section in
knowledge_base.txtis scored by keyword matches - Top 3 most relevant sections are injected into the prompt as
[RAG INFORMATION]
User preferences are stored in a JSON database (db.json):
- Preference phrases are detected in user messages
- Preferences are saved per user ID (UUID stored in localStorage)
- Active preferences are injected into prompts as
[RESPONSE_PREFERENCE]
The final prompt sent to OpenAI follows this strict order:
- System Message: Defines bot role and constraints
- Memory Injection: User preference (if exists)
- RAG Injection: Relevant knowledge base fragments
- Chat History: Recent conversation context
- User Question: Current query
- Assistant Instruction: Final guidance
-
RAG Test: Ask "What is the refund policy?"
- Expected: Should return refund policy from knowledge base
-
Memory Test: Say "I want concise answers", then ask a question
- Expected: Response should be shorter and more direct
-
Out-of-scope Test: Ask something not in the knowledge base
- Expected: Bot should say it cannot answer and suggest contacting support
- Long queries: RAG should still return precise matches
- Preference false positives: Use phrases like "I want concise answers" rather than just "concise"
Edit knowledge_base.txt to add or modify FAQ content. Use numbered sections for best results:
1. Topic Name:
Content here...
2. Another Topic:
More content...
Modify lib/rag.ts to implement:
- Vector similarity search (requires embeddings)
- More sophisticated scoring
- Section metadata filtering
Current implementation uses lowdb (JSON file). Alternatives:
- SQLite: Better for production, multi-user scenarios
- Redis: Fast, scalable, great for sessions
- PostgreSQL: Full-featured database with complex queries
- Vector-based RAG using OpenAI embeddings + Pinecone
- Tool-based memory (Claude-style on-demand retrieval)
- Multi-user authentication
- Admin UI for knowledge base management
- Analytics dashboard
- File upload for dynamic knowledge base updates
See claude.md for a Claude-style design using:
- Clean Slate memory pattern
- Tool-based on-demand memory retrieval
- Conditional context injection
npm run build
npm startMIT
This is an MVP/learning project. Feel free to fork and experiment!
For issues or questions about the implementation, please refer to the original specification document.
