|
@@ -1,6 +1,7 @@
|
|
|
package com.agent.management.service.impl;
|
|
package com.agent.management.service.impl;
|
|
|
|
|
|
|
|
import com.agent.management.common.exception.BusinessException;
|
|
import com.agent.management.common.exception.BusinessException;
|
|
|
|
|
+import com.agent.management.config.ErrorPatternProperties;
|
|
|
import com.agent.management.model.entity.HermesErrorPattern;
|
|
import com.agent.management.model.entity.HermesErrorPattern;
|
|
|
import com.agent.management.repository.HermesErrorPatternRepository;
|
|
import com.agent.management.repository.HermesErrorPatternRepository;
|
|
|
import com.agent.management.service.HermesErrorPatternService;
|
|
import com.agent.management.service.HermesErrorPatternService;
|
|
@@ -12,9 +13,14 @@ import org.springframework.stereotype.Service;
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
|
import java.util.Comparator;
|
|
import java.util.Comparator;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
|
+import java.util.Set;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * Hermes 错误嗅探模式服务实现。
|
|
|
|
|
|
|
+ * 错误嗅探模式服务实现。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>内置默认模式来源:{@code application.yml} 的 {@code app.error-pattern.builtin},
|
|
|
|
|
+ * 由 {@link ErrorPatternProperties} 注入;未配置时使用代码内 {@link ErrorPatternProperties#DEFAULT_BUILTINS}。</p>
|
|
|
*
|
|
*
|
|
|
* <p>启动时若数据文件不存在或为空,自动写入内置默认模式({@link #initBuiltInPatterns})。
|
|
* <p>启动时若数据文件不存在或为空,自动写入内置默认模式({@link #initBuiltInPatterns})。
|
|
|
* 用户自定义后不被覆盖。</p>
|
|
* 用户自定义后不被覆盖。</p>
|
|
@@ -25,41 +31,67 @@ import java.util.List;
|
|
|
public class HermesErrorPatternServiceImpl implements HermesErrorPatternService {
|
|
public class HermesErrorPatternServiceImpl implements HermesErrorPatternService {
|
|
|
|
|
|
|
|
private final HermesErrorPatternRepository repository;
|
|
private final HermesErrorPatternRepository repository;
|
|
|
|
|
+ private final ErrorPatternProperties properties;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 嗅探扫描范围:只检查 finalText 的前 N 个字符。
|
|
* 嗅探扫描范围:只检查 finalText 的前 N 个字符。
|
|
|
*
|
|
*
|
|
|
- * <p>Hermes 的错误描述通常出现在 finalText 开头(AIAgent.run() 把错误作为 final_response 返回),
|
|
|
|
|
|
|
+ * <p>错误描述通常出现在 finalText 开头(AIAgent.run() 把错误作为 final_response 返回),
|
|
|
* 限制扫描范围可避免对超长正常回复做无效 contains。500 字符覆盖所有已知错误前缀。</p>
|
|
* 限制扫描范围可避免对超长正常回复做无效 contains。500 字符覆盖所有已知错误前缀。</p>
|
|
|
*/
|
|
*/
|
|
|
private static final int SCAN_LIMIT = 500;
|
|
private static final int SCAN_LIMIT = 500;
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 启动时初始化内置模式。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>分两种情况:</p>
|
|
|
|
|
+ * <ul>
|
|
|
|
|
+ * <li>数据文件为空(全新部署):写入全部 {@link ErrorPatternProperties#getBuiltin()}。</li>
|
|
|
|
|
+ * <li>数据文件已有模式(升级部署):按 {@code name} 增量补齐新增的内置模式,
|
|
|
|
|
+ * 已有条目(含用户对其的编辑/禁用状态)保持不变。</li>
|
|
|
|
|
+ * </ul>
|
|
|
|
|
+ */
|
|
|
@PostConstruct
|
|
@PostConstruct
|
|
|
public void initBuiltInPatterns() {
|
|
public void initBuiltInPatterns() {
|
|
|
List<HermesErrorPattern> existing = repository.findAll();
|
|
List<HermesErrorPattern> existing = repository.findAll();
|
|
|
- if (!existing.isEmpty()) {
|
|
|
|
|
- log.info("[HermesErrorPattern] 已存在 {} 条模式,跳过内置初始化", existing.size());
|
|
|
|
|
|
|
+ List<ErrorPatternProperties.BuiltinPattern> source =
|
|
|
|
|
+ properties.getBuiltin() != null && !properties.getBuiltin().isEmpty()
|
|
|
|
|
+ ? properties.getBuiltin()
|
|
|
|
|
+ : ErrorPatternProperties.DEFAULT_BUILTINS;
|
|
|
|
|
+
|
|
|
|
|
+ if (existing.isEmpty()) {
|
|
|
|
|
+ // 全新部署:写入全部内置
|
|
|
|
|
+ List<HermesErrorPattern> builtIn = new ArrayList<>(source.size());
|
|
|
|
|
+ for (ErrorPatternProperties.BuiltinPattern b : source) {
|
|
|
|
|
+ if (isBlank(b.getName()) || isBlank(b.getPattern())) continue;
|
|
|
|
|
+ builtIn.add(builtIn(b.getName(), b.getPattern(), b.getDescription()));
|
|
|
|
|
+ }
|
|
|
|
|
+ repository.saveAll(builtIn);
|
|
|
|
|
+ log.info("[HermesErrorPattern] 已写入 {} 条内置默认模式", builtIn.size());
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- List<HermesErrorPattern> builtIn = new ArrayList<>();
|
|
|
|
|
- builtIn.add(builtIn("LLM SDK 重试耗尽", "API call failed after",
|
|
|
|
|
- "OpenAI SDK 重试耗尽仍未成功,通常是限流或下游故障"));
|
|
|
|
|
- builtIn.add(builtIn("HTTP 4xx 客户端错误", "HTTP 4",
|
|
|
|
|
- "LLM 服务返回 4xx(含 429 限流、401 鉴权、400 参数等)"));
|
|
|
|
|
- builtIn.add(builtIn("HTTP 5xx 服务端错误", "HTTP 5",
|
|
|
|
|
- "LLM 服务返回 5xx,服务端临时故障"));
|
|
|
|
|
- builtIn.add(builtIn("Rate Limit(英文)", "rate limit",
|
|
|
|
|
- "OpenAI 兼容服务的标准限流错误"));
|
|
|
|
|
- builtIn.add(builtIn("智谱限流(具体)", "该模型当前访问量过大",
|
|
|
|
|
- "智谱 AI glm 系列特定限流描述"));
|
|
|
|
|
- builtIn.add(builtIn("额度 / 配额", "quota",
|
|
|
|
|
- "额度耗尽类错误(中英文 quota 关键词)"));
|
|
|
|
|
- builtIn.add(builtIn("认证失败(英文)", "invalid api key",
|
|
|
|
|
- "API Key 无效或被吊销"));
|
|
|
|
|
- builtIn.add(builtIn("认证失败(中文)", "无效的 api",
|
|
|
|
|
- "中文鉴权失败描述(兼容智谱等中文错误消息)"));
|
|
|
|
|
- repository.saveAll(builtIn);
|
|
|
|
|
- log.info("[HermesErrorPattern] 已写入 {} 条内置默认模式", builtIn.size());
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 升级部署:按 name 增量补齐(保留用户对已有内置的编辑/禁用状态)
|
|
|
|
|
+ Set<String> existingNames = existing.stream()
|
|
|
|
|
+ .map(HermesErrorPattern::getName)
|
|
|
|
|
+ .collect(Collectors.toSet());
|
|
|
|
|
+ List<HermesErrorPattern> toAdd = new ArrayList<>();
|
|
|
|
|
+ for (ErrorPatternProperties.BuiltinPattern b : source) {
|
|
|
|
|
+ if (isBlank(b.getName()) || isBlank(b.getPattern())) continue;
|
|
|
|
|
+ if (existingNames.contains(b.getName())) continue;
|
|
|
|
|
+ toAdd.add(builtIn(b.getName(), b.getPattern(), b.getDescription()));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (toAdd.isEmpty()) {
|
|
|
|
|
+ log.info("[HermesErrorPattern] 已存在 {} 条模式,无需补齐", existing.size());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ repository.saveAll(toAdd);
|
|
|
|
|
+ log.info("[HermesErrorPattern] 增量补齐 {} 条新增内置模式(原有 {} 条保留)",
|
|
|
|
|
+ toAdd.size(), existing.size());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static boolean isBlank(String s) {
|
|
|
|
|
+ return s == null || s.trim().isEmpty();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private HermesErrorPattern builtIn(String name, String pattern, String description) {
|
|
private HermesErrorPattern builtIn(String name, String pattern, String description) {
|