Feat: proxy 模块框架搭建

This commit is contained in:
LuanY77
2025-07-23 11:21:32 +08:00
parent 6bd3008353
commit d7b6b20f23
13 changed files with 811 additions and 0 deletions

View File

@@ -17,4 +17,6 @@ import java.lang.annotation.Target;
public @interface AIComponent {
String nodeId() default "";
String nodeName() default "";
}

View File

@@ -0,0 +1,63 @@
package com.yomahub.liteflow.ai.enums;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.core.NodeSwitchComponent;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
/**
* AI 节点类型枚举
*
* @author 苍镜月
* @since TODO
*/
public enum AITypeEnum {
/**
* AI对话 - 对应 NodeComponent
*/
CHAT("AIChat", NodeComponent.class),
/**
* AI分类 - 对应 NodeSwitchComponent
*/
CLASSIFY("AIClassify", NodeSwitchComponent.class),
/**
* AI检索 - 对应 NodeComponent
*/
RETRIEVAL("AIRetrieval", NodeComponent.class);
private final String type;
private final Class<? extends NodeComponent> componentClass;
private static final Map<String, Class<? extends NodeComponent>> cache;
AITypeEnum(String type, Class<? extends NodeComponent> componentClass) {
this.type = type;
this.componentClass = componentClass;
}
public String getType() {
return type;
}
public Class<? extends NodeComponent> getComponentClass() {
return componentClass;
}
static {
cache = Arrays.stream(AITypeEnum.values()).collect(Collectors.toMap(AITypeEnum::getType, AITypeEnum::getComponentClass));
}
/**
* 根据注解获取对应的 NodeComponent 类
* @param annotationType 注解类
* @return 对应的 NodeComponent 类
*/
public static Class<? extends NodeComponent> fromAnnotationType(Class<?> annotationType) {
return cache.get(annotationType.getSimpleName());
}
}

View File

@@ -0,0 +1,153 @@
package com.yomahub.liteflow.ai.proxy;
import com.yomahub.liteflow.ai.annotation.AIComponent;
import com.yomahub.liteflow.ai.proxy.handler.AbstractAIComponentHandler;
import com.yomahub.liteflow.ai.proxy.handler.ChatComponentHandler;
import com.yomahub.liteflow.ai.proxy.handler.ClassifyComponentHandler;
import com.yomahub.liteflow.ai.proxy.handler.RetrievalComponentHandler;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* AI组件工厂
* 实现工厂模式管理不同类型AI组件的创建
*
* @author 苍镜月
* @since TODO
*/
public class AIComponentFactory {
private static final LFLog LOG = LFLoggerManager.getLogger(AIComponentFactory.class);
private final Map<Class<? extends Annotation>, AbstractAIComponentHandler<?>> handlerMap;
public AIComponentFactory() {
this.handlerMap = new HashMap<>();
initializeHandlers();
}
/**
* 初始化处理器映射
*/
private void initializeHandlers() {
// 注册不同类型的AI组件处理器
registerHandler(new ChatComponentHandler());
registerHandler(new ClassifyComponentHandler());
registerHandler(new RetrievalComponentHandler());
LOG.info("Initialized AI component handlers: {}", handlerMap.keySet());
}
/**
* 注册处理器
*
* @param handler 处理器实例
*/
private void registerHandler(AbstractAIComponentHandler<?> handler) {
handlerMap.put(handler.getSupportedAnnotationType(), handler);
LOG.debug("Registered handler: {} for annotation: {}",
handler.getClass().getSimpleName(),
handler.getSupportedAnnotationType().getSimpleName());
}
/**
* 创建AI组件
*
* @param interfaceClass 接口类
* @param beanName bean名称
* @return NodeComponent实例如果不是AI组件则返回null
*/
public NodeComponent createAIComponent(Class<?> interfaceClass, String beanName) {
LOG.info("Attempting to create AI component for interface: {}, beanName: {}",
interfaceClass.getName(), beanName);
// 检查是否是AI组件
AIComponent aiComponent = interfaceClass.getAnnotation(AIComponent.class);
if (Objects.isNull(aiComponent)) {
LOG.debug("Interface {} is not an AI component", interfaceClass.getName());
return null;
}
// 查找对应的处理器
AbstractAIComponentHandler<?> handler = findHandler(interfaceClass);
if (Objects.isNull(handler)) {
LOG.warn("No handler found for AI component interface: {}", interfaceClass.getName());
return null;
}
// 使用处理器创建组件
try {
NodeComponent component = handler.createAIComponent(interfaceClass, beanName, aiComponent);
if (Objects.nonNull(component)) {
LOG.info("Successfully created AI component: {} with handler: {}",
beanName, handler.getClass().getSimpleName());
}
return component;
} catch (Exception e) {
LOG.error("Failed to create AI component: {}", beanName, e);
throw new RuntimeException("Failed to create AI component: " + beanName, e);
}
}
/**
* 查找适合的处理器
*
* @param interfaceClass 接口类
* @return 处理器实例如果没有找到则返回null
*/
private AbstractAIComponentHandler<?> findHandler(Class<?> interfaceClass) {
// 遍历所有支持的注解类型,查找匹配的处理器
for (Map.Entry<Class<? extends Annotation>, AbstractAIComponentHandler<?>> entry : handlerMap.entrySet()) {
Class<? extends Annotation> annotationType = entry.getKey();
if (interfaceClass.isAnnotationPresent(annotationType)) {
LOG.debug("Found handler: {} for annotation: {} on interface: {}",
entry.getValue().getClass().getSimpleName(),
annotationType.getSimpleName(),
interfaceClass.getName());
return entry.getValue();
}
}
return null;
}
/**
* 判断是否是AI组件接口
*
* @param interfaceClass 接口类
* @return true如果是AI组件
*/
public boolean isAIComponent(Class<?> interfaceClass) {
if (!interfaceClass.isInterface()) {
return false;
}
// 检查是否有AIComponent注解
if (!interfaceClass.isAnnotationPresent(AIComponent.class)) {
return false;
}
// 检查是否有任何支持的AI注解
for (Class<? extends Annotation> annotationType : handlerMap.keySet()) {
if (interfaceClass.isAnnotationPresent(annotationType)) {
return true;
}
}
return false;
}
/**
* 获取支持的注解类型
*
* @return 支持的注解类型集合
*/
public Map<Class<? extends Annotation>, AbstractAIComponentHandler<?>> getSupportedAnnotations() {
return new HashMap<>(handlerMap);
}
}

