新闻详情

新闻详情

首页 / 资讯中心 / 详情

Spring Boot 4升级实战:Java 21虚拟线程与AOT编译优化冷启动

发布时间:2026/9/26 13:08:33来源:尧图网络
Spring Boot 4升级实战:Java 21虚拟线程与AOT编译优化冷启动
年底部门做技术规划我在几十个存量服务里摸底了一圈发现大部分还在 Java 8 和 Spring Boot 2.x 上跑只有两个边缘服务试探着上了 Java 21。这种情况下谈“Spring Boot 4 最新适配”听起来像在说下一代产品。但真等 Spring Boot 4 发版再动手成本会高得多。我从 Milestone 版本开始适配了一个真实服务把 Java 21 基线、虚拟线程、AOT 编译这三件事串起来做了一遍冷启动从原来的 1.2 秒压到了 90ms 左右。这篇指南就是这轮适配的完整记录包括我踩的坑、压测数据、构建脚本以及那些官方文档里不会写清楚的细节。内容适合三类人准备把存量工程升级到 Spring Boot 4 的团队想用虚拟线程优化高并发场景的开发者以及在 Serverless、边缘节点这类对冷启动极度敏感的环境中部署 Spring 服务的人。1. Spring Boot 4 的升级清单先想清楚你要搬什么1.1 为什么 Spring Boot 4 值得关注Spring Boot 3.x 的技术基线是 Spring Framework 6 和 Java 17当时引入 Jakarta EE 9 已经让一批老工程折腾了一阵子。Spring Boot 4 对应 Spring Framework 7最核心的变化不是某个注解改了而是整个框架对“现代 JDK 特性”的支持从“可用”变成了“默认”。Java 21 有几个特性直接改变服务端开发方式。虚拟线程Project Loom 的正式落地JEP 444解决了高并发成本问题record pattern 和 switch 模式匹配让编码更简洁而 JDK 自带的 ZGC 则在低延迟 GC 上给了更多选择。但这些能力如果没有框架层面的适配靠业务代码自己折腾收益会大打折扣。Spring Boot 4 做的事情就是把虚拟线程、AOT 编译这些能力揉进了框架默认行为里。另一个背景是冷启动。现在的部署形态早就不是“一次启动跑几个月”了K8s 弹性扩容、Serverless 按需拉起、发布时的滚动重启每次启动都是不可用时间。对一个大型 Spring 应用来说JIT 模式下 1-2 秒启动只能算正常但放到 100ms 这个量级就必须换一条技术路径也就是 AOT 编译。1.2 升级前要确认的基线我适配的工程是一个内部订单查询服务Spring Boot 2.7 Java 8 起步。先明确一下升级到 Spring Boot 4 需要具备哪些前置条件JDK 版本至少 Java 17强烈建议直接用 Java 21 LTS。标题里的“Java 21”不是噱头虚拟线程和后续 AOT 工具链在 21 上最稳。构建工具Maven 3.9 或 Gradle 8.5旧版本对 Java 21 的编译参数解析存在问题。依赖梳理Spring Cloud、MyBatis、Redisson、Flyway 这些三方库需要确认是否已适配 Spring Boot 4。这一步最费时间后面会专门说。工程规范如果有自定义 Starter 或者用了 spring.factories 扩展机制这次改动会比较大。如果工程还在 Java 8 上不建议直接跳。先做一次 Java 17 Spring Boot 3 的过渡把老 API 和依赖问题清完再进入 Spring Boot 4 的适配跨度过大容易让排查范围失控。1.3 几个“不那么明显”的破坏性变化官方迁移指南通常会列出主要变更但实际适配时最耗时间的是那些文档里一笔带过、启动时才暴露的问题。配置属性绑定更严格是第一个坑。Spring Boot 4 对ConfigurationProperties的类型校验和未知属性检查更严格以前“多个前缀拼写错误但不影响启动”的情况现在直接报错。我们有一个自定义配置项app.retry.max-attempts写成了max-attemts在 2.7 上毫无感知升级后启动失败。自动配置注册机制变了。老的spring.factories中EnableAutoConfiguration条目已经被新的AutoConfiguration.imports文件取代。如果自己封装过 Starter需要删掉spring.factories改用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports声明自动配置类。Actuator 端点和安全默认值也有调整部分端点默认不再暴露健康检查的返回结构变化会影响到依赖它的监控系统。这类问题通常在升级后的联调阶段才暴露但对没有专门测试环境的团队来说会非常影响上线计划。2. 环境与构建适配先解决“编译不过”的问题2.1 JDK 21 安装与“源发行版 21 需要目标发行版 21”警告很多人在升级 JDK 后第一个遇到的报错就是编译时提示java: 警告: 源发行版 21 需要目标发行版 21这个警告的本质是javac的-source和-target参数不一致。Java 21 的编译器要求如果指定源码版本为 21目标字节码版本也必须至少是 21。常见场景是 IDEA 里 Project Structure 配了 Java 21但 pom.xml 里还写着maven.compiler.source1.8、maven.compiler.target17之类的组合。正确的做法是在 Maven 里用release统一控制它同时设置-source和-target并且会校验 JDK 内置 API 的可用性避免你用了 Java 21 的 API 却声明 target 是 17 的情况。properties java.version21/java.version maven.compiler.release21/maven.compiler.release /properties如果用 Gradle在build.gradle里这样设置java { toolchain { languageVersion JavaLanguageVersion.of(21) } }另一个容易忽略的点如果项目里既有 Maven 又有 IDE 自带的编译器配置一定要以构建脚本为准。IDEA 的 Project Structure 配置会写入.idea目录不会进 Git团队其他人拉代码后还是编译失败。我习惯在 CI 里第一步就跑mvn clean compile让构建器直接把问题暴露出来。2.2 构建脚本中的 Spring Boot 4 适配Maven 工程最直接的方式是修改 parentparent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version4.0.0-M1/version relativePath/ /parent这里提醒一下我当时用的是 Milestone 版本API 在正式版出来前可能还有调整。如果你们公司对版本敏感可以等 GA 版再动适配思路是一致的。spring-boot-maven-plugin的版本会自动跟随 parent但 AOT 相关功能需要在插件里显式配置。Spring Boot 4 里 AOT 处理分离出了一些新的 goal不再是 Spring Boot 3.x 里那样“藏在 native profile 里”。我后面第 4 章会给出完整配置。Gradle 用户需要改build.gradleplugins { id java id org.springframework.boot version 4.0.0-M1 id io.spring.dependency-management version 1.1.7 }2.3 三方库兼容矩阵按照我的经验升级到 Spring Boot 4 最耗时的环节不是框架本身而是三方库的适配状态。我这次梳理后的兼容情况如下组件原版本适配情况说明Spring Cloud2021.0.x需升级到对应新版本旧版依赖的自动配置类已被移除MyBatis3.5.x基本兼容动态代理在 AOT 下需额外配置Redisson3.27需要升级旧版对 Java 21 的虚拟线程支持不完整Flyway9.x需升级到 10旧版解析逻辑在 Java 21 下有兼容问题Fastjson22.0.x基本兼容反射 API 调用需要适配Lombok1.18.30需升级旧版无法处理 JDK 21 新语法我的建议是不要一上来就全量升级。先创建一个空白的 Spring Boot 4 工程把你的接口和依赖逐步引入每引入一个跑一次测试定位问题会快很多。3. 虚拟线程接入从“线程池排队”到“并发资源不限量”3.1 平台线程 vs 虚拟线程为什么并发一高就挂说虚拟线程之前先复习一下为什么传统 web 服务在高并发下容易挂。Tomcat 默认的连接池是 200 个线程每个平台线程对应一个内核线程默认栈大小 1MB。当 500 个请求同时进来其中 200 个在线程上执行剩下 300 个在队列里等待。问题在于大多数业务请求都在等 IO。查数据库、调下游 HTTP 接口、读 Redis这些操作基本都是阻塞的线程在等待期间不能做别的事。200 个线程很快被全部占住后续请求只能排队延迟从几十毫秒涨到几秒吞吐量却上不去。虚拟线程的逻辑完全不同。虚拟线程是 JVM 管理的对象不直接绑定内核线程阻塞在 IO 上时会被挂起释放底层的载体线程carrier thread去执行其他虚拟线程。一个 Java 进程里可以创建几十万个虚拟线程内存开销远小于平台线程。我用一个生活类比解释平台线程模型相当于银行只开了 200 个柜台每个客户进来必须占一个柜台直到办完业务窗口满了就在大厅排队。虚拟线程模型相当于大厅里有一个智能叫号系统客户排队时不需要占柜台柜台前面只保留正在办理的那一小批人一个柜台可以服务海量客户。3.2 Spring Boot 3.5 vs Spring Boot 4虚拟线程开关的变化在 Spring Boot 3.2 开始官方提供了虚拟线程的接入支持但需要手动配置。到了 3.5用 Java 21 启用虚拟线程的路径已经很清晰主要两步spring.threads.virtual.enabledtrue同时还需要一个自定义的TomcatProtocolHandlerCustomizer把 Tomcat 的线程协议处理器切换成虚拟线程版本。Spring Boot 4 里这块顺滑了很多。我实测的版本中开启虚拟线程不再需要自定义容器回调只需要保留配置项即可spring.threads.virtual.enabledtrue如果默认状态下你用的是 reactive 模式WebFlux虚拟线程更多作用于业务侧的自定义线程池两种形态要区分。在传统 Servlet 技术栈上这个配置直接就接管了 Tomcat 的工作线程池。判断虚拟线程是否真正生效可以用一个最简单的方法在接口里打印当前线程信息。GetMapping(/thread-info) public MapString, String threadInfo() { Thread t Thread.currentThread(); return Map.of( name, t.toString(), isVirtual, String.valueOf(t.isVirtual()) ); }如果看到线程名类似http-nio-8080-exec-1说明还是平台线程如果看到带#字样的虚拟线程名且isVirtual返回 true说明已经生效。3.3 代码适配三个最容易出问题的地方配置开关打开只是第一步业务代码里的线程模型需要对应调整否则收益会打折扣甚至引入新问题。第一个坑是自定义线程池。很多老工程会用Executors.newFixedThreadPool(50)包装业务任务虚拟线程环境下这种写法就浪费了。改成虚拟线程工厂ExecutorService executor Executors.newVirtualThreadPerTaskExecutor();它的语义是每个任务创建一个新的虚拟线程任务结束虚拟线程即销毁没有“共享池排队”的概念。适用于大部分短任务和 IO 密集型任务。长任务、CPU 密集型任务则要看情况不能让虚拟线程无限量堆积。第二个坑是synchronized和 pinning 问题。虚拟线程在synchronized代码块里发生阻塞时不能主动释放载体线程只能“钉住”在载体线程上。如果大量虚拟线程同时在synchronized里做 IO就退化成平台线程模型失去虚拟线程的意义。我们代码里有一个老旧的缓存加载方法用synchronized保护整个远程调用过程。适配后我改成了ReentrantLock远程调用放在锁外只保护状态更新部分。压测数据从每秒 3000 涨到了 12000效果非常明显。第三个坑是 ThreadLocal 与虚拟线程的组合。虚拟线程数量可能非常庞大ThreadLocal 里如果存大对象或者有线程关联的清理逻辑资源释放颗粒度会变得很差。建议优先选择把上下文信息放入方法参数或者用ScopedValueJava 21 预览特性这类一次性绑定值的方案。3.4 压测一组直观的对比数据我在一个 demo 服务上做了简单的对比压测。服务逻辑是模拟真实业务每个请求 sleep 100ms代表一次下游 IO 等待。压测工具用wrk并发 500时长 30 秒。运行模式吞吐量TPSP99 延迟Spring Boot 3.5 Tomcat 默认 200 线程约 1980245msSpring Boot 3.5 手动配置虚拟线程约 476062msSpring Boot 4 虚拟线程约 490058ms第一行的问题很直观500 并发进来200 个线程全被阻塞剩余请求排队延迟暴涨。后面两行的吞吐量提升主要来自“阻塞不占线程”200 个载体线程已经能满足远高于 500 的并发请求。这里要强调一点虚拟线程解决的是“等待 IO”时的资源占用它不会让 CPU 跑得更快也不意味着可以无限放大数据库连接数。数据库连接池、下游 HTTP 连接池、Redis 连接池连接数还是受限于资源本身的容量压测时别急着把这些池调大。4. AOT 编译把冷启动从秒级压到百毫秒级的路径4.1 JIT 应用为什么启动慢JVM 应用启动要经历类加载、字节码验证、解释执行随后 JIT 编译器把热点方法编译成机器码。对一个类路径上有几百 MB jar、加载上万个类的 Spring 应用来说1-2 秒启动是常态。更麻烦的是JIT 编译是“运行中逐步发生”的服务刚启动时大量方法还在解释执行第一次请求往往最慢。这决定了纯 JIT 模式很难把冷启动压到百毫秒级。AOT 编译的思路是在构建期就把字节码编译成机器码或者至少把“反射、代理、配置绑定”这些运行期开销提前处理完让启动时剩下的工作变得非常轻量。4.2 GraalVM Native Image 与 Spring AOT 的配合标题里的 AOT 编译其实包含两个层面。一是 GraalVM 的native-image它把 JVM 字节码静态编译成独立可执行文件不再需要 JVM 运行时直接以机器码执行启动和内存占用都能大幅优化。二是 Spring Boot 的 AOT 引擎它在构建期分析 Spring 容器处理掉框架运行期靠反射才能完成的部分再配合native-image生成可执行文件。两者配合的关键是解决反射和动态代理问题。JVM 模式可以随时随地用Class.forName、动态生成代理类Native Image 不行——它需要在构建期就确定哪些类会被反射哪些代理要生成。Spring AOT 引擎做的就是让框架层面这些机制在构建期运行把结果固化下来不再依赖运行期扫描。4.3 实战构建步骤从零到 Native 可执行文件前置条件是安装 GraalVM 的 JDK 21 版本。用 SDKMAN 安装sdk install java 21.0.2-graal然后设置环境变量export JAVA_HOME~/.sdkman/candidates/java/21.0.2-graal export PATH$JAVA_HOME/bin:$PATHMaven 工程在 pom 里增加 native profileprofile idnative/id build plugins plugin groupIdorg.graalvm.buildtools/groupId artifactIdnative-maven-plugin/artifactId version0.10.4/version extensionstrue/extensions configuration buildArgs buildArg-H:ReportExceptionStackTraces/buildArg /buildArgs /configuration /plugin /plugins /build /profile构建命令很简单mvn -Pnative native:compile构建产物在target/目录下是一个不依赖 JRE 的可执行文件。我实测一个包含 Web、MyBatis、Redis 的工程构建产物 68MB启动时间测试如下time ./target/order-service输出结果大致是Started DemoApplication in 0.089 seconds real 0m0.092s这是我在本地 Mac 上的数据换到 Linux 容器里也基本在 100ms 上下。对比 JVM 模式 1.2 秒的启动时间提升了一个数量级。4.4 各种运行模式的实测数据与“100ms 内”的实现路径我把同一个服务用不同模式分别跑了一遍数据如下运行模式启动时间常驻内存可执行文件/包大小JVM 模式Spring Boot 2.7 Java 81.24s约 320MB28MBJVM 模式Spring Boot 4 Java 211.18s约 280MB24MBJVM 虚拟线程Spring Boot 41.16s约 275MB24MBNative ImageSpring Boot 492ms约 85MB68MBNative Image 虚拟线程95ms约 80MB68MB一个有趣的现象是 Native 模式里虚拟线程对启动时间的影响不大因为 Native Image 本身的启动已经足够快。但虚拟线程还是保留了高并发能力上的优势。要想稳定压进 100ms 内除了使用 Native Image还有几个细节要处理关闭不必要的自动配置。用spring.autoconfigure.exclude排除掉不需要的模块比如没有用到 JPA 就把 JPA 自动配置排除能减少构建期和运行期的工作量。精简 Bean 范围。把SpringBootApplication的扫描范围限制在实际包路径下不要用根包扫描。使用ConstructorBinding风格的ConfigurationProperties减少反射绑定开销。监听端口提前绑定。如果应用要在完全启动后才监听端口可以配置server.port0让它更快完成绑定或者自定义WebServerFactoryCustomizer提前初始化连接器。一条很实用的技巧衡量冷启动不要只看“Started Application”日志时间要以“端口可提供服务”为准。可以用一个循环探测脚本for i in $(seq 1 100); do if curl -s -o /dev/null -w %{http_code} http://localhost:8080/actuator/health | grep -q 200; then echo READY at ${i}0ms break fi sleep 0.1 done5. AOT 适配中的坑反射、资源和构建环境5.1 反射与动态代理最经典的 Native 拦路虎我第一次把包含 MyBatis 的服务用 Native Image 构建时启动直接报错java.lang.ClassNotFoundException: com.example.mapper.UserMapper原因很典型MyBatis 的 Mapper 是通过动态代理生成的Native Image 的可达性分析在构建期无法理解“运行期才会被加载的 Mapper 接口”因此没有把这些类包含进可执行文件。解决这类问题标准做法是补充反射配置。可以用 GraalVM 的reflect-config.json也可以在代码上用注解声明。Spring Boot 4 提供了RegisterReflectionForBinding可以写在配置类或启动类上例如SpringBootApplication RegisterReflectionForBinding( classes { UserMapper.class, OrderQueryRequest.class } ) public class DemoApplication { // ... }这个注解会让 AOT 引擎在构建期把这些类的反射元数据注册进去把它当作“运行时确实会反射访问”的类处理。效果等同于手写 reflect-config.json但更好维护。Jackson 序列化也有类似问题。如果反序列化用了一个泛型类型构建期分析不到运行时会报InvalidDefinitionException。常见解法是在ObjectMapper的构造过程里显式注册所有用到的类型或者同样加上RegisterReflectionForBinding。这类坑的规律是凡是“运行期通过字符串加载类、通过反射构造对象、通过动态代理生成实现”的机制在 Native 下都要显式声明。排查时我总是先搜代码里这些关键词Class.forName、Proxy.newProxyInstance、ObjectMapper.readValue、getDeclaredMethod。5.2 资源文件与外部化配置另一个容易出问题的是资源文件。JVM 模式下classpath:下的资源文件随 jar 打包随手getResourceAsStream就能读。Native Image 不会默认打包所有资源需要指定。例如业务里有一段模板文件templates/sms.tpl构建后运行时竟然找不到。解决方法是在resource-config.json中声明{ resources: { includes: [ { pattern: templates/.*\\.tpl } ] } }Spring Boot 的配置外部化机制也有影响。默认情况下application.yml会被打进可执行文件但--spring.config.location指向的外部文件仍然可以正常读取前提是文件确实存在。不过动态加载 classpath 外 jar 包的机制在 Native Image 下是不支持的这类功能如果用得多不建议切 Native。5.3 构建环境为什么本地成功但 CI 失败本地构建 Native 成功后我在 CI 里又踩了一脚。CI 用的是普通 Maven 容器镜像没有装 native 工具链构建时直接报error: Unable to locate gccNative Image 在 Linux 上需要 gcc、glibc-devel、zlib-devel 等系统组件。最稳妥的方案是直接用官方提供的构建镜像FROM ghcr.io/graalvm/graalvm-ce:latest AS builder RUN gu install native-image COPY . /build WORKDIR /build RUN mvn -Pnative native:compile FROM alpine:latest COPY --frombuilder /build/target/order-service /app/order-service RUN apk add --no-cache libstdc EXPOSE 8080 ENTRYPOINT [/app/order-service]注意整个构建过程会消耗大量内存Native Image 官方建议至少 8GB 堆内存。如果 CI 节点内存小构建会被 OOM 打断。我一开始用 4GB 的配置构建失败调成 10GB 才通过。这个先在本地验证再上 CI否则排查问题会比较痛苦。6. 整体升级路线从 Spring Boot 3.5 平滑过渡到 46.1 分阶段推进的路线图依赖和线上情况允许的话我建议按四个阶段走不要一次性把三件事全做完。第一个阶段Java 21 Spring Boot 3.5 虚拟线程。这个组合风险最低Spring Boot 3.5 对 Java 21 已经完全适配虚拟线程的接入方式也相对成熟。先把吞吐量和延迟的收益拿到手同时检验三方库在 Java 21 下有没有隐藏问题。第二个阶段升级到 Spring Boot 4逐项解决破坏性变更。重点验证配置属性绑定、自动配置注册、starter 依赖调整这三块。此时工程还跑在 JVM 模式回滚容易调试方便。第三个阶段选择合适服务做 AOT/Native 试点。优先选短生命周期、高并发、无大量动态类加载的服务。把它构建、部署、监控跑通。第四个阶段容器镜像、CI/CD 发布流程适配 Native 产物逐步扩大范围。这个顺序的核心逻辑是每个阶段都有清晰可验证的收益且每一步失败都能及时回退不会把团队逼到必须“一步到位”的墙角。6.2 适合 Native 的服务类型不是所有服务都适合AOT/Native 模式在冷启动和内存上的优势明显但也有明显代价构建时间变长、反射配置维护成本高、某些动态能力受限。我的判断标准很简单适合切 Native 的服务有这些特征生命周期短每次请求都是新进程的 Serverless 函数、单实例并发高把线程资源省下来给业务、内存预算紧Native 模式下内存可以降一半以上、启动频率高弹性扩容频繁。不适合切 Native 的服务有这些特征依赖动态类加载、大量反射、RPC 运行期做了大量字节码增强、通过配置文件经常变数据源或动态加载插件。我内部有一个“性价比评估”的公式冷启动收益 × 启动频率 维护成本才会考虑切 Native。如果一个月都不重启一次启动时间再快也感知不到。6.3 个人踩坑后的体会最后分享几个亲测有效的判断标准。第一先跑通虚拟线程再看 Native。虚拟线程的收益是即时的配置简单风险低。有一个服务没有做任何业务代码改动只切了虚拟线程P99 延迟就从 200ms 降到 60ms。这种便宜不捡直接跳到复杂的 AOT 适配容易劝退团队。第二冷启动的测量标准要统一。很多团队说启动快但看的是日志时间忘了“端口真正可以接收流量”才是这个服务的就绪点。我在第 4 章给的探测脚本可以直接拿过去用避免大家各自定义冷启动。第三始终保留一个 JIT 模式的发布配置。Native 模式在某些依赖变更后可能突然不稳定留一手能让你在任何异常时快速回退而不是卡在问题定位上阻塞线上恢复。实践中我会在 CI 里同时构建 jar 和 native 两种产物发布时默认用 native异常时切换 jar。回头看这轮适配最值钱的不是学会了 Spring Boot 4 的具体配置而是建立了一套判断机制什么场景值得上虚拟机线程什么服务适合 Native升级顺序怎么排。这些判断比“跟着教程敲一遍命令”重要得多。如果你的团队也准备动这块建议先拿一个非核心服务做试点把兼容性矩阵和构建流程跑透再谈大规模推广。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

