Case study
CPAL
Canvas Personal Assistant for Learning: a RAG chatbot that answers Canvas LMS support questions with concise, cited responses.
- FastAPI
- React
- Python
- Go pipeline
- Pinecone
- Postgres
- Gemini
- Fly.io
The frustration
Students and instructors click through a dozen Canvas documentation pages to answer one simple question. Every answer technically exists, but finding it means knowing which guide, which forum thread, which page.
The dig
Every Canvas question already had an answer, buried somewhere in the Canvas Community guides and solved forum threads. The friction wasn't missing information; it was retrieval. That's a shape I know well, the same shape as the cluttered spreadsheets and copy-paste workflows I untangled as an LMS admin. So I built a RAG system over the sources people already trust.
The feature
Ask CPAL a Canvas question in plain language. It rewrites your question for better recall, searches an index of Community guides and solved threads, and answers concisely with citations back to the original sources, so you can verify instead of trust.
How it works
Question in. Cited answer out.
- 1
Extract
A Go pipeline crawls Canvas Community guides and solved forum threads into clean Markdown with metadata.
- 2
Embed
Python chunks the corpus and generates MiniLM embeddings, upserted with metadata into Pinecone.
- 3
Retrieve
FastAPI rewrites the question for recall, runs similarity search, and swaps forum questions for their accepted answers.
- 4
Answer
The LLM synthesizes a concise Markdown answer with source links. Every Q&A is logged to Postgres for later eval.
Architecture
The pieces.
Backend
FastAPI serves the API and the built frontend from one container. CAPTCHA-guarded query endpoint.
Frontend
Vite, React, and TypeScript. Ask, stream, verify: sources rendered with every answer.
Retrieval
Pinecone vector store, MiniLM embeddings, top-k search with score filtering.
LLM
Gemini for query rewriting and answer synthesis over retrieved passages.
Data pipeline
Go extractor to Python chunking to embedding generation to vector upsert. Run once to bootstrap the index.
Ops
Q&A events logged to Postgres for quality review. Single-container deploy on Fly.io.
Receipts
See for yourself.
The full source, pipeline, backend, frontend, and deploy config, is on GitHub. CPAL is archived now: Instructure redesigned the Community site and broke the extractor's assumptions. The architecture stands as a reference for how I design RAG systems.