View File

@@ -0,0 +1,67 @@
package com.yomahub.liteflow.ai.proxy;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import java.util.Objects;
/**
* AI组件后置处理器
*
* @author 苍镜月
* @since TODO
*/
public class AIComponentPostProcessor implements BeanPostProcessor, Ordered {
private static final LFLog LOG = LFLoggerManager.getLogger(AIComponentPostProcessor.class);
private final AIComponentFactory aiComponentFactory = new AIComponentFactory();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> clazz = bean.getClass();
// 检查是否是AI组件接口
if (aiComponentFactory.isAIComponent(clazz)) {
LOG.info("Detected AI component interface: {} with beanName: {}", clazz.getName(), beanName);
try {
// 使用工厂创建AI组件
NodeComponent aiComponent = aiComponentFactory.createAIComponent(clazz, beanName);
if (Objects.nonNull(aiComponent)) {
LOG.info("Successfully created AI component for interface: {}, replacing bean: {}",
clazz.getName(), beanName);
return aiComponent;
} else {
LOG.warn("Failed to create AI component for interface: {}, returning original bean",
clazz.getName());
return bean;
}
} catch (Exception e) {
LOG.error("Error creating AI component for interface: {}, beanName: {}",
clazz.getName(), beanName, e);
// 如果创建失败返回原始bean而不是抛出异常
return bean;
}
}
return bean;
}
@Override
public int getOrder() {
// 设置较高的优先级,确保在其他后置处理器之前执行
return Ordered.HIGHEST_PRECEDENCE + 100;
}
}

View File