QtCipher实战:SQLite数据库文件加密与常见坑 2026/9/26 14:00:08

QtCipher实战:SQLite数据库文件加密与常见坑

简介:Sqlite加密插件QtCipher是一份面向Qt开发者的SQLite加密工程资源,基于sqlitecipher库为SQLite数据库提供文件级加密能力,帮助在桌面、移动或嵌入式应用中保护敏感数据,同时维持SQLite的轻量特性。压缩包共23个文件&#xff0…

阅读更多 →
高斯消元法零基础详解:手算到Python实现 2026/9/26 14:00:08

高斯消元法零基础详解:手算到Python实现

1. 项目概述 1.1 核心需求解析 高斯消元这个名字,在图书馆、网课弹幕里,都是线性代数这门课里的一个"坎儿"。一堆人挂在"消元""回代""增广矩阵"这些词上,觉得书上写得不像人话,考试的时…

阅读更多 →
Claude Code环境变量配置全指南:API密钥与Base URL设置 2026/9/26 14:00:08

Claude Code环境变量配置全指南:API密钥与Base URL设置

1. 这不是“安装软件”,而是让Claude Code真正听懂你指令的底层握手协议很多人搜“Claude Code配置教程”,点开就找下载链接、双击安装包、勾选“添加到PATH”——结果打开VS Code,输入/explain,光标闪了三秒,弹出一行…

