让 AI 帮我把项目升到 Spring Boot 3:它扛了体力活,也埋了几个坑
让 AI 帮我把项目升到 Spring Boot 3:它扛了体力活,也埋了几个坑我们组有个内部服务,一直跑在 Spring Boot 2 上 2.x 早就停止开源免费维护了,安全扫描隔三岔五报一堆依赖漏洞,升级这件事拖了很久,终于排到了我头上 这次我决定全程拉着 AI 一起干 前后大概用了一周多(中间还穿插着别的需求),最后顺利上线 回头看,AI 确实帮我扛了大部分体力活,但也有几个坑是它挖的,或者至少是它没提醒我的 这篇把过程和教训记下来,给同样准备升级的同学参考 先声明:下面说的都是我们这个项目的情况,每个项目的依赖和历史包袱不一样,具体以 Spring 官方的迁移指南为准 一开始我问 AI:“把这个项目从 Spring Boot 2 升到 3,需要改什么?”它给了一份清单,大方向没错:Java 版本要 17 以上、javax 包要换成 jakarta、Spring Security 的配置写法变了,等等

2026-10-14鱼鱼
让 AI 帮我看别人的 PR,我怎么避免被它带偏
让 AI 帮我看别人的 PR,我怎么避免被它带偏code review 一直是我又爱又烦的环节 爱的是能提前拦住问题;烦的是有些 PR 又长又绕,下午三点看到,眼睛先花了 后来我开始让 AI 帮忙“先看一眼” 效率确实上来了:它能很快列出一堆疑点,有的还挺准 但用了一阵子,我也被它带偏过——有一次它言之凿凿说某段并发不安全,我跟着在评论区写了很长一段,作者委婉回复:那段代码根本不会并发进入 我再看,确实如此 尴尬归尴尬,也逼我把用法收紧了 这篇不是教你“用 AI 替代 review”,而是聊聊:怎么让它当助手,却不把结论权交出去 先说我自己的体感(不是评测数据,是使用感受) 相对擅长: 扫一眼有没有明显的空指针、资源没关、错误被吞

2026-10-14鱼鱼
让 AI 写正则表达式:我现在一定先要它给反例
让 AI 写正则表达式:我现在一定先要它给反例正则大概是我最早放心交给 AI 的活 原因很简单:我自己写正则也是边查边试,每次写完都不太敢相信它 AI 张口就来,还附带逐段解释,看上去比我靠谱多了 用了一阵之后我发现,AI 写的正则有个很稳定的特点:它几乎总能匹配上你给的例子 问题是,正则真正出事的地方从来不在“该匹配的没匹配上”,而在“不该匹配的也匹配上了” 而后者,你不主动问,它不会告诉你 所以我现在有个死规矩:让 AI 写正则,先别要正则,先要反例 那次是要从一堆构建日志里提取版本号,格式是“主版本.次版本.修订号” 我给了 AI 三个例子,它很快给出 \d+\.\d+\.\d+,解释也清清楚楚 我跑了一下,三个例子全中,就提交了