@@ -0,0 +1,188 @@
package com.yomahub.liteflow.ai.proxy.handler;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.ai.annotation.AIComponent;
import com.yomahub.liteflow.ai.enums.AITypeEnum;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.exception.ProxyException;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import com.yomahub.liteflow.util.SerialsUtil;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.InvocationHandlerAdapter;
import net.bytebuddy.matcher.ElementMatcher;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.util.Objects;
/**
* AI组件处理器抽象基类
*
* @author 苍镜月
* @since TODO
*/
public abstract class AbstractAIComponentHandler<T extends Annotation> {
protected final LFLog LOG = LFLoggerManager.getLogger(this.getClass());
/**
* 获取对应的 AI 组件类型
*
* @return {@link AITypeEnum}
*/
public abstract AITypeEnum getAIType();
/**
* 获取支持的注解类型
*
* @return 注解Class
*/
public abstract Class<T> getSupportedAnnotationType();
/**
* 创建AI组件
*
* @param interfaceClass 接口类
* @param beanName bean名称
* @param aiComponent AI组件注解
* @return NodeComponent实例
*/
public NodeComponent createAIComponent(Class<?> interfaceClass, String beanName, AIComponent aiComponent) {
LOG.info("Creating AI component for interface: {}, beanName: {}, type: {}",
interfaceClass.getName(), beanName, getAIType());
// 解析AI注解
AIProxyWrapBean<T> wrapBean = parseAIAnnotations(interfaceClass, beanName, aiComponent);
if (Objects.isNull(wrapBean)) {
LOG.warn("Failed to parse AI annotations for interface: {}, beanName: {}",
interfaceClass.getName(), beanName);
return null;
}
// 创建代理组件
return createProxyComponent(wrapBean);
}
/**
* 解析AI注解信息
*
* @param interfaceClass 接口类
* @param beanName bean名称
* @param aiComponent AI组件注解
* @return 包装bean
*/
public AIProxyWrapBean<T> parseAIAnnotations(Class<?> interfaceClass, String beanName, AIComponent aiComponent) {
LOG.info("Parsing AI annotations for interface: {}, beanName: {}", interfaceClass.getName(), beanName);
T aiAnnotation = findAIAnnotation(interfaceClass);
// 如果没有找到 AI 注解,则记录警告并返回 null
if (Objects.isNull(aiAnnotation)) {
LOG.warn("No {} annotation found for interface: {}, beanName: {}",
getSupportedAnnotationType().getSimpleName(), interfaceClass.getName(), beanName);
return null;
}
return createWrapBean(aiComponent, aiAnnotation, interfaceClass, beanName);
}
/**
* 查找AI注解
*
* @param clazz 类
* @return AI注解
*/
protected T findAIAnnotation(Class<?> clazz) {
return clazz.getAnnotation(getSupportedAnnotationType());
}
/**
* 创建包装Bean
*
* @param aiComponent AI组件注解
* @param annotation 具体AI注解
* @param interfaceClass 接口类
* @param beanName bean名称
* @return 包装bean
*/
protected abstract AIProxyWrapBean<T> createWrapBean(AIComponent aiComponent, T annotation,
Class<?> interfaceClass, String beanName);
/**
* 创建代理组件
*
* @param wrapBean 包装bean
* @return NodeComponent实例
*/
private NodeComponent createProxyComponent(AIProxyWrapBean<T> wrapBean) {
AITypeEnum aiType = getAIType();
Class<? extends NodeComponent> nodeComponentClass = aiType.getComponentClass();
// 创建 ByteBuddy 代理
try {
NodeComponent nodeComponent = new ByteBuddy()
.subclass(nodeComponentClass)
.name(generateProxyClassName(wrapBean))
.implement(wrapBean.getInterfaceClass())
.method(getInterceptMethodName())
.intercept(InvocationHandlerAdapter.of(getInvocationHandler(wrapBean)))
.annotateType(wrapBean.getAiComponent(), wrapBean.getAnnotation())
.make()
.load(this.getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded()
.newInstance();
nodeComponent.setNodeId(wrapBean.getNodeId());
nodeComponent.setName(wrapBean.getNodeName());
LOG.info("Created AI component: {}, beanName: {}, type: {}",
nodeComponent.getNodeId(), wrapBean.getBeanName(), aiType);
return nodeComponent;
} catch (Exception e) {
throw new ProxyException(e);
}
}
/**
* 生成代理类名称
*
* @param wrapBean 包装bean
* @return 代理类名称
*/
private String generateProxyClassName(AIProxyWrapBean<T> wrapBean) {
return StrUtil.format("{}$ByteBuddy${}${}",
wrapBean.getInterfaceClass().getName(),
wrapBean.getAiComponent().nodeId(),
SerialsUtil.generateShortUUID());
}
/**
* 获取InvocationHandler
*
* @param wrapBean 包装bean
* @return InvocationHandler实例
*/
protected abstract InvocationHandler getInvocationHandler(AIProxyWrapBean<T> wrapBean);
/**
* 获取拦截方法名称
*
* @return 拦截方法名称
*/
protected abstract ElementMatcher<? super MethodDescription> getInterceptMethodName();
/**
* 判断是否支持指定的注解类型
*
* @param annotationType 注解类型
* @return true如果支持
*/
public boolean supports(Class<? extends Annotation> annotationType) {
return getSupportedAnnotationType().equals(annotationType);
}
}

View File

@@ -0,0 +1,50 @@
package com.yomahub.liteflow.ai.proxy.handler;
import com.yomahub.liteflow.ai.annotation.AIChat;
import com.yomahub.liteflow.ai.annotation.AIComponent;
import com.yomahub.liteflow.ai.enums.AITypeEnum;
import com.yomahub.liteflow.ai.proxy.invocation.ChatAIInvocationHandler;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.reflect.InvocationHandler;
/**
* 聊天组件处理器
* 具体策略实现
*
* @author 苍镜月
* @since TODO
*/
public class ChatComponentHandler extends AbstractAIComponentHandler<AIChat> {
private static final String INTERCEPT_METHOD_NAME = "process";
@Override
public AITypeEnum getAIType() {
return AITypeEnum.CHAT;
}
@Override
public Class<AIChat> getSupportedAnnotationType() {
return AIChat.class;
}
@Override
protected AIProxyWrapBean<AIChat> createWrapBean(AIComponent aiComponent, AIChat annotation,
Class<?> interfaceClass, String beanName) {
return new AIProxyWrapBean<>(aiComponent, annotation, interfaceClass, beanName);
}
@Override
protected InvocationHandler getInvocationHandler(AIProxyWrapBean<AIChat> wrapBean) {
return new ChatAIInvocationHandler(wrapBean);
}
@Override
protected ElementMatcher<? super MethodDescription> getInterceptMethodName() {
return ElementMatchers.named(INTERCEPT_METHOD_NAME);
}
}

View File

@@ -0,0 +1,50 @@
package com.yomahub.liteflow.ai.proxy.handler;
import com.yomahub.liteflow.ai.annotation.AIClassify;
import com.yomahub.liteflow.ai.annotation.AIComponent;
import com.yomahub.liteflow.ai.enums.AITypeEnum;
import com.yomahub.liteflow.ai.proxy.invocation.ClassifyAIInvocationHandler;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.reflect.InvocationHandler;
/**
* 分类组件处理器
* 具体策略实现
*
* @author 苍镜月
* @since TODO
*/
public class ClassifyComponentHandler extends AbstractAIComponentHandler<AIClassify> {
private static final String INTERCEPT_METHOD_NAME = "processSwitch";
@Override
public AITypeEnum getAIType() {
return AITypeEnum.CLASSIFY;
}
@Override
public Class<AIClassify> getSupportedAnnotationType() {
return AIClassify.class;
}
@Override
protected AIProxyWrapBean<AIClassify> createWrapBean(AIComponent aiComponent, AIClassify annotation,
Class<?> interfaceClass, String beanName) {
return new AIProxyWrapBean<>(aiComponent, annotation, interfaceClass, beanName);
}
@Override
protected InvocationHandler getInvocationHandler(AIProxyWrapBean<AIClassify> wrapBean) {
return new ClassifyAIInvocationHandler(wrapBean);
}
@Override
protected ElementMatcher<? super MethodDescription> getInterceptMethodName() {
return ElementMatchers.named(INTERCEPT_METHOD_NAME);
}
}

View File

@@ -0,0 +1,50 @@
package com.yomahub.liteflow.ai.proxy.handler;
import com.yomahub.liteflow.ai.annotation.AIComponent;
import com.yomahub.liteflow.ai.annotation.AIRetrieval;
import com.yomahub.liteflow.ai.enums.AITypeEnum;
import com.yomahub.liteflow.ai.proxy.invocation.RetrievalAIInvocationHandler;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.reflect.InvocationHandler;
/**
* 检索组件处理器
* 具体策略实现
*
* @author 苍镜月
* @since TODO
*/
public class RetrievalComponentHandler extends AbstractAIComponentHandler<AIRetrieval> {
private static final String INTERCEPT_METHOD_NAME = "process";
@Override
public AITypeEnum getAIType() {
return AITypeEnum.RETRIEVAL;
}
@Override
public Class<AIRetrieval> getSupportedAnnotationType() {
return AIRetrieval.class;
}
@Override
protected AIProxyWrapBean<AIRetrieval> createWrapBean(AIComponent aiComponent, AIRetrieval annotation,
Class<?> interfaceClass, String beanName) {
return new AIProxyWrapBean<>(aiComponent, annotation, interfaceClass, beanName);
}
@Override
protected InvocationHandler getInvocationHandler(AIProxyWrapBean<AIRetrieval> wrapBean) {
return new RetrievalAIInvocationHandler(wrapBean);
}
@Override
protected ElementMatcher<? super MethodDescription> getInterceptMethodName() {
return ElementMatchers.named(INTERCEPT_METHOD_NAME);
}
}

View File

@@ -0,0 +1,41 @@
package com.yomahub.liteflow.ai.proxy.invocation;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 抽象AI调用处理器
*
* @author 苍镜月
* @since TODO
*/
public abstract class AbstractAIInvocationHandler implements InvocationHandler {
private final LFLog LOG = LFLoggerManager.getLogger(this.getClass());
protected AIProxyWrapBean<?> wrapBean;
public AbstractAIInvocationHandler(AIProxyWrapBean<?> wrapBean) {
this.wrapBean = wrapBean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
return executeAIProcess((NodeComponent) proxy, args);
}
/**
* 执行AI节点处理逻辑
*
* @param nodeComponent AI节点组件
* @param args
* @return 处理结果
*/
protected abstract Object executeAIProcess(NodeComponent nodeComponent, Object[] args);
}

View File

@@ -0,0 +1,25 @@
package com.yomahub.liteflow.ai.proxy.invocation;
import com.yomahub.liteflow.ai.annotation.AIChat;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
import com.yomahub.liteflow.core.NodeComponent;
/**
* 聊天组件的调用处理器
*
* @author 苍镜月
* @since TODO
*/
public class ChatAIInvocationHandler extends AbstractAIInvocationHandler {
public ChatAIInvocationHandler(AIProxyWrapBean<AIChat> wrapBean) {
super(wrapBean);
}
@Override
protected Object executeAIProcess(NodeComponent nodeComponent, Object[] args) {
return null;
}
}

View File

@@ -0,0 +1,24 @@
package com.yomahub.liteflow.ai.proxy.invocation;
import com.yomahub.liteflow.ai.annotation.AIClassify;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
import com.yomahub.liteflow.core.NodeComponent;
/**
* 分类组件的调用处理器
*
* @author 苍镜月
* @since TODO
*/
public class ClassifyAIInvocationHandler extends AbstractAIInvocationHandler {
public ClassifyAIInvocationHandler(AIProxyWrapBean<AIClassify> wrapBean) {
super(wrapBean);
}
@Override
protected Object executeAIProcess(NodeComponent nodeComponent, Object[] args) {
return null;
}
}

View File

@@ -0,0 +1,24 @@
package com.yomahub.liteflow.ai.proxy.invocation;
import com.yomahub.liteflow.ai.annotation.AIRetrieval;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
import com.yomahub.liteflow.core.NodeComponent;
/**
* RAG组件的调用处理器
*
* @author 苍镜月
* @since TODO
*/
public class RetrievalAIInvocationHandler extends AbstractAIInvocationHandler {
public RetrievalAIInvocationHandler(AIProxyWrapBean<AIRetrieval> wrapBean) {
super(wrapBean);
}
@Override
protected Object executeAIProcess(NodeComponent nodeComponent, Object[] args) {
return null;
}
}

View File

@@ -0,0 +1,74 @@
package com.yomahub.liteflow.ai.proxy.wrap;
import com.yomahub.liteflow.ai.annotation.AIComponent;
import java.lang.annotation.Annotation;
/**
* TODO
*
* @author 苍镜月
* @since TODO
*/
public class AIProxyWrapBean<T extends Annotation> {
protected AIComponent aiComponent;
protected T annotation;
protected Class<?> interfaceClass;
protected String beanName;
public AIProxyWrapBean() {
}
public AIProxyWrapBean(AIComponent aiComponent, T annotation,
Class<?> interfaceClass, String beanName) {
this.aiComponent = aiComponent;
this.annotation = annotation;
this.interfaceClass = interfaceClass;
this.beanName = beanName;
}
public String getNodeId() {
return aiComponent.nodeId();
}
public String getNodeName() {
return aiComponent.nodeName();
}
public AIComponent getAiComponent() {
return aiComponent;
}
public T getAnnotation() {
return annotation;
}
public Class<?> getInterfaceClass() {
return interfaceClass;
}
public String getBeanName() {
return beanName;
}
public void setAiComponent(AIComponent aiComponent) {
this.aiComponent = aiComponent;
}
public void setAnnotation(T annotation) {
this.annotation = annotation;
}
public void setInterfaceClass(Class<?> interfaceClass) {
this.interfaceClass = interfaceClass;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}