尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Spring AOP ProxyFactory 源码深度解析:代理创建与通知链组装
1. 从一次线上问题说起为什么我要啃 ProxyFactory 源码前段时间排查一个线上问题某个业务方法上的自定义注解突然失效了日志里没有任何异常方法也正常执行就是增强逻辑没生效。当时第一反应是切面没注册上查了 Bean 定义、切点表达式、通知类型全都正常。最后把断点打在ProxyFactory的getProxy()方法上才发现问题出在代理对象的创建环节——目标类被另一个框架提前代理过一层导致我配置的切点匹配到了外层代理类而不是原始类。这个问题折腾了大半天也让我下定决心把 Spring AOP 最核心的ProxyFactory彻底梳理一遍。很多人学 Spring AOP上来就背Aspect、Pointcut、Around的用法能跑通 Demo 就觉得自己会了。但真到了生产环境遇到代理失效、增强顺序错乱、循环依赖、this调用不走代理这些坑光会写注解是远远不够的。ProxyFactory是 Spring AOP 里真正干活的角色它把切面配置翻译成代理对象是连接声明式 AOP 和底层字节码生成的桥梁。搞懂它你就能明白为什么有的 Bean 被 JDK 动态代理、有的被 CGLIB 代理、exposeProxy到底解决什么问题、多个通知是怎么串成一条调用链的。这篇文章我会从设计思路、核心字段、代理创建流程、通知链组装、常见问题排查几个维度把ProxyFactory拆开揉碎讲清楚适合已经用过 Spring AOP 但想深入源码的开发者也适合正在准备面试、想搞明白底层原理的朋友。2. ProxyFactory 的整体设计与选型思路2.1 它在 Spring AOP 体系里处于什么位置Spring AOP 的整个链路可以粗略分成三段切面解析、代理创建、方法调用。Aspect注解的解析由AnnotationAwareAspectJAutoProxyCreator这类后置处理器完成它负责把切面信息转换成Advisor集合而ProxyFactory处在中间那段接收目标对象和Advisor列表产出最终的代理对象方法调用阶段则由JdkDynamicAopProxy或CglibAopProxy里的拦截器链负责。你可以把ProxyFactory理解成一个代理工厂的调度中心。它本身不直接生成字节码而是根据配置决定用哪种代理策略然后把活派给具体的AopProxy实现。这种设计的好处是职责分离ProxyFactory管配置和决策AopProxy管子节码生成AdvisorChainFactory管通知链组装各司其职。从继承关系看ProxyFactory继承自ProxyCreatorSupport而ProxyCreatorSupport又持有AopProxyFactory默认是DefaultAopProxyFactory。这个AopProxyFactory才是真正决定用 JDK 还是 CGLIB的角色。理解这层关系很重要因为很多代理选型的问题答案都藏在DefaultAopProxyFactory的createAopProxy方法里。2.2 为什么要有 ProxyFactory 这层抽象有人会问Spring 直接调 JDK 的Proxy.newProxyInstance或者 CGLIB 的Enhancer不就行了为什么要多一层ProxyFactory核心原因是统一编程模型。JDK 动态代理和 CGLIB 的 API 差异很大前者基于接口需要InvocationHandler后者基于继承需要MethodInterceptor和CallbackFilter。如果业务代码直接依赖这两套 API切换代理方式时改动量巨大。ProxyFactory把两者的差异封装起来对外只暴露addAdvisor、setTarget、getProxy这几个统一方法屏蔽了底层实现细节。另一个原因是通知链的统一管理。无论用哪种代理方法调用时都需要按顺序执行多个通知前置、后置、环绕、异常、返回。ProxyFactory通过AdvisedSupport维护Advisor列表再由AdvisorChainFactory统一组装成MethodInterceptor链这样 JDK 和 CGLIB 两条路径可以复用同一套通知链逻辑。还有一个容易被忽略的点ProxyFactory支持运行时代理配置。你可以在创建代理之前动态添加、删除Advisor甚至替换目标对象。这种灵活性在框架集成场景里非常有用比如某些 ORM 框架需要在运行时根据实体类动态织入增强逻辑。2.3 核心字段与继承结构拆解ProxyFactory的字段大部分来自父类我挑几个最关键的说明字段/属性所在类作用targetSourceAdvisedSupport封装目标对象支持热替换、池化等高级用法advisorsAdvisedSupport通知器列表决定织入哪些增强逻辑interfacesAdvisedSupport代理需要实现的接口列表proxyTargetClassProxyConfig是否强制使用 CGLIB 代理exposeProxyProxyConfig是否把代理对象暴露到AopContextoptimizeProxyConfig是否对 CGLIB 代理做优化frozenAdvisedSupport冻结配置后不允许再修改通知链这里要特别提一下targetSource。很多人只知道setTarget(Object)其实它内部会包装成一个SingletonTargetSource。如果你需要每次调用都拿新对象可以用PrototypeTargetSource需要对象池就用PoolingTargetSource。TargetSource的设计让ProxyFactory的能力远超简单的静态代理。proxyTargetClass和optimize这两个布尔值经常被混淆。proxyTargetClasstrue表示强制走 CGLIBoptimizetrue表示对 CGLIB 生成的代理做优化比如使用更激进的字节码策略但它只在 CGLIB 路径下生效。实际项目里我一般只设proxyTargetClassoptimize很少动因为优化带来的收益有限反而可能引入兼容性问题。3. 代理创建的核心流程与实操要点3.1 getProxy 方法到底做了什么getProxy()是ProxyFactory最常用的入口它内部调用createAopProxy().getProxy()。整个流程可以拆成两大步决定代理策略和生成代理对象。第一步createAopProxy()会委托给AopProxyFactory默认实现是DefaultAopProxyFactory。它的createAopProxy方法逻辑大致如下// 伪代码展示核心判断逻辑 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class? targetClass config.getTargetClass(); if (targetClass null) { throw new AopConfigException(TargetSource cannot determine target class...); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); }这段逻辑有几个关键判断点我逐个解释isOptimize()或isProxyTargetClass()为 true说明用户明确要求用 CGLIB进入 CGLIB 分支。hasNoUserSuppliedProxyInterfaces()为 true说明没有指定任何接口JDK 动态代理无法工作它必须基于接口所以也只能走 CGLIB。目标类是接口或已经是代理类即使要求 CGLIB也退回 JDK 代理。因为接口本身无法被继承增强已经是代理类的话再 CGLIB 会出问题。第二步拿到AopProxy实例后调用getProxy()。JDK 路径会调Proxy.newProxyInstanceCGLIB 路径会配置Enhancer并生成子类。两条路径最终都会把AdvisedSupport里的通知链信息传进去供方法调用时使用。3.2 JDK 代理与 CGLIB 代理的选型实战选型这件事理论上一句话有接口用 JDK没接口用 CGLIB。但实际项目里要考虑的因素更多。先看一个我踩过的坑。某次我把proxyTargetClass设成 true想强制用 CGLIB结果目标类里有个final方法增强死活不生效。原因是 CGLIB 通过继承生成子类final方法无法被重写自然也就无法织入通知。这个坑在 JDK 代理里不存在因为 JDK 代理是基于接口的跟方法是不是 final 没关系。再看另一个场景。目标类实现了接口但接口方法签名和实现类不完全一致比如实现类多了一些 public 方法。如果用 JDK 代理代理对象只能调用接口里声明的方法实现类独有的方法调不到。这时候就得用 CGLIB让代理类继承实现类才能覆盖所有 public 方法。我把选型要点整理成一张表场景推荐策略原因目标类实现了接口且只需增强接口方法JDK 代理轻量、无第三方依赖、生成快目标类没有接口CGLIBJDK 代理无法工作需要增强实现类独有方法CGLIBJDK 代理只能看到接口方法目标方法被final修饰JDK 代理CGLIB 无法重写 final 方法目标类是final类JDK 代理CGLIB 无法继承 final 类对性能极度敏感、代理对象创建频繁JDK 代理CGLIB 生成字节码开销更大提示Spring Boot 2.x 之后默认proxyTargetClasstrue也就是默认走 CGLIB。这是为了支持Transactional标注在类上、以及避免接口注入问题。如果你的项目依赖 JDK 代理的某些特性记得显式配置spring.aop.proxy-target-classfalse。3.3 通知链是怎么组装出来的代理对象创建好之后方法调用时怎么知道该执行哪些通知这就要靠AdvisorChainFactory。ProxyFactory在创建AopProxy时会把AdvisedSupport传进去后者持有AdvisorChainFactory默认DefaultAdvisorChainFactory。当代理方法被调用时JdkDynamicAopProxy.invoke或CglibAopProxy的拦截器会调用AdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice把当前方法匹配的Advisor转换成MethodInterceptor列表。这个转换过程有几个细节值得注意切点匹配每个Advisor里的Pointcut会判断当前方法是否匹配不匹配的直接跳过。通知适配Advisor里的Advice会被AdvisorAdapter适配成MethodInterceptor。比如BeforeAdvice会被MethodBeforeAdviceAdapter包装。顺序排序多个Advisor会按照Ordered接口或Order注解排序决定通知的执行顺序。组装好的拦截器链会被缓存起来CachedIntrospectionResults类似机制避免每次调用都重新计算。这也是为什么 Spring AOP 在方法调用层面的性能损耗相对可控。3.4 exposeProxy 到底解决什么问题exposeProxy这个配置我第一次看到时完全不知道干嘛用的直到遇到同类方法调用不走代理的问题才明白。假设有个 Service 类方法 A 调用了同类的方法 B而方法 B 上标注了Transactional。直接调this.B()是不会走代理的因为this是原始对象不是代理对象事务自然不生效。解决办法之一就是开启exposeProxy然后通过AopContext.currentProxy()拿到当前代理对象再调用((Service) AopContext.currentProxy()).B()。开启方式很简单// 注解方式 EnableAspectJAutoProxy(exposeProxy true) // XML 方式 aop:aspectj-autoproxy expose-proxytrue/但这里有个坑AopContext底层用的是ThreadLocal如果方法调用跨线程子线程里拿不到代理对象。另外开启exposeProxy会带来轻微的性能开销因为每次调用都要往ThreadLocal里塞代理对象。所以我的建议是能用设计规避就用设计规避比如把方法 B 抽到另一个 Bean 里实在不行再开exposeProxy。4. 手写一个 ProxyFactory 实操案例4.1 场景设定与目标光看源码容易飘我写一个不依赖 Spring 容器的纯手工案例用ProxyFactory给一个普通对象织入日志和耗时统计。这样能最直观地看到ProxyFactory的每个 API 在干什么。场景有一个订单查询服务我想在不修改原代码的前提下给它的查询方法加上入参日志和耗时统计两个增强。4.2 代码实现与逐行注释先定义业务接口和实现public interface OrderService { String queryOrder(Long orderId); } public class OrderServiceImpl implements OrderService { Override public String queryOrder(Long orderId) { // 模拟业务耗时 try { Thread.sleep(50); } catch (InterruptedException e) { } return 订单- orderId; } }接着定义两个通知。这里用MethodInterceptor来自 AOP 联盟包因为它最灵活import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; // 日志通知 public class LogInterceptor implements MethodInterceptor { Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println([日志] 调用方法: invocation.getMethod().getName() , 参数: java.util.Arrays.toString(invocation.getArguments())); return invocation.proceed(); } } // 耗时通知 public class TimeInterceptor implements MethodInterceptor { Override public Object invoke(MethodInvocation invocation) throws Throwable { long start System.currentTimeMillis(); try { return invocation.proceed(); } finally { System.out.println([耗时] invocation.getMethod().getName() 执行了 (System.currentTimeMillis() - start) ms); } } }最后用ProxyFactory组装import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.aop.support.NameMatchMethodPointcut; public class Main { public static void main(String[] args) { // 1. 创建目标对象 OrderService target new OrderServiceImpl(); // 2. 创建 ProxyFactory设置目标和接口 ProxyFactory factory new ProxyFactory(); factory.setTarget(target); factory.setInterfaces(OrderService.class); // 3. 构造切点只匹配 queryOrder 方法 NameMatchMethodPointcut pointcut new NameMatchMethodPointcut(); pointcut.addMethodName(queryOrder); // 4. 组装 Advisor 并加入工厂 factory.addAdvisor(new DefaultPointcutAdvisor(pointcut, new LogInterceptor())); factory.addAdvisor(new DefaultPointcutAdvisor(pointcut, new TimeInterceptor())); // 5. 生成代理对象 OrderService proxy (OrderService) factory.getProxy(); // 6. 调用 String result proxy.queryOrder(1001L); System.out.println(返回结果: result); } }运行结果大致是[日志] 调用方法: queryOrder, 参数: [1001] [耗时] queryOrder 执行了 52 ms 返回结果: 订单-10014.3 关键参数与执行顺序验证上面代码里有几个点值得展开。第一setInterfaces的作用。如果不设置接口ProxyFactory会走 CGLIB 分支。这里显式设置了OrderService.class所以走的是 JDK 代理。你可以把这一行注释掉再跑一次会发现代理类变成了OrderServiceImpl的子类输出结果一样但底层机制完全不同。第二通知的执行顺序。我加了两个 Advisor日志在前、耗时在后。实际输出里日志先打印耗时后打印说明拦截器链是按添加顺序执行的。如果想让耗时通知包住日志通知把添加顺序反过来即可。这里涉及一个常见误区很多人以为Order能控制一切其实对于手动添加的 Advisor添加顺序才是决定因素Order只在自动扫描切面时起作用。第三NameMatchMethodPointcut的匹配规则。它按方法名精确匹配addMethodName(queryOrder)只匹配这个名字。如果想用通配符可以用JdkRegexpMethodPointcut或者AspectJExpressionPointcut。后者支持完整的 AspectJ 切点表达式功能最强但解析开销也最大。注意手动addAdvisor时如果 Advisor 没有实现Ordered接口排序完全依赖添加顺序。生产环境里如果通知顺序很重要建议给 Advisor 显式实现Ordered或继承AbstractPointcutAdvisor并设置 order 值。4.4 从手工案例反推 Spring 自动代理手工案例跑通后再回头看 Spring 的自动代理就清晰多了。AnnotationAwareAspectJAutoProxyCreator本质上就是在 Bean 初始化后帮我们做了上面那些手工步骤解析切面得到 Advisor 列表、创建 ProxyFactory、设置 target 和 interfaces、添加 Advisor、调用 getProxy、把代理对象放回容器。区别在于自动代理会处理更多边界情况比如多个切面的排序、Order的解析、循环依赖的处理、exposeProxy的自动设置等。但核心骨架跟我们的手工案例一模一样。理解了手工流程再看自动代理的源码就不会迷路。5. 常见问题与排查技巧实录5.1 增强不生效的排查清单增强不生效是最高频的问题我整理了一个排查顺序基本能覆盖 90% 的场景排查项检查方法常见原因切点是否匹配打印切点表达式用AopUtils.canApply验证表达式写错、包路径不对代理是否创建打印AopUtils.isAopProxy(bean)目标类没被后置处理器扫描到代理类型是否正确打印AopUtils.isJdkDynamicProxy/isCglibProxy接口缺失或proxyTargetClass配置冲突方法是否可被增强检查是否final、static、privateCGLIB 无法重写 final 方法调用是否走代理检查是否this调用同类内部调用绕过代理通知是否注册打印Advised.getAdvisors()切面类没加Aspect或没被扫描这个清单我实际用过很多次按顺序查下来基本都能定位。其中同类内部调用和final 方法是最隐蔽的两个坑因为它们不会报错只是静默失效。5.2 循环依赖下代理创建的坑Spring 解决循环依赖靠的是三级缓存其中第二级缓存earlySingletonObjects存的就是提前暴露的代理对象。这里有个细节如果 A 依赖 BB 依赖 A且 A 需要被代理那么 A 的代理对象会在 A 完全初始化之前就被创建出来。这个机制带来的问题是如果 A 的代理配置依赖于某个还没初始化的 Bean就可能拿到不完整的配置。我遇到过一次切面里注入了另一个 Bean而那个 Bean 又依赖被代理的目标对象结果切面里的依赖是 null。解决办法是给切面依赖加Lazy延迟到真正调用时再解析。另一个相关配置是allowCircularReferences。Spring Boot 2.6 之后默认禁止循环依赖如果你的项目升级后突然报循环依赖错误要么重构代码消除循环要么显式开启这个开关。但我的建议是优先重构循环依赖本身就是设计问题。5.3 代理对象类型转换异常ClassCastException在 AOP 场景里也很常见典型报错是cannot be cast to XXX。原因通常是目标类实现了接口但代码里试图把代理对象强转成实现类。比如OrderService proxy (OrderService) factory.getProxy(); OrderServiceImpl impl (OrderServiceImpl) proxy; // 这里会抛异常如果走的是 JDK 代理代理对象只实现了OrderService接口跟OrderServiceImpl没有继承关系强转必然失败。解决办法有两个要么强制用 CGLIBsetProxyTargetClass(true)要么在代码里面向接口编程不要强转实现类。这个坑在依赖注入时也会出现。如果你用Autowired注入实现类类型而代理是 JDK 代理就会注入失败。Spring 4.3 之后支持按接口注入所以最佳实践是面向接口注入从根源上避免这个问题。5.4 性能相关的经验数据关于 JDK 代理和 CGLIB 的性能网上说法很多我分享几个实测数据仅代表我自己的测试环境不同 JDK 版本和场景会有差异代理对象创建JDK 代理平均比 CGLIB 快 3 到 5 倍。因为 CGLIB 需要生成字节码并加载类开销明显更大。方法调用在 JDK 8 之后两者差距已经很小JDK 代理甚至在某些场景下更快。早期JDK 代理调用慢的说法已经不太成立。内存占用CGLIB 生成的代理类会占用 Metaspace如果代理类数量巨大比如成千上万个不同的目标类Metaspace 压力会比较明显。基于这些数据我的建议是不要为了性能刻意选 JDK 代理优先根据功能需求选型。如果功能上两者都满足再考虑性能。大多数业务系统里AOP 调用的性能损耗相对于业务逻辑本身可以忽略不计。提示如果确实遇到 AOP 性能瓶颈先别急着换代理方式优先检查切点表达式是否过于宽泛。一个execution(* *(..))的切点会匹配所有方法导致每次调用都要走完整的匹配流程这才是真正的性能杀手。6. 几个容易被忽略的高级用法6.1 用 TargetSource 实现动态目标切换前面提过TargetSource这里展开讲一个实用场景灰度发布。假设你有一个服务需要根据请求头里的用户标识把请求路由到不同版本的目标对象上。用TargetSource可以优雅实现public class GrayTargetSource implements TargetSource { private final Object stableVersion; private final Object grayVersion; public GrayTargetSource(Object stableVersion, Object grayVersion) { this.stableVersion stableVersion; this.grayVersion grayVersion; } Override public Class? getTargetClass() { return stableVersion.getClass(); } Override public boolean isStatic() { return false; } Override public Object getTarget() { // 根据上下文决定返回哪个版本 return isGrayUser() ? grayVersion : stableVersion; } Override public void releaseTarget(Object target) { // 无需释放 } private boolean isGrayUser() { // 实际场景从 ThreadLocal 或请求上下文获取 return false; } }然后把它设置到ProxyFactoryfactory.setTargetSource(new GrayTargetSource(stableObj, grayObj));这样每次方法调用时TargetSource.getTarget()都会被调用实现动态路由。这个用法比在业务代码里写 if-else 优雅得多而且对业务代码零侵入。6.2 冻结配置防止运行时篡改AdvisedSupport提供了setFrozen(true)方法冻结之后任何修改 Advisor 的操作都会抛AopConfigException。这个功能在框架开发里很有用可以防止下游代码意外修改代理配置。factory.setFrozen(true); factory.addAdvisor(...); // 这里会抛异常我一般只在编写基础框架时用这个业务代码里很少需要。但如果你在做一个被多方复用的组件冻结配置能避免很多莫名其妙增强失效的问题。6.3 用 Introduction 给对象动态添加接口Spring AOP 除了方法增强还支持Introduction引入可以在运行时给对象添加新的接口实现。这个功能用ProxyFactory实现起来很直接// 定义一个要引入的接口和实现 public interface Auditable { void audit(); } public class AuditableImpl implements Auditable { Override public void audit() { System.out.println(执行审计逻辑); } } // 通过 IntroductionAdvisor 引入 DefaultIntroductionAdvisor advisor new DefaultIntroductionAdvisor(new AuditableImpl()); factory.addAdvisor(advisor); // 代理对象现在可以强转成 Auditable Auditable auditable (Auditable) factory.getProxy(); auditable.audit();这个用法在需要给一批对象统一添加某个能力比如审计、标记时特别方便比继承或组合更灵活。不过要注意Introduction只能添加接口不能添加类因为 Java 是单继承的。7. 我个人的一些实操体会ProxyFactory这个类我前前后后读了好几遍每次都有新收获。最开始只关注getProxy()怎么用后来慢慢理解了AdvisedSupport的配置管理、AopProxyFactory的策略选择、AdvisorChainFactory的链式组装才算真正把 Spring AOP 的骨架摸清楚。如果你也想深入这块我的建议是先跑通手工案例再对照自动代理源码。手工案例能让你看清每个 API 的职责自动代理源码能让你理解 Spring 是怎么把这些 API 串起来的。两者结合比单纯读源码效率高得多。另外遇到 AOP 相关的问题别急着搜答案先按切点匹配、代理创建、方法调用三段式排查。大部分问题都能通过打印AopUtils.isAopProxy、Advised.getAdvisors()、AopUtils.getTargetClass这几个信息定位到。这几个方法我几乎每次排查都会用到建议你也记下来。最后分享一个小技巧调试 AOP 问题时可以在DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法上打断点看看当前方法到底匹配到了哪些拦截器。这个方法能直接告诉你为什么这个通知没执行比看日志快得多。
RELATED