2026-10-16鱼鱼
并发之AQS全解析
并发之AQS全解析我们知道juc(java.util.concurrent)包下有很多实用的类,提供了很多并发工具,例如线程池、原子类、并发工具、信号量工具、锁等,可以说基本实现都为悲观锁,底层原理基本都使用了AQS(AbstractQueuedSynchronizer),AQS不是一种概念,是并发中实打实的工具类 本篇文章针对AQS做解析 AQS是多线程访问共享资源的同步器框架 AQS的资源可以是独占的也可以是共享的 我们先来简单看一下它的使用方式和ApI(因为是抽象类,是不能直接使用的),下图是AQS的整体脉络 AQS核心就是一个状态值state,同时维护了一个线程的阻塞队列,队列的节点为有两种状态:SHARED(共享)和EXCLUSIVE(独占),节点状态有五种:
![并发之AQS全解析]()
2021-03-12鱼鱼
JVM源码解析(2) ContextClassLoader与ClassUtil.forName()方法浅析
JVM源码解析(2) ContextClassLoader与ClassUtil.forName()方法浅析在Spring获取Context的源代码中,我们看到了对ClassUtil的方法调用,通过给定ClassName和ClassLoader进行Class的加载: ClassUtil.forName是仅供于Spring内部使用的获取Class对象的方法,来看一下源码: 首先 对于缓存的Class一块,在类的静态块中就能看出其逻辑: 在上面的resolvePrimitiveClassName方法中,先对长度做了一个判断,因为较长的packagename会影响执行的性能: 最终加载Class依旧是通过ClassLoader的,先来看一下获取ClassLoader的方法实现: 此处优先使用了ContextClassLoader作为 类加载器而非默认的AppClassLoader,在JVM源码解析 从 Launcher类浅谈ClassLoader中,提到了关于 类加载器的相关知识,使用ContextClassLoader是为了弥补双亲委派加载机制的对于自定义 类加载器的缺憾:那些自定义的 类加载器并没有机会上场,在使用了AppClassLoader后我们的自定义ClassLoader所加载的Class是无法被加载进去的,使用ContextClassLoader,我们可以在定义线程时,通过Thread的init方法(子线程调用,私有方法)或是setContextClassLoader直接指定使用自定义的ClassLoader
![JVM源码解析(2) ContextClassLoader与ClassUtil.forName()方法浅析]()
2020-08-16鱼鱼
盘点redis中特殊的数据类型 HyperLogLog Bitmap
盘点redis中特殊的数据类型 HyperLogLog Bitmap 基数计数(cardinality counting)通常用来统计一个集合中不重复的元素个数,例如统计某个网站的UV,或者用户搜索网站的关键词数量 数据分析、网络监控及数据库优化等领域都会涉及到基数计数的需求 要实现基数计数,最简单的做法是记录集合中所有不重复的元素集合S_uSu,当新来一个元素x_ixi,若S_uSu中不包含元素x_ixi,则将x_ixi加入S_uSu,否则不加入,计数值就是S_uSu的元素数量 这种做法存在两个问题: 当统计的数据量变大时,相应的存储内存也会线性增长 当集合S_uSu变大,判断其是否包含新加入元素x_ixi的成本变大 大数据量背景下,要实现基数计数,首先需要确定存储统计数据的方案,以及如何根据存储的数据计算基数值;另外还有一些场景下需要融合多个独立统计的基数值,例如对一个网站分别统计了三天的UV,现在需要知道这三天的UV总量是多少,怎么融合多个统计值
![盘点redis中特殊的数据类型 HyperLogLog Bitmap]()
2022-01-12鱼鱼
Spring源码解析(3) IoC容器配置读取和容器refresh
Spring源码解析(3) IoC容器配置读取和容器refresh在文章Spring源码解析(I) 基于SSM看Spring的使用和Spring启动监听中,讲述了web容器启动后会触发的方法实现中生成Context的部分,回顾下核心方法: 我们已经分析到了0.处,他对我们生成的容器做了一个判断,对于web.xml监听初始化的Context,其生成的WebApplicationContext都是ConfigurableWebApplicationContext的子类,所以必然会进入if分支 首先通过loadParentContext先加载了父容器,默认是null 然后调用了configureAndRefreshWebApplicationContext方法进行初始化和配置项的读取

2020-08-09鱼鱼
多轮对话里的「目标漂移」:Agent 跑着跑着忘了你要什么
多轮对话里的「目标漂移」:Agent 跑着跑着忘了你要什么和 Agent 多轮协作久了,会遇到一种安静的失败:它一直很忙,工具也在调,中间步骤看起来都“合理”,可收工时你发现——干的已经不是你起初要的那件事 我把这叫目标漂移(goal drift) 不是偶发幻觉那么简单,更像是上下文变长后,约束被一步步冲淡 这篇文章记我怎么发现漂移、怎么在过程中拉回,以及设计 Agent 时能做哪些防漂 常见几种面孔: 每一步单独看都有道理:重构有益、修复积极、干净也好 合起来却违背委托 危险在于局部合理、全局偏航 图:目标漂移四种脸:膨胀、替换、偷换、遗忘(原创示意图) 我的个人理解(含推测): 所以漂移不完全是“模型不听话”,也是交互方式与系统设计的结果

