推进框架中的模块注册机制。引入 ByteBuddy 完成针对模块的代理实现。

- 调整部分包结构
- 重构 AgentRegisterContext ,将不同的 Context 内容按照对应模块进行封装
- 调整了‘添加可扫描包’的添加逻辑、新增了添加外部目录的扫描逻辑
- 新增几个异常类
- 在 ModuleCheckFactory 中新增了对于执行模块‘是否实现无参构造方法’的校验逻辑
- 引入 ByteBuddy 库负责构造执行模块实例,并添加对应的hook逻辑
- 调整 ModuleRegisterFactory 的逻辑,允许注册加载Module内的Hook方法
- 调整依赖引用关系,因为Partner-Main、Partner-Demo都继承自Partner-Api包,故将通用依赖移动至Api的pom文件中
This commit is contained in:
2025-08-05 01:01:42 +08:00
parent ca3ffca4ea
commit 507917157d
25 changed files with 423 additions and 149 deletions

7
.idea/dictionaries/project.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="project">
<words>
<w>zuper</w>
</words>
</dictionary>
</component>

View File

@@ -12,11 +12,58 @@
<artifactId>Partner-Api</artifactId> <artifactId>Partner-Api</artifactId>
<dependencies> <dependencies>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.17.6</version>
</dependency>
<dependency> <dependency>
<groupId>org.reflections</groupId> <groupId>org.reflections</groupId>
<artifactId>reflections</artifactId> <artifactId>reflections</artifactId>
<version>0.10.2</version> <version>0.10.2</version>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.13.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.17</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.17</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.18.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.36</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.56</version>
</dependency>
</dependencies> </dependencies>
<properties> <properties>

View File

@@ -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.capability.exception.CapabilityFactoryExecuteFailedException;
import work.slhaf.partner.api.factory.context.AgentRegisterContext;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;

View File

