From 507917157d57d553e2a4315a139c439dd0db2f26 Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Tue, 5 Aug 2025 01:01:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A8=E8=BF=9B=E6=A1=86=E6=9E=B6=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E6=A8=A1=E5=9D=97=E6=B3=A8=E5=86=8C=E6=9C=BA=E5=88=B6?= =?UTF-8?q?=E3=80=82=E5=BC=95=E5=85=A5=20ByteBuddy=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E9=92=88=E5=AF=B9=E6=A8=A1=E5=9D=97=E7=9A=84=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整部分包结构 - 重构 AgentRegisterContext ,将不同的 Context 内容按照对应模块进行封装 - 调整了‘添加可扫描包’的添加逻辑、新增了添加外部目录的扫描逻辑 - 新增几个异常类 - 在 ModuleCheckFactory 中新增了对于执行模块‘是否实现无参构造方法’的校验逻辑 - 引入 ByteBuddy 库负责构造执行模块实例,并添加对应的hook逻辑 - 调整 ModuleRegisterFactory 的逻辑,允许注册加载Module内的Hook方法 - 调整依赖引用关系,因为Partner-Main、Partner-Demo都继承自Partner-Api包,故将通用依赖移动至Api的pom文件中 --- .idea/dictionaries/project.xml | 7 ++ Partner-Api/pom.xml | 47 +++++++++++ .../{entity => }/AgentBaseFactory.java | 3 +- .../api/factory/AgentRegisterFactory.java | 55 ++++++++---- .../capability/CapabilityCheckFactory.java | 10 ++- .../capability/CapabilityInjectFactory.java | 12 +-- .../capability/CapabilityRegisterFactory.java | 18 ++-- .../factory/config/ConfigLoaderFactory.java | 10 ++- .../factory/context/AgentRegisterContext.java | 28 +++++++ .../context/CapabilityFactoryContext.java | 17 ++++ .../factory/context/ConfigFactoryContext.java | 14 ++++ .../factory/context/ModuleFactoryContext.java | 17 ++++ .../factory/entity/AgentRegisterContext.java | 40 --------- .../AgentRegisterFactoryFailedException.java | 11 +++ .../ExternalModuleLoadFailedException.java | 11 +++ .../ExternalModulePathNotExistException.java | 8 +- .../factory/module/ModuleCheckFactory.java | 30 +++++-- .../module/ModulePreHookExecuteFactory.java | 4 +- .../factory/module/ModuleProxyFactory.java | 83 ++++++++++++++++++- .../factory/module/ModuleRegisterFactory.java | 65 +++++++++++++-- ...ModuleInstanceGenerateFailedException.java | 11 +++ .../ModuleProxyGenerateFailedException.java | 11 +++ .../api/factory/module/pojo/MetaMethod.java | 11 +++ Partner-Test-Demo/pom.xml | 5 -- pom.xml | 44 ---------- 25 files changed, 423 insertions(+), 149 deletions(-) create mode 100644 .idea/dictionaries/project.xml rename Partner-Api/src/main/java/work/slhaf/partner/api/factory/{entity => }/AgentBaseFactory.java (86%) create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/AgentRegisterContext.java create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/CapabilityFactoryContext.java create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/ConfigFactoryContext.java create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/ModuleFactoryContext.java delete mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/entity/AgentRegisterContext.java create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/AgentRegisterFactoryFailedException.java create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/ExternalModuleLoadFailedException.java create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/exception/ModuleInstanceGenerateFailedException.java create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/exception/ModuleProxyGenerateFailedException.java create mode 100644 Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/pojo/MetaMethod.java diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml new file mode 100644 index 00000000..e3f440ad --- /dev/null +++ b/.idea/dictionaries/project.xml @@ -0,0 +1,7 @@ + + + + zuper + + + \ No newline at end of file diff --git a/Partner-Api/pom.xml b/Partner-Api/pom.xml index 51066335..15b6ee64 100644 --- a/Partner-Api/pom.xml +++ b/Partner-Api/pom.xml @@ -12,11 +12,58 @@ Partner-Api + + net.bytebuddy + byte-buddy + 1.17.6 + org.reflections reflections 0.10.2 + + org.projectlombok + lombok + 1.18.36 + provided + + + junit + junit + 4.13.2 + test + + + org.junit.jupiter + junit-jupiter + 5.13.2 + + + org.slf4j + slf4j-api + 2.0.17 + + + ch.qos.logback + logback-classic + 1.5.17 + + + commons-io + commons-io + 2.18.0 + + + cn.hutool + hutool-all + 5.8.36 + + + com.alibaba + fastjson + 2.0.56 + diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/entity/AgentBaseFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/AgentBaseFactory.java similarity index 86% rename from Partner-Api/src/main/java/work/slhaf/partner/api/factory/entity/AgentBaseFactory.java rename to Partner-Api/src/main/java/work/slhaf/partner/api/factory/AgentBaseFactory.java index db2a74c8..5e9735d8 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/entity/AgentBaseFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/AgentBaseFactory.java @@ -1,6 +1,7 @@ -package work.slhaf.partner.api.factory.entity; +package work.slhaf.partner.api.factory; import work.slhaf.partner.api.factory.capability.exception.CapabilityFactoryExecuteFailedException; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; import java.lang.reflect.InvocationTargetException; diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/AgentRegisterFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/AgentRegisterFactory.java index 96a89a54..20f50211 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/AgentRegisterFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/AgentRegisterFactory.java @@ -1,32 +1,35 @@ package work.slhaf.partner.api.factory; import cn.hutool.core.bean.BeanUtil; +import org.reflections.util.ClasspathHelper; import work.slhaf.partner.api.entity.AgentContext; import work.slhaf.partner.api.factory.capability.CapabilityCheckFactory; import work.slhaf.partner.api.factory.capability.CapabilityInjectFactory; import work.slhaf.partner.api.factory.capability.CapabilityRegisterFactory; import work.slhaf.partner.api.factory.config.ConfigLoaderFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; +import work.slhaf.partner.api.factory.exception.ExternalModuleLoadFailedException; import work.slhaf.partner.api.factory.exception.ExternalModulePathNotExistException; import work.slhaf.partner.api.factory.module.ModuleCheckFactory; -import work.slhaf.partner.api.factory.module.ModuleProxyFactory; import work.slhaf.partner.api.factory.module.ModulePreHookExecuteFactory; +import work.slhaf.partner.api.factory.module.ModuleProxyFactory; import work.slhaf.partner.api.factory.module.ModuleRegisterFactory; import java.io.File; +import java.net.URL; import java.util.ArrayList; import java.util.List; public class AgentRegisterFactory { - private static List paths = new ArrayList<>(); + private static final List urls = new ArrayList<>(); private AgentRegisterFactory() { } - public static AgentContext launch(String path) { - paths.add(path); - AgentRegisterContext registerContext = new AgentRegisterContext(paths); + public static AgentContext launch(String packageName) { + urls.addAll(packageNameToURL(packageName)); + AgentRegisterContext registerContext = new AgentRegisterContext(urls); //流程 //0. 加载配置 new ConfigLoaderFactory().execute(registerContext); @@ -44,17 +47,41 @@ public class AgentRegisterFactory { new ModulePreHookExecuteFactory().execute(registerContext); AgentContext agentContext = new AgentContext(); - BeanUtil.copyProperties(registerContext,agentContext); + BeanUtil.copyProperties(registerContext, agentContext); return agentContext; } - //TODO 也需要可指定路径,当前只是新增了可扫描包 - public static void addScanPath(String path) { - File file = new File(path); - if (!file.exists() || !file.isDirectory()) { - throw new ExternalModulePathNotExistException("不存在的外部模块目录: "+path); - } - paths.add(path); + /** + * 添加可扫描包 + * @param packageName 指定的包名 + */ + public static void addScanPackage(String packageName) { + urls.addAll(packageNameToURL(packageName)); } + /** + * 添加外部模块目录 + * @param externalPackagePath 指定的外部模块目录路径 + */ + public static void addScanDir(String externalPackagePath) { + File file = new File(externalPackagePath); + if (!file.exists() || !file.isDirectory()) { + throw new ExternalModulePathNotExistException("不存在的外部模块目录: " + externalPackagePath); + } + try { + for (File f : file.listFiles()) { + if (f.getName().endsWith(".jar")) { + urls.add(f.toURI().toURL()); + } + } + } catch (Exception e) { + throw new ExternalModuleLoadFailedException("外部模块URL获取失败: " + externalPackagePath, e); + } + } + + private static List packageNameToURL(String packageName) { + return ClasspathHelper.forPackage(packageName).stream().toList(); + } + + } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityCheckFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityCheckFactory.java index 4f1f0815..a3103483 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityCheckFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityCheckFactory.java @@ -2,13 +2,14 @@ package work.slhaf.partner.api.factory.capability; import org.reflections.Reflections; import work.slhaf.partner.api.common.util.AgentUtil; +import work.slhaf.partner.api.factory.AgentBaseFactory; import work.slhaf.partner.api.factory.capability.annotation.*; import work.slhaf.partner.api.factory.capability.exception.DuplicateCapabilityException; import work.slhaf.partner.api.factory.capability.exception.UnMatchedCapabilityException; import work.slhaf.partner.api.factory.capability.exception.UnMatchedCapabilityMethodException; import work.slhaf.partner.api.factory.capability.exception.UnMatchedCoordinatedMethodException; -import work.slhaf.partner.api.factory.entity.AgentBaseFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.CapabilityFactoryContext; import java.lang.reflect.Method; import java.util.*; @@ -28,9 +29,10 @@ public class CapabilityCheckFactory extends AgentBaseFactory { @Override protected void setVariables(AgentRegisterContext context) { + CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext(); reflections = context.getReflections(); - cores = context.getCores(); - capabilities = context.getCapabilities(); + cores = factoryContext.getCores(); + capabilities = factoryContext.getCapabilities(); } @Override diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityInjectFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityInjectFactory.java index 02b0621f..f4457697 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityInjectFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityInjectFactory.java @@ -1,12 +1,13 @@ package work.slhaf.partner.api.factory.capability; import org.reflections.Reflections; +import work.slhaf.partner.api.factory.AgentBaseFactory; import work.slhaf.partner.api.factory.capability.annotation.Capability; import work.slhaf.partner.api.factory.capability.annotation.InjectCapability; import work.slhaf.partner.api.factory.capability.annotation.ToCoordinated; import work.slhaf.partner.api.factory.capability.exception.ProxySetFailedExceptionCapability; -import work.slhaf.partner.api.factory.entity.AgentBaseFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.CapabilityFactoryContext; import java.lang.reflect.Field; import java.lang.reflect.Proxy; @@ -28,10 +29,11 @@ public class CapabilityInjectFactory extends AgentBaseFactory { @Override protected void setVariables(AgentRegisterContext context) { + CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext(); reflections = context.getReflections(); - coordinatedMethodsRouterTable = context.getCoordinatedMethodsRouterTable(); - methodsRouterTable = context.getMethodsRouterTable(); - capabilityHolderInstances = context.getCapabilityHolderInstances(); + coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable(); + methodsRouterTable = factoryContext.getMethodsRouterTable(); + capabilityHolderInstances = factoryContext.getCapabilityHolderInstances(); } @Override diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityRegisterFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityRegisterFactory.java index ef3b9d66..d8e0dd96 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityRegisterFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/capability/CapabilityRegisterFactory.java @@ -1,12 +1,13 @@ package work.slhaf.partner.api.factory.capability; import org.reflections.Reflections; +import work.slhaf.partner.api.factory.AgentBaseFactory; import work.slhaf.partner.api.factory.capability.annotation.*; import work.slhaf.partner.api.factory.capability.exception.CapabilityFactoryExecuteFailedException; import work.slhaf.partner.api.factory.capability.exception.CoreInstancesCreateFailedExceptionCapability; import work.slhaf.partner.api.factory.capability.exception.DuplicateMethodException; -import work.slhaf.partner.api.factory.entity.AgentBaseFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.CapabilityFactoryContext; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -35,13 +36,14 @@ public final class CapabilityRegisterFactory extends AgentBaseFactory { @Override protected void setVariables(AgentRegisterContext context) { + CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext(); reflections = context.getReflections(); - methodsRouterTable = context.getMethodsRouterTable(); - coordinatedMethodsRouterTable = context.getCoordinatedMethodsRouterTable(); - capabilityCoreInstances = context.getCapabilityCoreInstances(); - cores = context.getCores(); - capabilities = context.getCapabilities(); - capabilityHolderInstances = context.getCapabilityHolderInstances(); + methodsRouterTable = factoryContext.getMethodsRouterTable(); + coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable(); + capabilityCoreInstances = factoryContext.getCapabilityCoreInstances(); + cores = factoryContext.getCores(); + capabilities = factoryContext.getCapabilities(); + capabilityHolderInstances = factoryContext.getCapabilityHolderInstances(); } @Override diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/config/ConfigLoaderFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/config/ConfigLoaderFactory.java index c69a7b2b..c195c109 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/config/ConfigLoaderFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/config/ConfigLoaderFactory.java @@ -2,9 +2,10 @@ package work.slhaf.partner.api.factory.config; import lombok.Setter; import work.slhaf.partner.api.common.chat.pojo.Message; +import work.slhaf.partner.api.factory.AgentBaseFactory; import work.slhaf.partner.api.factory.config.pojo.ModelConfig; -import work.slhaf.partner.api.factory.entity.AgentBaseFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.ConfigFactoryContext; import java.util.HashMap; import java.util.List; @@ -18,8 +19,9 @@ public class ConfigLoaderFactory extends AgentBaseFactory { @Override protected void setVariables(AgentRegisterContext context) { - modelConfigMap = context.getModelConfigMap(); - modelPromptMap = context.getModelPromptMap(); + ConfigFactoryContext factoryContext = context.getConfigFactoryContext(); + modelConfigMap = factoryContext.getModelConfigMap(); + modelPromptMap = factoryContext.getModelPromptMap(); } @Override diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/AgentRegisterContext.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/AgentRegisterContext.java new file mode 100644 index 00000000..4ada2fd5 --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/AgentRegisterContext.java @@ -0,0 +1,28 @@ +package work.slhaf.partner.api.factory.context; + +import lombok.Data; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; +import org.reflections.util.ConfigurationBuilder; + +import java.net.URL; +import java.util.List; + +@Data +public class AgentRegisterContext { + private Reflections reflections; + private CapabilityFactoryContext capabilityFactoryContext = new CapabilityFactoryContext(); + private ConfigFactoryContext configFactoryContext = new ConfigFactoryContext(); + private ModuleFactoryContext moduleFactoryContext = new ModuleFactoryContext(); + + public AgentRegisterContext(List urls) { + reflections = new Reflections(new ConfigurationBuilder().setScanners( + Scanners.FieldsAnnotated, + Scanners.SubTypes, + Scanners.MethodsAnnotated, + Scanners.TypesAnnotated + ) + .setUrls(urls) + ); + } +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/CapabilityFactoryContext.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/CapabilityFactoryContext.java new file mode 100644 index 00000000..85033d39 --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/CapabilityFactoryContext.java @@ -0,0 +1,17 @@ +package work.slhaf.partner.api.factory.context; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Set; +import java.util.function.Function; + +@Data +public class CapabilityFactoryContext { + private final HashMap> methodsRouterTable = new HashMap<>(); + private final HashMap> coordinatedMethodsRouterTable = new HashMap<>(); + private final HashMap, Object> capabilityCoreInstances = new HashMap<>(); + private final HashMap, Object> capabilityHolderInstances = new HashMap<>(); + private Set> cores; + private Set> capabilities; +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/ConfigFactoryContext.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/ConfigFactoryContext.java new file mode 100644 index 00000000..17ff36ac --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/ConfigFactoryContext.java @@ -0,0 +1,14 @@ +package work.slhaf.partner.api.factory.context; + +import lombok.Data; +import work.slhaf.partner.api.common.chat.pojo.Message; +import work.slhaf.partner.api.factory.config.pojo.ModelConfig; + +import java.util.HashMap; +import java.util.List; + +@Data +public class ConfigFactoryContext { + private HashMap> modelPromptMap = new HashMap<>(); + private HashMap modelConfigMap = new HashMap<>(); +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/ModuleFactoryContext.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/ModuleFactoryContext.java new file mode 100644 index 00000000..7496e766 --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/context/ModuleFactoryContext.java @@ -0,0 +1,17 @@ +package work.slhaf.partner.api.factory.context; + +import lombok.Data; +import work.slhaf.partner.api.factory.module.pojo.MetaMethod; +import work.slhaf.partner.api.factory.module.pojo.MetaModule; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +@Data +public class ModuleFactoryContext { + private List moduleList = new ArrayList<>(); + private HashMap,Set> preHookMethods = new HashMap<>(); + private HashMap,Set> postHookMethods = new HashMap<>(); +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/entity/AgentRegisterContext.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/entity/AgentRegisterContext.java deleted file mode 100644 index 0fd2e79c..00000000 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/entity/AgentRegisterContext.java +++ /dev/null @@ -1,40 +0,0 @@ -package work.slhaf.partner.api.factory.entity; - -import lombok.Data; -import org.reflections.Reflections; -import org.reflections.scanners.Scanners; -import org.reflections.util.ConfigurationBuilder; -import work.slhaf.partner.api.common.chat.pojo.Message; -import work.slhaf.partner.api.factory.config.pojo.ModelConfig; -import work.slhaf.partner.api.factory.module.pojo.MetaModule; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.function.Function; - -@Data -public class AgentRegisterContext { - private Reflections reflections; - private final HashMap> methodsRouterTable = new HashMap<>(); - private final HashMap> coordinatedMethodsRouterTable = new HashMap<>(); - private final HashMap, Object> capabilityCoreInstances = new HashMap<>(); - private final HashMap, Object> capabilityHolderInstances = new HashMap<>(); - private Set> cores; - private Set> capabilities; - private HashMap> modelPromptMap = new HashMap<>(); - private HashMap modelConfigMap = new HashMap<>(); - private List moduleList = new ArrayList<>(); - - public AgentRegisterContext(List paths) { - reflections = new Reflections(new ConfigurationBuilder().setScanners( - Scanners.FieldsAnnotated, - Scanners.SubTypes, - Scanners.MethodsAnnotated, - Scanners.TypesAnnotated - ) - .forPackages(paths.toArray(paths.toArray(new String[0]))) - ); - } -} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/AgentRegisterFactoryFailedException.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/AgentRegisterFactoryFailedException.java new file mode 100644 index 00000000..14b5a7c9 --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/AgentRegisterFactoryFailedException.java @@ -0,0 +1,11 @@ +package work.slhaf.partner.api.factory.exception; + +public class AgentRegisterFactoryFailedException extends RuntimeException { + public AgentRegisterFactoryFailedException(String message, Throwable cause) { + super("AgentRegisterFactory 执行失败: " + message, cause); + } + + public AgentRegisterFactoryFailedException(String message) { + super("AgentRegisterFactory 执行失败: " + message); + } +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/ExternalModuleLoadFailedException.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/ExternalModuleLoadFailedException.java new file mode 100644 index 00000000..a49e6168 --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/ExternalModuleLoadFailedException.java @@ -0,0 +1,11 @@ +package work.slhaf.partner.api.factory.exception; + +public class ExternalModuleLoadFailedException extends AgentRegisterFactoryFailedException{ + public ExternalModuleLoadFailedException(String message, Throwable cause) { + super(message, cause); + } + + public ExternalModuleLoadFailedException(String message) { + super(message); + } +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/ExternalModulePathNotExistException.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/ExternalModulePathNotExistException.java index 95fb61dc..55563014 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/ExternalModulePathNotExistException.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/exception/ExternalModulePathNotExistException.java @@ -1,7 +1,11 @@ package work.slhaf.partner.api.factory.exception; -public class ExternalModulePathNotExistException extends RuntimeException { +public class ExternalModulePathNotExistException extends AgentRegisterFactoryFailedException { public ExternalModulePathNotExistException(String message) { - super("AgentRegisterFactory 执行失败: " + message); + super(message); + } + + public ExternalModulePathNotExistException(String message, Throwable cause) { + super(message, cause); } } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleCheckFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleCheckFactory.java index 679326c9..338a193a 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleCheckFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleCheckFactory.java @@ -1,9 +1,9 @@ package work.slhaf.partner.api.factory.module; import org.reflections.Reflections; +import work.slhaf.partner.api.factory.AgentBaseFactory; import work.slhaf.partner.api.factory.config.ModelConfigManager; -import work.slhaf.partner.api.factory.entity.AgentBaseFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; import work.slhaf.partner.api.factory.module.annotation.After; import work.slhaf.partner.api.factory.module.annotation.AgentModule; import work.slhaf.partner.api.factory.module.annotation.Before; @@ -28,14 +28,27 @@ public class ModuleCheckFactory extends AgentBaseFactory { @Override protected void run() { + Set> types = reflections.getTypesAnnotatedWith(AgentModule.class); //检查注解AgentModule所在类是否继承了AgentInteractionModule - agentModuleAnnotationCheck(); + agentModuleAnnotationCheck(types); + //检查AgentModule是否具备无参构造方法 + moduleConstructorsCheck(types); //检查hook注解所在方法是否位于AgentInteractionModule子类/AgentInteractionSubModule子类/ActivateModel子类 hookLocationCheck(); //检查实现了ActivateModel的模块数量、名称与prompt是否一致 activateModelImplCheck(); } + private void moduleConstructorsCheck(Set> types) { + for (Class type : types) { + try { + type.getConstructor(); + } catch (NoSuchMethodException e) { + throw new ModuleCheckException("缺少无参构造方法的模块: " + type.getSimpleName(), e); + } + } + } + private void activateModelImplCheck() { try { Set> types = reflections.getSubTypesOf(ActivateModel.class); @@ -47,10 +60,10 @@ public class ModuleCheckFactory extends AgentBaseFactory { Set promptKeySet = ModelConfigManager.INSTANCE.getModelPromptMap().keySet(); if (!promptKeySet.containsAll(modelKeySet)) { modelKeySet.removeAll(promptKeySet); - throw new ModuleCheckException("存在未配置Prompt的ActivateModel实现! 缺少Prompt的ModelKey列表: "+ modelKeySet); + throw new ModuleCheckException("存在未配置Prompt的ActivateModel实现! 缺少Prompt的ModelKey列表: " + modelKeySet); } - }catch (Exception e) { - throw new ModuleCheckException("ActivateModel 检测出错",e); + } catch (Exception e) { + throw new ModuleCheckException("ActivateModel 检测出错", e); } } @@ -89,12 +102,11 @@ public class ModuleCheckFactory extends AgentBaseFactory { if (ActivateModel.class.isAssignableFrom(type)) { continue; } - throw new ModuleCheckException("在不支持的类中使用了hook注解: "+type.getSimpleName()); + throw new ModuleCheckException("在不支持的类中使用了hook注解: " + type.getSimpleName()); } } - private void agentModuleAnnotationCheck() { - Set> types = reflections.getTypesAnnotatedWith(AgentModule.class); + private void agentModuleAnnotationCheck(Set> types) { for (Class type : types) { if (type.isAnnotation()) { continue; diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModulePreHookExecuteFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModulePreHookExecuteFactory.java index 49f1e369..5a007c71 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModulePreHookExecuteFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModulePreHookExecuteFactory.java @@ -1,7 +1,7 @@ package work.slhaf.partner.api.factory.module; -import work.slhaf.partner.api.factory.entity.AgentBaseFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import work.slhaf.partner.api.factory.AgentBaseFactory; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; import java.lang.reflect.InvocationTargetException; diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleProxyFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleProxyFactory.java index 30ed77aa..62053cdd 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleProxyFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleProxyFactory.java @@ -1,21 +1,96 @@ package work.slhaf.partner.api.factory.module; -import work.slhaf.partner.api.factory.entity.AgentBaseFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.implementation.MethodDelegation; +import net.bytebuddy.implementation.bind.annotation.*; +import net.bytebuddy.matcher.ElementMatchers; +import work.slhaf.partner.api.factory.AgentBaseFactory; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.ModuleFactoryContext; +import work.slhaf.partner.api.factory.module.exception.ModuleInstanceGenerateFailedException; +import work.slhaf.partner.api.factory.module.exception.ModuleProxyGenerateFailedException; +import work.slhaf.partner.api.factory.module.pojo.MetaMethod; +import work.slhaf.partner.api.factory.module.pojo.MetaModule; +import work.slhaf.partner.api.flow.abstracts.AgentInteractionModule; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; /** * 通过扫描注解@Before,获取到各个模块的后hook逻辑并通过动态代理添加到执行逻辑之后 */ public class ModuleProxyFactory extends AgentBaseFactory { + + private List moduleList; + private HashMap, Set> postHookMethods; + @Override protected void setVariables(AgentRegisterContext context) { - + ModuleFactoryContext factoryContext = context.getModuleFactoryContext(); + moduleList = factoryContext.getModuleList(); + postHookMethods = factoryContext.getPostHookMethods(); } @Override protected void run() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { - //TODO 通过动态代理生成实例、添加PostHook逻辑 + //TODO 生成实例、并通过动态代理添加PostHook逻辑 + generateInstances(); + setPostHookProxy(); + } + + private void setPostHookProxy() { + for (MetaModule module : moduleList) { + Class clazz = module.getClazz(); + try { + Class proxyClass = new ByteBuddy() + .subclass(clazz) + .method(ElementMatchers.isOverriddenFrom(AgentInteractionModule.class)) + .intercept(MethodDelegation.to(new ModuleProxyInterceptor(postHookMethods.get(clazz).stream().sorted(Comparator.comparing(MetaMethod::getOrder)).toList()))) + .make() + .load(ModuleProxyFactory.class.getClassLoader()) + .getLoaded(); + + AgentInteractionModule interactionModule = (AgentInteractionModule) proxyClass.getConstructor().newInstance(); + //TODO 检测代理写法是否正确 + //TODO 添加ModuleManager,负责统一管理Module的加载、卸载 + } catch (Exception e) { + throw new ModuleProxyGenerateFailedException("创建代理对象失败: " + clazz.getSimpleName(), e); + } + } + } + + private void generateInstances() { + for (MetaModule metaModule : moduleList) { + try { + Class clazz = metaModule.getClazz(); + Object instance = clazz.getConstructor().newInstance(); + metaModule.setInstance(instance); + } catch (Exception e) { + throw new ModuleInstanceGenerateFailedException("模块实例构造失败:" + e.getMessage()); + } + } + } + + private static class ModuleProxyInterceptor { + + private List postHookMethods; + + private ModuleProxyInterceptor(List postHookMethods) { + this.postHookMethods = postHookMethods; + } + + @RuntimeType + public Object intercept(@Origin Method method, @AllArguments Object[] allArguments, @SuperCall Callable zuper, @This Object proxy) throws Exception { + Object res = zuper.call(); + for (MetaMethod metaMethod : postHookMethods) { + metaMethod.getMethod().invoke(proxy, allArguments); + } + return res; + } } } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleRegisterFactory.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleRegisterFactory.java index bfc2b395..8358b180 100644 --- a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleRegisterFactory.java +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/ModuleRegisterFactory.java @@ -1,15 +1,17 @@ package work.slhaf.partner.api.factory.module; import org.reflections.Reflections; -import work.slhaf.partner.api.factory.entity.AgentBaseFactory; -import work.slhaf.partner.api.factory.entity.AgentRegisterContext; +import work.slhaf.partner.api.factory.AgentBaseFactory; +import work.slhaf.partner.api.factory.context.AgentRegisterContext; +import work.slhaf.partner.api.factory.context.ModuleFactoryContext; +import work.slhaf.partner.api.factory.module.annotation.After; import work.slhaf.partner.api.factory.module.annotation.AgentModule; +import work.slhaf.partner.api.factory.module.annotation.Before; +import work.slhaf.partner.api.factory.module.pojo.MetaMethod; import work.slhaf.partner.api.factory.module.pojo.MetaModule; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Set; +import java.lang.reflect.Method; +import java.util.*; /** * 负责扫描@Module注解获取模块实例 @@ -18,15 +20,63 @@ public class ModuleRegisterFactory extends AgentBaseFactory { private Reflections reflections; private List moduleList; + private HashMap, Set> postHookMethods; + private HashMap, Set> preHookMethods; @Override protected void setVariables(AgentRegisterContext context) { + ModuleFactoryContext factoryContext = context.getModuleFactoryContext(); reflections = context.getReflections(); - moduleList = context.getModuleList(); + moduleList = factoryContext.getModuleList(); + postHookMethods = factoryContext.getPostHookMethods(); + preHookMethods = factoryContext.getPreHookMethods(); } @Override protected void run() { + registerModuleList(); + registerHookSet(); + } + + private void registerHookSet() { + setPostHookMethods(); + setPreHookMethods(); + } + + private void setPreHookMethods() { + Set methods = reflections.getMethodsAnnotatedWith(After.class); + for (Method method : methods) { + MetaMethod metaMethod = new MetaMethod(); + metaMethod.setMethod(method); + metaMethod.setOrder(method.getAnnotation(After.class).order()); + + addMetaMethod(method, metaMethod, postHookMethods); + } + } + + private void setPostHookMethods() { + Set methods = reflections.getMethodsAnnotatedWith(Before.class); + for (Method method : methods) { + MetaMethod metaMethod = new MetaMethod(); + metaMethod.setMethod(method); + metaMethod.setOrder(method.getAnnotation(Before.class).order()); + + addMetaMethod(method, metaMethod, preHookMethods); + } + } + + private void addMetaMethod(Method method, MetaMethod metaMethod, HashMap, Set> preHookMethods) { + Class clazz = method.getDeclaringClass(); + if (preHookMethods.containsKey(clazz)) { + preHookMethods.get(clazz).add(metaMethod); + }else { + HashSet metaMethods = new HashSet<>(); + metaMethods.add(metaMethod); + preHookMethods.put(clazz, metaMethods); + } + } + + private void registerModuleList() { //反射扫描获取@AgentModule所在类, 该部分为Agent流程执行模块 Set> modules = reflections.getTypesAnnotatedWith(AgentModule.class); for (Class module : modules) { @@ -38,5 +88,6 @@ public class ModuleRegisterFactory extends AgentBaseFactory { moduleList.add(metaModule); } moduleList.sort(Comparator.comparing(MetaModule::getOrder)); + } } diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/exception/ModuleInstanceGenerateFailedException.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/exception/ModuleInstanceGenerateFailedException.java new file mode 100644 index 00000000..e7591588 --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/exception/ModuleInstanceGenerateFailedException.java @@ -0,0 +1,11 @@ +package work.slhaf.partner.api.factory.module.exception; + +public class ModuleInstanceGenerateFailedException extends ModuleFactoryFailedException{ + public ModuleInstanceGenerateFailedException(String message) { + super(message); + } + + public ModuleInstanceGenerateFailedException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/exception/ModuleProxyGenerateFailedException.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/exception/ModuleProxyGenerateFailedException.java new file mode 100644 index 00000000..2f95cd25 --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/exception/ModuleProxyGenerateFailedException.java @@ -0,0 +1,11 @@ +package work.slhaf.partner.api.factory.module.exception; + +public class ModuleProxyGenerateFailedException extends ModuleFactoryFailedException{ + public ModuleProxyGenerateFailedException(String message) { + super(message); + } + + public ModuleProxyGenerateFailedException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/pojo/MetaMethod.java b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/pojo/MetaMethod.java new file mode 100644 index 00000000..d8f11fdf --- /dev/null +++ b/Partner-Api/src/main/java/work/slhaf/partner/api/factory/module/pojo/MetaMethod.java @@ -0,0 +1,11 @@ +package work.slhaf.partner.api.factory.module.pojo; + +import lombok.Data; + +import java.lang.reflect.Method; + +@Data +public class MetaMethod { + private int order; + private Method method; +} diff --git a/Partner-Test-Demo/pom.xml b/Partner-Test-Demo/pom.xml index b06b8ca7..691c3e20 100644 --- a/Partner-Test-Demo/pom.xml +++ b/Partner-Test-Demo/pom.xml @@ -12,11 +12,6 @@ Partner-Test-Demo - - org.reflections - reflections - 0.10.2 - work.slhaf Partner-Api diff --git a/pom.xml b/pom.xml index b7287697..07fa185d 100644 --- a/pom.xml +++ b/pom.xml @@ -19,50 +19,6 @@ 21 UTF-8 - - - org.projectlombok - lombok - 1.18.36 - provided - - - junit - junit - 4.13.2 - test - - - org.junit.jupiter - junit-jupiter - 5.13.2 - - - org.slf4j - slf4j-api - 2.0.17 - - - ch.qos.logback - logback-classic - 1.5.17 - - - commons-io - commons-io - 2.18.0 - - - cn.hutool - hutool-all - 5.8.36 - - - com.alibaba - fastjson - 2.0.56 - -