Qdrant Knowledge Base And Memory Architecture¶
Goal¶
Kwilo should use Qdrant as the single semantic retrieval layer for:
- Platform exam knowledge: KCET, NEET, JEE Main, JEE Advanced previous-year papers.
- Platform academic knowledge: exam syllabi, official syllabus documents, textbooks, reference material.
- Institution knowledge bases: school, college, training-provider, and enterprise documents.
- Trainer/faculty knowledge bases: private or shared uploaded notes, papers, lesson material.
- Learner and trainer memory: long-term user facts, preferences, mastery evidence, misconceptions, teaching patterns, and retrieval context.
Postgres remains the transactional source of truth for users, permissions, document metadata, ingestion state, structured exam/question records, attempts, analytics snapshots, consent, audit logs, and memory profile tables. Qdrant owns semantic vectors, retrievable text payloads, and metadata filters for semantic search. We should not keep pgvector as a parallel semantic store after migration.
Current State¶
VidyaNet Backend¶
The current knowledge base flow is split across:
apps/backend/src/services/knowledge_base.py- Uploads documents.
- Tracks
TeacherKnowledgeDocument. - Calls doc-intelligence ingestion.
- Deletes/retries by deleting rows from
curriculum_embeddings. apps/backend/src/services/rag_service.py- Generates embeddings with Vertex AI.
- Searches Postgres
curriculum_embeddingsusing pgvector. - Supports filters such as
org_unit_id,subject,class_level,semester,program,branch,document_type. apps/backend/src/models/user_memory.py- Defines
UserLearningProfile,ConversationInsight, andMemoryEmbedding. MemoryEmbeddingstores JSON embeddings in Postgres and is not wired into hot-path retrieval yet.apps/backend/src/services/memory_service.py- Builds profile/context prompt memory.
- Semantic memory retrieval is currently TODO.
kwiloai_memory¶
The local ../kwiloai_memory package is already designed for the target direction:
- Library-first package consumed by
apps/backend, not a separate HTTP service. - Caller supplies
AsyncSession,AsyncQdrantClient, collection name, and embedding adapter. retrieve()composes mastery, prerequisite gaps, profile, and Qdrant fact search.- Qdrant fact search is tenant/user/role filtered by:
tenant_iduser_idroletier2_modestatus=activecurrent=true- Memory roles are richer than current backend user roles:
student,teacher,parent,external_educator,school_admin,org_admin,principal,org_unit_admin.
This means the backend should integrate kwiloai_memory rather than creating a second custom memory implementation.
Architecture Decision¶
Use Qdrant as the only semantic/vector database.
Use multiple Qdrant collections, not one overloaded collection:
| Collection | Purpose |
|---|---|
kwilo_knowledge_chunks_v1 |
Platform, institution, trainer/faculty, syllabus, textbook, and document chunks. |
kwilo_exam_questions_v1 |
Previous-year questions, answer keys, solutions, and topic metadata for KCET, NEET, JEE Main, JEE Advanced. |
kwilo_user_memory_v1 |
User-specific memory facts and semantic summaries. |
kwilo_memory_staging / kwilo_memory_prod |
Existing kwiloai_memory package collections. These should either be migrated into kwilo_user_memory_v1 or kept as aliases until all consumers move. |
Separate collections keep payload schemas stable, reduce accidental data exposure, and let us tune indexes differently for documents, exam questions, and user memory.
Collection Schemas¶
kwilo_knowledge_chunks_v1¶
One Qdrant point per retrievable chunk.
Point ID:
Payload:
{
"schema_version": "v1",
"corpus": "knowledge",
"tenant_type": "platform|institution|trainer|learner",
"org_unit_id": "uuid|null",
"owner_user_id": "uuid|null",
"visibility": "platform|institution|private|class|course",
"source_type": "textbook|syllabus|notes|question_paper|reference|web",
"document_id": "string",
"chunk_index": 12,
"content": "retrievable chunk text",
"title": "document title",
"filename": "source.pdf",
"subject": "Physics",
"board": "CBSE|NCERT|Karnataka|KEA|NTA|JEE",
"class_level": 12,
"academic_level_id": "uuid|null",
"semester": null,
"program": null,
"branch": null,
"chapter": "Electrostatics",
"topic": "Capacitance",
"subtopic": "Parallel Plate Capacitor",
"page_number": 42,
"source_url": "https://...",
"rights_status": "licensed|official_public|permission_obtained|restricted_reference|user_uploaded",
"created_at": "iso8601",
"updated_at": "iso8601"
}
Required payload indexes:
corpustenant_typeorg_unit_idowner_user_idvisibilitysource_typedocument_idsubjectboardclass_levelacademic_level_idsemesterprogrambranchchaptertopicrights_status
kwilo_exam_questions_v1¶
One Qdrant point per question. Long passages or solutions can be additional points linked by question_id.
Point ID:
Payload:
{
"schema_version": "v1",
"corpus": "exam_question",
"exam": "KCET|NEET|JEE_MAIN|JEE_ADVANCED",
"year": 2024,
"session": "April|May|Paper 1|Paper 2|null",
"shift": "1|2|null",
"paper_id": "string",
"question_id": "string",
"question_number": 42,
"language": "en",
"subject": "Physics",
"chapter": "Electrostatics",
"topic": "Capacitance",
"subtopic": "Energy Stored In Capacitor",
"question_type": "single_correct|multiple_correct|integer|numerical|assertion_reason|matrix_match",
"difficulty": 0.62,
"marks": 4,
"negative_marks": 1,
"has_diagram": true,
"answer_available": true,
"solution_available": true,
"content": "question + options + normalized formula text",
"source_url": "https://...",
"rights_status": "licensed|official_public|permission_obtained|restricted_reference",
"review_status": "raw|machine_tagged|human_reviewed",
"topic_confidence": 0.91,
"created_at": "iso8601",
"updated_at": "iso8601"
}
Required payload indexes:
examyearsessionshiftpaper_idquestion_idsubjectchaptertopicsubtopicquestion_typedifficultyrights_statusreview_status
kwilo_user_memory_v1¶
The payload should align with kwiloai_memory.services.facts.search_facts.
Point ID:
Payload:
{
"schema_version": "v1",
"corpus": "user_memory",
"tenant_id": "uuid",
"org_unit_id": "uuid|null",
"user_id": "uuid",
"role": "student|teacher|parent|external_educator|school_admin|org_admin|principal|org_unit_admin",
"tier2_mode": "learner|educator",
"fact_id": "uuid",
"fact_type": "misconception|preference|goal|achievement|common_question|teaching_pattern|semantic_summary|other",
"content": "memory content",
"concept_id": "uuid|null",
"subject": "Physics",
"topic": "Newton's Laws",
"confidence": 0.86,
"status": "active|quarantined|deleted",
"current": true,
"source_conversation_id": "uuid|null",
"source_message_ids": ["uuid"],
"created_at": "iso8601",
"updated_at": "iso8601"
}
Required payload indexes:
tenant_idorg_unit_iduser_idroletier2_modefact_typesubjecttopicstatuscurrent
Retrieval Gateway¶
Add a backend service layer, tentatively SemanticRetrievalService, that hides collection details from product features.
The service should expose:
search_knowledge(query, filters, user_context)search_exam_questions(query, filters, user_context)retrieve_user_memory(query, user_context)retrieve_learning_context(query, user_context, intent)generate_question_bank_blueprint(filters, constraints)generate_mock_test_blueprint(exam, subject, target_profile)
For AI Tutor, AI Teacher, mock-test generation, and question-bank generation, retrieval should run in parallel:
- Retrieve user memory with
kwiloai_memory.retrieve()or a compatible wrapper. - Retrieve institution/trainer/platform knowledge chunks.
- Retrieve previous-year exam questions when the intent is exam-prep or assessment generation.
- Merge, dedupe, and rerank.
- Build a prompt context with source citations and rights flags.
Authorization And Visibility¶
Qdrant filters are mandatory. Never run unfiltered semantic search.
Rules:
- Platform content: visible to all eligible users.
- Institution content: visible only when
org_unit_idmatches. - Trainer private content: visible only to
owner_user_id, unless explicitly shared. - Class/course content: visible only to users enrolled in that class/course or trainers assigned to it.
- User memory: visible only to that user and permitted supervisory roles, according to memory consent and safety policy.
- Restricted exam content: usable for internal analytics but not displayed verbatim unless rights allow it.
All frontend calls go through the backend. Qdrant must not be queried directly from browser clients.
Migration From pgvector To Qdrant¶
Knowledge Base Migration¶
Source:
- Postgres
curriculum_embeddings - Postgres
teacher_knowledge_documents
Steps:
- Add Qdrant client configuration:
QDRANT_URLQDRANT_API_KEYQDRANT_KNOWLEDGE_COLLECTIONQDRANT_EXAM_COLLECTIONQDRANT_USER_MEMORY_COLLECTIONVECTOR_BACKEND=qdrant|pgvector|dual- Create Qdrant collection bootstrap script.
- Add dual-write in doc-intelligence ingestion:
- Keep current Postgres writes temporarily.
- Upsert each generated chunk to
kwilo_knowledge_chunks_v1. - Build backfill script:
- Read
curriculum_embeddingsin batches. - Join with
teacher_knowledge_documentsbydocument_id. - Upsert Qdrant points with deterministic IDs.
- Store migrated counts by
document_id. - Add parity validation:
- Compare chunk counts per document.
- Run top-k retrieval comparison on a seed query set.
- Validate delete/retry removes stale Qdrant points.
- Switch reads:
- Feature flag backend retrieval to Qdrant.
- Keep pgvector fallback for one release.
- Stop pgvector writes.
- Archive/drop
curriculum_embeddingsonly after production signoff and backups.
User Memory Migration¶
Source:
- Current backend
memory_embeddings - Current backend
conversation_insights - Current backend
user_learning_profiles - Future/parallel
kwiloai_memorytables
Steps:
- Install and configure
kwiloai-memorypackage inapps/backend. - Run
kwiloai_memoryAlembic migrations against the backend memory database or a dedicated memory database. - Map backend user roles to
MemoryRole. - Add Qdrant client factory using
kwiloai_memory.adapters.qdrant._parse_qdrant_url. - Backfill
memory_embeddingstokwilo_user_memory_v1: - Point ID:
memory:{memory_embedding_id} - Payload fields:
tenant_id,user_id,role,tier2_mode,fact_type,content,subject,topic,status,current. - Convert or link
ConversationInsightrows into Qdrant facts where appropriate. - Keep
UserLearningProfilein Postgres because it is structured profile state, not a semantic search index. - Wire
MemoryService.get_enriched_context()to callkwiloai_memory.retrieve()for relevant facts. - Validate:
- No cross-tenant memory leakage.
- No cross-user memory leakage.
- Memory retrieval latency remains acceptable on chat hot path.
- Retire legacy
MemoryEmbeddingwrites after Qdrant path is stable.
Previous-Year Exam Data Pipeline¶
Source Acquisition¶
Priority order:
- Official sources:
- NTA for NEET and JEE Main.
- JEE Advanced official archives.
- KEA for KCET.
- Licensed publisher/coaching archives for missing historical years.
- Third-party mirrors only as discovery signals, not as final trusted sources.
Each paper must have:
- Source URL.
- Local object-storage URI.
- SHA256 checksum.
- Rights status.
- Paper metadata: exam, year, session, shift, subject, language.
- Parse confidence.
- Review status.
Ingestion¶
- Download paper and answer key.
- Store original PDF/images in object storage.
- Extract page layout and OCR through doc-intelligence.
- Segment questions, options, passages, diagrams, formulas.
- Align answer key and marks.
- Tag syllabus nodes:
- subject
- chapter
- topic
- subtopic
- difficulty
- Human-review low-confidence questions and high-value papers.
- Store structured records in Postgres.
- Upsert semantic points to
kwilo_exam_questions_v1. - Generate analytics snapshots.
Analytics¶
Use Postgres/materialized analytics tables for aggregate calculations.
Qdrant is used to retrieve and cluster semantically related questions; Postgres is used to compute and serve:
- Topic weightage by exam/year/subject.
- Chapter frequency by year range.
- Marks distribution.
- Difficulty trend.
- Repeated concept clusters.
- Student weak-topic history.
- Trainer-generated paper coverage.
Analytics jobs should periodically read from structured question tables and, where useful, enrich from Qdrant similarity clusters.
Product Features Enabled¶
Trainers / Faculty¶
- Search institutional/trainer KB semantically.
- Search previous-year questions by exam, subject, chapter, topic, difficulty, year range.
- Generate question banks.
- Generate question papers from a blueprint.
- Generate answer keys and solutions.
- Compare generated paper coverage against past exam weightage.
- Get “what to teach next” recommendations from learner gaps.
Learners¶
- Personalized doubt answering grounded in:
- user memory,
- institution/trainer content,
- platform syllabus/textbooks,
- previous-year questions.
- Topic-wise practice.
- Mock tests based on historical weightage.
- Revision plans based on weak topics, due reviews, and target exam date.
- Similar-question recommendations.
Admins¶
- Ingestion dashboard.
- Source/rights dashboard.
- Review queue for OCR/topic tagging.
- Tenant-level KB usage analytics.
- Erasure and consent audit for user memory.
Dedicated PR Plan¶
Each PR must be based on staging.
PR 1: Documentation And Architecture¶
Scope:
- Add this architecture plan.
- Record collection schemas, migration plan, and phased implementation.
Validation:
- Docs-only review.
PR 2: Qdrant Foundation In Backend¶
Scope:
- Add
qdrant-clientdependency if not already present. - Add backend config for Qdrant URL/API key/collections.
- Add
QdrantClientProvider. - Add collection bootstrap/check command.
- Add unit tests with mocked Qdrant client.
No product behavior change.
PR 3: Knowledge Base Dual-Write¶
Scope:
- Extend doc-intelligence/backend ingestion contract to upsert chunks into Qdrant.
- Keep pgvector writes for rollback.
- Update delete/retry to delete Qdrant points by
document_id. - Add migration/backfill script for
curriculum_embeddings.
Validation:
- Backfill dry run.
- Count parity by document.
- Search smoke tests.
PR 4: Qdrant Read Path For Knowledge Retrieval¶
Scope:
- Add Qdrant-backed
RAGServiceimplementation behindVECTOR_BACKEND. - Update AI Tutor/AI Teacher retrieval to use Qdrant path.
- Keep pgvector fallback.
Validation:
- Query parity tests against a curated seed set.
- Tenant visibility tests.
PR 5: kwiloai_memory Integration¶
Scope:
- Add package dependency from GAR.
- Add memory config and Qdrant client wiring.
- Run or document
kwiloai_memorymigrations. - Map backend roles to
MemoryRole. - Call
kwiloai_memory.retrieve()from AI Tutor memory enrichment.
Validation:
- Unit tests for role mapping and context construction.
- Mocked retrieval tests.
PR 6: User Memory Backfill And Cutover¶
Scope:
- Backfill legacy
memory_embeddingsinto Qdrant. - Convert eligible
ConversationInsightrows into Qdrant facts. - Stop writing semantic memory to Postgres.
- Keep structured
UserLearningProfilein Postgres.
Validation:
- Cross-tenant isolation tests.
- Cross-user isolation tests.
- Backfill count checks.
PR 7: Exam KB Core Schema And Ingestion¶
Scope:
- Add structured exam paper/question tables.
- Add source manifest format.
- Add ingestion job model.
- Add Qdrant upsert for question points.
- Ingest initial sample set.
Validation:
- Question count and answer-key coverage checks.
- Topic tagging confidence report.
PR 8: Exam KB Retrieval And Analytics¶
Scope:
- Search API for exam questions.
- Topic-weightage analytics endpoints.
- Faculty question-bank backend service.
- Mock-test blueprint generation.
Validation:
- Weightage correctness tests against known sample data.
- Retrieval filter tests.
PR 9: UI Surfaces¶
Scope:
- Faculty question-bank and paper-generation UI.
- Learner practice/mock-test entry points.
- Knowledge source citations.
- Admin ingestion/review dashboard.
Validation:
- Playwright flows for trainer and learner.
PR 10: Decommission pgvector Semantic Store¶
Scope:
- Stop pgvector writes.
- Remove pgvector retrieval code.
- Archive/drop
curriculum_embeddingsandmemory_embeddingsonly after backup and production signoff.
Validation:
- Production parity report.
- Backup verification.
Operational Requirements¶
- Qdrant must not be directly queried by browser clients.
- Qdrant API key must remain mandatory.
- Prefer private networking or ingress restrictions for Qdrant.
- Schedule Qdrant snapshots and restore drills.
- Emit metrics:
- search latency,
- no-result rate,
- Qdrant errors,
- ingestion throughput,
- backfill progress,
- ACL filter rejection counts.
- Add audit events for:
- KB ingestion,
- memory fact creation,
- memory fact retrieval,
- deletion/erasure,
- exam source import.
Open Questions¶
- Confirm whether “BSEAG” means B.Sc Agriculture entrance preparation under KCET/UGCET or a separate exam.
- Decide whether Qdrant should stay publicly reachable at
qdrant.kwilo.aior be moved behind private ingress/VPN. - Decide if platform exam KB exact question display requires explicit licenses for each source.
- Decide whether user memory Qdrant collection should reuse existing
kwilo_memory_prod/stagingcollection names or migrate tokwilo_user_memory_v1. - Decide the canonical embedding model and dimension.
kwiloai_memorycurrently assumes 768-dimensional vectors.