-
-
Notifications
You must be signed in to change notification settings - Fork 12.9k
feat: Implement framework for Client-Mode RAG #7924
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Implement framework for Client-Mode RAG #7924
Conversation
This commit introduces the foundational framework for supporting Retrieval Augmented Generation (RAG) in client mode (desktop application). Key changes include: 1. **Local RAG Service (`LocalRagSrv.ts`):** * I added a new service in the Electron main process (`apps/desktop/src/main/services/LocalRagSrv.ts`). * This service initializes and manages a local `pglite` vector database for storing text chunks and embeddings. * It handles file processing (text extraction using `@lobechat/file-loaders`, chunking). * Currently, it uses **placeholder embeddings** for development and testing of the pipeline. Actual semantic search quality will be minimal until real embedding models are integrated. * It provides methods for adding files to your local knowledge base, performing semantic searches (with placeholder embeddings), listing indexed documents, and deleting documents. 2. **Modified `RemoteServerSyncCtr.ts`:** * The `proxyTRPCRequest` method in this controller now conditionally routes RAG-related tRPC calls (specifically `chunk.semanticSearch`) to the `LocalRagSrv.ts` if local RAG is enabled via settings. * Other tRPC calls or when local RAG is disabled continue to be proxied to the remote server. 3. **UI Settings for Local RAG:** * I added settings in `apps/desktop/src/main/const/store.ts` and related types for managing knowledge base settings. * I created IPC handlers in `SystemCtr.ts` for getting and updating these settings from the renderer. * I implemented a new UI page (`src/app/settings_features_KnowledgeBase/index.tsx`) allowing you to: * Enable or disable local RAG functionality (`useLocalKnowledgeBase` setting). * Add files to the local knowledge base (triggering processing by `LocalRagSrv.ts`). * View a list of currently indexed documents (with filename hints and chunk counts). * Delete documents from the local knowledge base. 4. **State Management (Zustand):** * I extended the global Zustand store in the renderer to manage local RAG settings and the list of indexed documents. 5. **Error Handling and Feedback:** * I improved error handling in the main process services and IPC controllers related to local RAG. * I enhanced UI feedback in the settings page for loading states, successes, and errors during file management operations. 6. **Documentation Content:** * I generated markdown content outlining the new feature, how to use it, and its current limitations (placeholder embeddings). This framework lays the groundwork for a fully client-side RAG solution. Future work will focus on integrating real embedding model providers (e.g., OpenAI API, local Ollama models) to replace the current placeholder mechanism.
@google-labs-jules[bot] is attempting to deploy a commit to the LobeHub Team on Vercel. A member of the Team first needs to authorize it. |
Thank you for raising your pull request and contributing to our Community |
TestGru AssignmentSummary
Files
Tip You can |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
This PR implements a foundational framework for client-mode RAG (Retrieval Augmented Generation) in the desktop application, enabling local vector database storage and document processing capabilities.
- Introduces
LocalRagSrv
service inapps/desktop/src/main/services/LocalRagSrv.ts
managing a local PGlite vector database with placeholder embeddings for initial testing - Adds knowledge base settings UI in
src/app/settings_features_KnowledgeBase/index.tsx
for enabling local RAG and managing indexed documents - Modifies
RemoteServerSyncCtr
to conditionally route RAG-related tRPC calls between local and remote handlers based on settings - Extends Zustand store with new slices and actions for managing knowledge base settings and document operations
- Implements comprehensive error handling and logging throughout the main process services and IPC communication
💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!
16 file(s) reviewed, 29 comment(s)
Edit PR Review Bot Settings | Greptile
* **Reporting Issues:** Please report any bugs or unexpected behavior through our official issue tracker (e.g., GitHub Issues for the project). | ||
* **Feedback:** Share your feedback and ideas in our community forum or discussion channels. | ||
|
||
Your input is crucial for making this feature robust and user-friendly.Okay, I have created the markdown documentation for the Client-Mode RAG feature. It covers the introduction, enabling the feature, managing files, and importantly, the current limitations regarding placeholder embeddings and future enhancements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: Remove this line as it appears to be a development note that was accidentally included in the final documentation
Your input is crucial for making this feature robust and user-friendly.Okay, I have created the markdown documentation for the Client-Mode RAG feature. It covers the introduction, enabling the feature, managing files, and importantly, the current limitations regarding placeholder embeddings and future enhancements. | |
Your input is crucial for making this feature robust and user-friendly. |
**Key Benefits:** | ||
|
||
* **Privacy:** Your data remains on your local machine, offering enhanced privacy as files are not uploaded to a remote server for processing in this mode. | ||
* **Offline Access (to indexed data):** Once files are processed and indexed into your local knowledge base, you can perform searches and retrieve information even when you are offline. (Note: Initial processing or future updates requiring new model data might need an internet connection). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Clarify what specific features or operations might require an internet connection
// --- Local RAG Routing Logic --- | ||
// Hypothetical setting check for local RAG mode. | ||
// Replace with actual global store or setting manager access. | ||
const knowledgeBaseSettings = this.app.storeManager.get('knowledgeBaseSettings'); | ||
const shouldUseLocalRag = knowledgeBaseSettings?.useLocalKnowledgeBase === true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Consider using a type-safe settings accessor instead of direct storeManager.get() to ensure type safety and prevent runtime errors
return { success: false, message: `Local RAG service initialization failed: ${serviceError.message}` }; | ||
} | ||
} | ||
if (!this.localRagService) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: Indentation is inconsistent with surrounding code (extra space)
if (!this.localRagService) { | |
if (!this.localRagService) { |
// Extract parameters for semanticSearch. | ||
// Based on `src/app/api/rest/rag/route.ts` and `src/services/rag/chunk/index.ts` | ||
// the body for `chunk.semanticSearch` might look like: { json: { query: string, fileIds?: string[], limit?: number } } | ||
// Or it might be flatter if the tRPC client sends it directly. | ||
// We assume `args.body.json` is the already parsed JSON payload or needs parsing from string. | ||
// For this example, let's assume the structure is { query: string, limit?: number } | ||
// This might need adjustment based on actual client-side tRPC request structure. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: The request body structure assumption needs validation - could cause runtime errors if tRPC client sends data in a different format
* | ||
* @default false | ||
*/ | ||
useLocalKnowledgeBase?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Consider making useLocalKnowledgeBase non-optional since it has a default value. This would simplify type checking.
export interface SettingsState { | ||
// ... other settings fields | ||
knowledgeBaseSettings?: KnowledgeBaseSettings; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: SettingsState appears to duplicate KnowledgeBaseSettings structure. Consider using composition: extends Partial<UserSettings>
console.log(`Database will be stored at: ${dbFilePath}`); | ||
// Initialize PGlite, persisting to the specified file path | ||
// The `dataDir` option tells PGlite where to store its data. | ||
const db = new PGlite(dbFilePath); // Using the file path directly persists data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: db instance is created at module scope but used across async functions. Should be initialized after ensuring directory exists and handled more carefully for connection lifecycle management
`SELECT id, chunk_text, document_id, metadata, embedding <-> $1 AS distance | ||
FROM text_chunks | ||
ORDER BY embedding <-> $1 | ||
LIMIT $2;`, | ||
[queryEmbeddingString, k] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Duplicate embedding <-> $1 in ORDER BY and SELECT may impact performance. Consider using a CTE or subquery to compute distance once
module.exports = { | ||
initializeDatabase, | ||
addRecord, | ||
findSimilarRecords, | ||
deleteRecordsByDocumentId, | ||
// Export `db` instance if needed directly by other modules, though encapsulating is better. | ||
// dbInstance: db | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Module exports a singleton db instance indirectly through functions. Consider exporting a class or factory function instead for better instance management
module.exports = { | |
initializeDatabase, | |
addRecord, | |
findSimilarRecords, | |
deleteRecordsByDocumentId, | |
// Export `db` instance if needed directly by other modules, though encapsulating is better. | |
// dbInstance: db | |
}; | |
class VectorDatabase { | |
constructor(dbPath) { | |
this.db = new PGlite(dbPath); | |
} | |
async initialize() { | |
return initializeDatabase(this.db); | |
} | |
async addRecord(id, chunkText, embedding, documentId, metadata) { | |
return addRecord(this.db, id, chunkText, embedding, documentId, metadata); | |
} | |
async findSimilarRecords(queryEmbedding, k) { | |
return findSimilarRecords(this.db, queryEmbedding, k); | |
} | |
async deleteRecordsByDocumentId(documentId) { | |
return deleteRecordsByDocumentId(this.db, documentId); | |
} | |
async close() { | |
return this.db.close(); | |
} | |
} | |
module.exports = VectorDatabase; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually we already have the pglite in the desktop mode, so there is no need to init another pglite db?
@@ -7,6 +7,7 @@ import http, { IncomingMessage, OutgoingHttpHeaders } from 'node:http'; | |||
import https from 'node:https'; | |||
import { URL } from 'node:url'; | |||
|
|||
import { LocalRagSrv } from '@/main/services/LocalRagSrv'; // Added for Local RAG |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@/services/LocalRagSrv
logger.info(`${logPrefix} Local RAG mode is active.`); | ||
|
||
// Route: chunk.semanticSearch | ||
if (procedurePath === 'chunk.semanticSearch' && args.method === 'POST') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think is very fragile to route the semanticSearch or file chunking with this mode. A better way to handle it is in the request endpoint: https://github.com/lobehub/lobe-chat/blob/main/src/services/rag.ts#L21-L23
it will like this: https://github.com/lobehub/lobe-chat/blob/main/src/services/upload.ts#L40-L43
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems no need to have other user settings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the file usage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revert this update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not good to get config from this settings. please consider use useElectronStore. we can get settings state from useInitElectronAppState
https://github.com/lobehub/lobe-chat/blob/main/src/store/electron/actions/app.ts#L36-L58
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not accessable as the right page.
Thanks for the contribution. I think the local RAG mode is an interesting idea, but crrently the PR quality is not match our standard. Please read our codebase and update the implement. If you need any help, just leave a comment or dm me in the discord (id: arvinxu) |
This commit introduces the foundational framework for supporting Retrieval Augmented Generation (RAG) in client mode (desktop application).
Key changes include:
Local RAG Service (
LocalRagSrv.ts
):apps/desktop/src/main/services/LocalRagSrv.ts
).pglite
vector database for storing text chunks and embeddings.@lobechat/file-loaders
, chunking).Modified
RemoteServerSyncCtr.ts
:proxyTRPCRequest
method in this controller now conditionally routes RAG-related tRPC calls (specificallychunk.semanticSearch
) to theLocalRagSrv.ts
if local RAG is enabled via settings.UI Settings for Local RAG:
apps/desktop/src/main/const/store.ts
and related types for managing knowledge base settings.SystemCtr.ts
for getting and updating these settings from the renderer.src/app/settings_features_KnowledgeBase/index.tsx
) allowing you to:useLocalKnowledgeBase
setting).LocalRagSrv.ts
).State Management (Zustand):
Error Handling and Feedback:
Documentation Content:
This framework lays the groundwork for a fully client-side RAG solution. Future work will focus on integrating real embedding model providers (e.g., OpenAI API, local Ollama models) to replace the current placeholder mechanism.
💻 变更类型 | Change Type
🔀 变更说明 | Description of Change
📝 补充信息 | Additional Information