推进核心服务与模块注册机制

- 完善Agent流程执行框架
- Api包下新增flow流程包,该部分对应模块的执行流程
- 明确ModuleFactory与CapabilityFactory以及ModuleHook的共同运作流程
- 调整了Hook注解名称
This commit is contained in:
2025-07-24 23:31:02 +08:00
parent effa1df7fa
commit ade922cbc2
113 changed files with 744 additions and 497 deletions

View File

@@ -1,7 +1,17 @@
package work.slhaf.partner.api;
public class Agent {
public static void run(Class<?> clazz) {
import work.slhaf.partner.api.entity.AgentContext;
import work.slhaf.partner.api.factory.AgentRegisterFactory;
import work.slhaf.partner.api.flow.AgentInteraction;
/**
* Agent启动类
*/
public class Agent {
public static void run(Class<?> clazz) {
AgentContext context = AgentRegisterFactory.launch(clazz.getPackage().getName());
AgentInteraction.launch(context);
}
}

View File

@@ -1,16 +0,0 @@
package work.slhaf.partner.api;
import work.slhaf.partner.api.common.entity.AgentRegisterContext;
public class AgentRegisterFactory {
private AgentRegisterContext context = new AgentRegisterContext();
private AgentRegisterFactory(){}
public static void launch(){
//TODO 通过调用module与capability的注册逻辑完成完整的注册过程需要考虑hook机制
AgentRegisterFactory factory = new AgentRegisterFactory();
}
}

View File

@@ -0,0 +1,70 @@
package work.slhaf.partner.api.common.chat;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import work.slhaf.partner.api.common.chat.constant.ChatConstant;
import work.slhaf.partner.api.common.chat.pojo.ChatBody;
import work.slhaf.partner.api.common.chat.pojo.ChatResponse;
import work.slhaf.partner.api.common.chat.pojo.Message;
import work.slhaf.partner.api.common.chat.pojo.PrimaryChatResponse;
import java.util.List;
@Data
@NoArgsConstructor
public class ChatClient {
private String clientId;
private String url;
private String apikey;
private String model;
private double top_p;
private double temperature;
private int max_tokens;
public ChatClient(String url, String apikey, String model) {
this.url = url;
this.apikey = apikey;
this.model = model;
}
public ChatResponse runChat(List<Message> messages) {
HttpRequest request = HttpRequest.post(url);
request.header("Content-Type", "application/json");
request.header("Authorization", "Bearer " + apikey);
ChatBody body;
if (top_p > 0) {
body = ChatBody.builder()
.model(model)
.messages(messages)
.top_p(top_p)
.temperature(temperature)
.max_tokens(max_tokens)
.build();
} else {
body = ChatBody.builder()
.model(model)
.messages(messages)
.build();
}
HttpResponse response = request.body(JSONUtil.toJsonStr(body)).execute();
ChatResponse finalResponse;
PrimaryChatResponse primaryChatResponse = JSONUtil.toBean(response.body(), PrimaryChatResponse.class);
finalResponse = ChatResponse.builder()
.type(ChatConstant.Response.SUCCESS)
.message(primaryChatResponse.getChoices().get(0).getMessage().getContent())
.usageBean(primaryChatResponse.getUsage())
.build();
response.close();
return finalResponse;
}
}

View File

@@ -0,0 +1,15 @@
package work.slhaf.partner.api.common.chat.constant;
public class ChatConstant {
public static class Character {
public static final String USER = "user";
public static final String SYSTEM = "system";
public static final String ASSISTANT = "assistant";
}
public static class Response {
public static final String SUCCESS = "success";
public static final String ERROR = "error";
}
}

View File

@@ -0,0 +1,25 @@
package work.slhaf.partner.api.common.chat.pojo;
import lombok.*;
import java.util.List;
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChatBody {
@NonNull
private String model;
@NonNull
private List<Message> messages;
@Builder.Default
private double temperature = 1;
@Builder.Default
private double top_p = 1;
private boolean stream;
@Builder.Default
private int max_tokens = 1024;
private int presence_penalty;
private int frequency_penalty;
}

View File

@@ -0,0 +1,16 @@
package work.slhaf.partner.api.common.chat.pojo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ChatResponse {
private String type;
private String message;
private PrimaryChatResponse.UsageBean usageBean;
}

View File

@@ -0,0 +1,22 @@
package work.slhaf.partner.api.common.chat.pojo;
import lombok.*;
import work.slhaf.partner.api.common.entity.PersistableObject;
import java.io.Serial;
@EqualsAndHashCode(callSuper = true)
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message extends PersistableObject {
@Serial
private static final long serialVersionUID = 1L;
@NonNull
private String role;
@NonNull
private String content;
}

View File

@@ -0,0 +1,20 @@
package work.slhaf.partner.api.common.chat.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import work.slhaf.partner.api.common.entity.PersistableObject;
import java.io.Serial;
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public class MetaMessage extends PersistableObject {
@Serial
private static final long serialVersionUID = 1L;
private Message userMessage;
private Message assistantMessage;
}

View File

@@ -0,0 +1,111 @@
package work.slhaf.partner.api.common.chat.pojo;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class PrimaryChatResponse {
/**
* id
*/
private String id;
/**
* object
*/
private String object;
/**
* created
*/
private int created;
/**
* model
*/
private String model;
/**
* choices
*/
private List<ChoicesBean> choices;
/**
* usage
*/
private UsageBean usage;
/**
* system_fingerprint
*/
private String system_fingerprint;
@Setter
@Getter
public static class UsageBean {
/**
* prompt_tokens
*/
private int prompt_tokens;
/**
* completion_tokens
*/
private int completion_tokens;
/**
* total_tokens
*/
private int total_tokens;
/**
* prompt_cache_hit_tokens
*/
private int prompt_cache_hit_tokens;
/**
* prompt_cache_miss_tokens
*/
private int prompt_cache_miss_tokens;
@Override
public String toString() {
return "UsageBean{" +
"prompt_tokens=" + prompt_tokens +
", completion_tokens=" + completion_tokens +
", total_tokens=" + total_tokens +
", prompt_cache_hit_tokens=" + prompt_cache_hit_tokens +
", prompt_cache_miss_tokens=" + prompt_cache_miss_tokens +
'}';
}
}
@Setter
@Getter
public static class ChoicesBean {
/**
* index
*/
private int index;
/**
* message
*/
private MessageBean message;
/**
* logprobs
*/
private Object logprobs;
/**
* finish_reason
*/
private String finish_reason;
@Setter
@Getter
public static class MessageBean {
/**
* role
*/
private String role;
/**
* content
*/
private String content;
}
}
}

View File

@@ -1,10 +0,0 @@
package work.slhaf.partner.api.common.entity;
import lombok.Data;
import org.reflections.Reflections;
@Data
public class AgentRegisterContext {
//TODO 抽取出必要的注册工厂共用的上下文
private Reflections reflections;
}

View File

@@ -0,0 +1,6 @@
package work.slhaf.partner.api.common.entity;
import java.io.Serializable;
public abstract class PersistableObject implements Serializable {
}

View File

@@ -0,0 +1,17 @@
package work.slhaf.partner.api.entity;
import lombok.Data;
import java.util.HashMap;
import java.util.Set;
import java.util.function.Function;
@Data
public class AgentContext {
private HashMap<String, Function<Object[], Object>> methodsRouterTable;
private HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable;
private HashMap<Class<?>, Object> capabilityCoreInstances;
private HashMap<Class<?>, Object> capabilityHolderInstances;
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
}

View File

@@ -0,0 +1,37 @@
package work.slhaf.partner.api.factory;
import cn.hutool.core.bean.BeanUtil;
import work.slhaf.partner.api.entity.AgentContext;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
import work.slhaf.partner.api.factory.capability.CapabilityCheckFactory;
import work.slhaf.partner.api.factory.capability.CapabilityRegisterFactory;
import work.slhaf.partner.api.factory.module.ModuleCheckFactory;
import work.slhaf.partner.api.factory.module.ModuleRegisterFactory;
public class AgentRegisterFactory {
private AgentRegisterFactory() {
}
public static AgentContext launch(String path) {
AgentRegisterContext registerContext = new AgentRegisterContext(path);
//流程
//1. 执行register和check逻辑
new CapabilityRegisterFactory().execute(registerContext);
new CapabilityCheckFactory().execute(registerContext);
new ModuleRegisterFactory().execute(registerContext);
new ModuleCheckFactory().execute(registerContext);
//2. 为module通过动态代理添加后hook逻辑并进行实例化
//3. 先一步注入Capability,避免因前hook逻辑存在针对能力的引用而报错
//4. 执行前hook逻辑
AgentContext agentContext = new AgentContext();
BeanUtil.copyProperties(registerContext,agentContext);
return agentContext;
}
}

View File

@@ -1,178 +1,41 @@
package work.slhaf.partner.api.capability;
package work.slhaf.partner.api.factory.capability;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import work.slhaf.partner.api.capability.annotation.*;
import work.slhaf.partner.api.capability.exception.*;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
import work.slhaf.partner.api.common.util.AgentUtil;
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 java.lang.reflect.*;
import java.net.URL;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static work.slhaf.partner.api.common.util.AgentUtil.methodSignature;
public final class CapabilityRegisterFactory {
public class CapabilityCheckFactory extends AgentBaseFactory {
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 CapabilityRegisterFactory() {
@Override
protected void setVariables(AgentRegisterContext context) {
reflections = context.getReflections();
cores = context.getCores();
capabilities = context.getCapabilities();
}
//TODO 需决定是否分离检查与路由表生成注入逻辑如果分离可进一步添加hook点但目前似乎并非必要
public void registerCapabilities(String scannerPath) {
setBasicVariable(scannerPath);
//检查可注册能力是否正常
statusCheck();
//扫描现有Capability, value为键返回函数路由表, 函数路由表内部通过反射调用对应core的方法
generateRouterTable();
//通过动态代理注入能力
injectCapability();
}
private void generateRouterTable() {
generateMethodsRouterTable();
generateCoordinatedMethodsRouterTable();
}
private void generateCoordinatedMethodsRouterTable() {
Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(Coordinated.class);
if (methodsAnnotatedWith.isEmpty()) {
return;
}
try {
//获取所有CM实例
HashMap<String, Object> cognationManagerInstances = getCognationManagerInstances();
methodsAnnotatedWith.forEach(method -> {
String key = method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method);
Function<Object[], Object> function = args -> {
try {
return method.invoke(cognationManagerInstances.get(key), args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
coordinatedMethodsRouterTable.put(key, function);
});
} catch (Exception e) {
throw new FactoryExecuteFailedException("创建协调方法路由表出错", e);
}
}
private HashMap<String, Object> getCognationManagerInstances() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
HashMap<String, Object> map = new HashMap<>();
for (Class<?> c : reflections.getTypesAnnotatedWith(CoordinateManager.class)) {
Constructor<?> constructor = c.getDeclaredConstructor();
Object instance = constructor.newInstance();
Arrays.stream(c.getMethods())
.filter(method -> method.isAnnotationPresent(Coordinated.class))
.forEach(method -> {
String key = method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method);
map.put(key, instance);
});
}
return map;
}
private void setBasicVariable(String scannerPath) {
setReflections(scannerPath);
setAnnotatedClasses();
}
private void setAnnotatedClasses() {
cores = reflections.getTypesAnnotatedWith(CapabilityCore.class);
capabilities = reflections.getTypesAnnotatedWith(Capability.class);
}
private void setReflections(String scannerPath) {
//后续可替换为根据传入的启动类获取路径
Collection<URL> urls = ClasspathHelper.forPackage(scannerPath);
reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(urls)
.setScanners(
Scanners.TypesAnnotated,
Scanners.MethodsAnnotated,
Scanners.SubTypes,
Scanners.FieldsAnnotated
)
);
}
private void generateMethodsRouterTable() {
//扫描`@Capability``@CapabilityMethod`注解的类与方法
//`capabilityValue.methodSignature`作为key,函数对象为通过反射拿到的core实例对应的方法
cores.forEach(core -> Arrays.stream(core.getMethods())
.filter(method -> method.isAnnotationPresent(CapabilityMethod.class))
.forEach(method -> {
Function<Object[], Object> function = args -> {
try {
return method.invoke(capabilityCoreInstances.get(core), args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
String key = core.getAnnotation(CapabilityCore.class).value() + "." + methodSignature(method);
if (methodsRouterTable.containsKey(key)) {
throw new DuplicateMethodException("重复注册能力方法: " + core.getPackage().getName() + "." + core.getSimpleName() + "#" + method.getName());
}
methodsRouterTable.put(key, function);
}));
}
private void injectCapability() {
//获取现有的`@InjectCapability`注解所在字段并获取对应的类通过动态代理注入对象
Set<Field> fields = reflections.getFieldsAnnotatedWith(InjectCapability.class);
//在动态代理内部通过函数路由表调用对应的方法
createProxy(fields);
}
private void createProxy(Set<Field> fields) {
try {
for (Field field : fields) {
field.setAccessible(true);
Class<?> fieldType = field.getType();
Object instance = Proxy.newProxyInstance(
fieldType.getClassLoader(),
new Class[]{fieldType},
(proxy, method, objects) -> {
if (method.isAnnotationPresent(ToCoordinated.class)) {
String key = method.getDeclaringClass().getAnnotation(Capability.class).value() + "." + methodSignature(method);
return coordinatedMethodsRouterTable.get(key).apply(objects);
}
String key = fieldType.getAnnotation(Capability.class).value() + "." + methodSignature(method);
return methodsRouterTable.get(key).apply(objects);
}
);
field.set(capabilityHolderInstances.get(field.getDeclaringClass()), instance);
}
} catch (Exception e) {
throw new ProxySetFailedException("代理设置失败", e);
}
}
private void statusCheck() {
capabilityHolderCheck();
@Override
protected void run() {
checkCountAndCapabilities();
checkCapabilityMethods();
checkCoordinatedMethods();
checkInjectCapability();
//检查完毕设置core的实例类
setCapabilityCoreInstances();
}
private void checkInjectCapability() {
@@ -183,25 +46,6 @@ public final class CapabilityRegisterFactory {
});
}
private void capabilityHolderCheck() {
if (capabilityHolderInstances.isEmpty()) {
throw new EmptyCapabilityHolderException("Capability 持有者实例为空");
}
}
private void setCapabilityCoreInstances() {
try {
for (Class<?> core : cores) {
Constructor<?> constructor = core.getDeclaredConstructor();
constructor.setAccessible(true);
capabilityCoreInstances.put(core, constructor.newInstance());
}
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException |
IllegalAccessException e) {
throw new CoreInstancesCreateFailedException("core实例创建失败");
}
}
private void checkCoordinatedMethods() {
//检查各个capability中是否含有ToCoordinated注解
//如果含有则需要查找AbstractCognationManager的子类,看这里是否有对应的Coordinated注解所在方法
@@ -249,7 +93,6 @@ public final class CapabilityRegisterFactory {
return methodsCoordinated;
}
private void checkCapabilityMethods() {
HashMap<String, List<Method>> capabilitiesMethods = getCapabilityMethods(capabilities);
StringBuilder sb = new StringBuilder();
@@ -317,7 +160,6 @@ public final class CapabilityRegisterFactory {
}
}
private boolean checkValuesMatched(Set<Class<?>> cores, Set<Class<?>> capabilities) {
Set<String> coresValues = new HashSet<>();
Set<String> capabilitiesValues = new HashSet<>();
@@ -342,10 +184,6 @@ public final class CapabilityRegisterFactory {
return coresValues.equals(capabilitiesValues);
}
public void registerModule(CapabilityHolder capabilityHolder) {
capabilityHolderInstances.put(capabilityHolder.getClass(), capabilityHolder);
}
record LackRecord(List<String> coreLack, List<String> capLack) {
public boolean hasNotEmptyRecord() {
return !coreLack.isEmpty() || !capLack.isEmpty();

View File

@@ -0,0 +1,67 @@
package work.slhaf.partner.api.factory.capability;
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.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.ProxySetFailedException;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Set;
import java.util.function.Function;
import static work.slhaf.partner.api.common.util.AgentUtil.methodSignature;
public class CapabilityInjectFactory extends AgentBaseFactory {
private Reflections reflections;
private HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable;
private HashMap<String, Function<Object[], Object>> methodsRouterTable;
private HashMap<Class<?>, Object> capabilityHolderInstances;
@Override
protected void setVariables(AgentRegisterContext context) {
reflections = context.getReflections();
coordinatedMethodsRouterTable = context.getCoordinatedMethodsRouterTable();
methodsRouterTable = context.getMethodsRouterTable();
capabilityHolderInstances = context.getCapabilityHolderInstances();
}
@Override
protected void run() {
//获取现有的`@InjectCapability`注解所在字段,并获取对应的类,通过动态代理注入对象
Set<Field> fields = reflections.getFieldsAnnotatedWith(InjectCapability.class);
//在动态代理内部,通过函数路由表调用对应的方法
createProxy(fields);
}
private void createProxy(Set<Field> fields) {
try {
for (Field field : fields) {
field.setAccessible(true);
Class<?> fieldType = field.getType();
Object instance = Proxy.newProxyInstance(
fieldType.getClassLoader(),
new Class[]{fieldType},
(proxy, method, objects) -> {
if (method.isAnnotationPresent(ToCoordinated.class)) {
String key = method.getDeclaringClass().getAnnotation(Capability.class).value() + "." + methodSignature(method);
return coordinatedMethodsRouterTable.get(key).apply(objects);
}
String key = fieldType.getAnnotation(Capability.class).value() + "." + methodSignature(method);
return methodsRouterTable.get(key).apply(objects);
}
);
field.set(capabilityHolderInstances.get(field.getDeclaringClass()), instance);
}
} catch (Exception e) {
throw new ProxySetFailedException("代理设置失败", e);
}
}
}

View File

@@ -0,0 +1,142 @@
package work.slhaf.partner.api.factory.capability;
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.capability.annotation.*;
import work.slhaf.partner.api.factory.capability.exception.CoreInstancesCreateFailedException;
import work.slhaf.partner.api.factory.capability.exception.DuplicateMethodException;
import work.slhaf.partner.api.factory.capability.exception.FactoryExecuteFailedException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import java.util.function.Function;
import static work.slhaf.partner.api.common.util.AgentUtil.methodSignature;
public final class CapabilityRegisterFactory extends AgentBaseFactory {
private Reflections reflections;
private HashMap<String, Function<Object[], Object>> methodsRouterTable;
private HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable;
private HashMap<Class<?>, Object> capabilityCoreInstances;
private HashMap<Class<?>, Object> capabilityHolderInstances;
private Set<Class<?>> cores;
private Set<Class<?>> capabilities;
@Override
protected void setVariables(AgentRegisterContext context) {
reflections = context.getReflections();
methodsRouterTable = context.getMethodsRouterTable();
coordinatedMethodsRouterTable = context.getCoordinatedMethodsRouterTable();
capabilityCoreInstances = context.getCapabilityCoreInstances();
capabilityHolderInstances = context.getCapabilityHolderInstances();
cores = context.getCores();
capabilities = context.getCapabilities();
}
@Override
protected void run() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
setCapabilityCoreInstances();
setAnnotatedClasses();
generateRouterTable();
}
private void setAnnotatedClasses() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
cores.addAll(reflections.getTypesAnnotatedWith(CapabilityCore.class));
capabilities.addAll(reflections.getTypesAnnotatedWith(Capability.class));
setCapabilityHolderInstances();
}
private void setCapabilityHolderInstances() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
for (Class<?> clazz : reflections.getTypesAnnotatedWith(CapabilityHolder.class)) {
Object o = clazz.getDeclaredConstructor().newInstance();
capabilityHolderInstances.put(clazz, o);
}
}
private void generateRouterTable() {
generateMethodsRouterTable();
generateCoordinatedMethodsRouterTable();
}
private void generateCoordinatedMethodsRouterTable() {
Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(Coordinated.class);
if (methodsAnnotatedWith.isEmpty()) {
return;
}
try {
//获取所有CM实例
HashMap<String, Object> coordinateManagerInstances = getCoordinateManagerInstances();
methodsAnnotatedWith.forEach(method -> {
String key = method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method);
Function<Object[], Object> function = args -> {
try {
return method.invoke(coordinateManagerInstances.get(key), args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
coordinatedMethodsRouterTable.put(key, function);
});
} catch (Exception e) {
throw new FactoryExecuteFailedException("创建协调方法路由表出错", e);
}
}
private HashMap<String, Object> getCoordinateManagerInstances() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
HashMap<String, Object> map = new HashMap<>();
for (Class<?> c : reflections.getTypesAnnotatedWith(CoordinateManager.class)) {
Constructor<?> constructor = c.getDeclaredConstructor();
Object instance = constructor.newInstance();
Arrays.stream(c.getMethods())
.filter(method -> method.isAnnotationPresent(Coordinated.class))
.forEach(method -> {
String key = method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method);
map.put(key, instance);
});
}
return map;
}
private void generateMethodsRouterTable() {
//扫描`@Capability`与`@CapabilityMethod`注解的类与方法
//将`capabilityValue.methodSignature`作为key,函数对象为通过反射拿到的core实例对应的方法
cores.forEach(core -> Arrays.stream(core.getMethods())
.filter(method -> method.isAnnotationPresent(CapabilityMethod.class))
.forEach(method -> {
Function<Object[], Object> function = args -> {
try {
return method.invoke(capabilityCoreInstances.get(core), args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
String key = core.getAnnotation(CapabilityCore.class).value() + "." + methodSignature(method);
if (methodsRouterTable.containsKey(key)) {
throw new DuplicateMethodException("重复注册能力方法: " + core.getPackage().getName() + "." + core.getSimpleName() + "#" + method.getName());
}
methodsRouterTable.put(key, function);
}));
}
private void setCapabilityCoreInstances() {
try {
for (Class<?> core : cores) {
Constructor<?> constructor = core.getDeclaredConstructor();
constructor.setAccessible(true);
capabilityCoreInstances.put(core, constructor.newInstance());
}
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException |
IllegalAccessException e) {
throw new CoreInstancesCreateFailedException("core实例创建失败");
}
}
}

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.annotation;
package work.slhaf.partner.api.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.annotation;
package work.slhaf.partner.api.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.annotation;
package work.slhaf.partner.api.factory.capability.annotation;
import java.lang.annotation.*;

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.annotation;
package work.slhaf.partner.api.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.annotation;
package work.slhaf.partner.api.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.annotation;
package work.slhaf.partner.api.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.annotation;
package work.slhaf.partner.api.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.annotation;
package work.slhaf.partner.api.factory.capability.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class CapabilityCheckFailedException extends RuntimeException {
public CapabilityCheckFailedException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class CoreInstancesCreateFailedException extends FactoryExecuteFailedException {
public CoreInstancesCreateFailedException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class DuplicateCapabilityException extends CapabilityCheckFailedException {
public DuplicateCapabilityException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class DuplicateMethodException extends CapabilityCheckFailedException{
public DuplicateMethodException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class EmptyCapabilityHolderException extends CapabilityCheckFailedException{
public EmptyCapabilityHolderException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class FactoryExecuteFailedException extends RuntimeException {
public FactoryExecuteFailedException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class ProxySetFailedException extends FactoryExecuteFailedException{
public ProxySetFailedException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class UnMatchedCapabilityException extends CapabilityCheckFailedException{
public UnMatchedCapabilityException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class UnMatchedCapabilityMethodException extends CapabilityCheckFailedException {
public UnMatchedCapabilityMethodException(String message) {

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.api.capability.exception;
package work.slhaf.partner.api.factory.capability.exception;
public class UnMatchedCoordinatedMethodException extends CapabilityCheckFailedException {
public UnMatchedCoordinatedMethodException(String message) {

View File

@@ -0,0 +1,20 @@
package work.slhaf.partner.api.factory.entity;
import work.slhaf.partner.api.factory.capability.exception.FactoryExecuteFailedException;
import java.lang.reflect.InvocationTargetException;
public abstract class AgentBaseFactory {
public void execute(AgentRegisterContext context) {
try {
setVariables(context);
run();
} catch (Exception e) {
throw new FactoryExecuteFailedException(e.getMessage(), e);
}
}
protected abstract void setVariables(AgentRegisterContext context);
protected abstract void run() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException;
}

View File

@@ -0,0 +1,23 @@
package work.slhaf.partner.api.factory.entity;
import lombok.Data;
import org.reflections.Reflections;
import java.util.HashMap;
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;
public AgentRegisterContext(String path) {
reflections = new Reflections(path);
}
}

View File

@@ -0,0 +1,17 @@
package work.slhaf.partner.api.factory.module;
import work.slhaf.partner.api.factory.entity.AgentBaseFactory;
import work.slhaf.partner.api.factory.entity.AgentRegisterContext;
public class ModuleCheckFactory extends AgentBaseFactory {
@Override
protected void setVariables(AgentRegisterContext context) {
}
@Override
protected void run() {
//检查注解AgentModule所在类是否继承了AgentInteractionModule
//检查hook注解所在方法是否位于AgentInteractionModule子类/AgentInteractionSubModule子类/ActivateModel子类
}
}

View File

@@ -0,0 +1,4 @@
package work.slhaf.partner.api.factory.module;
public class ModuleHookExecutor {
}

View File

@@ -0,0 +1,20 @@
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;
public class ModuleRegisterFactory extends AgentBaseFactory {
private Reflections reflections;
@Override
protected void setVariables(AgentRegisterContext context) {
reflections = context.getReflections();
}
@Override
protected void run() {
//反射扫描获取InteractionModule所在类与hook注解所在方法
}
}

View File

@@ -0,0 +1,13 @@
package work.slhaf.partner.api.factory.module.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface After {
int order() default 0;
}

View File

@@ -0,0 +1,24 @@
package work.slhaf.partner.api.factory.module.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于注解执行模块
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AgentModule {
/**
* 模块名称
*/
String name();
/**
* 模块执行顺序,数字越小执行越靠前
*/
int order();
}

View File

@@ -0,0 +1,12 @@
package work.slhaf.partner.api.factory.module.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Before {
int order() default 0;
}

View File

@@ -0,0 +1,15 @@
package work.slhaf.partner.api.flow;
import work.slhaf.partner.api.entity.AgentContext;
/**
* Agent执行流程
*/
public class AgentInteraction {
private AgentInteraction(){}
public static void launch(AgentContext context){
//流程执行启动需考虑模块热插拔可结合http调整模块启用情况并序列化至本地或数据库中
}
}

View File

@@ -0,0 +1,74 @@
package work.slhaf.partner.api.flow.abstracts;
import work.slhaf.partner.api.common.chat.ChatClient;
import work.slhaf.partner.api.common.chat.constant.ChatConstant;
import work.slhaf.partner.api.common.chat.pojo.ChatResponse;
import work.slhaf.partner.api.common.chat.pojo.Message;
import work.slhaf.partner.api.factory.module.annotation.Before;
import java.util.ArrayList;
import java.util.List;
public interface ActivateModel {
@Before
default void modelSettings() {
// Model model = new Model();
// ModelConfig modelConfig = ModelConfig.load(modelKey());
// model.setBaseMessages(withAwareness() ? ResourcesUtil.Prompt.loadPromptWithSelfAwareness(modelKey(), promptModule()) : ResourcesUtil.Prompt.loadPrompt(modelKey(), promptModule()));
// model.setChatClient(new ChatClient(modelConfig.getBaseUrl(), modelConfig.getApikey(), modelConfig.getModel()));
}
default ChatResponse chat() {
Model model = getModel();
List<Message> temp = new ArrayList<>();
temp.addAll(model.getBaseMessages());
temp.addAll(model.getChatMessages());
return model.getChatClient().runChat(temp);
}
default ChatResponse singleChat(String input) {
Model model = getModel();
List<Message> temp = new ArrayList<>(model.getBaseMessages());
temp.add(new Message(ChatConstant.Character.USER, input));
return model.getChatClient().runChat(temp);
}
default void updateChatClientSettings() {
Model model = getModel();
model.getChatClient().setTemperature(0.4);
model.getChatClient().setTop_p(0.8);
}
default List<Message> chatMessages() {
return getModel().getChatMessages();
}
default List<Message> baseMessages() {
return getModel().getBaseMessages();
}
default ChatClient chatClient() {
return getModel().getChatClient();
}
/**
* 仅适用Module子类否则需要重写
*
* @return 持有的model实例
*/
default Model getModel() {
return ((Module) this).getModel();
}
default void setModel(Model model) {
((Module) this).setModel(model);
}
String modelKey();
boolean withAwareness();
String promptModule();
}

View File

@@ -0,0 +1,10 @@
package work.slhaf.partner.api.flow.abstracts;
import work.slhaf.partner.api.flow.entity.InteractionFlowContext;
/**
* 流程执行模块基类
*/
public abstract class AgentInteractionModule extends Module {
public abstract void execute(InteractionFlowContext context);
}

View File

@@ -0,0 +1,13 @@
package work.slhaf.partner.api.flow.abstracts;
/**
* 流程子模块基类
* @param <I> 输入类型
* @param <O> 输出类型
*/
public abstract class AgentInteractionSubModule<I, O> extends Module {
public abstract O execute(I data);
}

View File

@@ -0,0 +1,16 @@
package work.slhaf.partner.api.flow.abstracts;
import lombok.Data;
import work.slhaf.partner.api.common.chat.ChatClient;
import work.slhaf.partner.api.common.chat.pojo.Message;
import java.util.List;
@Data
public class Model {
protected ChatClient chatClient;
protected List<Message> chatMessages;
protected List<Message> baseMessages;
}

View File

@@ -0,0 +1,14 @@
package work.slhaf.partner.api.flow.abstracts;
import lombok.Getter;
import lombok.Setter;
import work.slhaf.partner.api.factory.capability.annotation.CapabilityHolder;
@CapabilityHolder
public abstract class Module {
@Getter
@Setter
protected Model model = new Model();
}

View File

@@ -0,0 +1,10 @@
package work.slhaf.partner.api.flow.entity;
import lombok.Data;
/**
* 流程上下文
*/
@Data
public class InteractionFlowContext {
}

View File

@@ -1,4 +0,0 @@
package work.slhaf.partner.api.module;
public class ModuleRegisterFactory {
}