Просмотр исходного кода

1. 优化了错误模式匹配规则,匹配时忽略大小写以及“-”/“_”/空格等分隔符差异,避免因格式不一致导致漏判。

weisijie 2 недель назад
Родитель
Сommit
a326e376aa

+ 14 - 2
backend/src/main/java/com/agent/management/service/impl/HermesErrorPatternServiceImpl.java

@@ -197,17 +197,29 @@ public class HermesErrorPatternServiceImpl implements HermesErrorPatternService
         String haystack = finalText.length() > SCAN_LIMIT
                 ? finalText.substring(0, SCAN_LIMIT)
                 : finalText;
-        String haystackLower = haystack.toLowerCase();
+        String haystackNorm = normalize(haystack);
         for (HermesErrorPattern p : repository.findAllByEnabledTrue()) {
             String needle = p.getPattern();
             if (needle == null || needle.isBlank()) continue;
-            if (haystackLower.contains(needle.toLowerCase())) {
+            if (haystackNorm.contains(normalize(needle))) {
                 return ErrorDetectionResult.of(p.getName());
             }
         }
         return ErrorDetectionResult.notError();
     }
 
+    /**
+     * 归一化文本以宽松匹配。
+     *
+     * <p>将 {@code -}、{@code _}、任意空白视为等价的单一分隔符(统一替换为单个空格),
+     * 再小写化。这样模式 {@code api_error} 即可匹配 {@code API ERROR} / {@code api-error} 等。
+     * 但不会与"无分隔符"形式(如 {@code apierror})等价,避免误报。</p>
+     */
+    private static String normalize(String s) {
+        if (s == null) return "";
+        return s.replaceAll("[-_\\s]+", " ").toLowerCase();
+    }
+
     private void validatePattern(HermesErrorPattern req) {
         if (req == null) throw new BusinessException("请求体为空");
         if (req.getName() == null || req.getName().trim().isEmpty()) {

+ 64 - 0
backend/src/test/java/com/agent/management/service/HermesErrorPatternServiceTest.java

@@ -118,6 +118,70 @@ class HermesErrorPatternServiceTest {
         assertThat(service.isErrorResponse(body).isError()).isFalse();
     }
 
+    // ========== 分隔符归一化(- / _ / 空格 等价) ==========
+
+    @Test
+    void isResponse_underscorePatternMatchesSpacedText() {
+        // 用户场景:pattern "api_error" 应匹配文本 "API ERROR ..."
+        HermesErrorPattern p = new HermesErrorPattern();
+        p.setName("API 错误");
+        p.setPattern("api_error");
+        p.setEnabled(true);
+        service.create(p);
+
+        assertThat(service.isErrorResponse("调用失败:API ERROR encountered").isError()).isTrue();
+    }
+
+    @Test
+    void isResponse_hyphenPatternMatchesUnderscoreText() {
+        // pattern "rate-limit" 应匹配文本 "RATE_LIMIT exceeded"
+        HermesErrorPattern p = new HermesErrorPattern();
+        p.setName("限流");
+        p.setPattern("rate-limit");
+        p.setEnabled(true);
+        service.create(p);
+
+        assertThat(service.isErrorResponse("RATE_LIMIT exceeded").isError()).isTrue();
+    }
+
+    @Test
+    void isResponse_multipleSeparatorsAllEquivalent() {
+        // 多分隔符混合:pattern "context_length_exceeded" 应匹配 "CONTEXT-LENGTH EXCEEDED"
+        HermesErrorPattern p = new HermesErrorPattern();
+        p.setName("上下文超限");
+        p.setPattern("context_length_exceeded");
+        p.setEnabled(true);
+        service.create(p);
+
+        assertThat(service.isErrorResponse("请求失败:CONTEXT-LENGTH EXCEEDED").isError()).isTrue();
+        assertThat(service.isErrorResponse("请求失败:CONTEXT LENGTH EXCEEDED").isError()).isTrue();
+        assertThat(service.isErrorResponse("请求失败:CONTEXT_LENGTH_EXCEEDED").isError()).isTrue();
+    }
+
+    @Test
+    void isResponse_noSeparatorPatternDoesNotMatchSeparatedText() {
+        // 防止过度归一化:pattern "apierror"(无分隔符)不应匹配 "API ERROR"(有分隔符)
+        HermesErrorPattern p = new HermesErrorPattern();
+        p.setName("连写模式");
+        p.setPattern("apierror");
+        p.setEnabled(true);
+        service.create(p);
+
+        assertThat(service.isErrorResponse("调用失败:API ERROR encountered").isError()).isFalse();
+    }
+
+    @Test
+    void isResponse_separatedPatternDoesNotMatchNoSeparatorText() {
+        // 反向同样不匹配:pattern "api error"(带分隔符)不应匹配 "APIERROR"(无分隔符)
+        HermesErrorPattern p = new HermesErrorPattern();
+        p.setName("带分隔符模式");
+        p.setPattern("api error");
+        p.setEnabled(true);
+        service.create(p);
+
+        assertThat(service.isErrorResponse("调用失败:APIERROR encountered").isError()).isFalse();
+    }
+
     // ========== 内置初始化 ==========
 
     @Test

+ 4 - 0
prompt.md

@@ -1467,3 +1467,7 @@ docs/rag 下的也根据分类放到那几个目录下,文件名称统一。
 
 ---
 
+我希望错误模式匹配时,首先忽略大小写,其次将“-”、“_”和空格等字符的差异忽略,防止错误模式“api_error”无法匹配“API ERROR”的情况。
+
+---
+