2026-10-14鱼鱼
多智能体协作的几种常见模式
多智能体协作的几种常见模式一个 Agent 不够用时,自然会想到“多找几个 Agent 分工” 但多智能体并不是数量越多越好——它带来分工优势的同时,也带来了通信成本、调试难度和 token 开销 本文梳理几种常见协作模式及其适用场景,给出主管—工人、评审循环的 Python 示例和 Java 版的消息结构,并总结常见坑、检查清单与 FAQ 从“大而全”的单个 Agent 到“小而专”的分工 单 Agent 加工具,已经能解决很大一类问题 但随着任务变复杂,常见瓶颈会逐渐出现: 上下文被挤满:几十个工具的说明、长长的历史、大量检索结果挤在一个窗口里,模型注意力被稀释; 角色冲突:同一个提示词里既要求“大胆创作”又要求“严格挑错”,两种要求互相拉扯;

2026-10-14鱼鱼
Agent 的规划与任务分解:让复杂任务可控
Agent 的规划与任务分解:让复杂任务可控简单问题一两步就能搞定,但“调研三个竞品并写一份对比报告”这类任务,如果让模型边想边做,很容易跑偏、遗漏或重复 规划(Planning) 就是让 Agent 在动手之前,先把大任务拆成可执行的小步骤 本文从动机讲起,比较三种常见规划模式,给出结构化计划的数据格式,以及一个带依赖调度、失败重试和重规划的完整 Python 示例,并附上 Java 版的计划模型、常见坑和检查清单 三种规划模式:ReAct、Plan-and-Execute 与层次化分解 回忆一下 ReAct:模型每一步只决定“下一步做什么” 这在短链路任务里很灵活,但当任务变长,会出现几类典型问题: 目标漂移:做到第 10 步,模型被中间的工具结果带偏,开始回答另一个问题;

2026-10-14鱼鱼
Agent 的 Token 账单怎么省:Prompt Caching、上下文瘦身与模型分级
Agent 的 Token 账单怎么省:Prompt Caching、上下文瘦身与模型分级做 Agent 的人,大概都经历过这么一个时刻:功能调通了,效果也还行,兴冲冲地跑了一批真实任务,然后打开账单页面,沉默了 同样是调用大模型,Agent 为什么比普通聊天贵这么多?钱都花在哪了?能不能在不明显影响效果的前提下省下来?这篇文章想把这笔账算清楚,再聊几种我觉得性价比最高的省钱办法 先声明一下:各家模型的价格和缓存规则变得很快,文中涉及的具体规则,以我写作时(2026 年 10 月)看到的官方文档为准,你落地之前最好再核对一遍 思路是通用的,数字请以官方为准 图片来源:Negative Space / StockSnap(CC0 1.0) 普通聊天,一问一答,输入的就是你的问题加上一些历史

2026-10-14鱼鱼
JEV 是什么:一个不写字、只做判断的模型(附我的调试台 jev.fishmaple.cn)
JEV 是什么:一个不写字、只做判断的模型(附我的调试台 jev.fishmaple.cn)先放链接:jev.fishmaple.cn 这是我前两天搭的一个小调试台,叫 Jev Lab 打开就能用,填一个 OpenRouter 的 Key,就可以直接在浏览器里调 JEV 这篇想聊聊 JEV 到底是个什么东西,它跟传统分类器、重排序差在哪,以及九月它出来之后,OpenAI、微软、Cloudflare、阿里、Perplexity 这些大厂怎么对标的 九月中旬刷 OpenRouter 的模型列表,看到一个叫 typesafe/jev-1.13 的东西,上线日期是 2026 年 9 月 18 日 价格那栏把我看愣了:输入每百万 token 0.042 美元,输出是 0 输出免费?我第一反应是标错了

2026-10-14鱼鱼