相关推荐

P-MOS管三合一电源入口保护电路:防反接、缓启动、过压保护详解

P-MOS管三合一电源入口保护电路:防反接、缓启动、过压保护详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/13 4:27:15
豆包图片批量下载不求人:脚本管理器+原图提取器全攻略

豆包图片批量下载不求人:脚本管理器+原图提取器全攻略

直接说结论:批量下载这件事,最稳的方案不是截图,也不是一个个右键另存为,而是用一个浏览器端的脚本扩展配合一段“原图地址提取器”,把豆包图片页面上所有高清大图的直链全部抓出来,然后自动批量下载。整个…

📅 2026/10/13 4:27:15
前端组件库调试痛点看 yalc:用快照与显式推送替代 npm link

前端组件库调试痛点看 yalc:用快照与显式推送替代 npm link

如果你维护过跨业务项目复用的前端组件库,大概率经历过这种尴尬:在某业务项目里发现了组件的样式问题,改完组件库代码要重新构建、再手动把产物拷贝进目标项目的node_modules里反复验证,来回几次就烦了。我一开始也是这么干的&…

📅 2026/10/13 4:22:15
MORE NEWS

更多资讯

📰

STM32 CAN总线实战:从协议原理到配置收发

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

多模态Agent如何规划UI测试路径:从感知融合到动态决策的工程实践

1. 多模态 Agent 做 UI 测试,到底难在哪UI 测试这件事,做过的人都懂——写起来不难,维护起来要命。一个按钮挪了位置、一个弹窗改了文案、一个加载动画多转了半秒,传统基于选择器的自动化脚本就可能集体飘红。而多模态 Agent 的出…

📰

多步任务总在细节崩盘?用技能编排让智能体真正稳定

最初让我意识到"工具调用"和"技能编排"是两码事的,是一次很普通的实测:我在一个demo里给智能体接入了邮件发送、日历查询和文档搜索三个工具,模型只凭从三个工具拿到的零散结果,接连搞砸了一个"帮用户确…

📰

Agent技能系统实战:为大模型装上可插拔的“手”和“脚”

这两年但凡碰过AI应用开发的,应该都绕不开一个词——Agent(智能体)。模型本身只是“脑子”,真正让它干活的,是那一套技能系统,也就是项目标题里说的“agent-skills”。不少团队早期做Agent产品时都有一个共…

📰

AnyPS5:跨平台文件处理与格式转换的轻量化解决方案

1. 项目缘起与核心定位AnyPS5 这个名字第一次出现在我视野里的时候,我正被一堆跨平台文件处理的需求折腾得够呛。团队里有人用 Windows 做设计,有人用 macOS 写代码,还有人习惯在 Linux 环境下跑批处理脚本,每次交付物在三个系统之…

📰

UCINET数据导入实战:格式规范、Excel整理与高频排错

1. 先搞清楚UCINET到底在等什么数据很多人在UCINET上栽的第一个跟头,不是不会跑算法,而是数据根本喂不进去。明明Excel里填得工工整整,一点Import却报错,或者导进去之后变成一团乱麻,节点对不上、值全错位。这些问题的…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