- 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:
usuario -> interfaz web -> API -> recuperador RAG -> fuentes -> prompt con reglas -> LLM -> respuesta citada
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:
Nombre de la app: Usuario: Problema: Fuentes: Tono: Formato de respuesta: Límites:
Example for an educational version:
Nombre: EduLexia Usuario: profesores y alumnos de FP Problema: resolver dudas sobre materiales del curso Fuentes: apuntes, rubricas, programaciones y ejercicios Tono: claro, práctico y pedagógico Formato: respuesta breve, pasos, fuentes y tarea sugerida Límites: no inventar temario ni calificaciones
Step 2: create the project foundation
To learn the pattern from Lexia, clone the repository and run it locally:
git clone https://github.com/raym33/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":["prueba de embeddings"]}'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": "Manual del curso",
"cita": "Manual del curso, apartado 1",
"texto": "Contenido del fragmento...",
"materia": "curso"
}
]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.
Recuperando fuentes... Generando respuesta citada... No hay indice disponible. Ejecuta npm run ingest y npm run embed. El modelo local no responde. Revisa 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": "Que plazo tengo para entregar la actividad?",
"fuente_esperada": "rubrica-entrega#p2"
},
{
"pregunta": "Como se califica el proyecto final?",
"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.