@@ -1,32 +1,35 @@
package work.slhaf.partner.api.factory; package work.slhaf.partner.api.factory;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import org.reflections.util.ClasspathHelper;
import work.slhaf.partner.api.entity.AgentContext; import work.slhaf.partner.api.entity.AgentContext;
import work.slhaf.partner.api.factory.capability.CapabilityCheckFactory; import work.slhaf.partner.api.factory.capability.CapabilityCheckFactory;
import work.slhaf.partner.api.factory.capability.CapabilityInjectFactory; import work.slhaf.partner.api.factory.capability.CapabilityInjectFactory;
import work.slhaf.partner.api.factory.capability.CapabilityRegisterFactory; import work.slhaf.partner.api.factory.capability.CapabilityRegisterFactory;
import work.slhaf.partner.api.factory.config.ConfigLoaderFactory; 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.exception.ExternalModulePathNotExistException;
import work.slhaf.partner.api.factory.module.ModuleCheckFactory; 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.ModulePreHookExecuteFactory;
import work.slhaf.partner.api.factory.module.ModuleProxyFactory;
import work.slhaf.partner.api.factory.module.ModuleRegisterFactory; import work.slhaf.partner.api.factory.module.ModuleRegisterFactory;
import java.io.File; import java.io.File;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class AgentRegisterFactory { public class AgentRegisterFactory {
private static List<String> paths = new ArrayList<>(); private static final List<URL> urls = new ArrayList<>();
private AgentRegisterFactory() { private AgentRegisterFactory() {
} }
public static AgentContext launch(String path) { public static AgentContext launch(String packageName) {
paths.add(path); urls.addAll(packageNameToURL(packageName));
AgentRegisterContext registerContext = new AgentRegisterContext(paths); AgentRegisterContext registerContext = new AgentRegisterContext(urls);
//流程 //流程
//0. 加载配置 //0. 加载配置
new ConfigLoaderFactory().execute(registerContext); new ConfigLoaderFactory().execute(registerContext);
@@ -44,17 +47,41 @@ public class AgentRegisterFactory {
new ModulePreHookExecuteFactory().execute(registerContext); new ModulePreHookExecuteFactory().execute(registerContext);
AgentContext agentContext = new AgentContext(); AgentContext agentContext = new AgentContext();
BeanUtil.copyProperties(registerContext,agentContext); BeanUtil.copyProperties(registerContext, agentContext);
return agentContext; return agentContext;
} }
//TODO 也需要可指定路径,当前只是新增了可扫描包 /**
public static void addScanPath(String path) { * 添加可扫描包
File file = new File(path); * @param packageName 指定的包名
if (!file.exists() || !file.isDirectory()) { */
throw new ExternalModulePathNotExistException("不存在的外部模块目录: "+path); public static void addScanPackage(String packageName) {
} urls.addAll(packageNameToURL(packageName));
paths.add(path);
} }
/**
* 添加外部模块目录
* @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<URL> packageNameToURL(String packageName) {
return ClasspathHelper.forPackage(packageName).stream().toList();
}
} }

View File

@@ -2,13 +2,14 @@ package work.slhaf.partner.api.factory.capability;
import org.reflections.Reflections; import org.reflections.Reflections;
import work.slhaf.partner.api.common.util.AgentUtil; 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.annotation.*;
import work.slhaf.partner.api.factory.capability.exception.DuplicateCapabilityException; 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.UnMatchedCapabilityException;
import work.slhaf.partner.api.factory.capability.exception.UnMatchedCapabilityMethodException; import work.slhaf.partner.api.factory.capability.exception.UnMatchedCapabilityMethodException;
import work.slhaf.partner.api.factory.capability.exception.UnMatchedCoordinatedMethodException; import work.slhaf.partner.api.factory.capability.exception.UnMatchedCoordinatedMethodException;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory; import work.slhaf.partner.api.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext; import work.slhaf.partner.api.factory.context.CapabilityFactoryContext;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@@ -28,9 +29,10 @@ public class CapabilityCheckFactory extends AgentBaseFactory {
@Override @Override
protected void setVariables(AgentRegisterContext context) { protected void setVariables(AgentRegisterContext context) {
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
reflections = context.getReflections(); reflections = context.getReflections();
cores = context.getCores(); cores = factoryContext.getCores();
capabilities = context.getCapabilities(); capabilities = factoryContext.getCapabilities();
} }
@Override @Override

View File

@@ -1,12 +1,13 @@
package work.slhaf.partner.api.factory.capability; package work.slhaf.partner.api.factory.capability;
import org.reflections.Reflections; 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.Capability;
import work.slhaf.partner.api.factory.capability.annotation.InjectCapability; 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.annotation.ToCoordinated;
import work.slhaf.partner.api.factory.capability.exception.ProxySetFailedExceptionCapability; import work.slhaf.partner.api.factory.capability.exception.ProxySetFailedExceptionCapability;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory; import work.slhaf.partner.api.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext; import work.slhaf.partner.api.factory.context.CapabilityFactoryContext;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
@@ -28,10 +29,11 @@ public class CapabilityInjectFactory extends AgentBaseFactory {
@Override @Override
protected void setVariables(AgentRegisterContext context) { protected void setVariables(AgentRegisterContext context) {
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
reflections = context.getReflections(); reflections = context.getReflections();
coordinatedMethodsRouterTable = context.getCoordinatedMethodsRouterTable(); coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable();
methodsRouterTable = context.getMethodsRouterTable(); methodsRouterTable = factoryContext.getMethodsRouterTable();
capabilityHolderInstances = context.getCapabilityHolderInstances(); capabilityHolderInstances = factoryContext.getCapabilityHolderInstances();
} }
@Override @Override

View File

@@ -1,12 +1,13 @@
package work.slhaf.partner.api.factory.capability; package work.slhaf.partner.api.factory.capability;
import org.reflections.Reflections; 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.annotation.*;
import work.slhaf.partner.api.factory.capability.exception.CapabilityFactoryExecuteFailedException; 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.CoreInstancesCreateFailedExceptionCapability;
import work.slhaf.partner.api.factory.capability.exception.DuplicateMethodException; import work.slhaf.partner.api.factory.capability.exception.DuplicateMethodException;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory; import work.slhaf.partner.api.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext; import work.slhaf.partner.api.factory.context.CapabilityFactoryContext;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@@ -35,13 +36,14 @@ public final class CapabilityRegisterFactory extends AgentBaseFactory {
@Override @Override
protected void setVariables(AgentRegisterContext context) { protected void setVariables(AgentRegisterContext context) {
CapabilityFactoryContext factoryContext = context.getCapabilityFactoryContext();
reflections = context.getReflections(); reflections = context.getReflections();
methodsRouterTable = context.getMethodsRouterTable(); methodsRouterTable = factoryContext.getMethodsRouterTable();
coordinatedMethodsRouterTable = context.getCoordinatedMethodsRouterTable(); coordinatedMethodsRouterTable = factoryContext.getCoordinatedMethodsRouterTable();
capabilityCoreInstances = context.getCapabilityCoreInstances(); capabilityCoreInstances = factoryContext.getCapabilityCoreInstances();
cores = context.getCores(); cores = factoryContext.getCores();
capabilities = context.getCapabilities(); capabilities = factoryContext.getCapabilities();
capabilityHolderInstances = context.getCapabilityHolderInstances(); capabilityHolderInstances = factoryContext.getCapabilityHolderInstances();
} }
@Override @Override

View File

@@ -2,9 +2,10 @@ package work.slhaf.partner.api.factory.config;
import lombok.Setter; import lombok.Setter;
import work.slhaf.partner.api.common.chat.pojo.Message; 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.config.pojo.ModelConfig;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory; import work.slhaf.partner.api.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext; import work.slhaf.partner.api.factory.context.ConfigFactoryContext;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -18,8 +19,9 @@ public class ConfigLoaderFactory extends AgentBaseFactory {
@Override @Override
protected void setVariables(AgentRegisterContext context) { protected void setVariables(AgentRegisterContext context) {
modelConfigMap = context.getModelConfigMap(); ConfigFactoryContext factoryContext = context.getConfigFactoryContext();
modelPromptMap = context.getModelPromptMap(); modelConfigMap = factoryContext.getModelConfigMap();
modelPromptMap = factoryContext.getModelPromptMap();
} }
@Override @Override

View File

@@ -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<URL> urls) {
reflections = new Reflections(new ConfigurationBuilder().setScanners(
Scanners.FieldsAnnotated,
Scanners.SubTypes,
Scanners.MethodsAnnotated,
Scanners.TypesAnnotated
)
.setUrls(urls)
);
}
}

View File

@@ -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<String, Function<Object[], Object>> methodsRouterTable = new HashMap<>();
private final HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable = new HashMap<>();
private final HashMap<Class<?>, Object> capabilityCoreInstances = new HashMap<>();
private final HashMap<Class<?>, Object> capabilityHolderInstances = new HashMap<>();
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
}

View File

@@ -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<String, List<Message>> modelPromptMap = new HashMap<>();
private HashMap<String, ModelConfig> modelConfigMap = new HashMap<>();
}

View File

@@ -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<MetaModule> moduleList = new ArrayList<>();
private HashMap<Class<?>,Set<MetaMethod>> preHookMethods = new HashMap<>();
private HashMap<Class<?>,Set<MetaMethod>> postHookMethods = new HashMap<>();
}

View File

@@ -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<String, Function<Object[], Object>> methodsRouterTable = new HashMap<>();
private final HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable = new HashMap<>();
private final HashMap<Class<?>, Object> capabilityCoreInstances = new HashMap<>();
private final HashMap<Class<?>, Object> capabilityHolderInstances = new HashMap<>();
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
private HashMap<String, List<Message>> modelPromptMap = new HashMap<>();
private HashMap<String, ModelConfig> modelConfigMap = new HashMap<>();
private List<MetaModule> moduleList = new ArrayList<>();
public AgentRegisterContext(List<String> paths) {
reflections = new Reflections(new ConfigurationBuilder().setScanners(
Scanners.FieldsAnnotated,
Scanners.SubTypes,
Scanners.MethodsAnnotated,
Scanners.TypesAnnotated
)
.forPackages(paths.toArray(paths.toArray(new String[0])))
);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -1,7 +1,11 @@
package work.slhaf.partner.api.factory.exception; package work.slhaf.partner.api.factory.exception;
public class ExternalModulePathNotExistException extends RuntimeException { public class ExternalModulePathNotExistException extends AgentRegisterFactoryFailedException {
public ExternalModulePathNotExistException(String message) { public ExternalModulePathNotExistException(String message) {
super("AgentRegisterFactory 执行失败: " + message); super(message);
}
public ExternalModulePathNotExistException(String message, Throwable cause) {
super(message, cause);
} }
} }

View File

@@ -1,9 +1,9 @@
package work.slhaf.partner.api.factory.module; package work.slhaf.partner.api.factory.module;
import org.reflections.Reflections; 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.config.ModelConfigManager;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory; import work.slhaf.partner.api.factory.context.AgentRegisterContext;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
import work.slhaf.partner.api.factory.module.annotation.After; 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.AgentModule;
import work.slhaf.partner.api.factory.module.annotation.Before; import work.slhaf.partner.api.factory.module.annotation.Before;
@@ -28,14 +28,27 @@ public class ModuleCheckFactory extends AgentBaseFactory {
@Override @Override
protected void run() { protected void run() {
Set<Class<?>> types = reflections.getTypesAnnotatedWith(AgentModule.class);
//检查注解AgentModule所在类是否继承了AgentInteractionModule //检查注解AgentModule所在类是否继承了AgentInteractionModule
agentModuleAnnotationCheck(); agentModuleAnnotationCheck(types);
//检查AgentModule是否具备无参构造方法
moduleConstructorsCheck(types);
//检查hook注解所在方法是否位于AgentInteractionModule子类/AgentInteractionSubModule子类/ActivateModel子类 //检查hook注解所在方法是否位于AgentInteractionModule子类/AgentInteractionSubModule子类/ActivateModel子类
hookLocationCheck(); hookLocationCheck();
//检查实现了ActivateModel的模块数量、名称与prompt是否一致 //检查实现了ActivateModel的模块数量、名称与prompt是否一致
activateModelImplCheck(); activateModelImplCheck();
} }
private void moduleConstructorsCheck(Set<Class<?>> types) {
for (Class<?> type : types) {
try {
type.getConstructor();
} catch (NoSuchMethodException e) {
throw new ModuleCheckException("缺少无参构造方法的模块: " + type.getSimpleName(), e);
}
}
}
private void activateModelImplCheck() { private void activateModelImplCheck() {
try { try {
Set<Class<? extends ActivateModel>> types = reflections.getSubTypesOf(ActivateModel.class); Set<Class<? extends ActivateModel>> types = reflections.getSubTypesOf(ActivateModel.class);
@@ -47,10 +60,10 @@ public class ModuleCheckFactory extends AgentBaseFactory {
Set<String> promptKeySet = ModelConfigManager.INSTANCE.getModelPromptMap().keySet(); Set<String> promptKeySet = ModelConfigManager.INSTANCE.getModelPromptMap().keySet();
if (!promptKeySet.containsAll(modelKeySet)) { if (!promptKeySet.containsAll(modelKeySet)) {
modelKeySet.removeAll(promptKeySet); modelKeySet.removeAll(promptKeySet);
throw new ModuleCheckException("存在未配置Prompt的ActivateModel实现! 缺少Prompt的ModelKey列表: "+ modelKeySet); throw new ModuleCheckException("存在未配置Prompt的ActivateModel实现! 缺少Prompt的ModelKey列表: " + modelKeySet);
} }
}catch (Exception e) { } catch (Exception e) {
throw new ModuleCheckException("ActivateModel 检测出错",e); throw new ModuleCheckException("ActivateModel 检测出错", e);
} }
} }
@@ -89,12 +102,11 @@ public class ModuleCheckFactory extends AgentBaseFactory {
if (ActivateModel.class.isAssignableFrom(type)) { if (ActivateModel.class.isAssignableFrom(type)) {
continue; continue;
} }
throw new ModuleCheckException("在不支持的类中使用了hook注解: "+type.getSimpleName()); throw new ModuleCheckException("在不支持的类中使用了hook注解: " + type.getSimpleName());
} }
} }
private void agentModuleAnnotationCheck() { private void agentModuleAnnotationCheck(Set<Class<?>> types) {
Set<Class<?>> types = reflections.getTypesAnnotatedWith(AgentModule.class);
for (Class<?> type : types) { for (Class<?> type : types) {
if (type.isAnnotation()) { if (type.isAnnotation()) {
continue; continue;

View File

@@ -1,7 +1,7 @@
package work.slhaf.partner.api.factory.module; package work.slhaf.partner.api.factory.module;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory; import work.slhaf.partner.api.factory.AgentBaseFactory;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext; import work.slhaf.partner.api.factory.context.AgentRegisterContext;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;

View File

@@ -1,21 +1,96 @@
package work.slhaf.partner.api.factory.module; package work.slhaf.partner.api.factory.module;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory; import net.bytebuddy.ByteBuddy;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext; 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.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;
/** /**
* 通过扫描注解<code>@Before</code>获取到各个模块的后hook逻辑并通过动态代理添加到执行逻辑之后 * 通过扫描注解<code>@Before</code>获取到各个模块的后hook逻辑并通过动态代理添加到执行逻辑之后
*/ */
public class ModuleProxyFactory extends AgentBaseFactory { public class ModuleProxyFactory extends AgentBaseFactory {
private List<MetaModule> moduleList;
private HashMap<Class<?>, Set<MetaMethod>> postHookMethods;
@Override @Override
protected void setVariables(AgentRegisterContext context) { protected void setVariables(AgentRegisterContext context) {
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
moduleList = factoryContext.getModuleList();
postHookMethods = factoryContext.getPostHookMethods();
} }
@Override @Override
protected void run() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { 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<MetaMethod> postHookMethods;
private ModuleProxyInterceptor(List<MetaMethod> 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;
}
} }
} }

View File

@@ -1,15 +1,17 @@
package work.slhaf.partner.api.factory.module; package work.slhaf.partner.api.factory.module;
import org.reflections.Reflections; import org.reflections.Reflections;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory; import work.slhaf.partner.api.factory.AgentBaseFactory;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext; 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.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 work.slhaf.partner.api.factory.module.pojo.MetaModule;
import java.util.Arrays; import java.lang.reflect.Method;
import java.util.Comparator; import java.util.*;
import java.util.List;
import java.util.Set;
/** /**
* 负责扫描<code>@Module</code>注解获取模块实例 * 负责扫描<code>@Module</code>注解获取模块实例
@@ -18,15 +20,63 @@ public class ModuleRegisterFactory extends AgentBaseFactory {
private Reflections reflections; private Reflections reflections;
private List<MetaModule> moduleList; private List<MetaModule> moduleList;
private HashMap<Class<?>, Set<MetaMethod>> postHookMethods;
private HashMap<Class<?>, Set<MetaMethod>> preHookMethods;
@Override @Override
protected void setVariables(AgentRegisterContext context) { protected void setVariables(AgentRegisterContext context) {
ModuleFactoryContext factoryContext = context.getModuleFactoryContext();
reflections = context.getReflections(); reflections = context.getReflections();
moduleList = context.getModuleList(); moduleList = factoryContext.getModuleList();
postHookMethods = factoryContext.getPostHookMethods();
preHookMethods = factoryContext.getPreHookMethods();
} }
@Override @Override
protected void run() { protected void run() {
registerModuleList();
registerHookSet();
}
private void registerHookSet() {
setPostHookMethods();
setPreHookMethods();
}
private void setPreHookMethods() {
Set<Method> 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<Method> 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<Class<?>, Set<MetaMethod>> preHookMethods) {
Class<?> clazz = method.getDeclaringClass();
if (preHookMethods.containsKey(clazz)) {
preHookMethods.get(clazz).add(metaMethod);
}else {
HashSet<MetaMethod> metaMethods = new HashSet<>();
metaMethods.add(metaMethod);
preHookMethods.put(clazz, metaMethods);
}
}
private void registerModuleList() {
//反射扫描获取@AgentModule所在类, 该部分为Agent流程执行模块 //反射扫描获取@AgentModule所在类, 该部分为Agent流程执行模块
Set<Class<?>> modules = reflections.getTypesAnnotatedWith(AgentModule.class); Set<Class<?>> modules = reflections.getTypesAnnotatedWith(AgentModule.class);
for (Class<?> module : modules) { for (Class<?> module : modules) {
@@ -38,5 +88,6 @@ public class ModuleRegisterFactory extends AgentBaseFactory {
moduleList.add(metaModule); moduleList.add(metaModule);
} }
moduleList.sort(Comparator.comparing(MetaModule::getOrder)); moduleList.sort(Comparator.comparing(MetaModule::getOrder));
} }
} }

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -12,11 +12,6 @@
<artifactId>Partner-Test-Demo</artifactId> <artifactId>Partner-Test-Demo</artifactId>
<dependencies> <dependencies>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
<dependency> <dependency>
<groupId>work.slhaf</groupId> <groupId>work.slhaf</groupId>
<artifactId>Partner-Api</artifactId> <artifactId>Partner-Api</artifactId>

44
pom.xml
View File

@@ -19,50 +19,6 @@
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.13.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.17</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.17</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.18.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.36</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.56</version>
</dependency>
</dependencies>
<build> <build>
<plugins> <plugins>