@hazeljs/rag 0.2.0-beta.61 β 0.2.0-beta.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +342 -221
- package/dist/agentic/decorators/adaptive-retrieval.decorator.d.ts +1 -0
- package/dist/agentic/decorators/adaptive-retrieval.decorator.d.ts.map +1 -1
- package/dist/agentic/decorators/adaptive-retrieval.decorator.js +4 -15
- package/dist/agentic/decorators/adaptive-retrieval.decorator.js.map +1 -1
- package/dist/agentic/decorators/corrective-rag.decorator.d.ts +1 -0
- package/dist/agentic/decorators/corrective-rag.decorator.d.ts.map +1 -1
- package/dist/agentic/decorators/corrective-rag.decorator.js +7 -11
- package/dist/agentic/decorators/corrective-rag.decorator.js.map +1 -1
- package/dist/agentic/decorators/hyde.decorator.d.ts +1 -0
- package/dist/agentic/decorators/hyde.decorator.d.ts.map +1 -1
- package/dist/agentic/decorators/hyde.decorator.js +7 -6
- package/dist/agentic/decorators/hyde.decorator.js.map +1 -1
- package/dist/agentic/decorators/multi-hop.decorator.d.ts +1 -0
- package/dist/agentic/decorators/multi-hop.decorator.d.ts.map +1 -1
- package/dist/agentic/decorators/multi-hop.decorator.js +8 -19
- package/dist/agentic/decorators/multi-hop.decorator.js.map +1 -1
- package/dist/agentic/decorators/query-planner.decorator.d.ts +1 -0
- package/dist/agentic/decorators/query-planner.decorator.d.ts.map +1 -1
- package/dist/agentic/decorators/query-planner.decorator.js +4 -18
- package/dist/agentic/decorators/query-planner.decorator.js.map +1 -1
- package/dist/agentic/decorators/query-rewriter.decorator.d.ts +1 -0
- package/dist/agentic/decorators/query-rewriter.decorator.d.ts.map +1 -1
- package/dist/agentic/decorators/query-rewriter.decorator.js +8 -5
- package/dist/agentic/decorators/query-rewriter.decorator.js.map +1 -1
- package/dist/agentic/decorators/self-reflective.decorator.d.ts +2 -0
- package/dist/agentic/decorators/self-reflective.decorator.d.ts.map +1 -1
- package/dist/agentic/decorators/self-reflective.decorator.js +11 -32
- package/dist/agentic/decorators/self-reflective.decorator.js.map +1 -1
- package/dist/graph/community-summarizer.d.ts +1 -0
- package/dist/graph/community-summarizer.d.ts.map +1 -1
- package/dist/graph/community-summarizer.js +12 -20
- package/dist/graph/community-summarizer.js.map +1 -1
- package/dist/graph/entity-extractor.d.ts +1 -0
- package/dist/graph/entity-extractor.d.ts.map +1 -1
- package/dist/graph/entity-extractor.js +8 -27
- package/dist/graph/entity-extractor.js.map +1 -1
- package/dist/graph/graph-rag-pipeline.d.ts +1 -0
- package/dist/graph/graph-rag-pipeline.d.ts.map +1 -1
- package/dist/graph/graph-rag-pipeline.js +4 -11
- package/dist/graph/graph-rag-pipeline.js.map +1 -1
- package/dist/prompts/agentic/adaptive-retrieval.prompt.d.ts +8 -0
- package/dist/prompts/agentic/adaptive-retrieval.prompt.d.ts.map +1 -0
- package/dist/prompts/agentic/adaptive-retrieval.prompt.js +27 -0
- package/dist/prompts/agentic/adaptive-retrieval.prompt.js.map +1 -0
- package/dist/prompts/agentic/corrective-rag.prompt.d.ts +9 -0
- package/dist/prompts/agentic/corrective-rag.prompt.d.ts.map +1 -0
- package/dist/prompts/agentic/corrective-rag.prompt.js +23 -0
- package/dist/prompts/agentic/corrective-rag.prompt.js.map +1 -0
- package/dist/prompts/agentic/hyde.prompt.d.ts +9 -0
- package/dist/prompts/agentic/hyde.prompt.d.ts.map +1 -0
- package/dist/prompts/agentic/hyde.prompt.js +18 -0
- package/dist/prompts/agentic/hyde.prompt.js.map +1 -0
- package/dist/prompts/agentic/multi-hop.prompt.d.ts +15 -0
- package/dist/prompts/agentic/multi-hop.prompt.d.ts.map +1 -0
- package/dist/prompts/agentic/multi-hop.prompt.js +38 -0
- package/dist/prompts/agentic/multi-hop.prompt.js.map +1 -0
- package/dist/prompts/agentic/query-planner.prompt.d.ts +8 -0
- package/dist/prompts/agentic/query-planner.prompt.d.ts.map +1 -0
- package/dist/prompts/agentic/query-planner.prompt.js +30 -0
- package/dist/prompts/agentic/query-planner.prompt.js.map +1 -0
- package/dist/prompts/agentic/query-rewriter.prompt.d.ts +10 -0
- package/dist/prompts/agentic/query-rewriter.prompt.d.ts.map +1 -0
- package/dist/prompts/agentic/query-rewriter.prompt.js +17 -0
- package/dist/prompts/agentic/query-rewriter.prompt.js.map +1 -0
- package/dist/prompts/agentic/self-reflective-improve.prompt.d.ts +10 -0
- package/dist/prompts/agentic/self-reflective-improve.prompt.d.ts.map +1 -0
- package/dist/prompts/agentic/self-reflective-improve.prompt.js +24 -0
- package/dist/prompts/agentic/self-reflective-improve.prompt.js.map +1 -0
- package/dist/prompts/agentic/self-reflective.prompt.d.ts +9 -0
- package/dist/prompts/agentic/self-reflective.prompt.d.ts.map +1 -0
- package/dist/prompts/agentic/self-reflective.prompt.js +32 -0
- package/dist/prompts/agentic/self-reflective.prompt.js.map +1 -0
- package/dist/prompts/community-summary.prompt.d.ts +9 -0
- package/dist/prompts/community-summary.prompt.d.ts.map +1 -0
- package/dist/prompts/community-summary.prompt.js +30 -0
- package/dist/prompts/community-summary.prompt.js.map +1 -0
- package/dist/prompts/entity-extraction.prompt.d.ts +10 -0
- package/dist/prompts/entity-extraction.prompt.d.ts.map +1 -0
- package/dist/prompts/entity-extraction.prompt.js +39 -0
- package/dist/prompts/entity-extraction.prompt.js.map +1 -0
- package/dist/prompts/graph-search.prompt.d.ts +10 -0
- package/dist/prompts/graph-search.prompt.d.ts.map +1 -0
- package/dist/prompts/graph-search.prompt.js +23 -0
- package/dist/prompts/graph-search.prompt.js.map +1 -0
- package/dist/prompts/index.d.ts +13 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +29 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/rag-answer.prompt.d.ts +9 -0
- package/dist/prompts/rag-answer.prompt.d.ts.map +1 -0
- package/dist/prompts/rag-answer.prompt.js +20 -0
- package/dist/prompts/rag-answer.prompt.js.map +1 -0
- package/dist/rag.service.d.ts +1 -0
- package/dist/rag.service.d.ts.map +1 -1
- package/dist/rag.service.js +7 -8
- package/dist/rag.service.js.map +1 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Your docs. Your data. AI that actually knows them.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Load documents from any source, build a knowledge graph, embed into vector stores, and retrieve answers with semantic, hybrid, or graph-based search. Full RAG + GraphRAG pipeline β no PhD required.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@hazeljs/rag)
|
|
8
8
|
[](https://www.npmjs.com/package/@hazeljs/rag)
|
|
@@ -10,14 +10,18 @@ Semantic search, embeddings, document indexing. Pinecone, Weaviate, Qdrant, Chro
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
13
|
+
- π **11 Document Loaders** β TXT, Markdown, JSON, CSV, HTML, PDF, DOCX, web scraping, YouTube transcripts, GitHub repos, and inline text. All return the same `Document[]` interface.
|
|
14
|
+
- πΈοΈ **GraphRAG** β Extract entities and relationships from documents, build a knowledge graph, detect communities, and answer questions with entity-centric (local), thematic (global), or hybrid search.
|
|
15
|
+
- π **Vector Search** β Semantic similarity search with configurable embeddings and vector stores
|
|
16
|
+
- π€ **RAG Pipeline** β Complete load β split β embed β retrieve β augment workflow
|
|
17
|
+
- π― **Multiple Strategies** β Similarity, Hybrid (vector + BM25), Multi-Query retrieval
|
|
18
|
+
- π **5 Vector Stores** β Memory, Pinecone, Qdrant, Weaviate, ChromaDB (unified interface)
|
|
19
|
+
- π **Embedding Providers** β OpenAI and Cohere, easily extensible
|
|
20
|
+
- βοΈ **Smart Text Splitting** β Recursive, character, and token splitters
|
|
21
|
+
- π **Metadata Filtering** β Filter results by any metadata field
|
|
22
|
+
- π§ **Memory System** β Conversation history, entity memory, fact storage, working memory
|
|
23
|
+
|
|
24
|
+
---
|
|
21
25
|
|
|
22
26
|
## Installation
|
|
23
27
|
|
|
@@ -25,28 +29,34 @@ Semantic search, embeddings, document indexing. Pinecone, Weaviate, Qdrant, Chro
|
|
|
25
29
|
npm install @hazeljs/rag
|
|
26
30
|
```
|
|
27
31
|
|
|
28
|
-
### Optional
|
|
32
|
+
### Optional peer dependencies
|
|
29
33
|
|
|
30
|
-
Install
|
|
34
|
+
Install only what you need:
|
|
31
35
|
|
|
32
36
|
```bash
|
|
33
|
-
#
|
|
37
|
+
# LLM (required for GraphRAG and RAG query synthesis)
|
|
34
38
|
npm install openai
|
|
35
39
|
|
|
36
|
-
# Vector
|
|
37
|
-
npm install @pinecone-database/pinecone
|
|
38
|
-
npm install weaviate-ts-client # Weaviate
|
|
40
|
+
# Vector stores
|
|
41
|
+
npm install @pinecone-database/pinecone # Pinecone
|
|
39
42
|
npm install @qdrant/js-client-rest # Qdrant
|
|
43
|
+
npm install weaviate-ts-client # Weaviate
|
|
40
44
|
npm install chromadb # ChromaDB
|
|
41
45
|
|
|
42
|
-
#
|
|
43
|
-
npm install cohere-ai
|
|
44
|
-
|
|
46
|
+
# Alternative embedding providers
|
|
47
|
+
npm install cohere-ai
|
|
48
|
+
|
|
49
|
+
# Document loaders
|
|
50
|
+
npm install pdf-parse # PdfLoader
|
|
51
|
+
npm install mammoth # DocxLoader
|
|
52
|
+
npm install cheerio # HtmlFileLoader / WebLoader CSS selectors
|
|
45
53
|
```
|
|
46
54
|
|
|
55
|
+
---
|
|
56
|
+
|
|
47
57
|
## Quick Start
|
|
48
58
|
|
|
49
|
-
### Basic RAG
|
|
59
|
+
### Basic RAG pipeline
|
|
50
60
|
|
|
51
61
|
```typescript
|
|
52
62
|
import {
|
|
@@ -54,271 +64,400 @@ import {
|
|
|
54
64
|
MemoryVectorStore,
|
|
55
65
|
OpenAIEmbeddings,
|
|
56
66
|
RecursiveTextSplitter,
|
|
67
|
+
DirectoryLoader,
|
|
57
68
|
} from '@hazeljs/rag';
|
|
58
69
|
|
|
59
|
-
|
|
60
|
-
const embeddings = new OpenAIEmbeddings({
|
|
61
|
-
apiKey: process.env.OPENAI_API_KEY!,
|
|
62
|
-
model: 'text-embedding-3-small',
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// 2. Setup vector store
|
|
70
|
+
const embeddings = new OpenAIEmbeddings({ apiKey: process.env.OPENAI_API_KEY });
|
|
66
71
|
const vectorStore = new MemoryVectorStore(embeddings);
|
|
67
72
|
|
|
68
|
-
// 3. Setup text splitter
|
|
69
|
-
const textSplitter = new RecursiveTextSplitter({
|
|
70
|
-
chunkSize: 1000,
|
|
71
|
-
chunkOverlap: 200,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// 4. Create RAG pipeline
|
|
75
73
|
const rag = new RAGPipeline({
|
|
76
74
|
vectorStore,
|
|
77
75
|
embeddingProvider: embeddings,
|
|
78
|
-
textSplitter,
|
|
76
|
+
textSplitter: new RecursiveTextSplitter({ chunkSize: 800, chunkOverlap: 150 }),
|
|
79
77
|
topK: 5,
|
|
80
78
|
});
|
|
81
|
-
|
|
82
|
-
// 5. Initialize
|
|
83
79
|
await rag.initialize();
|
|
84
80
|
|
|
85
|
-
//
|
|
86
|
-
await
|
|
87
|
-
|
|
88
|
-
content: 'HazelJS is a modern TypeScript framework for building scalable applications.',
|
|
89
|
-
metadata: { source: 'docs', category: 'intro' },
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
content: 'The framework includes built-in support for microservices, caching, and AI.',
|
|
93
|
-
metadata: { source: 'docs', category: 'features' },
|
|
94
|
-
},
|
|
95
|
-
]);
|
|
96
|
-
|
|
97
|
-
// 7. Query
|
|
98
|
-
const result = await rag.query('What is HazelJS?', {
|
|
99
|
-
topK: 3,
|
|
100
|
-
filter: { source: 'docs' },
|
|
101
|
-
});
|
|
81
|
+
// Load from disk β auto-detects file types
|
|
82
|
+
const docs = await new DirectoryLoader({ dirPath: './knowledge-base', recursive: true }).load();
|
|
83
|
+
await rag.addDocuments(docs);
|
|
102
84
|
|
|
85
|
+
const result = await rag.query('What is HazelJS?', { topK: 3 });
|
|
103
86
|
console.log(result.answer);
|
|
104
87
|
console.log(result.sources);
|
|
105
88
|
```
|
|
106
89
|
|
|
107
|
-
|
|
90
|
+
---
|
|
108
91
|
|
|
109
|
-
|
|
110
|
-
import OpenAI from 'openai';
|
|
92
|
+
## Document Loaders
|
|
111
93
|
|
|
112
|
-
|
|
94
|
+
Every loader extends `BaseDocumentLoader` and returns `Document[]` ready for chunking and indexing.
|
|
113
95
|
|
|
114
|
-
|
|
115
|
-
const llmFunction = async (prompt: string) => {
|
|
116
|
-
const response = await openai.chat.completions.create({
|
|
117
|
-
model: 'gpt-4',
|
|
118
|
-
messages: [{ role: 'user', content: prompt }],
|
|
119
|
-
});
|
|
120
|
-
return response.choices[0].message.content || '';
|
|
121
|
-
};
|
|
96
|
+
### Built-in loaders
|
|
122
97
|
|
|
123
|
-
|
|
124
|
-
|
|
98
|
+
| Loader | Source | Extra install |
|
|
99
|
+
|--------|--------|:---:|
|
|
100
|
+
| `TextFileLoader` | `.txt` files | β |
|
|
101
|
+
| `MarkdownFileLoader` | `.md` / `.mdx` with heading splits and YAML front-matter | β |
|
|
102
|
+
| `JSONFileLoader` | `.json` with `textKey` / JSON Pointer extraction | β |
|
|
103
|
+
| `CSVFileLoader` | `.csv` rows mapped to documents | β |
|
|
104
|
+
| `HtmlFileLoader` | `.html` tag stripping; optional CSS selector via cheerio | opt. |
|
|
105
|
+
| `DirectoryLoader` | Recursive walk; auto-detects loader by extension | β |
|
|
106
|
+
| `PdfLoader` | PDFs; split by page or full document | `pdf-parse` |
|
|
107
|
+
| `DocxLoader` | Word documents; plain text or HTML output | `mammoth` |
|
|
108
|
+
| `WebLoader` | HTTP scraping with retry/timeout; optional CSS selector | opt. |
|
|
109
|
+
| `YouTubeTranscriptLoader` | YouTube transcripts; no API key; segment by duration | β |
|
|
110
|
+
| `GitHubLoader` | GitHub REST API; filter by path, extension, `maxFiles` | β |
|
|
125
111
|
|
|
126
|
-
|
|
127
|
-
const result = await rag.query('What is HazelJS?', {
|
|
128
|
-
llmPrompt: `Based on the following context, answer the question.
|
|
112
|
+
### Examples
|
|
129
113
|
|
|
130
|
-
|
|
131
|
-
{
|
|
132
|
-
|
|
133
|
-
|
|
114
|
+
```typescript
|
|
115
|
+
import {
|
|
116
|
+
TextFileLoader,
|
|
117
|
+
MarkdownFileLoader,
|
|
118
|
+
JSONFileLoader,
|
|
119
|
+
CSVFileLoader,
|
|
120
|
+
PdfLoader,
|
|
121
|
+
DocxLoader,
|
|
122
|
+
WebLoader,
|
|
123
|
+
YouTubeTranscriptLoader,
|
|
124
|
+
GitHubLoader,
|
|
125
|
+
DirectoryLoader,
|
|
126
|
+
} from '@hazeljs/rag';
|
|
134
127
|
|
|
135
|
-
|
|
136
|
-
});
|
|
128
|
+
// Plain text
|
|
129
|
+
const textDocs = await new TextFileLoader({ filePath: './notes.txt' }).load();
|
|
130
|
+
|
|
131
|
+
// Markdown β one document per heading section
|
|
132
|
+
const mdDocs = await new MarkdownFileLoader({
|
|
133
|
+
filePath: './guide.md',
|
|
134
|
+
splitByHeading: true,
|
|
135
|
+
parseYamlFrontMatter: true,
|
|
136
|
+
}).load();
|
|
137
|
+
|
|
138
|
+
// JSON β extract the 'body' field from each element
|
|
139
|
+
const jsonDocs = await new JSONFileLoader({ filePath: './articles.json', textKey: 'body' }).load();
|
|
140
|
+
|
|
141
|
+
// CSV β map columns to content / metadata
|
|
142
|
+
const csvDocs = await new CSVFileLoader({
|
|
143
|
+
filePath: './faqs.csv',
|
|
144
|
+
contentColumns: ['question', 'answer'],
|
|
145
|
+
metadataColumns: ['category'],
|
|
146
|
+
}).load();
|
|
147
|
+
|
|
148
|
+
// PDF β one document per page
|
|
149
|
+
const pdfDocs = await new PdfLoader({ filePath: './report.pdf', splitByPage: true }).load();
|
|
150
|
+
|
|
151
|
+
// DOCX
|
|
152
|
+
const wordDocs = await new DocxLoader({ filePath: './agreement.docx' }).load();
|
|
153
|
+
|
|
154
|
+
// Web scraping
|
|
155
|
+
const webDocs = await new WebLoader({
|
|
156
|
+
urls: ['https://hazeljs.com/docs', 'https://hazeljs.com/blog'],
|
|
157
|
+
timeout: 10_000,
|
|
158
|
+
maxRetries: 3,
|
|
159
|
+
}).load();
|
|
160
|
+
|
|
161
|
+
// YouTube transcript (no API key needed)
|
|
162
|
+
const ytDocs = await new YouTubeTranscriptLoader({
|
|
163
|
+
videoUrl: 'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
164
|
+
segmentDuration: 60, // group into 60-second chunks
|
|
165
|
+
}).load();
|
|
166
|
+
|
|
167
|
+
// GitHub repository
|
|
168
|
+
const githubDocs = await new GitHubLoader({
|
|
169
|
+
owner: 'hazeljs',
|
|
170
|
+
repo: 'hazel',
|
|
171
|
+
directory: 'docs',
|
|
172
|
+
extensions: ['.md'],
|
|
173
|
+
token: process.env.GITHUB_TOKEN,
|
|
174
|
+
}).load();
|
|
175
|
+
|
|
176
|
+
// Directory β auto-detects every file type
|
|
177
|
+
const allDocs = await new DirectoryLoader({
|
|
178
|
+
dirPath: './knowledge-base',
|
|
179
|
+
recursive: true,
|
|
180
|
+
extensions: ['.md', '.txt', '.pdf'],
|
|
181
|
+
}).load();
|
|
137
182
|
```
|
|
138
183
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
### Memory Vector Store (Development)
|
|
184
|
+
### Custom loaders
|
|
142
185
|
|
|
143
186
|
```typescript
|
|
144
|
-
import {
|
|
187
|
+
import { BaseDocumentLoader, Loader, DocumentLoaderRegistry } from '@hazeljs/rag';
|
|
145
188
|
|
|
146
|
-
|
|
147
|
-
|
|
189
|
+
@Loader({ name: 'NotionLoader', extensions: [] })
|
|
190
|
+
export class NotionLoader extends BaseDocumentLoader {
|
|
191
|
+
constructor(private readonly databaseId: string) { super(); }
|
|
192
|
+
|
|
193
|
+
async load() {
|
|
194
|
+
const pages = await fetchNotionPages(this.databaseId);
|
|
195
|
+
return pages.map(p =>
|
|
196
|
+
this.createDocument(p.content, { source: `notion:${p.id}`, title: p.title }),
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Register so DirectoryLoader can auto-detect it
|
|
202
|
+
DocumentLoaderRegistry.register(NotionLoader, (id: string) => new NotionLoader(id));
|
|
148
203
|
```
|
|
149
204
|
|
|
150
|
-
|
|
205
|
+
---
|
|
151
206
|
|
|
152
|
-
|
|
153
|
-
import { Pinecone } from '@pinecone-database/pinecone';
|
|
154
|
-
import { PineconeVectorStore } from '@hazeljs/rag';
|
|
207
|
+
## GraphRAG
|
|
155
208
|
|
|
156
|
-
|
|
157
|
-
const index = pinecone.index('my-index');
|
|
209
|
+
GraphRAG builds a **knowledge graph** from your documents β entities, relationships, and community clusters β and enables three complementary search modes that go far beyond cosine similarity.
|
|
158
210
|
|
|
159
|
-
|
|
160
|
-
```
|
|
211
|
+
### Why GraphRAG?
|
|
161
212
|
|
|
162
|
-
|
|
213
|
+
| Question type | Traditional RAG | GraphRAG |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| "What does X do?" | β
Good | β
Excellent (entity traversal) |
|
|
216
|
+
| "How do X and Y relate?" | β Poor | β
Excellent (relationships) |
|
|
217
|
+
| "What are the main architectural layers?" | β Poor | β
Excellent (community reports) |
|
|
218
|
+
| Multi-document cross-referencing | β Fragmented | β
Native |
|
|
163
219
|
|
|
164
|
-
|
|
165
|
-
import { QdrantClient } from '@qdrant/js-client-rest';
|
|
166
|
-
import { QdrantVectorStore } from '@hazeljs/rag';
|
|
220
|
+
### Build the graph
|
|
167
221
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
222
|
+
```typescript
|
|
223
|
+
import OpenAI from 'openai';
|
|
224
|
+
import { GraphRAGPipeline, DirectoryLoader } from '@hazeljs/rag';
|
|
225
|
+
|
|
226
|
+
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
227
|
+
|
|
228
|
+
const graphRag = new GraphRAGPipeline({
|
|
229
|
+
// Provider-agnostic: any LLM that accepts a string prompt
|
|
230
|
+
llm: async (prompt) => {
|
|
231
|
+
const res = await openai.chat.completions.create({
|
|
232
|
+
model: 'gpt-4o-mini',
|
|
233
|
+
temperature: 0,
|
|
234
|
+
messages: [{ role: 'user', content: prompt }],
|
|
235
|
+
});
|
|
236
|
+
return res.choices[0].message.content ?? '';
|
|
237
|
+
},
|
|
238
|
+
extractionChunkSize: 2000, // chars per LLM extraction call
|
|
239
|
+
generateCommunityReports: true, // LLM summaries per community cluster
|
|
240
|
+
maxCommunitySize: 15, // split clusters larger than this
|
|
241
|
+
localSearchDepth: 2, // BFS hops for local search
|
|
242
|
+
localSearchTopK: 5, // seed entities per query
|
|
243
|
+
globalSearchTopK: 5, // community reports for global search
|
|
171
244
|
});
|
|
172
|
-
```
|
|
173
245
|
|
|
174
|
-
|
|
246
|
+
const docs = await new DirectoryLoader({ dirPath: './knowledge-base', recursive: true }).load();
|
|
247
|
+
const stats = await graphRag.build(docs);
|
|
248
|
+
// { documentsProcessed, entitiesExtracted, relationshipsExtracted,
|
|
249
|
+
// communitiesDetected, communityReportsGenerated, duration }
|
|
250
|
+
```
|
|
175
251
|
|
|
176
|
-
###
|
|
252
|
+
### Search modes
|
|
177
253
|
|
|
178
254
|
```typescript
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
255
|
+
// LOCAL β entity-centric, BFS graph traversal
|
|
256
|
+
// Best for: specific questions about named concepts, classes, or technologies
|
|
257
|
+
const local = await graphRag.search(
|
|
258
|
+
'How does dependency injection work?',
|
|
259
|
+
{ mode: 'local' },
|
|
260
|
+
);
|
|
261
|
+
console.log(local.answer);
|
|
262
|
+
console.log(local.entities); // entities found and traversed
|
|
263
|
+
console.log(local.relationships); // evidence relationships
|
|
264
|
+
|
|
265
|
+
// GLOBAL β community report ranking
|
|
266
|
+
// Best for: broad thematic questions, architecture overviews
|
|
267
|
+
const global = await graphRag.search(
|
|
268
|
+
'What are the main architectural layers of this system?',
|
|
269
|
+
{ mode: 'global' },
|
|
270
|
+
);
|
|
271
|
+
console.log(global.communities); // ranked community reports used
|
|
272
|
+
|
|
273
|
+
// HYBRID β runs both in parallel, single synthesis call (recommended default)
|
|
274
|
+
const result = await graphRag.search('What vector stores does @hazeljs/rag support?');
|
|
275
|
+
// mode defaults to 'hybrid'
|
|
276
|
+
console.log(`${result.mode} search in ${result.duration}ms`);
|
|
186
277
|
```
|
|
187
278
|
|
|
188
|
-
###
|
|
279
|
+
### Incremental updates
|
|
189
280
|
|
|
190
281
|
```typescript
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
apiKey: process.env.COHERE_API_KEY!,
|
|
195
|
-
model: 'embed-english-v3.0',
|
|
196
|
-
});
|
|
282
|
+
const newDocs = await new WebLoader({ urls: ['https://hazeljs.com/blog/new'] }).load();
|
|
283
|
+
await graphRag.addDocuments(newDocs);
|
|
284
|
+
// Re-runs community detection and regenerates reports automatically
|
|
197
285
|
```
|
|
198
286
|
|
|
199
|
-
###
|
|
287
|
+
### Inspect the graph
|
|
200
288
|
|
|
201
289
|
```typescript
|
|
202
|
-
|
|
290
|
+
const graph = graphRag.getGraph();
|
|
203
291
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
292
|
+
// Entities, relationships, community reports
|
|
293
|
+
console.log([...graph.entities.values()].slice(0, 5));
|
|
294
|
+
console.log([...graph.relationships.values()].slice(0, 5));
|
|
295
|
+
console.log([...graph.communityReports.values()].map(r => r.title));
|
|
296
|
+
|
|
297
|
+
// Statistics
|
|
298
|
+
const stats = graphRag.getStats();
|
|
299
|
+
console.log(stats.entityTypeBreakdown); // { TECHNOLOGY: 14, CONCEPT: 12, ... }
|
|
300
|
+
console.log(stats.topEntities.slice(0, 5)); // most-connected entities
|
|
208
301
|
```
|
|
209
302
|
|
|
210
|
-
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Vector Stores
|
|
211
306
|
|
|
212
|
-
|
|
307
|
+
All stores implement the same interface β swap them with a one-line change.
|
|
213
308
|
|
|
214
309
|
```typescript
|
|
215
|
-
import {
|
|
310
|
+
import { MemoryVectorStore, OpenAIEmbeddings } from '@hazeljs/rag';
|
|
216
311
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
chunkOverlap: 200,
|
|
220
|
-
separators: ['\n\n', '\n', '. ', ' ', ''],
|
|
221
|
-
});
|
|
312
|
+
// Development
|
|
313
|
+
const vectorStore = new MemoryVectorStore(embeddings);
|
|
222
314
|
|
|
223
|
-
|
|
224
|
-
|
|
315
|
+
// Pinecone (production, serverless)
|
|
316
|
+
import { PineconeVectorStore } from '@hazeljs/rag';
|
|
317
|
+
const vectorStore = new PineconeVectorStore(embeddings, {
|
|
318
|
+
apiKey: process.env.PINECONE_API_KEY,
|
|
319
|
+
indexName: 'my-knowledge-base',
|
|
320
|
+
});
|
|
225
321
|
|
|
226
|
-
|
|
322
|
+
// Qdrant (high-performance, self-hosted)
|
|
323
|
+
import { QdrantVectorStore } from '@hazeljs/rag';
|
|
324
|
+
const vectorStore = new QdrantVectorStore(embeddings, {
|
|
325
|
+
url: process.env.QDRANT_URL || 'http://localhost:6333',
|
|
326
|
+
collectionName: 'my-collection',
|
|
327
|
+
});
|
|
227
328
|
|
|
228
|
-
|
|
329
|
+
// Weaviate (GraphQL, flexible)
|
|
330
|
+
import { WeaviateVectorStore } from '@hazeljs/rag';
|
|
331
|
+
const vectorStore = new WeaviateVectorStore(embeddings, {
|
|
332
|
+
host: process.env.WEAVIATE_HOST || 'http://localhost:8080',
|
|
333
|
+
className: 'MyKnowledgeBase',
|
|
334
|
+
});
|
|
229
335
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
336
|
+
// ChromaDB (prototyping)
|
|
337
|
+
import { ChromaVectorStore } from '@hazeljs/rag';
|
|
338
|
+
const vectorStore = new ChromaVectorStore(embeddings, {
|
|
339
|
+
url: process.env.CHROMA_URL || 'http://localhost:8000',
|
|
340
|
+
collectionName: 'my-collection',
|
|
234
341
|
});
|
|
235
342
|
```
|
|
236
343
|
|
|
237
|
-
###
|
|
344
|
+
### Vector store comparison
|
|
238
345
|
|
|
239
|
-
|
|
346
|
+
| | Memory | Pinecone | Qdrant | Weaviate | ChromaDB |
|
|
347
|
+
|---|:---:|:---:|:---:|:---:|:---:|
|
|
348
|
+
| Setup | None | API Key | Docker | Docker | Docker |
|
|
349
|
+
| Persistence | β | β
| β
| β
| β
|
|
|
350
|
+
| Best for | Dev/Test | Production | High-perf | GraphQL | Prototyping |
|
|
351
|
+
| Cost | Free | Paid | OSS | OSS | OSS |
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Embedding Providers
|
|
240
356
|
|
|
241
357
|
```typescript
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
358
|
+
import { OpenAIEmbeddings, CohereEmbeddings } from '@hazeljs/rag';
|
|
359
|
+
|
|
360
|
+
// OpenAI
|
|
361
|
+
const openaiEmbed = new OpenAIEmbeddings({
|
|
362
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
363
|
+
model: 'text-embedding-3-small', // 1536 dims
|
|
364
|
+
// model: 'text-embedding-3-large', // 3072 dims, highest quality
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// Cohere (multilingual)
|
|
368
|
+
const cohereEmbed = new CohereEmbeddings({
|
|
369
|
+
apiKey: process.env.COHERE_API_KEY,
|
|
370
|
+
model: 'embed-multilingual-v3.0',
|
|
245
371
|
});
|
|
246
372
|
```
|
|
247
373
|
|
|
248
|
-
|
|
374
|
+
---
|
|
249
375
|
|
|
250
|
-
|
|
376
|
+
## Retrieval Strategies
|
|
251
377
|
|
|
252
378
|
```typescript
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
379
|
+
import { HybridSearchRetrieval, MultiQueryRetrieval } from '@hazeljs/rag';
|
|
380
|
+
|
|
381
|
+
// Hybrid β vector + BM25 keyword fusion
|
|
382
|
+
const hybrid = new HybridSearchRetrieval(vectorStore, {
|
|
383
|
+
vectorWeight: 0.7,
|
|
384
|
+
keywordWeight: 0.3,
|
|
385
|
+
topK: 10,
|
|
256
386
|
});
|
|
387
|
+
const results = await hybrid.search('machine learning algorithms', { topK: 5 });
|
|
388
|
+
|
|
389
|
+
// Multi-query β LLM generates N query variations, deduplicates results
|
|
390
|
+
const multiQuery = new MultiQueryRetrieval(vectorStore, {
|
|
391
|
+
llmApiKey: process.env.OPENAI_API_KEY,
|
|
392
|
+
numQueries: 3,
|
|
393
|
+
topK: 10,
|
|
394
|
+
});
|
|
395
|
+
const results2 = await multiQuery.search('How do I deploy my app?', { topK: 5 });
|
|
257
396
|
```
|
|
258
397
|
|
|
259
|
-
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## Text Splitting
|
|
260
401
|
|
|
261
402
|
```typescript
|
|
262
|
-
|
|
263
|
-
{
|
|
264
|
-
content: 'Document 1',
|
|
265
|
-
metadata: { category: 'tech', year: 2024 },
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
content: 'Document 2',
|
|
269
|
-
metadata: { category: 'science', year: 2023 },
|
|
270
|
-
},
|
|
271
|
-
]);
|
|
403
|
+
import { RecursiveTextSplitter } from '@hazeljs/rag';
|
|
272
404
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
405
|
+
const splitter = new RecursiveTextSplitter({
|
|
406
|
+
chunkSize: 1000, // target chars per chunk
|
|
407
|
+
chunkOverlap: 200, // overlap for context continuity
|
|
408
|
+
separators: ['\n\n', '\n', '. ', ' '],
|
|
276
409
|
});
|
|
410
|
+
|
|
411
|
+
const chunks = splitter.split(longDocument);
|
|
277
412
|
```
|
|
278
413
|
|
|
279
|
-
|
|
414
|
+
---
|
|
280
415
|
|
|
281
|
-
|
|
416
|
+
## Memory System
|
|
282
417
|
|
|
283
418
|
```typescript
|
|
284
|
-
import {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
419
|
+
import {
|
|
420
|
+
RAGPipelineWithMemory,
|
|
421
|
+
MemoryManager,
|
|
422
|
+
HybridMemory,
|
|
423
|
+
BufferMemory,
|
|
424
|
+
VectorMemory,
|
|
425
|
+
} from '@hazeljs/rag';
|
|
288
426
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return [{ content: text, metadata: { source: this.filePath } }];
|
|
293
|
-
}
|
|
427
|
+
const buffer = new BufferMemory({ maxSize: 20 });
|
|
428
|
+
const vectorMemory = new VectorMemory(vectorStore, embeddings);
|
|
429
|
+
const memory = new MemoryManager(new HybridMemory(buffer, vectorMemory));
|
|
294
430
|
|
|
295
|
-
|
|
296
|
-
// PDF parsing logic
|
|
297
|
-
return '';
|
|
298
|
-
}
|
|
299
|
-
}
|
|
431
|
+
const rag = new RAGPipelineWithMemory(config, memory, llmFunction);
|
|
300
432
|
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
433
|
+
const response = await rag.queryWithMemory(
|
|
434
|
+
'What did we discuss about deployment?',
|
|
435
|
+
'session-123',
|
|
436
|
+
'user-456',
|
|
437
|
+
);
|
|
438
|
+
console.log(response.answer);
|
|
439
|
+
console.log(response.memories);
|
|
304
440
|
```
|
|
305
441
|
|
|
306
|
-
|
|
442
|
+
---
|
|
307
443
|
|
|
308
|
-
|
|
309
|
-
// Add multiple documents efficiently
|
|
310
|
-
const ids = await rag.addDocuments(documents);
|
|
444
|
+
## API Reference
|
|
311
445
|
|
|
312
|
-
|
|
313
|
-
await rag.deleteDocuments(ids);
|
|
446
|
+
### `GraphRAGPipeline`
|
|
314
447
|
|
|
315
|
-
|
|
316
|
-
|
|
448
|
+
```typescript
|
|
449
|
+
class GraphRAGPipeline {
|
|
450
|
+
constructor(config: GraphRAGConfig);
|
|
451
|
+
build(docs: Document[]): Promise<GraphBuildStats>;
|
|
452
|
+
addDocuments(docs: Document[]): Promise<GraphBuildStats>;
|
|
453
|
+
search(query: string, options?: GraphSearchOptions): Promise<GraphSearchResult>;
|
|
454
|
+
getGraph(): KnowledgeGraph;
|
|
455
|
+
getStats(): GraphStats;
|
|
456
|
+
clear(): void;
|
|
457
|
+
}
|
|
317
458
|
```
|
|
318
459
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
### RAGPipeline
|
|
460
|
+
### `RAGPipeline`
|
|
322
461
|
|
|
323
462
|
```typescript
|
|
324
463
|
class RAGPipeline {
|
|
@@ -326,53 +465,35 @@ class RAGPipeline {
|
|
|
326
465
|
initialize(): Promise<void>;
|
|
327
466
|
addDocuments(documents: Document[]): Promise<string[]>;
|
|
328
467
|
query(query: string, options?: RAGQueryOptions): Promise<RAGResponse>;
|
|
329
|
-
|
|
468
|
+
search(query: string, options?: QueryOptions): Promise<SearchResult[]>;
|
|
330
469
|
deleteDocuments(ids: string[]): Promise<void>;
|
|
331
470
|
clear(): Promise<void>;
|
|
332
471
|
}
|
|
333
472
|
```
|
|
334
473
|
|
|
335
|
-
###
|
|
474
|
+
### `Document`
|
|
336
475
|
|
|
337
476
|
```typescript
|
|
338
477
|
interface Document {
|
|
339
478
|
id?: string;
|
|
340
479
|
content: string;
|
|
341
|
-
metadata?: Record<string,
|
|
480
|
+
metadata?: Record<string, unknown>;
|
|
342
481
|
embedding?: number[];
|
|
343
482
|
}
|
|
344
|
-
|
|
345
|
-
interface SearchResult {
|
|
346
|
-
id: string;
|
|
347
|
-
content: string;
|
|
348
|
-
metadata?: Record<string, any>;
|
|
349
|
-
score: number;
|
|
350
|
-
embedding?: number[];
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
interface RAGResponse {
|
|
354
|
-
answer: string;
|
|
355
|
-
sources: SearchResult[];
|
|
356
|
-
context: string;
|
|
357
|
-
}
|
|
358
483
|
```
|
|
359
484
|
|
|
360
|
-
|
|
485
|
+
---
|
|
361
486
|
|
|
362
|
-
|
|
363
|
-
- π¬ **Chatbots** - Context-aware conversational AI
|
|
364
|
-
- π **Knowledge Base** - Internal knowledge management
|
|
365
|
-
- π **Content Recommendations** - Similar content discovery
|
|
366
|
-
- π **Educational Tools** - Q&A systems with source citations
|
|
367
|
-
- π’ **Enterprise Search** - Semantic search across company data
|
|
487
|
+
## Use Cases
|
|
368
488
|
|
|
369
|
-
|
|
489
|
+
- π **Documentation Q&A** β Index all your docs and answer developer questions
|
|
490
|
+
- πΈοΈ **Codebase Understanding** β GraphRAG over a repo to explain architecture and dependencies
|
|
491
|
+
- π¬ **Context-Aware Chatbots** β RAG + memory for multi-turn conversations
|
|
492
|
+
- π **Enterprise Knowledge Base** β Combine web, GitHub, PDFs, and internal wikis
|
|
493
|
+
- π **Research Assistants** β Multi-document reasoning with knowledge graph traversal
|
|
494
|
+
- π **Content Intelligence** β Semantic search + relationship mapping across articles
|
|
370
495
|
|
|
371
|
-
|
|
372
|
-
2. **Chunk Size** - Balance between context and precision (500-1500 tokens)
|
|
373
|
-
3. **Overlap** - Use 10-20% overlap for better context continuity
|
|
374
|
-
4. **Caching** - Cache embeddings for frequently accessed documents
|
|
375
|
-
5. **Filtering** - Use metadata filters to reduce search space
|
|
496
|
+
---
|
|
376
497
|
|
|
377
498
|
## License
|
|
378
499
|
|
|
@@ -380,4 +501,4 @@ Apache 2.0
|
|
|
380
501
|
|
|
381
502
|
## Contributing
|
|
382
503
|
|
|
383
|
-
Contributions are welcome!
|
|
504
|
+
Contributions are welcome! See [CONTRIBUTING.md](../../CONTRIBUTING.md) for details.
|