Cuong2004 commited on
Commit
9584356
·
1 Parent(s): 69263c1

Enhance CV result handling in agent executor by filtering based on confidence threshold and updating logging. Adjust match threshold and count in RAG service for improved guideline retrieval.

Browse files
src/agent/agent-executor.ts CHANGED
@@ -206,23 +206,35 @@ Tạo response JSON (ONLY JSON, no markdown):
206
  const cvResult = await this.callCVModel(imageUrl, cvType);
207
 
208
  logger.info(`CV analysis complete. Top condition: ${cvResult.top_conditions[0]?.name || 'none'}`);
 
209
 
210
- // Step 2: Call triage rules with CV results
 
 
 
 
 
 
 
 
 
 
 
211
  logger.info('Step 2: Applying triage rules...');
212
  const triageInput = {
213
  symptoms: {
214
  main_complaint: userText || 'Triệu chứng dựa trên hình ảnh',
215
  context: conversationContext
216
  },
217
- cv_results: {
218
  model_used: cvType === 'derm' ? 'derm_cv' : cvType === 'eye' ? 'eye_cv' : 'wound_cv',
219
  raw_output: {
220
- top_predictions: cvResult.top_conditions.map(c => ({
221
  condition: c.name,
222
  probability: c.prob
223
  }))
224
  }
225
- }
226
  };
227
 
228
  const triageResult = this.triageService.evaluateSymptoms(triageInput);
@@ -230,7 +242,16 @@ Tạo response JSON (ONLY JSON, no markdown):
230
 
231
  // Step 3: Get guidelines from RAG
232
  logger.info('[AGENT] Step 3: Retrieving medical guidelines from RAG...');
233
- const suspectedConditions = cvResult.top_conditions.slice(0, 2).map(c => c.name);
 
 
 
 
 
 
 
 
 
