Jelajahi Sumber

feat(report): 非 DAN 解析下传 expected_indicators 驱动 LangGraph LLM

Xiaogang Liao 3 hari lalu
induk
melakukan
c4da15ab28

+ 22 - 4
cfc-backend/src/main/java/com/etotem/cfc/service/LangGraphReportParseService.java

@@ -49,7 +49,11 @@ public class LangGraphReportParseService {
      * 转换后无有效指标数据时返回 null。
      */
     public ParsedReportPayload.Payload parseByScript(String pdfPath) {
-        Map<String, Object> data = postParse("/api/v1/report/parse", pdfPath);
+        return parseByScript(pdfPath, null);
+    }
+
+    public ParsedReportPayload.Payload parseByScript(String pdfPath, List<String> indicators) {
+        Map<String, Object> data = postParse("/api/v1/report/parse", pdfPath, indicators);
         if (data == null) {
             return null;
         }
@@ -64,9 +68,13 @@ public class LangGraphReportParseService {
      * 均无有效数据时返回 null,调用方回退 opencode。
      */
     public ParsedReportPayload.Payload parseWithDetect(String pdfPath) {
+        return parseWithDetect(pdfPath, null);
+    }
+
+    public ParsedReportPayload.Payload parseWithDetect(String pdfPath, List<String> indicators) {
         String detected = detectType(pdfPath);
         if (detected != null && !DETECTED_GENERIC.equals(detected)) {
-            ParsedReportPayload.Payload typed = parseByType(pdfPath, detected);
+            ParsedReportPayload.Payload typed = parseByType(pdfPath, detected, indicators);
             if (typed != null) {
                 log.info("LangGraph 识别到类型 {} 并解析成功", detected);
                 return typed;
@@ -75,7 +83,7 @@ public class LangGraphReportParseService {
         } else {
             log.info("LangGraph 无法识别报告类型(generic),尝试算法脚本解析");
         }
-        return parseByScript(pdfPath);
+        return parseByScript(pdfPath, indicators);
     }
 
     /** 调 /report/detect-type 识别报告类型,失败返回 null */
@@ -89,10 +97,13 @@ public class LangGraphReportParseService {
     }
 
     /** 调 /report/parse-typed 按指定类型解析(brain_status/cognitive_aptitude/scanned_image) */
-    private ParsedReportPayload.Payload parseByType(String pdfPath, String reportType) {
+    private ParsedReportPayload.Payload parseByType(String pdfPath, String reportType, List<String> indicators) {
         Map<String, Object> body = new HashMap<>();
         body.put("file_path", pdfPath);
         body.put("report_type", reportType);
+        if (indicators != null && !indicators.isEmpty()) {
+            body.put("indicators", indicators);
+        }
         Map<String, Object> data = postParse("/api/v1/report/parse-typed", body);
         if (data == null) {
             return null;
@@ -105,8 +116,15 @@ public class LangGraphReportParseService {
 
     /** 调 LangGraph 端点(仅为 file_path 场景),返回 data 字典;网络错误/非200/空 data 返回 null */
     private Map<String, Object> postParse(String path, String pdfPath) {
+        return postParse(path, pdfPath, null);
+    }
+
+    private Map<String, Object> postParse(String path, String pdfPath, List<String> indicators) {
         Map<String, Object> body = new HashMap<>();
         body.put("file_path", pdfPath);
+        if (indicators != null && !indicators.isEmpty()) {
+            body.put("indicators", indicators);
+        }
         return postParse(path, body);
     }
 

+ 6 - 3
cfc-backend/src/main/java/com/etotem/cfc/service/ReportCollectService.java

@@ -181,12 +181,16 @@ public class ReportCollectService {
                 }
             }
 
+            // 采集指标清单(用于驱动非 DAN 的 LangGraph LLM 解析)
+            String validationTypeId = (!"unknown".equals(typeId)) ? typeId : draft.getReportType();
+            List<String> expectedIndicators = loadExpectedIndicators(validationTypeId);
+
             ParsedReportPayload.Payload payload;
             String method;
             if (!"unknown".equals(typeId) && fp.get("parserPath") != null) {
                 // 指纹成功:脚本已迁移到 LangGraph(/report/parse,算法 + LLM 兜底)
                 method = METHOD_LANGGRAPH_SCRIPT;
-                payload = langGraphReportParseService.parseByScript(pdfPath);
+                payload = langGraphReportParseService.parseByScript(pdfPath, expectedIndicators);
                 // LangGraph 脚本解析为空时回退 opencode,避免已知类型整单失败
                 if (payload == null) {
                     log.warn("已知类型 LangGraph 脚本解析为空,回退 opencode typeId={}", typeId);
@@ -196,7 +200,7 @@ public class ReportCollectService {
             } else {
                 // 无指纹:先用 LangGraph 识别(detect-type → parse-typed / script),识别不了再 opencode
                 method = METHOD_LANGGRAPH_DETECT;
-                payload = langGraphReportParseService.parseWithDetect(pdfPath);
+                payload = langGraphReportParseService.parseWithDetect(pdfPath, expectedIndicators);
                 if (payload == null) {
                     log.warn("无指纹 LangGraph 识别/解析为空,回退 opencode typeId={}", typeId);
                     method = METHOD_OPENCODE;
@@ -211,7 +215,6 @@ public class ReportCollectService {
 
             harmReportPayloadValid(payload);
             // 采集指标完整性校验(report_type_registry.expected_indicators 定义驱动)
-            String validationTypeId = (!"unknown".equals(typeId)) ? typeId : draft.getReportType();
             try {
                 runCollectValidation(draftId, validationTypeId, payload);
             } catch (Exception e) {