- Separate interface, API, corpus, embeddings, and generative model.
- Create a reusable local RAG architecture for different domains.
- Design prompts that require answers with sources and clear boundaries.
- Prepare the app for a local demo and for deploying the web part on Vercel.
The application map
Before coding, view the system as a chain of small pieces:
user -> web interface -> API -> RAG retriever -> sources -> prompt with rules -> LLM -> cited answer
What we are going to build
The final project will have these pieces:
- A web interface with a query box, answer, sources, and history.
- A Node.js backend with endpoints to query, search, and check index status.
- A corpus folder with chunked documents.
- Local embeddings generated with LM Studio, Ollama, or an OpenAI-compatible server.
- Semantic retrieval and keyword search.
- A system prompt that requires citations and abstention when sources are missing.
Step 1: define your domain
Don't start with code. Start with the product. Fill in this brief:
App name: User: Problem: Sources: Tone: Response format: Boundaries:
Example for an educational version:
Name: EduLexia User: vocational training teachers and students Problem: answer questions about course materials Sources: notes, rubrics, syllabi, and exercises Tone: clear, practical, and pedagogical Format: brief answer, steps, sources, and suggested task Boundaries: don't invent syllabus content or grades
Step 2: create the project foundation
To learn the pattern from Lexia, clone the repository and run it locally:
git clone https://github.com/aulafy/lexia.git cd lexia cp .env.example .env npm start
Key configuration variables:
PORT=5174 LM_BASE=http://127.0.0.1:1234/v1 CHAT_MODEL=gemma-3-12b-it EMBED_MODEL=bge-m3 USE_RERANK=0 TOP_K=6
Step 3: connect a local model runtime
In LM Studio, load a chat model and an embeddings model. Enable the OpenAI-compatible local server at http://127.0.0.1:1234/v1.
curl http://127.0.0.1:1234/v1/models
Test embeddings:
curl -s http://127.0.0.1:1234/v1/embeddings \
-H 'content-type: application/json' \
-d '{"model":"bge-m3","input":["embedding test"]}'Step 4: prepare your document library
For a first prototype, use a small JSON corpus. The important thing is that each chunk has text and a citation.
corpus/ documentos.json
[
{
"id": "doc-001#p1",
"titulo": "Course manual",
"cita": "Course manual, section 1",
"texto": "Fragment content...",
"materia": "course"
}
]Step 5: generate the embeddings index
npm run embed
Expected files:
data/embeddings.bin data/embeddings.ids.txt data/embeddings.meta.json
Step 6: build the query API
The core route of a Lexia-style app is a RAG query:
POST /api/consulta
async function consulta(pregunta) {
const fuentes = await retrieve(pregunta, 6);
const prompt = buildPrompt(pregunta, fuentes);
const respuesta = await chat(prompt);
return { respuesta, fuentes };
}Step 7: add hybrid retrieval
Lexia combines semantic search and keyword search. This is an important decision because technical domains have precise vocabulary.
- Embeddings: capture meaning.
- BM25 or lexical search: captures exact words.
- Authority weights: prioritize canonical sources.
- Optional reranker: reorders candidates when you need more precision.
Step 8: design the interface
The minimum interface should show:
- Query box.
- Mode selector: answer, draft, or search.
- Main answer.
- Retrieved sources with snippets.
- Local history.
- Index status and helpful error messages.
Retrieving sources... Generating cited answer... No index available. Run npm run ingest and npm run embed. The local model isn't responding. Check LM Studio.
Step 9: responsible guardrails
Step 10: evaluate before publishing
Create five known questions and note which source should appear. Don't evaluate only whether the answer sounds good.
[
{
"pregunta": "What deadline do I have to submit the activity?",
"fuente_esperada": "rubrica-entrega#p2"
},
{
"pregunta": "How is the final project graded?",
"fuente_esperada": "rubrica-final#p1"
}
]Simple metrics:
- Hit@3: the expected source appears among the top three.
- Hit@6: it appears among the top six.
- Cited answer: the answer includes references.
- Correct abstention: if there is no source, the app acknowledges it.
Step 11: prepare for Vercel
Vercel is perfect for publishing the web part and educational content. For a RAG app with local models, remember this separation:
- Static or Next.js web can be deployed on Vercel.
- The local model and embeddings live on your machine or private server.
- If you need a public demo, use sample data and a controlled remote backend.
npm run build vercel deploy
Final challenge
Create a mini Lexia for your own domain:
- Choose a domain.
- Prepare 15 corpus chunks without sensitive data.
- Configure local model and embeddings.
- Create five evaluation questions.
- Customize the prompt.