234
  const guidelineInput = {
235
  symptoms: userText,
236
  suspected_conditions: suspectedConditions,
@@ -243,9 +264,14 @@ Tạo response JSON (ONLY JSON, no markdown):
243
 
244
  // Step 4: Use LLM to synthesize final response
245
  logger.info('Step 4: Synthesizing final response with LLM...');
 
 
 
 
 
246
  const finalResult = await this.synthesizeFinalResponse(
247
  userText,
248
- cvResult,
249
  triageResult,
250
  guidelines,
251
  conversationContext
@@ -369,6 +395,11 @@ Tạo response JSON (ONLY JSON, no markdown):
369
  guidelines: any[],
370
  conversationContext?: string
371
  ): Promise<TriageResult> {
 
 
 
 
 
372
  const prompt = `Bạn là trợ lý y tế AI. Dựa trên thông tin sau, hãy tạo một phản hồi có cấu trúc:
373
 
374
  User input: ${userText}
@@ -376,9 +407,11 @@ User input: ${userText}
376
  ${conversationContext ? `Conversation context: ${conversationContext}` : ''}
377
 
378
  ${cvResult.top_conditions.length > 0 ? `
379
- CV Analysis Results:
380
  ${cvResult.top_conditions.map((c: any, i: number) => `${i + 1}. ${c.name}: ${(c.prob * 100).toFixed(1)}%`).join('\n')}
381
- ` : ''}
 
 
382
 
383
  Triage Level: ${triageResult.triage}
384
  Red Flags: ${triageResult.red_flags?.join(', ') || 'Không có'}
@@ -387,20 +420,26 @@ Reasoning: ${triageResult.reasoning}
387
  Medical Guidelines:
388
  ${guidelines.map((g, i) => `${i + 1}. ${g.content || g.snippet || g}`).join('\n')}
389
 
 
 
 
 
 
 
390
  Hãy tạo response JSON với format sau (ONLY JSON, no markdown):
391
  {
392
  "triage_level": "${triageResult.triage}",
393
  "symptom_summary": "Tóm tắt triệu chứng của người dùng bằng tiếng Việt",
394
  "red_flags": ${JSON.stringify(triageResult.red_flags || [])},
395
  "suspected_conditions": [
396
- ${cvResult.top_conditions.length > 0 ? cvResult.top_conditions.slice(0, 3).map((c: any) =>
397
  `{"name": "${c.name}", "source": "cv_model", "confidence": "${c.prob > 0.8 ? 'high' : c.prob > 0.5 ? 'medium' : 'low'}"}`
398
- ).join(',\n ') : ''}
399
  ],
400
  "cv_findings": {
401
- "model_used": "${cvResult.top_conditions.length > 0 ? 'derm_cv' : 'none'}",
402
  "raw_output": ${JSON.stringify(cvResult.top_conditions.length > 0 ? {
403
- top_predictions: cvResult.top_conditions.map((c: any) => ({ condition: c.name, probability: c.prob }))
404
  } : {})}
405
  },
406
  "recommendation": {
 
206
  const cvResult = await this.callCVModel(imageUrl, cvType);
207
 
208
  logger.info(`CV analysis complete. Top condition: ${cvResult.top_conditions[0]?.name || 'none'}`);
209
+ logger.info(`CV confidence: ${cvResult.top_conditions[0]?.prob ? (cvResult.top_conditions[0].prob * 100).toFixed(1) + '%' : 'N/A'}`);
210
 
211
+ // Filter CV results by confidence threshold (only use if confidence >= 0.5)
212
+ const CV_CONFIDENCE_THRESHOLD = 0.5;
213
+ const validCVResults = cvResult.top_conditions.filter((c: any) => c.prob >= CV_CONFIDENCE_THRESHOLD);
214
+
215
+ if (validCVResults.length === 0) {
216
+ logger.warn(`[AGENT] CV results có confidence quá thấp (< ${CV_CONFIDENCE_THRESHOLD * 100}%). Sẽ bỏ qua CV results và chỉ dùng text-based analysis.`);
217
+ logger.info(`[AGENT] Top CV result: ${cvResult.top_conditions[0]?.name} (${(cvResult.top_conditions[0]?.prob * 100 || 0).toFixed(1)}%)`);
218
+ } else {
219
+ logger.info(`[AGENT] Sử dụng ${validCVResults.length} CV results với confidence >= ${CV_CONFIDENCE_THRESHOLD * 100}%`);
220
+ }
221
+
222
+ // Step 2: Call triage rules with CV results (only if valid)
223
  logger.info('Step 2: Applying triage rules...');
224
  const triageInput = {
225
  symptoms: {
226
  main_complaint: userText || 'Triệu chứng dựa trên hình ảnh',
227
  context: conversationContext
228
  },
229
+ cv_results: validCVResults.length > 0 ? {
230
  model_used: cvType === 'derm' ? 'derm_cv' : cvType === 'eye' ? 'eye_cv' : 'wound_cv',
231
  raw_output: {
232
+ top_predictions: validCVResults.map(c => ({
233
  condition: c.name,
234
  probability: c.prob
235
  }))
236
  }
237
+ } : undefined
238
  };
239
 
240
  const triageResult = this.triageService.evaluateSymptoms(triageInput);
 
242
 
243
  // Step 3: Get guidelines from RAG
244
  logger.info('[AGENT] Step 3: Retrieving medical guidelines from RAG...');
245
+ // Chỉ dùng CV conditions nếu có valid results với confidence đủ cao
246
+ // Chỉ lấy 1 kết quả CV có confidence cao nhất
247
+ const suspectedConditions = validCVResults.length > 0
248
+ ? validCVResults.slice(0, 1).map(c => c.name)
249
+ : [];
250
+
251
+ if (validCVResults.length === 0) {
252
+ logger.info('[AGENT] Không dùng CV conditions trong RAG search vì confidence quá thấp. Chỉ dùng user symptoms.');
253
+ }
254
+
255
  const guidelineInput = {
256
  symptoms: userText,
257
  suspected_conditions: suspectedConditions,
 
264
 
265
  // Step 4: Use LLM to synthesize final response
266
  logger.info('Step 4: Synthesizing final response with LLM...');
267
+ // Chỉ truyền valid CV results
268
+ const filteredCVResult = {
269
+ top_conditions: validCVResults.length > 0 ? validCVResults : []
270
+ };
271
+
272
  const finalResult = await this.synthesizeFinalResponse(
273
  userText,
274
+ filteredCVResult,
275
  triageResult,
276
  guidelines,
277
  conversationContext
 
395
  guidelines: any[],
396
  conversationContext?: string
397
  ): Promise<TriageResult> {
398
+ // Determine CV model used
399
+ const cvModelUsed = cvResult.top_conditions.length > 0
400
+ ? (cvResult.top_conditions[0] as any).model_used || 'derm_cv'
401
+ : 'none';
402
+
403
  const prompt = `Bạn là trợ lý y tế AI. Dựa trên thông tin sau, hãy tạo một phản hồi có cấu trúc:
404
 
405
  User input: ${userText}
 
407
  ${conversationContext ? `Conversation context: ${conversationContext}` : ''}
408
 
409
  ${cvResult.top_conditions.length > 0 ? `
410
+ CV Analysis Results (chỉ các kết quả có độ tin cậy cao):
411
  ${cvResult.top_conditions.map((c: any, i: number) => `${i + 1}. ${c.name}: ${(c.prob * 100).toFixed(1)}%`).join('\n')}
412
+ ` : `
413
+ Lưu ý: Phân tích hình ảnh không cho kết quả đủ tin cậy, sẽ dựa chủ yếu vào mô tả triệu chứng của người dùng.
414
+ `}
415
 
416
  Triage Level: ${triageResult.triage}
417
  Red Flags: ${triageResult.red_flags?.join(', ') || 'Không có'}
 
420
  Medical Guidelines:
421
  ${guidelines.map((g, i) => `${i + 1}. ${g.content || g.snippet || g}`).join('\n')}
422
 
423
+ QUAN TRỌNG:
424
+ ${cvResult.top_conditions.length === 0 ? '- Phân tích hình ảnh không đủ tin cậy, chỉ dựa vào mô tả triệu chứng và guidelines.' : ''}
425
+ - Chỉ đưa suspected_conditions từ CV nếu có và có độ tin cậy cao.
426
+ - Nếu CV results không phù hợp hoặc confidence thấp, chỉ dựa vào user symptoms và guidelines.
427
+ - Luôn nhấn mạnh: "Thông tin chỉ mang tính tham khảo, cần bác sĩ khám để chẩn đoán chính xác"
428
+
429
  Hãy tạo response JSON với format sau (ONLY JSON, no markdown):
430
  {
431
  "triage_level": "${triageResult.triage}",
432
  "symptom_summary": "Tóm tắt triệu chứng của người dùng bằng tiếng Việt",
433
  "red_flags": ${JSON.stringify(triageResult.red_flags || [])},
434
  "suspected_conditions": [
435
+ ${cvResult.top_conditions.length > 0 ? cvResult.top_conditions.slice(0, 1).map((c: any) =>
436
  `{"name": "${c.name}", "source": "cv_model", "confidence": "${c.prob > 0.8 ? 'high' : c.prob > 0.5 ? 'medium' : 'low'}"}`
437
+ ).join(',\n ') : '[]'}
438
  ],
439
  "cv_findings": {
440
+ "model_used": "${cvModelUsed}",
441
  "raw_output": ${JSON.stringify(cvResult.top_conditions.length > 0 ? {
442
+ top_predictions: cvResult.top_conditions.slice(0, 1).map((c: any) => ({ condition: c.name, probability: c.prob }))
443
  } : {})}
444
  },
445
  "recommendation": {
src/services/rag.service.ts CHANGED
@@ -33,14 +33,14 @@ export class RAGService {
33
 
34
  // Call Supabase RPC function
35
  logger.info('[MCP RAG] Calling match_guideline_chunks RPC...');
36
- logger.info(`[MCP RAG] RPC params: { match_threshold: 0.5, match_count: 5 }`);
37
 
38
  const { data: docs, error } = await this.supabaseService.getClient().rpc(
39
  'match_guideline_chunks',
40
  {
41
  query_embedding: queryEmbedding,
42
- match_threshold: 0.5, // Similarity threshold
43
- match_count: 5 // Number of chunks to retrieve
44
  }
45
  );
46
 
 
33
 
34
  // Call Supabase RPC function
35
  logger.info('[MCP RAG] Calling match_guideline_chunks RPC...');
36
+ logger.info(`[MCP RAG] RPC params: { match_threshold: 0.3, match_count: 3 }`);
37
 
38
  const { data: docs, error } = await this.supabaseService.getClient().rpc(
39
  'match_guideline_chunks',
40
  {
41
  query_embedding: queryEmbedding,
42
+ match_threshold: 0.3, // Similarity threshold
43
+ match_count: 3 // Number of chunks to retrieve
44
  }
45
  );
46