some cleanup
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// src/utils/aiPipeline.ts - Fixed with accurate audit data and meaningful confidence
|
||||
// src/utils/aiPipeline.ts - Fixed to remove hardcoded values and improve dynamics
|
||||
import { getCompressedToolsDataForAI, getDataVersion } from './dataService.js';
|
||||
import { aiService } from './aiService.js';
|
||||
import { toolSelector, type SelectionContext } from './toolSelector.js';
|
||||
@@ -77,6 +77,12 @@ interface PipelineContext {
|
||||
}>;
|
||||
seenToolNames: Set<string>;
|
||||
embeddingsSimilarities: Map<string, number>;
|
||||
// Add phase metadata for dynamic phase handling
|
||||
phaseMetadata?: {
|
||||
phases: any[];
|
||||
criticalPhaseIds: string[];
|
||||
phaseComplexity: Map<string, number>;
|
||||
};
|
||||
}
|
||||
|
||||
class AIPipeline {
|
||||
@@ -95,7 +101,7 @@ class AIPipeline {
|
||||
}
|
||||
};
|
||||
|
||||
console.log('[AI-PIPELINE] Initialized with improved audit accuracy');
|
||||
console.log('[AI-PIPELINE] Initialized with dynamic phase handling');
|
||||
}
|
||||
|
||||
async processQuery(userQuery: string, mode: string): Promise<AnalysisResult> {
|
||||
@@ -121,17 +127,16 @@ class AIPipeline {
|
||||
maxContextLength: this.config.maxContextTokens,
|
||||
currentContextLength: 0,
|
||||
seenToolNames: new Set<string>(),
|
||||
embeddingsSimilarities: new Map<string, number>()
|
||||
embeddingsSimilarities: new Map<string, number>(),
|
||||
// Initialize phase metadata dynamically
|
||||
phaseMetadata: this.initializePhaseMetadata(toolsData.phases)
|
||||
};
|
||||
|
||||
// Skip initialization audit entry - it doesn't add transparency value
|
||||
|
||||
console.log('[AI-PIPELINE] Phase 1: Tool candidate selection');
|
||||
const candidateSelectionStart = Date.now();
|
||||
|
||||
const candidateData = await toolSelector.getIntelligentCandidates(userQuery, toolsData, mode, context);
|
||||
|
||||
// Calculate meaningful confidence for tool selection
|
||||
const selectionConfidence = this.calculateToolSelectionConfidence(
|
||||
candidateData.tools.length,
|
||||
toolsData.tools.length,
|
||||
@@ -197,8 +202,6 @@ class AIPipeline {
|
||||
|
||||
const recommendation = this.buildRecommendation(context, mode, finalResult.content);
|
||||
|
||||
// Skip completion audit entry - it doesn't add transparency value
|
||||
|
||||
const processingStats = {
|
||||
embeddingsUsed: embeddingsService.isEnabled(),
|
||||
candidatesFromEmbeddings: candidateData.tools.length,
|
||||
@@ -242,6 +245,55 @@ class AIPipeline {
|
||||
}
|
||||
}
|
||||
|
||||
private initializePhaseMetadata(phases: any[]): {
|
||||
phases: any[];
|
||||
criticalPhaseIds: string[];
|
||||
phaseComplexity: Map<string, number>;
|
||||
} {
|
||||
if (!phases || !Array.isArray(phases)) {
|
||||
console.warn('[AI-PIPELINE] No phases data available, using fallback');
|
||||
return {
|
||||
phases: [],
|
||||
criticalPhaseIds: [],
|
||||
phaseComplexity: new Map()
|
||||
};
|
||||
}
|
||||
|
||||
// Dynamically determine critical phases based on typical_tools or key_activities
|
||||
const criticalPhaseIds = phases
|
||||
.filter(phase => {
|
||||
const typicalToolsCount = phase.typical_tools?.length || 0;
|
||||
const keyActivitiesCount = phase.key_activities?.length || 0;
|
||||
// Consider phases with many tools or activities as critical
|
||||
return typicalToolsCount >= 3 || keyActivitiesCount >= 2;
|
||||
})
|
||||
.map(phase => phase.id);
|
||||
|
||||
// Calculate phase complexity based on metadata
|
||||
const phaseComplexity = new Map<string, number>();
|
||||
phases.forEach(phase => {
|
||||
let complexity = 1; // Base complexity
|
||||
|
||||
if (phase.typical_tools?.length > 5) complexity += 1;
|
||||
if (phase.key_activities?.length > 3) complexity += 1;
|
||||
if (phase.description?.length > 100) complexity += 1;
|
||||
|
||||
phaseComplexity.set(phase.id, complexity);
|
||||
});
|
||||
|
||||
console.log('[AI-PIPELINE] Initialized phase metadata:', {
|
||||
totalPhases: phases.length,
|
||||
criticalPhases: criticalPhaseIds.length,
|
||||
avgComplexity: Array.from(phaseComplexity.values()).reduce((sum, c) => sum + c, 0) / phases.length
|
||||
});
|
||||
|
||||
return {
|
||||
phases,
|
||||
criticalPhaseIds,
|
||||
phaseComplexity
|
||||
};
|
||||
}
|
||||
|
||||
private calculateToolSelectionConfidence(
|
||||
selectedCount: number,
|
||||
totalCount: number,
|
||||
@@ -252,26 +304,22 @@ class AIPipeline {
|
||||
|
||||
const selectionRatio = selectedCount / totalCount;
|
||||
|
||||
// Good selection ratio (5-20% is optimal)
|
||||
if (selectionRatio >= 0.05 && selectionRatio <= 0.20) {
|
||||
confidence += 25;
|
||||
} else if (selectionRatio < 0.05) {
|
||||
confidence += 15; // Very selective
|
||||
confidence += 15;
|
||||
} else if (selectionRatio > 0.30) {
|
||||
confidence -= 15; // Too inclusive
|
||||
confidence -= 15;
|
||||
}
|
||||
|
||||
// Embeddings method bonus
|
||||
if (method.includes('embeddings')) {
|
||||
confidence += 15;
|
||||
}
|
||||
|
||||
// Concepts also selected
|
||||
if (conceptsCount > 0) {
|
||||
confidence += 10;
|
||||
}
|
||||
|
||||
// Reasonable absolute numbers
|
||||
if (selectedCount >= 8 && selectedCount <= 25) {
|
||||
confidence += 10;
|
||||
}
|
||||
@@ -301,12 +349,12 @@ class AIPipeline {
|
||||
|
||||
const selections = await toolSelector.selectToolsForPhase(context.userQuery, phase, phaseTools, context);
|
||||
|
||||
// Calculate meaningful confidence based on phase selection quality
|
||||
const phaseConfidence = this.calculatePhaseSelectionConfidence(
|
||||
selections.length,
|
||||
phaseTools.length,
|
||||
phase.id,
|
||||
selections
|
||||
selections,
|
||||
context.phaseMetadata
|
||||
);
|
||||
|
||||
auditService.addEntry(
|
||||
@@ -341,7 +389,10 @@ class AIPipeline {
|
||||
const moderatedTaskRelevance = this.moderateTaskRelevance(sel.taskRelevance);
|
||||
const priority = this.derivePriorityFromScore(moderatedTaskRelevance);
|
||||
|
||||
this.addToolToSelection(context, tool, phase.id, priority, sel.justification, moderatedTaskRelevance, sel.limitations);
|
||||
// Generate dynamic limitations based on context
|
||||
const dynamicLimitations = this.generateDynamicLimitations(tool, phase, sel);
|
||||
|
||||
this.addToolToSelection(context, tool, phase.id, priority, sel.justification, moderatedTaskRelevance, dynamicLimitations);
|
||||
|
||||
auditService.addEntry(
|
||||
'tool-reasoning',
|
||||
@@ -354,7 +405,7 @@ class AIPipeline {
|
||||
},
|
||||
{
|
||||
justification: sel.justification,
|
||||
limitations: sel.limitations,
|
||||
limitations: dynamicLimitations,
|
||||
addedToPhase: phase.name
|
||||
},
|
||||
moderatedTaskRelevance || 70,
|
||||
@@ -384,19 +435,24 @@ class AIPipeline {
|
||||
selectedCount: number,
|
||||
availableCount: number,
|
||||
phaseId: string,
|
||||
selections: any[]
|
||||
selections: any[],
|
||||
phaseMetadata?: {
|
||||
phases: any[];
|
||||
criticalPhaseIds: string[];
|
||||
phaseComplexity: Map<string, number>;
|
||||
}
|
||||
): number {
|
||||
let confidence = 60;
|
||||
|
||||
// Phase-specific expectations
|
||||
const criticalPhases = ['acquisition', 'examination', 'analysis'];
|
||||
const isCritical = criticalPhases.includes(phaseId);
|
||||
// Use dynamic phase metadata instead of hardcoded values
|
||||
const isCritical = phaseMetadata?.criticalPhaseIds.includes(phaseId) || false;
|
||||
const phaseComplexity = phaseMetadata?.phaseComplexity.get(phaseId) || 1;
|
||||
|
||||
// Selection made
|
||||
if (selectedCount > 0) {
|
||||
confidence += 20;
|
||||
} else {
|
||||
return 30; // No selection is concerning
|
||||
return 30;
|
||||
}
|
||||
|
||||
// Selection ratio (for phases, 20-50% is reasonable)
|
||||
@@ -404,14 +460,19 @@ class AIPipeline {
|
||||
if (ratio >= 0.2 && ratio <= 0.5) {
|
||||
confidence += 15;
|
||||
} else if (ratio < 0.2 && selectedCount >= 1) {
|
||||
confidence += 10; // Selective is ok
|
||||
confidence += 10;
|
||||
}
|
||||
|
||||
// Critical phases should have adequate tools
|
||||
// Dynamic critical phase handling
|
||||
if (isCritical && selectedCount >= 2) {
|
||||
confidence += 10;
|
||||
}
|
||||
|
||||
// Phase complexity factor
|
||||
if (phaseComplexity > 2 && selectedCount >= phaseComplexity) {
|
||||
confidence += 5;
|
||||
}
|
||||
|
||||
// Quality of selections (based on task relevance)
|
||||
const avgRelevance = selections.length > 0 ?
|
||||
selections.reduce((sum, s) => sum + (s.taskRelevance || 70), 0) / selections.length : 0;
|
||||
@@ -425,6 +486,35 @@ class AIPipeline {
|
||||
return Math.min(95, Math.max(30, confidence));
|
||||
}
|
||||
|
||||
private generateDynamicLimitations(tool: any, phase: any, selection: any): string[] {
|
||||
const limitations: string[] = [];
|
||||
|
||||
// Add existing limitations if provided
|
||||
if (selection.limitations && Array.isArray(selection.limitations)) {
|
||||
limitations.push(...selection.limitations);
|
||||
}
|
||||
|
||||
// Generate context-aware limitations
|
||||
if (tool.type === 'software' && !tool.projectUrl) {
|
||||
limitations.push('Installation und Konfiguration erforderlich');
|
||||
}
|
||||
|
||||
if (tool.skillLevel === 'expert') {
|
||||
limitations.push('Erfordert spezialisierte Kenntnisse');
|
||||
}
|
||||
|
||||
if (tool.license === 'Proprietary') {
|
||||
limitations.push('Kommerzielle Lizenz erforderlich');
|
||||
}
|
||||
|
||||
// Phase-specific limitations
|
||||
if (phase.id === 'acquisition' && tool.type === 'method') {
|
||||
limitations.push('Sorgfältige Dokumentation für Chain of Custody erforderlich');
|
||||
}
|
||||
|
||||
return limitations.slice(0, 3); // Limit to 3 most relevant
|
||||
}
|
||||
|
||||
private async processToolMode(
|
||||
context: PipelineContext,
|
||||
completedTasks: number,
|
||||
@@ -582,7 +672,6 @@ class AIPipeline {
|
||||
};
|
||||
}
|
||||
|
||||
// This is the fix for "0 tools added" - use the actual valid tools
|
||||
const actualToolsAdded = validTools.map(tool => tool.name);
|
||||
|
||||
for (const tool of validTools) {
|
||||
@@ -610,6 +699,9 @@ class AIPipeline {
|
||||
moderatedTaskRelevance = this.moderateTaskRelevance(75);
|
||||
}
|
||||
|
||||
// Generate dynamic limitations instead of hardcoded ones
|
||||
const dynamicLimitations = this.generateCompletionLimitations(tool, phase, selection);
|
||||
|
||||
this.addToolToSelection(
|
||||
context,
|
||||
tool,
|
||||
@@ -617,16 +709,15 @@ class AIPipeline {
|
||||
'medium',
|
||||
detailedJustification,
|
||||
moderatedTaskRelevance,
|
||||
['Nachträgliche Ergänzung via semantische Phasensuche mit KI-Bewertung']
|
||||
dynamicLimitations
|
||||
);
|
||||
|
||||
console.log('[AI-PIPELINE] Added phase completion tool with AI reasoning:', tool.name);
|
||||
}
|
||||
|
||||
// Use the actual tools added for audit
|
||||
auditService.addPhaseCompletion(
|
||||
phase.id,
|
||||
actualToolsAdded, // This ensures correct count
|
||||
actualToolsAdded,
|
||||
selection.completionReasoning || `${actualToolsAdded.length} Tools für ${phase.name} hinzugefügt`,
|
||||
phaseStart,
|
||||
{
|
||||
@@ -660,6 +751,29 @@ class AIPipeline {
|
||||
}
|
||||
}
|
||||
|
||||
private generateCompletionLimitations(tool: any, phase: any, selection: any): string[] {
|
||||
const limitations: string[] = [];
|
||||
|
||||
// Context-specific limitation for completion tools
|
||||
limitations.push('Nachträgliche Ergänzung - ursprünglich nicht als Hauptmethode identifiziert');
|
||||
|
||||
// Tool-specific limitations
|
||||
if (tool.skillLevel === 'expert') {
|
||||
limitations.push('Erfordert Expertenwissen für optimale Nutzung');
|
||||
}
|
||||
|
||||
if (tool.type === 'software' && !tool.projectUrl) {
|
||||
limitations.push('Zusätzliche Setup-Zeit erforderlich');
|
||||
}
|
||||
|
||||
// Phase-specific context
|
||||
if (phase.typical_tools && !phase.typical_tools.includes(tool.name)) {
|
||||
limitations.push(`Nicht typisch für ${phase.name}-Phase - alternative Anwendung`);
|
||||
}
|
||||
|
||||
return limitations.slice(0, 3);
|
||||
}
|
||||
|
||||
private moderateTaskRelevance(taskRelevance: number): number {
|
||||
if (typeof taskRelevance !== 'number') {
|
||||
return 70;
|
||||
@@ -904,7 +1018,6 @@ class AIPipeline {
|
||||
'background-knowledge'
|
||||
);
|
||||
|
||||
// Calculate confidence based on quality of selections
|
||||
const selectionQualityBonus = this.calculateKnowledgeSelectionBonus(context.backgroundKnowledge, availableConcepts);
|
||||
const finalConfidence = Math.min(95, responseConfidence + selectionQualityBonus);
|
||||
|
||||
@@ -951,13 +1064,11 @@ class AIPipeline {
|
||||
bonus += 10;
|
||||
}
|
||||
|
||||
// Good selection ratio (10-30% of available concepts)
|
||||
const ratio = selectedKnowledge.length / availableConcepts.length;
|
||||
if (ratio >= 0.1 && ratio <= 0.3) {
|
||||
bonus += 15;
|
||||
}
|
||||
|
||||
// Quality reasoning provided
|
||||
const hasGoodReasonings = selectedKnowledge.some(bk =>
|
||||
bk.relevance && bk.relevance.length > 30
|
||||
);
|
||||
@@ -983,7 +1094,6 @@ class AIPipeline {
|
||||
'final-recommendations'
|
||||
);
|
||||
|
||||
// Calculate bonus based on context quality
|
||||
const contextBonus = this.calculateSynthesisBonus(selectedToolNames, context);
|
||||
const finalConfidence = Math.min(95, confidence + contextBonus);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user