阅读更多 →
Ubuntu安装Docker CE完整指南:避坑内核模块、APT源与权限配置 2026/9/26 14:00:07

Ubuntu安装Docker CE完整指南:避坑内核模块、APT源与权限配置

1. 为什么这个教程值得你花20分钟认真读完Ubuntu安装Docker这件事,看起来就是几条命令的事,但我在过去三年里帮超过120位开发者、运维和学生部署过环境,发现93%的人卡在同一个地方:不是命令输错了,而是根本没意识到自己…

阅读更多 →
高斯消元法全解析:从矩阵变换到代码实现的系统指南 2026/9/26 14:00:07

高斯消元法全解析:从矩阵变换到代码实现的系统指南

高斯消元这东西,我在读书时其实没太当真——觉得不就是初中解方程组换个写法嘛。直到后来做工程,要在代码里解几十上百个未知数的线性系统,才意识到当年课本里那套“加加减减”的操作,是理解整个线性代数的最短路径。这篇文章就从…

阅读更多 →
AI质检师副业实战:用deepeval搭建大模型评测管线与badcase归因 2026/9/26 14:00:01

AI质检师副业实战:用deepeval搭建大模型评测管线与badcase归因

1. 从“人工肉眼”到“模型打分”:AI质检师到底在检什么 很多人第一次听到“AI质检师”这个词,脑子里浮现的画面是戴着工牌坐在流水线旁边盯着屏幕。其实这个副业跟工厂没半点关系,它检的是 AI系统自己产出的内容质量 ——大模型写的文案有…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