@devilsdev/rag-pipeline-utils 1.0.0 → 1.0.1
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/.dockerignore +14 -14
- package/.eslintignore +5 -0
- package/.eslintrc.json +21 -0
- package/.github/workflows/ci.yml +46 -42
- package/.github/workflows/release.yml +20 -21
- package/CHANGELOG.md +13 -0
- package/Dockerfile +22 -22
- package/LICENSE +674 -674
- package/README.md +117 -116
- package/__tests__/fixtures/sample-eval-dataset.json +14 -14
- package/__tests__/fixtures/sample.pdf +1 -0
- package/__tests__/integration/cli/config-flow.test.js +29 -44
- package/__tests__/integration/config/load-config.test.js +52 -52
- package/__tests__/unit/core/plugin-registry.test.js +55 -55
- package/__tests__/unit/reranker/llm-reranker.test.js +42 -42
- package/__tests__/unit/reranker/reranker.snapshot.test.js +17 -17
- package/bin/cli.js +168 -168
- package/docs-site/docs/Architecture.md +76 -76
- package/docs-site/docs/CLI.md +69 -69
- package/docs-site/docs/Evaluation.md +61 -61
- package/docs-site/docs/FAQ.md +50 -50
- package/docs-site/docs/Plugins.md +61 -61
- package/docs-site/docs/Usage.md +72 -72
- package/jest.config.js +20 -13
- package/package.json +4 -2
- package/public/src/App.jsx +57 -57
- package/release.config.js +36 -23
- package/scripts/setup.js +7 -0
- package/scripts/test-global-setup.js +18 -0
- package/server.js +31 -31
- package/src/config/load-config.js +35 -35
- package/src/config/validate-schema.js +49 -49
- package/src/core/create-pipeline.js +82 -82
- package/src/core/plugin-registry.js +61 -61
- package/src/dag/dag-engine.js +69 -69
- package/src/evaluate/evaluator.js +44 -44
- package/src/evaluate/scoring.js +73 -73
- package/src/loader/csv-loader.js +30 -30
- package/src/loader/directory-loader.js +37 -37
- package/src/loader/html-loader.js +57 -57
- package/src/loader/markdown-loader.js +58 -58
- package/src/reranker/llm-reranker.js +48 -48
- package/src/utils/logger.js +29 -29
- package/src/utils/retry.js +42 -42
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { LLMReranker } from '../../../src/reranker/llm-reranker.js';
|
|
2
|
-
|
|
3
|
-
test('LLMReranker output snapshot', async () => {
|
|
4
|
-
const mockLLM = {
|
|
5
|
-
async generate() {
|
|
6
|
-
return '[1, 0, 2]';
|
|
7
|
-
}
|
|
8
|
-
};
|
|
9
|
-
const mockDocs = [
|
|
10
|
-
{ text: 'A' },
|
|
11
|
-
{ text: 'B' },
|
|
12
|
-
{ text: 'C' }
|
|
13
|
-
];
|
|
14
|
-
const reranker = new LLMReranker({ llm: mockLLM });
|
|
15
|
-
const result = await reranker.rerank('What is A?', mockDocs);
|
|
16
|
-
expect(result).toMatchSnapshot();
|
|
17
|
-
});
|
|
1
|
+
import { LLMReranker } from '../../../src/reranker/llm-reranker.js';
|
|
2
|
+
|
|
3
|
+
test('LLMReranker output snapshot', async () => {
|
|
4
|
+
const mockLLM = {
|
|
5
|
+
async generate() {
|
|
6
|
+
return '[1, 0, 2]';
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
const mockDocs = [
|
|
10
|
+
{ text: 'A' },
|
|
11
|
+
{ text: 'B' },
|
|
12
|
+
{ text: 'C' }
|
|
13
|
+
];
|
|
14
|
+
const reranker = new LLMReranker({ llm: mockLLM });
|
|
15
|
+
const result = await reranker.rerank('What is A?', mockDocs);
|
|
16
|
+
expect(result).toMatchSnapshot();
|
|
17
|
+
});
|
package/bin/cli.js
CHANGED
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Version: 0.1.
|
|
5
|
-
* Path: /bin/cli.js
|
|
6
|
-
* Description: CLI interface for rag-pipeline utilities with loaders, reranker, and evaluation
|
|
7
|
-
* Author: Ali Kahwaji
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { Command } from 'commander';
|
|
11
|
-
import { createRagPipeline, registry } from '../src/core/create-pipeline.js';
|
|
12
|
-
import { loadRagConfig } from '../src/config/load-config.js';
|
|
13
|
-
import { logger } from '../src/utils/logger.js';
|
|
14
|
-
import { evaluateRagDataset } from '../src/evaluate/evaluator.js';
|
|
15
|
-
import { LLMReranker } from '../src/reranker/llm-reranker.js';
|
|
16
|
-
|
|
17
|
-
import { MarkdownLoader } from '../src/loader/markdown-loader.js';
|
|
18
|
-
import { HTMLLoader } from '../src/loader/html-loader.js';
|
|
19
|
-
import { CSVLoader } from '../src/loader/csv-loader.js';
|
|
20
|
-
import { DirectoryLoader } from '../src/loader/directory-loader.js';
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
class PDFLoader {
|
|
24
|
-
async load(
|
|
25
|
-
return [{ chunk: () => [
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
class OpenAIEmbedder {
|
|
29
|
-
async embed(chunks) {
|
|
30
|
-
return chunks.map((text, i) => ({ id: `v${i}`, values: [0.1, 0.2, 0.3], metadata: { text } }));
|
|
31
|
-
}
|
|
32
|
-
async embedQuery(prompt) {
|
|
33
|
-
return [0.1, 0.2, 0.3];
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
class PineconeRetriever {
|
|
37
|
-
async store(
|
|
38
|
-
async retrieve(
|
|
39
|
-
return [
|
|
40
|
-
{ id: 'a', text: 'Chunk about pine trees', metadata: {} },
|
|
41
|
-
{ id: 'b', text: 'Chunk about vectors', metadata: {} },
|
|
42
|
-
{ id: 'c', text: 'Chunk about databases', metadata: {} }
|
|
43
|
-
];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
class OpenAILLM {
|
|
47
|
-
async generate(prompt, context) {
|
|
48
|
-
return `Generated answer using: ${context.map(d => d.text).join(', ')}`;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Register plugins
|
|
53
|
-
registry.register('loader', 'pdf', new PDFLoader());
|
|
54
|
-
registry.register('loader', 'markdown', new MarkdownLoader());
|
|
55
|
-
registry.register('loader', 'html', new HTMLLoader());
|
|
56
|
-
registry.register('loader', 'csv', new CSVLoader());
|
|
57
|
-
registry.register('loader', 'directory', new DirectoryLoader());
|
|
58
|
-
registry.register('embedder', 'openai', new OpenAIEmbedder());
|
|
59
|
-
registry.register('retriever', 'pinecone', new PineconeRetriever());
|
|
60
|
-
registry.register('llm', 'openai-gpt-4', new OpenAILLM());
|
|
61
|
-
|
|
62
|
-
const program = new Command();
|
|
63
|
-
program
|
|
64
|
-
.name('rag-pipeline')
|
|
65
|
-
.description('CLI for RAG pipeline utilities')
|
|
66
|
-
.version('0.1.
|
|
67
|
-
|
|
68
|
-
function resolveConfig(cliOpts) {
|
|
69
|
-
try {
|
|
70
|
-
const fileConfig = loadRagConfig();
|
|
71
|
-
return { ...fileConfig, ...cliOpts };
|
|
72
|
-
} catch (err) {
|
|
73
|
-
logger.warn({ error: err.message }, 'Config file fallback failed');
|
|
74
|
-
return cliOpts;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
program
|
|
79
|
-
.command('ingest')
|
|
80
|
-
.argument('<path>', 'Path to document(s)')
|
|
81
|
-
.option('--loader <type>', 'Document loader type')
|
|
82
|
-
.option('--embedder <type>', 'Embedder type')
|
|
83
|
-
.option('--retriever <type>', 'Vector store retriever type')
|
|
84
|
-
.action(async (
|
|
85
|
-
try {
|
|
86
|
-
const config = resolveConfig(opts);
|
|
87
|
-
const pipeline = createRagPipeline(config);
|
|
88
|
-
await pipeline.ingest(
|
|
89
|
-
|
|
90
|
-
} catch (err) {
|
|
91
|
-
logger.error({ error: err.message }, 'Ingestion failed');
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
.
|
|
100
|
-
.option('--
|
|
101
|
-
.option('--
|
|
102
|
-
.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
console.log('\n Answer:\n', answer);
|
|
109
|
-
} catch (err) {
|
|
110
|
-
logger.error({ error: err.message }, 'Query failed');
|
|
111
|
-
process.exit(1);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
program
|
|
116
|
-
.command('evaluate')
|
|
117
|
-
.argument('<dataset>', 'Path to JSON file of evaluation cases')
|
|
118
|
-
.option('--embedder <type>', 'Embedder type')
|
|
119
|
-
.option('--retriever <type>', 'Retriever type')
|
|
120
|
-
.option('--llm <type>', 'LLM type')
|
|
121
|
-
.action(async (dataset, opts) => {
|
|
122
|
-
try {
|
|
123
|
-
const config = resolveConfig(opts);
|
|
124
|
-
const results = await evaluateRagDataset(dataset, config);
|
|
125
|
-
const passRate = results.filter(r => r.success).length / results.length;
|
|
126
|
-
const avgBLEU = results.reduce((sum, r) => sum + r.scores.bleu, 0) / results.length;
|
|
127
|
-
const avgROUGE = results.reduce((sum, r) => sum + r.scores.rouge, 0) / results.length;
|
|
128
|
-
|
|
129
|
-
results.forEach((r, i) => {
|
|
130
|
-
console.log(`\nCase ${i + 1}:\nPrompt: ${r.prompt}\nPass: ${r.success}\nBLEU: ${r.scores.bleu.toFixed(2)}\nROUGE: ${r.scores.rouge.toFixed(2)}`);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
console.log(`\n Summary:\nPassed: ${Math.round(passRate * 100)}%\nAvg BLEU: ${avgBLEU.toFixed(2)}\nAvg ROUGE: ${avgROUGE.toFixed(2)}`);
|
|
134
|
-
} catch (err) {
|
|
135
|
-
logger.error({ error: err.message }, 'Evaluation failed');
|
|
136
|
-
process.exit(1);
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
program
|
|
141
|
-
.command('rerank')
|
|
142
|
-
.argument('<prompt>', 'Prompt to rerank context for')
|
|
143
|
-
.option('--retriever <type>', 'Retriever type')
|
|
144
|
-
.option('--llm <type>', 'LLM type')
|
|
145
|
-
.action(async (prompt, opts) => {
|
|
146
|
-
try {
|
|
147
|
-
const config = resolveConfig(opts);
|
|
148
|
-
const retriever = registry.get('retriever', config.retriever);
|
|
149
|
-
const llm = registry.get('llm', config.llm);
|
|
150
|
-
const embedder = registry.get('embedder', config.embedder);
|
|
151
|
-
|
|
152
|
-
const queryVector = await embedder.embedQuery(prompt);
|
|
153
|
-
const docs = await retriever.retrieve(queryVector);
|
|
154
|
-
|
|
155
|
-
const reranker = new LLMReranker({ llm });
|
|
156
|
-
const reranked = await reranker.rerank(prompt, docs);
|
|
157
|
-
|
|
158
|
-
console.log('\n Reranked Results:');
|
|
159
|
-
reranked.forEach((doc, i) => {
|
|
160
|
-
console.log(`\n#${i + 1}: ${doc.text}`);
|
|
161
|
-
});
|
|
162
|
-
} catch (err) {
|
|
163
|
-
logger.error({ error: err.message }, 'Rerank failed');
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
program.parse();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Version: 0.1.8
|
|
5
|
+
* Path: /bin/cli.js
|
|
6
|
+
* Description: CLI interface for rag-pipeline utilities with loaders, reranker, and evaluation
|
|
7
|
+
* Author: Ali Kahwaji
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { createRagPipeline, registry } from '../src/core/create-pipeline.js';
|
|
12
|
+
import { loadRagConfig } from '../src/config/load-config.js';
|
|
13
|
+
import { logger } from '../src/utils/logger.js';
|
|
14
|
+
import { evaluateRagDataset } from '../src/evaluate/evaluator.js';
|
|
15
|
+
import { LLMReranker } from '../src/reranker/llm-reranker.js';
|
|
16
|
+
|
|
17
|
+
import { MarkdownLoader } from '../src/loader/markdown-loader.js';
|
|
18
|
+
import { HTMLLoader } from '../src/loader/html-loader.js';
|
|
19
|
+
import { CSVLoader } from '../src/loader/csv-loader.js';
|
|
20
|
+
import { DirectoryLoader } from '../src/loader/directory-loader.js';
|
|
21
|
+
|
|
22
|
+
// Minimal test plugin implementations
|
|
23
|
+
class PDFLoader {
|
|
24
|
+
async load(filePath) {
|
|
25
|
+
return [{ chunk: () => [`Test loaded: ${filePath}`] }];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
class OpenAIEmbedder {
|
|
29
|
+
async embed(chunks) {
|
|
30
|
+
return chunks.map((text, i) => ({ id: `v${i}`, values: [0.1, 0.2, 0.3], metadata: { text } }));
|
|
31
|
+
}
|
|
32
|
+
async embedQuery(prompt) {
|
|
33
|
+
return [0.1, 0.2, 0.3];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class PineconeRetriever {
|
|
37
|
+
async store() {}
|
|
38
|
+
async retrieve() {
|
|
39
|
+
return [
|
|
40
|
+
{ id: 'a', text: 'Chunk about pine trees', metadata: {} },
|
|
41
|
+
{ id: 'b', text: 'Chunk about vectors', metadata: {} },
|
|
42
|
+
{ id: 'c', text: 'Chunk about databases', metadata: {} }
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
class OpenAILLM {
|
|
47
|
+
async generate(prompt, context) {
|
|
48
|
+
return `Generated answer using: ${context.map(d => d.text).join(', ')}`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Register mock/default plugins
|
|
53
|
+
registry.register('loader', 'pdf', new PDFLoader());
|
|
54
|
+
registry.register('loader', 'markdown', new MarkdownLoader());
|
|
55
|
+
registry.register('loader', 'html', new HTMLLoader());
|
|
56
|
+
registry.register('loader', 'csv', new CSVLoader());
|
|
57
|
+
registry.register('loader', 'directory', new DirectoryLoader());
|
|
58
|
+
registry.register('embedder', 'openai', new OpenAIEmbedder());
|
|
59
|
+
registry.register('retriever', 'pinecone', new PineconeRetriever());
|
|
60
|
+
registry.register('llm', 'openai-gpt-4', new OpenAILLM());
|
|
61
|
+
|
|
62
|
+
const program = new Command();
|
|
63
|
+
program
|
|
64
|
+
.name('rag-pipeline')
|
|
65
|
+
.description('CLI for RAG pipeline utilities')
|
|
66
|
+
.version('0.1.8');
|
|
67
|
+
|
|
68
|
+
function resolveConfig(cliOpts) {
|
|
69
|
+
try {
|
|
70
|
+
const fileConfig = loadRagConfig();
|
|
71
|
+
return { ...fileConfig, ...cliOpts };
|
|
72
|
+
} catch (err) {
|
|
73
|
+
logger.warn({ error: err.message }, 'Config file fallback failed');
|
|
74
|
+
return cliOpts;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
program
|
|
79
|
+
.command('ingest')
|
|
80
|
+
.argument('<path>', 'Path to document(s)')
|
|
81
|
+
.option('--loader <type>', 'Document loader type')
|
|
82
|
+
.option('--embedder <type>', 'Embedder type')
|
|
83
|
+
.option('--retriever <type>', 'Vector store retriever type')
|
|
84
|
+
.action(async (docPath, opts) => {
|
|
85
|
+
try {
|
|
86
|
+
const config = resolveConfig(opts);
|
|
87
|
+
const pipeline = createRagPipeline(config);
|
|
88
|
+
await pipeline.ingest(docPath);
|
|
89
|
+
console.log('Ingestion complete'); // required by test assertion
|
|
90
|
+
} catch (err) {
|
|
91
|
+
logger.error({ error: err.message }, 'Ingestion failed');
|
|
92
|
+
console.error('Error during ingestion:', err.message);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
program
|
|
98
|
+
.command('query')
|
|
99
|
+
.argument('<prompt>', 'Prompt to submit')
|
|
100
|
+
.option('--embedder <type>', 'Embedder type')
|
|
101
|
+
.option('--retriever <type>', 'Retriever type')
|
|
102
|
+
.option('--llm <type>', 'LLM type')
|
|
103
|
+
.action(async (prompt, opts) => {
|
|
104
|
+
try {
|
|
105
|
+
const config = resolveConfig(opts);
|
|
106
|
+
const pipeline = createRagPipeline(config);
|
|
107
|
+
const answer = await pipeline.query(prompt);
|
|
108
|
+
console.log('\n Answer:\n', answer);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
logger.error({ error: err.message }, 'Query failed');
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
program
|
|
116
|
+
.command('evaluate')
|
|
117
|
+
.argument('<dataset>', 'Path to JSON file of evaluation cases')
|
|
118
|
+
.option('--embedder <type>', 'Embedder type')
|
|
119
|
+
.option('--retriever <type>', 'Retriever type')
|
|
120
|
+
.option('--llm <type>', 'LLM type')
|
|
121
|
+
.action(async (dataset, opts) => {
|
|
122
|
+
try {
|
|
123
|
+
const config = resolveConfig(opts);
|
|
124
|
+
const results = await evaluateRagDataset(dataset, config);
|
|
125
|
+
const passRate = results.filter(r => r.success).length / results.length;
|
|
126
|
+
const avgBLEU = results.reduce((sum, r) => sum + r.scores.bleu, 0) / results.length;
|
|
127
|
+
const avgROUGE = results.reduce((sum, r) => sum + r.scores.rouge, 0) / results.length;
|
|
128
|
+
|
|
129
|
+
results.forEach((r, i) => {
|
|
130
|
+
console.log(`\nCase ${i + 1}:\nPrompt: ${r.prompt}\nPass: ${r.success}\nBLEU: ${r.scores.bleu.toFixed(2)}\nROUGE: ${r.scores.rouge.toFixed(2)}`);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
console.log(`\n Summary:\nPassed: ${Math.round(passRate * 100)}%\nAvg BLEU: ${avgBLEU.toFixed(2)}\nAvg ROUGE: ${avgROUGE.toFixed(2)}`);
|
|
134
|
+
} catch (err) {
|
|
135
|
+
logger.error({ error: err.message }, 'Evaluation failed');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
program
|
|
141
|
+
.command('rerank')
|
|
142
|
+
.argument('<prompt>', 'Prompt to rerank context for')
|
|
143
|
+
.option('--retriever <type>', 'Retriever type')
|
|
144
|
+
.option('--llm <type>', 'LLM type')
|
|
145
|
+
.action(async (prompt, opts) => {
|
|
146
|
+
try {
|
|
147
|
+
const config = resolveConfig(opts);
|
|
148
|
+
const retriever = registry.get('retriever', config.retriever);
|
|
149
|
+
const llm = registry.get('llm', config.llm);
|
|
150
|
+
const embedder = registry.get('embedder', config.embedder);
|
|
151
|
+
|
|
152
|
+
const queryVector = await embedder.embedQuery(prompt);
|
|
153
|
+
const docs = await retriever.retrieve(queryVector);
|
|
154
|
+
|
|
155
|
+
const reranker = new LLMReranker({ llm });
|
|
156
|
+
const reranked = await reranker.rerank(prompt, docs);
|
|
157
|
+
|
|
158
|
+
console.log('\n Reranked Results:');
|
|
159
|
+
reranked.forEach((doc, i) => {
|
|
160
|
+
console.log(`\n#${i + 1}: ${doc.text}`);
|
|
161
|
+
});
|
|
162
|
+
} catch (err) {
|
|
163
|
+
logger.error({ error: err.message }, 'Rerank failed');
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
program.parse();
|
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
# Architecture
|
|
2
|
-
|
|
3
|
-
This page outlines the internal architecture of the RAG pipeline utilities, emphasizing modularity, plugin design, and SOLID-compliant structure.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 🧩 Core Design Philosophy
|
|
8
|
-
|
|
9
|
-
The architecture adheres to enterprise-grade practices:
|
|
10
|
-
|
|
11
|
-
- **Single Responsibility**: Each component handles one domain concern
|
|
12
|
-
- **Pluggable Interfaces**: Any layer (loader, retriever, LLM) can be swapped
|
|
13
|
-
- **Streaming-Ready**: Async flows support token-based output
|
|
14
|
-
- **Environment-Safe**: Config via `.ragrc.json`, not hardcoded
|
|
15
|
-
- **Testable**: All modules can be mocked and unit tested
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## 🏗️ Layered Components
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
+-------------------------+
|
|
23
|
-
| createRagPipeline() |
|
|
24
|
-
+-------------------------+
|
|
25
|
-
| | |
|
|
26
|
-
▼ ▼ ▼
|
|
27
|
-
Loader Embedder Retriever
|
|
28
|
-
▼ | ▼
|
|
29
|
-
Chunks Embeddings Context
|
|
30
|
-
\ | /
|
|
31
|
-
▼ ▼ ▼
|
|
32
|
-
LLM Runner
|
|
33
|
-
|
|
|
34
|
-
Output
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## 📦 Core Interfaces
|
|
40
|
-
|
|
41
|
-
Each plugin is registered via the `PluginRegistry` and looked up by key.
|
|
42
|
-
|
|
43
|
-
```ts
|
|
44
|
-
registry.register('loader', 'pdf', new PDFLoader())
|
|
45
|
-
const loader = registry.get('loader', 'pdf');
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
All plugins implement interface contracts like:
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
interface Loader {
|
|
52
|
-
load(path: string): Promise<{ chunk(): string[] }[]>;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface Embedder {
|
|
56
|
-
embed(chunks: string[]): Vector[];
|
|
57
|
-
embedQuery(prompt: string): Vector;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
interface Retriever {
|
|
61
|
-
store(vectors: Vector[]): Promise<void>;
|
|
62
|
-
retrieve(query: Vector): Promise<Context[]>;
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## 🔁 DAG Support
|
|
69
|
-
|
|
70
|
-
The `dag-engine.js` module supports chaining multiple components:
|
|
71
|
-
- Example: Summarize → Retrieve → Rerank → LLM
|
|
72
|
-
- Enables more complex workflows than linear ingestion/query
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
Next → [Evaluation](./Evaluation.md)
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
This page outlines the internal architecture of the RAG pipeline utilities, emphasizing modularity, plugin design, and SOLID-compliant structure.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🧩 Core Design Philosophy
|
|
8
|
+
|
|
9
|
+
The architecture adheres to enterprise-grade practices:
|
|
10
|
+
|
|
11
|
+
- **Single Responsibility**: Each component handles one domain concern
|
|
12
|
+
- **Pluggable Interfaces**: Any layer (loader, retriever, LLM) can be swapped
|
|
13
|
+
- **Streaming-Ready**: Async flows support token-based output
|
|
14
|
+
- **Environment-Safe**: Config via `.ragrc.json`, not hardcoded
|
|
15
|
+
- **Testable**: All modules can be mocked and unit tested
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🏗️ Layered Components
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
+-------------------------+
|
|
23
|
+
| createRagPipeline() |
|
|
24
|
+
+-------------------------+
|
|
25
|
+
| | |
|
|
26
|
+
▼ ▼ ▼
|
|
27
|
+
Loader Embedder Retriever
|
|
28
|
+
▼ | ▼
|
|
29
|
+
Chunks Embeddings Context
|
|
30
|
+
\ | /
|
|
31
|
+
▼ ▼ ▼
|
|
32
|
+
LLM Runner
|
|
33
|
+
|
|
|
34
|
+
Output
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 📦 Core Interfaces
|
|
40
|
+
|
|
41
|
+
Each plugin is registered via the `PluginRegistry` and looked up by key.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
registry.register('loader', 'pdf', new PDFLoader())
|
|
45
|
+
const loader = registry.get('loader', 'pdf');
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
All plugins implement interface contracts like:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
interface Loader {
|
|
52
|
+
load(path: string): Promise<{ chunk(): string[] }[]>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface Embedder {
|
|
56
|
+
embed(chunks: string[]): Vector[];
|
|
57
|
+
embedQuery(prompt: string): Vector;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface Retriever {
|
|
61
|
+
store(vectors: Vector[]): Promise<void>;
|
|
62
|
+
retrieve(query: Vector): Promise<Context[]>;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 🔁 DAG Support
|
|
69
|
+
|
|
70
|
+
The `dag-engine.js` module supports chaining multiple components:
|
|
71
|
+
- Example: Summarize → Retrieve → Rerank → LLM
|
|
72
|
+
- Enables more complex workflows than linear ingestion/query
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
Next → [Evaluation](./Evaluation.md)
|
package/docs-site/docs/CLI.md
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
# CLI Reference
|
|
2
|
-
|
|
3
|
-
The CLI gives you interactive access to the RAG pipeline tools via terminal.
|
|
4
|
-
|
|
5
|
-
Install globally (optional):
|
|
6
|
-
```bash
|
|
7
|
-
npm install -g @yourorg/rag-pipeline-utils
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
Or run directly from your project:
|
|
11
|
-
```bash
|
|
12
|
-
npx rag-pipeline <command>
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## 🔧 Commands
|
|
18
|
-
|
|
19
|
-
### `ingest`
|
|
20
|
-
```bash
|
|
21
|
-
rag-pipeline ingest ./docs/sample.pdf --loader pdf
|
|
22
|
-
```
|
|
23
|
-
- Loads and indexes documents into vector store
|
|
24
|
-
|
|
25
|
-
### `query`
|
|
26
|
-
```bash
|
|
27
|
-
rag-pipeline query "Explain vector databases" --llm openai-gpt-4
|
|
28
|
-
```
|
|
29
|
-
- Retrieves context and generates response
|
|
30
|
-
|
|
31
|
-
### `evaluate`
|
|
32
|
-
```bash
|
|
33
|
-
rag-pipeline evaluate ./fixtures/eval.json
|
|
34
|
-
```
|
|
35
|
-
- Runs batch evaluation with BLEU/ROUGE scoring
|
|
36
|
-
|
|
37
|
-
### `rerank`
|
|
38
|
-
```bash
|
|
39
|
-
rag-pipeline rerank "What is RAG?" --retriever pinecone
|
|
40
|
-
```
|
|
41
|
-
- Reorders retrieved context using an LLM reranker
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## ⚙️ `.ragrc.json` Config
|
|
46
|
-
|
|
47
|
-
Defaults can be set in a file:
|
|
48
|
-
```json
|
|
49
|
-
{
|
|
50
|
-
"loader": "directory",
|
|
51
|
-
"embedder": "openai",
|
|
52
|
-
"retriever": "pinecone",
|
|
53
|
-
"llm": "openai-gpt-4",
|
|
54
|
-
"useReranker": true
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## 🐳 Docker Usage
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
docker build -t rag-pipeline .
|
|
64
|
-
docker run --rm -v $PWD:/data rag-pipeline query "What is retrieval?"
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
Next → [Architecture](./Architecture.md)
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
The CLI gives you interactive access to the RAG pipeline tools via terminal.
|
|
4
|
+
|
|
5
|
+
Install globally (optional):
|
|
6
|
+
```bash
|
|
7
|
+
npm install -g @yourorg/rag-pipeline-utils
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Or run directly from your project:
|
|
11
|
+
```bash
|
|
12
|
+
npx rag-pipeline <command>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 🔧 Commands
|
|
18
|
+
|
|
19
|
+
### `ingest`
|
|
20
|
+
```bash
|
|
21
|
+
rag-pipeline ingest ./docs/sample.pdf --loader pdf
|
|
22
|
+
```
|
|
23
|
+
- Loads and indexes documents into vector store
|
|
24
|
+
|
|
25
|
+
### `query`
|
|
26
|
+
```bash
|
|
27
|
+
rag-pipeline query "Explain vector databases" --llm openai-gpt-4
|
|
28
|
+
```
|
|
29
|
+
- Retrieves context and generates response
|
|
30
|
+
|
|
31
|
+
### `evaluate`
|
|
32
|
+
```bash
|
|
33
|
+
rag-pipeline evaluate ./fixtures/eval.json
|
|
34
|
+
```
|
|
35
|
+
- Runs batch evaluation with BLEU/ROUGE scoring
|
|
36
|
+
|
|
37
|
+
### `rerank`
|
|
38
|
+
```bash
|
|
39
|
+
rag-pipeline rerank "What is RAG?" --retriever pinecone
|
|
40
|
+
```
|
|
41
|
+
- Reorders retrieved context using an LLM reranker
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ⚙️ `.ragrc.json` Config
|
|
46
|
+
|
|
47
|
+
Defaults can be set in a file:
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"loader": "directory",
|
|
51
|
+
"embedder": "openai",
|
|
52
|
+
"retriever": "pinecone",
|
|
53
|
+
"llm": "openai-gpt-4",
|
|
54
|
+
"useReranker": true
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 🐳 Docker Usage
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
docker build -t rag-pipeline .
|
|
64
|
+
docker run --rm -v $PWD:/data rag-pipeline query "What is retrieval?"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
Next → [Architecture](./Architecture.md)
|