EchoMind: An AI Study Assistant for Fu Jen IM Students
An AI assistant for Fu Jen University Information Management students: course experience from 42 courses plus department rules, organized into a 667-question knowledge base across 60 categories. It retrieves before it answers (RAG), switches between four models, takes photo questions, and has eight mini games for study breaks. About two months of work; I built the AI core, the backend and most of the frontend.
EchoMind in about a minute. The cover and characters are AI-generated (Codex), the narration is an AI voice (Gemini TTS), and the answer is illustrative.
Systems Analysis and Design, in the second semester of sophomore year, asked us to build a complete system. We picked a problem we ran into every semester: when choosing courses or preparing for exams, the most useful information lives in the heads of senior students.
What question types show up on the Calculus midterm? Does this course have a lot of homework, and does the teacher take attendance? What English score do we need to graduate? Ask ChatGPT and you get a generic answer, because it does not know our department’s courses.
So the idea behind EchoMind was simple: turn the seniors’ experience and the department’s rules into our own knowledge base, and when a student asks, retrieve the most relevant entries before the model answers. It was also my first complete LLM-plus-RAG application, built end to end.
The home page greets you by time of day. Below the input you can toggle knowledge search, pick a model, or attach a photo.
In normal chat, the backend first retrieves the three most relevant Q&As, adds them to the prompt, then asks the model.
To be honest, this mode can’t be demonstrated right now: of the four Groq models it used, some have been decommissioned by Groq and the account no longer has access to the others, so normal chat on the live site currently returns errors. It will work again once it switches to models Groq still offers.
With knowledge search on, no model is involved: it lists the closest original Q&As, for when you want the seniors' own words. Because it needs no language model, it still works today.
RAG is only as good as its knowledge base. Building it took more time than anything else in the project; it grew several times, from 400 to 667 questions in April.
Course experience: 42 courses. From Calculus, Accounting, Introduction to Business, Programming, Data Structures, Databases, Statistics and Economics to Systems Analysis and Design, Networking, Web Programming, Cloud, E-commerce, Marketing and Production Management, plus general education, languages, PE and military training. Each course has about seven questions, all things you want to know before enrolling: exam question types, how much homework and how many quizzes, whether attendance is taken, how long to prepare, and the teacher’s style.
Department rules.
Category
Questions
Category
Questions
Graduation requirements
81
Course selection, add/drop, withdrawal
20 each
English requirement
45
Department resources and equipment
20
Certificates and further study
40
Department organizations and events
20
Faculty information
35
Learning resources
13
Course planning and advice
28
Semester break dates
10
Professional development
22
Programming proficiency test
9
Leave of absence
20
Career planning
7
Transfers, double majors, minors
5
Capstone projects and competitions
5
Every question is tagged with an importance level, keywords, related resources (syllabus, past exams, TAs, iLearn) and an answer. A Python script converts the JSON to vectors in batches of 90 and rebuilds the Pinecone index.
Frontend: Next.js 15, TypeScript, Tailwind and framer-motion, statically exported to Cloudflare Pages. Login uses Firebase Auth (email/password or Google), and chat history lives in Firestore, readable only by its owner.
Backend: an API on Cloudflare Workers for chat, knowledge search, image upload and response caching.
Retrieval: each question is embedded into a 1024-dimension vector with Cohere’s embed-multilingual-v3.0, then matched in Pinecone. Chat takes the top 3 with a 0.3 similarity threshold; knowledge search shows the top 5 directly.
Generation: Groq models, switchable between Llama 4 Maverick, Llama 3.1 8B, DeepSeek R1 Distill 70B and Qwen QwQ 32B.
Images: chat images and avatars are stored in Cloudflare R2.
Vector search kept returning an empty list: a filtering step after retrieval dropped every entry without an importance field, so every match was filtered out. I gave missing fields a default of 1.0 and added logging at every step.
The same sentence, mismatched vectors: Cohere’s input_type has to be split: search_document when building the index, search_query when searching, never mixed. Cohere’s old and new APIs also return different formats, and the code has to handle both.
Dropping an extra framework layer: the first plan wrapped RAG in LlamaIndex with OpenAI embeddings. At the end of March I removed LlamaIndex and called Cohere and Pinecone directly, so each step is visible.
Chat history broke with images: after photo questions were added, conversations containing images broke in the chat history, which took another round of fixes at the end of April.
Deployment blocked by types and ESLint: it ran locally but failed in the cloud build because of missing type files and ESLint errors. Adding the types and adjusting the rules got it deployed.
Several people editing the knowledge base: multiple branches edited the same example.json, so merge conflicts piled up in that one file and had to be compared section by section.
Team: five people contributed across the three versions. On the 3.0 main branch I wrote about 80% of the commits (153), covering the AI core, the backend and most of the frontend; two classmates mainly built the games and two others the help page.
Looking back a year later, these are what I would change first:
Don’t hard-code model names: the model list is baked into the code, so when Groq retires a model, chat breaks entirely. Model settings should be configurable, with an automatic switch to a working model.
Show sources with answers: answers do not say which entries they used, so users cannot check. The next version would return and display the entries it relied on.
Fail loudly: when the embedding service fails, the system falls back to a random vector and keeps searching. It looks like it works, but the results are unreliable. It should report an error instead.
Verify identity on the backend: the frontend has Firebase login, but the Workers API does not verify it, and CORS allows every origin. Both need fixing before opening it up.
Connect the board to a backend: turn the prototype into real storage, with reporting and moderation.
Evaluate retrieval with a fixed question set: keep a set of standard questions and answers, run it before and after every change, and let the numbers decide.