@eucoder/rag 0.2.0
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 +384 -0
- package/dist/ab-testing.d.ts +52 -0
- package/dist/ab-testing.d.ts.map +1 -0
- package/dist/ab-testing.js +144 -0
- package/dist/ab-testing.js.map +1 -0
- package/dist/ab-testing.test.d.ts +2 -0
- package/dist/ab-testing.test.d.ts.map +1 -0
- package/dist/ab-testing.test.js +147 -0
- package/dist/ab-testing.test.js.map +1 -0
- package/dist/agentic-rag.d.ts +23 -0
- package/dist/agentic-rag.d.ts.map +1 -0
- package/dist/agentic-rag.js +170 -0
- package/dist/agentic-rag.js.map +1 -0
- package/dist/agentic-rag.test.d.ts +2 -0
- package/dist/agentic-rag.test.d.ts.map +1 -0
- package/dist/agentic-rag.test.js +174 -0
- package/dist/agentic-rag.test.js.map +1 -0
- package/dist/corrective-rag.d.ts +16 -0
- package/dist/corrective-rag.d.ts.map +1 -0
- package/dist/corrective-rag.js +85 -0
- package/dist/corrective-rag.js.map +1 -0
- package/dist/corrective-rag.test.d.ts +2 -0
- package/dist/corrective-rag.test.d.ts.map +1 -0
- package/dist/corrective-rag.test.js +140 -0
- package/dist/corrective-rag.test.js.map +1 -0
- package/dist/feedback.d.ts +77 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/feedback.js +44 -0
- package/dist/feedback.js.map +1 -0
- package/dist/feedback.test.d.ts +2 -0
- package/dist/feedback.test.d.ts.map +1 -0
- package/dist/feedback.test.js +202 -0
- package/dist/feedback.test.js.map +1 -0
- package/dist/hybrid-search.d.ts +14 -0
- package/dist/hybrid-search.d.ts.map +1 -0
- package/dist/hybrid-search.js +70 -0
- package/dist/hybrid-search.js.map +1 -0
- package/dist/hybrid-search.test.d.ts +2 -0
- package/dist/hybrid-search.test.d.ts.map +1 -0
- package/dist/hybrid-search.test.js +93 -0
- package/dist/hybrid-search.test.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge-graph.d.ts +24 -0
- package/dist/knowledge-graph.d.ts.map +1 -0
- package/dist/knowledge-graph.js +131 -0
- package/dist/knowledge-graph.js.map +1 -0
- package/dist/knowledge-graph.test.d.ts +2 -0
- package/dist/knowledge-graph.test.d.ts.map +1 -0
- package/dist/knowledge-graph.test.js +140 -0
- package/dist/knowledge-graph.test.js.map +1 -0
- package/dist/llm-grader.d.ts +19 -0
- package/dist/llm-grader.d.ts.map +1 -0
- package/dist/llm-grader.js +63 -0
- package/dist/llm-grader.js.map +1 -0
- package/dist/metrics.d.ts +26 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +100 -0
- package/dist/metrics.js.map +1 -0
- package/dist/optimizer.d.ts +52 -0
- package/dist/optimizer.d.ts.map +1 -0
- package/dist/optimizer.js +228 -0
- package/dist/optimizer.js.map +1 -0
- package/dist/optimizer.test.d.ts +2 -0
- package/dist/optimizer.test.d.ts.map +1 -0
- package/dist/optimizer.test.js +201 -0
- package/dist/optimizer.test.js.map +1 -0
- package/dist/self-improving.d.ts +85 -0
- package/dist/self-improving.d.ts.map +1 -0
- package/dist/self-improving.js +163 -0
- package/dist/self-improving.js.map +1 -0
- package/dist/self-improving.test.d.ts +2 -0
- package/dist/self-improving.test.d.ts.map +1 -0
- package/dist/self-improving.test.js +234 -0
- package/dist/self-improving.test.js.map +1 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +42 -0
- package/src/ab-testing.test.ts +239 -0
- package/src/ab-testing.ts +214 -0
- package/src/agentic-rag.test.ts +201 -0
- package/src/agentic-rag.ts +220 -0
- package/src/corrective-rag.test.ts +166 -0
- package/src/corrective-rag.ts +115 -0
- package/src/feedback.test.ts +227 -0
- package/src/feedback.ts +118 -0
- package/src/hybrid-search.test.ts +107 -0
- package/src/hybrid-search.ts +86 -0
- package/src/index.ts +57 -0
- package/src/knowledge-graph.test.ts +170 -0
- package/src/knowledge-graph.ts +182 -0
- package/src/llm-grader.ts +69 -0
- package/src/metrics.ts +121 -0
- package/src/optimizer.test.ts +232 -0
- package/src/optimizer.ts +307 -0
- package/src/self-improving.test.ts +341 -0
- package/src/self-improving.ts +239 -0
- package/src/types.ts +139 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import { ParameterOptimizer } from "./optimizer.js";
|
|
3
|
+
import { InMemoryFeedbackStorage } from "./feedback.js";
|
|
4
|
+
import type { OptimizableParams } from "./optimizer.js";
|
|
5
|
+
|
|
6
|
+
describe("ParameterOptimizer", () => {
|
|
7
|
+
let optimizer: ParameterOptimizer;
|
|
8
|
+
let storage: InMemoryFeedbackStorage;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
storage = new InMemoryFeedbackStorage();
|
|
12
|
+
optimizer = new ParameterOptimizer(storage);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should suggest collecting more data when feedback is insufficient", async () => {
|
|
16
|
+
const params: OptimizableParams = {
|
|
17
|
+
minScore: 0.5,
|
|
18
|
+
topK: 5,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Add only 5 feedback (not enough)
|
|
22
|
+
for (let i = 0; i < 5; i++) {
|
|
23
|
+
await storage.saveFeedback({
|
|
24
|
+
id: `test-${i}`,
|
|
25
|
+
query: `query ${i}`,
|
|
26
|
+
answer: { text: `answer ${i}`, citations: [], steps: [], rewrites: 0 },
|
|
27
|
+
rating: 4,
|
|
28
|
+
relevance: 0.8,
|
|
29
|
+
completeness: 0.7,
|
|
30
|
+
citationsQuality: 0.9,
|
|
31
|
+
timestamp: new Date(),
|
|
32
|
+
strategy: "strategy-a",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const suggestions = await optimizer.analyzeAndSuggest("strategy-a", params);
|
|
37
|
+
|
|
38
|
+
expect(suggestions).toHaveLength(1);
|
|
39
|
+
expect(suggestions[0]?.type).toBe("strategy");
|
|
40
|
+
expect(suggestions[0]?.target).toBe("data_collection");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should suggest increasing minScore when relevance is low", async () => {
|
|
44
|
+
const params: OptimizableParams = {
|
|
45
|
+
minScore: 0.3,
|
|
46
|
+
topK: 10,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Add 20 feedback with low relevance
|
|
50
|
+
for (let i = 0; i < 20; i++) {
|
|
51
|
+
await storage.saveFeedback({
|
|
52
|
+
id: `test-${i}`,
|
|
53
|
+
query: `query ${i}`,
|
|
54
|
+
answer: { text: `answer ${i}`, citations: [], steps: [], rewrites: 0 },
|
|
55
|
+
rating: 3,
|
|
56
|
+
relevance: 0.5,
|
|
57
|
+
completeness: 0.6,
|
|
58
|
+
citationsQuality: 0.7,
|
|
59
|
+
timestamp: new Date(),
|
|
60
|
+
strategy: "strategy-a",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const suggestions = await optimizer.analyzeAndSuggest("strategy-a", params);
|
|
65
|
+
|
|
66
|
+
const minScoreSuggestion = suggestions.find(s => s.target === "minScore");
|
|
67
|
+
expect(minScoreSuggestion).toBeDefined();
|
|
68
|
+
expect(minScoreSuggestion?.suggested).toBeGreaterThan(params.minScore!);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should suggest enabling self-reflection when completeness is low", async () => {
|
|
72
|
+
const params: OptimizableParams = {
|
|
73
|
+
enableSelfReflection: false,
|
|
74
|
+
maxIterations: 2,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Add 20 feedback with low completeness
|
|
78
|
+
for (let i = 0; i < 20; i++) {
|
|
79
|
+
await storage.saveFeedback({
|
|
80
|
+
id: `test-${i}`,
|
|
81
|
+
query: `query ${i}`,
|
|
82
|
+
answer: { text: `answer ${i}`, citations: [], steps: [], rewrites: 0 },
|
|
83
|
+
rating: 3,
|
|
84
|
+
relevance: 0.7,
|
|
85
|
+
completeness: 0.5,
|
|
86
|
+
citationsQuality: 0.8,
|
|
87
|
+
timestamp: new Date(),
|
|
88
|
+
strategy: "strategy-a",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const suggestions = await optimizer.analyzeAndSuggest("strategy-a", params);
|
|
93
|
+
|
|
94
|
+
const selfReflectionSuggestion = suggestions.find(s => s.target === "enableSelfReflection");
|
|
95
|
+
expect(selfReflectionSuggestion).toBeDefined();
|
|
96
|
+
expect(selfReflectionSuggestion?.suggested).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should suggest increasing semanticWeight when citations quality is low", async () => {
|
|
100
|
+
const params: OptimizableParams = {
|
|
101
|
+
semanticWeight: 0.5,
|
|
102
|
+
keywordWeight: 0.5,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Add 20 feedback with low citations quality
|
|
106
|
+
for (let i = 0; i < 20; i++) {
|
|
107
|
+
await storage.saveFeedback({
|
|
108
|
+
id: `test-${i}`,
|
|
109
|
+
query: `query ${i}`,
|
|
110
|
+
answer: { text: `answer ${i}`, citations: [], steps: [], rewrites: 0 },
|
|
111
|
+
rating: 3,
|
|
112
|
+
relevance: 0.7,
|
|
113
|
+
completeness: 0.7,
|
|
114
|
+
citationsQuality: 0.5,
|
|
115
|
+
timestamp: new Date(),
|
|
116
|
+
strategy: "strategy-a",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const suggestions = await optimizer.analyzeAndSuggest("strategy-a", params);
|
|
121
|
+
|
|
122
|
+
const semanticWeightSuggestion = suggestions.find(s => s.target === "semanticWeight");
|
|
123
|
+
expect(semanticWeightSuggestion).toBeDefined();
|
|
124
|
+
expect(semanticWeightSuggestion?.suggested).toBeGreaterThan(params.semanticWeight!);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should apply suggestions with sufficient confidence", () => {
|
|
128
|
+
const currentParams: OptimizableParams = {
|
|
129
|
+
minScore: 0.3,
|
|
130
|
+
topK: 5,
|
|
131
|
+
enableSelfReflection: false,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const suggestions = [
|
|
135
|
+
{
|
|
136
|
+
type: "parameter" as const,
|
|
137
|
+
target: "minScore",
|
|
138
|
+
current: 0.3,
|
|
139
|
+
suggested: 0.5,
|
|
140
|
+
expectedImprovement: 0.15,
|
|
141
|
+
confidence: 0.8,
|
|
142
|
+
reasoning: "Test suggestion",
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: "parameter" as const,
|
|
146
|
+
target: "topK",
|
|
147
|
+
current: 5,
|
|
148
|
+
suggested: 10,
|
|
149
|
+
expectedImprovement: 0.1,
|
|
150
|
+
confidence: 0.6, // Below threshold
|
|
151
|
+
reasoning: "Test suggestion",
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
const optimized = optimizer.applySuggestions(currentParams, suggestions, 0.7);
|
|
156
|
+
|
|
157
|
+
expect(optimized.minScore).toBe(0.5);
|
|
158
|
+
expect(optimized.topK).toBe(5); // Not applied due to low confidence
|
|
159
|
+
expect(optimized.enableSelfReflection).toBe(false);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("should generate report", async () => {
|
|
163
|
+
const params: OptimizableParams = {
|
|
164
|
+
minScore: 0.5,
|
|
165
|
+
topK: 10,
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// Add 15 feedback
|
|
169
|
+
for (let i = 0; i < 15; i++) {
|
|
170
|
+
await storage.saveFeedback({
|
|
171
|
+
id: `test-${i}`,
|
|
172
|
+
query: `query ${i}`,
|
|
173
|
+
answer: { text: `answer ${i}`, citations: [], steps: [], rewrites: 0 },
|
|
174
|
+
rating: 4,
|
|
175
|
+
relevance: 0.7,
|
|
176
|
+
completeness: 0.6,
|
|
177
|
+
citationsQuality: 0.8,
|
|
178
|
+
timestamp: new Date(),
|
|
179
|
+
strategy: "strategy-a",
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const report = await optimizer.generateReport("strategy-a", params);
|
|
184
|
+
|
|
185
|
+
expect(report).toContain("Report Ottimizzazione: strategy-a");
|
|
186
|
+
expect(report).toContain("Metriche Attuali");
|
|
187
|
+
expect(report).toContain("Total Queries");
|
|
188
|
+
expect(report).toContain("15");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should detect declining trend", async () => {
|
|
192
|
+
const params: OptimizableParams = {
|
|
193
|
+
minScore: 0.5,
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// Add older feedback with high relevance
|
|
197
|
+
for (let i = 0; i < 10; i++) {
|
|
198
|
+
await storage.saveFeedback({
|
|
199
|
+
id: `old-${i}`,
|
|
200
|
+
query: `query ${i}`,
|
|
201
|
+
answer: { text: `answer ${i}`, citations: [], steps: [], rewrites: 0 },
|
|
202
|
+
rating: 5,
|
|
203
|
+
relevance: 0.9,
|
|
204
|
+
completeness: 0.9,
|
|
205
|
+
citationsQuality: 0.9,
|
|
206
|
+
timestamp: new Date(Date.now() - 1000000),
|
|
207
|
+
strategy: "strategy-a",
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Add recent feedback with low relevance
|
|
212
|
+
for (let i = 0; i < 10; i++) {
|
|
213
|
+
await storage.saveFeedback({
|
|
214
|
+
id: `new-${i}`,
|
|
215
|
+
query: `query ${i}`,
|
|
216
|
+
answer: { text: `answer ${i}`, citations: [], steps: [], rewrites: 0 },
|
|
217
|
+
rating: 2,
|
|
218
|
+
relevance: 0.4,
|
|
219
|
+
completeness: 0.4,
|
|
220
|
+
citationsQuality: 0.4,
|
|
221
|
+
timestamp: new Date(),
|
|
222
|
+
strategy: "strategy-a",
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const suggestions = await optimizer.analyzeAndSuggest("strategy-a", params);
|
|
227
|
+
|
|
228
|
+
const trendSuggestion = suggestions.find(s => s.target === "overall_strategy");
|
|
229
|
+
expect(trendSuggestion).toBeDefined();
|
|
230
|
+
expect(trendSuggestion?.reasoning).toContain("declino");
|
|
231
|
+
});
|
|
232
|
+
});
|
package/src/optimizer.ts
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import type { RagFeedback, FeedbackStorage, OptimizationSuggestion } from "./feedback.js";
|
|
2
|
+
import { InMemoryFeedbackStorage } from "./feedback.js";
|
|
3
|
+
import { MetricsCalculator } from "./metrics.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parametri ottimizzabili per strategie RAG
|
|
7
|
+
*/
|
|
8
|
+
export interface OptimizableParams {
|
|
9
|
+
// Corrective RAG
|
|
10
|
+
minGoodHits?: number;
|
|
11
|
+
minScore?: number;
|
|
12
|
+
maxRewrites?: number;
|
|
13
|
+
|
|
14
|
+
// Hybrid Search
|
|
15
|
+
semanticWeight?: number;
|
|
16
|
+
keywordWeight?: number;
|
|
17
|
+
rrfK?: number;
|
|
18
|
+
|
|
19
|
+
// Agentic RAG
|
|
20
|
+
maxIterations?: number;
|
|
21
|
+
enableSelfReflection?: boolean;
|
|
22
|
+
enableChainOfThought?: boolean;
|
|
23
|
+
|
|
24
|
+
// General
|
|
25
|
+
topK?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Ottimizzatore automatico per parametri RAG
|
|
30
|
+
*/
|
|
31
|
+
export class ParameterOptimizer {
|
|
32
|
+
private storage: FeedbackStorage;
|
|
33
|
+
|
|
34
|
+
constructor(storage?: FeedbackStorage) {
|
|
35
|
+
this.storage = storage || new InMemoryFeedbackStorage();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Analizza i feedback e suggerisce ottimizzazioni
|
|
40
|
+
*/
|
|
41
|
+
async analyzeAndSuggest(
|
|
42
|
+
strategy: string,
|
|
43
|
+
currentParams: OptimizableParams
|
|
44
|
+
): Promise<OptimizationSuggestion[]> {
|
|
45
|
+
const feedbacks = await this.storage.getFeedback(strategy);
|
|
46
|
+
|
|
47
|
+
if (feedbacks.length < 10) {
|
|
48
|
+
return [{
|
|
49
|
+
type: "strategy",
|
|
50
|
+
target: "data_collection",
|
|
51
|
+
current: feedbacks.length,
|
|
52
|
+
suggested: 50,
|
|
53
|
+
expectedImprovement: 0,
|
|
54
|
+
confidence: 1,
|
|
55
|
+
reasoning: `Raccogli almeno 50 feedback per analisi affidabile (attualmente: ${feedbacks.length})`,
|
|
56
|
+
}];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const suggestions: OptimizationSuggestion[] = [];
|
|
60
|
+
|
|
61
|
+
// Analizza problemi di relevance
|
|
62
|
+
const relevanceSuggestions = this.analyzeRelevance(feedbacks, currentParams);
|
|
63
|
+
suggestions.push(...relevanceSuggestions);
|
|
64
|
+
|
|
65
|
+
// Analizza problemi di completeness
|
|
66
|
+
const completenessSuggestions = this.analyzeCompleteness(feedbacks, currentParams);
|
|
67
|
+
suggestions.push(...completenessSuggestions);
|
|
68
|
+
|
|
69
|
+
// Analizza problemi di citations quality
|
|
70
|
+
const citationsSuggestions = this.analyzeCitationsQuality(feedbacks, currentParams);
|
|
71
|
+
suggestions.push(...citationsSuggestions);
|
|
72
|
+
|
|
73
|
+
// Analizza trend temporale
|
|
74
|
+
const trendSuggestions = this.analyzeTrend(feedbacks, currentParams);
|
|
75
|
+
suggestions.push(...trendSuggestions);
|
|
76
|
+
|
|
77
|
+
return suggestions;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Analizza problemi di relevance
|
|
82
|
+
*/
|
|
83
|
+
private analyzeRelevance(
|
|
84
|
+
feedbacks: RagFeedback[],
|
|
85
|
+
params: OptimizableParams
|
|
86
|
+
): OptimizationSuggestion[] {
|
|
87
|
+
const suggestions: OptimizationSuggestion[] = [];
|
|
88
|
+
const avgRelevance = feedbacks.reduce((sum, f) => sum + f.relevance, 0) / feedbacks.length;
|
|
89
|
+
|
|
90
|
+
// Se relevance è bassa, suggerisci di aumentare minScore o topK
|
|
91
|
+
if (avgRelevance < 0.6) {
|
|
92
|
+
if (params.minScore !== undefined && params.minScore < 0.5) {
|
|
93
|
+
suggestions.push({
|
|
94
|
+
type: "parameter",
|
|
95
|
+
target: "minScore",
|
|
96
|
+
current: params.minScore,
|
|
97
|
+
suggested: Math.min(0.7, params.minScore + 0.1),
|
|
98
|
+
expectedImprovement: 0.15,
|
|
99
|
+
confidence: 0.8,
|
|
100
|
+
reasoning: `Relevance media bassa (${avgRelevance.toFixed(2)}). Aumenta minScore per filtrare risultati meno rilevanti.`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (params.topK !== undefined && params.topK < 10) {
|
|
105
|
+
suggestions.push({
|
|
106
|
+
type: "parameter",
|
|
107
|
+
target: "topK",
|
|
108
|
+
current: params.topK,
|
|
109
|
+
suggested: Math.min(15, params.topK + 3),
|
|
110
|
+
expectedImprovement: 0.1,
|
|
111
|
+
confidence: 0.7,
|
|
112
|
+
reasoning: `Relevance media bassa (${avgRelevance.toFixed(2)}). Aumenta topK per avere più candidati da cui scegliere.`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Se relevance è molto alta, potresti essere troppo conservativo
|
|
118
|
+
if (avgRelevance > 0.9 && params.minScore !== undefined && params.minScore > 0.7) {
|
|
119
|
+
suggestions.push({
|
|
120
|
+
type: "parameter",
|
|
121
|
+
target: "minScore",
|
|
122
|
+
current: params.minScore,
|
|
123
|
+
suggested: Math.max(0.5, params.minScore - 0.1),
|
|
124
|
+
expectedImprovement: 0.05,
|
|
125
|
+
confidence: 0.6,
|
|
126
|
+
reasoning: `Relevance molto alta (${avgRelevance.toFixed(2)}) ma potresti perdere risultati utili. Riduci minScore per aumentare recall.`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return suggestions;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Analizza problemi di completeness
|
|
135
|
+
*/
|
|
136
|
+
private analyzeCompleteness(
|
|
137
|
+
feedbacks: RagFeedback[],
|
|
138
|
+
params: OptimizableParams
|
|
139
|
+
): OptimizationSuggestion[] {
|
|
140
|
+
const suggestions: OptimizationSuggestion[] = [];
|
|
141
|
+
const avgCompleteness = feedbacks.reduce((sum, f) => sum + f.completeness, 0) / feedbacks.length;
|
|
142
|
+
|
|
143
|
+
// Se completeness è bassa, suggerisci di abilitare self-reflection o aumentare iterazioni
|
|
144
|
+
if (avgCompleteness < 0.6) {
|
|
145
|
+
if (params.enableSelfReflection === false) {
|
|
146
|
+
suggestions.push({
|
|
147
|
+
type: "parameter",
|
|
148
|
+
target: "enableSelfReflection",
|
|
149
|
+
current: false,
|
|
150
|
+
suggested: true,
|
|
151
|
+
expectedImprovement: 0.2,
|
|
152
|
+
confidence: 0.85,
|
|
153
|
+
reasoning: `Completeness bassa (${avgCompleteness.toFixed(2)}). Abilita self-reflection per migliorare qualità risposte.`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (params.maxIterations !== undefined && params.maxIterations < 3) {
|
|
158
|
+
suggestions.push({
|
|
159
|
+
type: "parameter",
|
|
160
|
+
target: "maxIterations",
|
|
161
|
+
current: params.maxIterations,
|
|
162
|
+
suggested: Math.min(5, params.maxIterations + 1),
|
|
163
|
+
expectedImprovement: 0.15,
|
|
164
|
+
confidence: 0.75,
|
|
165
|
+
reasoning: `Completeness bassa (${avgCompleteness.toFixed(2)}). Aumenta maxIterations per permettere più tentativi di miglioramento.`,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (params.enableChainOfThought === false) {
|
|
170
|
+
suggestions.push({
|
|
171
|
+
type: "parameter",
|
|
172
|
+
target: "enableChainOfThought",
|
|
173
|
+
current: false,
|
|
174
|
+
suggested: true,
|
|
175
|
+
expectedImprovement: 0.18,
|
|
176
|
+
confidence: 0.8,
|
|
177
|
+
reasoning: `Completeness bassa (${avgCompleteness.toFixed(2)}). Abilita chain-of-thought per risposte più strutturate.`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return suggestions;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Analizza problemi di citations quality
|
|
187
|
+
*/
|
|
188
|
+
private analyzeCitationsQuality(
|
|
189
|
+
feedbacks: RagFeedback[],
|
|
190
|
+
params: OptimizableParams
|
|
191
|
+
): OptimizationSuggestion[] {
|
|
192
|
+
const suggestions: OptimizationSuggestion[] = [];
|
|
193
|
+
const avgCitations = feedbacks.reduce((sum, f) => sum + f.citationsQuality, 0) / feedbacks.length;
|
|
194
|
+
|
|
195
|
+
// Se citations quality è bassa, suggerisci di migliorare hybrid search
|
|
196
|
+
if (avgCitations < 0.6) {
|
|
197
|
+
if (params.semanticWeight !== undefined && params.semanticWeight < 0.6) {
|
|
198
|
+
suggestions.push({
|
|
199
|
+
type: "parameter",
|
|
200
|
+
target: "semanticWeight",
|
|
201
|
+
current: params.semanticWeight,
|
|
202
|
+
suggested: Math.min(0.7, params.semanticWeight + 0.1),
|
|
203
|
+
expectedImprovement: 0.12,
|
|
204
|
+
confidence: 0.7,
|
|
205
|
+
reasoning: `Citations quality bassa (${avgCitations.toFixed(2)}). Aumenta semanticWeight per risultati più semanticamente rilevanti.`,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (params.rrfK !== undefined && params.rrfK > 80) {
|
|
210
|
+
suggestions.push({
|
|
211
|
+
type: "parameter",
|
|
212
|
+
target: "rrfK",
|
|
213
|
+
current: params.rrfK,
|
|
214
|
+
suggested: Math.max(50, params.rrfK - 20),
|
|
215
|
+
expectedImprovement: 0.1,
|
|
216
|
+
confidence: 0.65,
|
|
217
|
+
reasoning: `Citations quality bassa (${avgCitations.toFixed(2)}). Riduci rrfK per dare più peso ai risultati top-ranked.`,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return suggestions;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Analizza trend temporale
|
|
227
|
+
*/
|
|
228
|
+
private analyzeTrend(
|
|
229
|
+
feedbacks: RagFeedback[],
|
|
230
|
+
_params: OptimizableParams
|
|
231
|
+
): OptimizationSuggestion[] {
|
|
232
|
+
const suggestions: OptimizationSuggestion[] = [];
|
|
233
|
+
const trend = MetricsCalculator.identifyTrend(feedbacks);
|
|
234
|
+
|
|
235
|
+
if (trend === "declining") {
|
|
236
|
+
suggestions.push({
|
|
237
|
+
type: "strategy",
|
|
238
|
+
target: "overall_strategy",
|
|
239
|
+
current: "current",
|
|
240
|
+
suggested: "review",
|
|
241
|
+
expectedImprovement: 0.1,
|
|
242
|
+
confidence: 0.7,
|
|
243
|
+
reasoning: `Trend in declino negli ultimi feedback. Considera di rivedere la strategia o raccogliere feedback qualitativi per capire cosa non funziona.`,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return suggestions;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Applica automaticamente le ottimizzazioni suggerite
|
|
252
|
+
*/
|
|
253
|
+
applySuggestions(
|
|
254
|
+
currentParams: OptimizableParams,
|
|
255
|
+
suggestions: OptimizationSuggestion[],
|
|
256
|
+
minConfidence: number = 0.7
|
|
257
|
+
): OptimizableParams {
|
|
258
|
+
const optimized = { ...currentParams };
|
|
259
|
+
|
|
260
|
+
for (const suggestion of suggestions) {
|
|
261
|
+
if (suggestion.confidence >= minConfidence && suggestion.type === "parameter") {
|
|
262
|
+
(optimized as any)[suggestion.target] = suggestion.suggested;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return optimized;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Genera report di ottimizzazione
|
|
271
|
+
*/
|
|
272
|
+
async generateReport(
|
|
273
|
+
strategy: string,
|
|
274
|
+
currentParams: OptimizableParams
|
|
275
|
+
): Promise<string> {
|
|
276
|
+
const feedbacks = await this.storage.getFeedback(strategy);
|
|
277
|
+
const metrics = MetricsCalculator.calculateMetrics(feedbacks, strategy);
|
|
278
|
+
const suggestions = await this.analyzeAndSuggest(strategy, currentParams);
|
|
279
|
+
|
|
280
|
+
let report = `# Report Ottimizzazione: ${strategy}\n\n`;
|
|
281
|
+
report += `## Metriche Attuali\n`;
|
|
282
|
+
report += `- **Total Queries**: ${metrics.totalQueries}\n`;
|
|
283
|
+
report += `- **Overall Score**: ${metrics.overallScore.toFixed(3)}\n`;
|
|
284
|
+
report += `- **Average Relevance**: ${metrics.averageRelevance.toFixed(3)}\n`;
|
|
285
|
+
report += `- **Average Completeness**: ${metrics.averageCompleteness.toFixed(3)}\n`;
|
|
286
|
+
report += `- **Average Citations Quality**: ${metrics.averageCitationsQuality.toFixed(3)}\n`;
|
|
287
|
+
report += `- **Confidence**: ${(metrics.confidence * 100).toFixed(0)}%\n\n`;
|
|
288
|
+
|
|
289
|
+
report += `## Suggerimenti di Ottimizzazione\n\n`;
|
|
290
|
+
|
|
291
|
+
if (suggestions.length === 0) {
|
|
292
|
+
report += `Nessun suggerimento. I parametri attuali sembrano ottimali.\n`;
|
|
293
|
+
} else {
|
|
294
|
+
for (const suggestion of suggestions) {
|
|
295
|
+
report += `### ${suggestion.target}\n`;
|
|
296
|
+
report += `- **Tipo**: ${suggestion.type}\n`;
|
|
297
|
+
report += `- **Valore attuale**: ${JSON.stringify(suggestion.current)}\n`;
|
|
298
|
+
report += `- **Valore suggerito**: ${JSON.stringify(suggestion.suggested)}\n`;
|
|
299
|
+
report += `- **Miglioramento atteso**: +${(suggestion.expectedImprovement * 100).toFixed(1)}%\n`;
|
|
300
|
+
report += `- **Confidence**: ${(suggestion.confidence * 100).toFixed(0)}%\n`;
|
|
301
|
+
report += `- **Ragionamento**: ${suggestion.reasoning}\n\n`;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return report;
|
|
306
|
+
}
|
|
307
|
+
}
|