Skip to content

feat(rag): per-user annotation signals for personalized RAG retrieval (#3240)#3610

Merged
mrveiss merged 2 commits intoDev_new_guifrom
issue-3240
Apr 6, 2026
Merged

feat(rag): per-user annotation signals for personalized RAG retrieval (#3240)#3610
mrveiss merged 2 commits intoDev_new_guifrom
issue-3240

Conversation

@mrveiss
Copy link
Copy Markdown
Owner

@mrveiss mrveiss commented Apr 6, 2026

Closes #3240

Summary

Adds per-user scoping to the RAG feedback and pattern learning system so individual user engagement (accept/reject source cards) biases retrieval for that user only, without polluting global patterns.

Changes

  • retrieval_learner.pyuser_id param added throughout; Redis stream key rag:feedback:{date}rag:feedback:{uid}:{date}; pattern keys namespaced rag:retrieval_patterns:{uid}:{hash}; get_matching_pattern() uses 4-level fallback: user-exact → user-complexity-only → global-exact → global-complexity-only
  • rag_service.pyuser_id threaded through _store_feedback_in_stream(), _emit_ranked_feedback(), _lookup_retrieval_pattern(), _record_retrieval_outcome(), and advanced_search()
  • api/knowledge_rag_feedback.py (new)POST /knowledge_base/rag-feedback endpoint for user-scoped annotation events
  • core_routers.py — registers new knowledge_rag_feedback_router
  • KnowledgeResearchPanel.vueacceptSource() and rejectSource() now call _emitAnnotationFeedback() which posts to the new endpoint with user_id from useUserStore

Tests

  • retrieval_learner_user_scoped_test.py (new) — 14 tests: stream key namespacing, pattern key namespacing, user-scoped lookup, global fallback, preference of user over global, low-confidence user pattern skipping, record_pattern_outcome user scoping, end-to-end cycle
  • retrieval_learner_test.py — updated cursor key assertion for new key format

Note: tests require the backend Docker container for module resolution (models.task_context import chain); environment confirmed pre-existing limitation unrelated to this PR.

@mrveiss
Copy link
Copy Markdown
Owner Author

mrveiss commented Apr 6, 2026

Review fixes applied ✓

  • Critical_GLOBAL_USER renamed to GLOBAL_USER (public) throughout retrieval_learner.py, rag_service.py, knowledge_rag_feedback.py, and both test files
  • CriticalRagFeedbackRequest gains query: str field; query_text in the Redis stream entry now stores the actual search query instead of source_url; KnowledgeResearchPanel.vue passes query.value in the POST body
  • Important — deferred import moved to module-level: from knowledge.search_components.retrieval_learner import GLOBAL_USER, get_retrieval_learner
  • Importantdecision field typed as Literal["accepted", "rejected"] with from typing import Literal; invalid decisions now rejected at the API boundary
  • Important — unused req: Request = None parameter removed from record_rag_feedback; Request import removed
  • Minor_STREAM_TTL_SECONDS = TTL_30_DAYS moved from function body to module level in rag_service.py

@mrveiss mrveiss merged commit 3a39e35 into Dev_new_gui Apr 6, 2026
1 of 3 checks passed
@mrveiss mrveiss deleted the issue-3240 branch April 6, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant