ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

老Java项目接入AI IDE:从规则配置到团队落地的完整实战

老Java项目接入AI IDE:从规则配置到团队落地的完整实战 老Java项目接AI IDE这事我观望了快两年。原因很实在那些Demo里AI改的都是玩具工程而我手上这些项目动辄十几年积累SQL散落在JSP里一个工具类背后能牵扯出七八个隐式约定文档三年前就断更了。直到有个核心模块的维护者突然离职我要在两周内改一段涉及资金计算的逻辑才把Cursor真正推进生产环境试了一遍。试完之后我得承认之前把问题想偏了。AI IDE的难点从来不是模型聪不聪明而是项目的上下文能不能喂得进去。老Java项目恰恰是上下文最复杂、最不友好的一类。这篇文章把我从零推进老项目AI化这几个月攒下的完整方案整理出来——包括迁移前的准备、规则配置、实操姿势、踩坑清单和团队落地方法适合正在纠结要不要把老项目接进AI工作流的团队参考。1. 老Java项目接AI IDE先认清四个现实1.1 老项目真正的问题不是老而是历史包袱的结构性失忆把Java老项目和新技术栈Demo放在AI IDE面前对比差距就像让一个实习生直接去改没人维护的遗留系统。你对着一个十年历史的后台管理系统摆在AI面前的到底是什么样的代码库第一依赖关系是蜘蛛网式的。一个订单模块间接依赖可能达到几百个jar版本冲突是常态运行期靠反射、SPI、动态代理兜底。AI如果只看单文件根本理解不了某个Bean是怎么被装配出来的。它可能给你一个看起来正确的修改建议但那个类实际是通过Spring的DependsOn在初始化阶段被另一个模块装配的改了构造方法签名启动直接报错。第二隐含约定远多于显式约定。老项目的编码规范往往存在于老员工脑子里不在文档里——比如新增字段必须有默认值否则老数据反序列化会炸Controller里不允许直接return null必须包一层Result。这些约定AI不可能自己猜出来你不告诉它它就按通用最佳实践来然后随手就给你造出一个生产事故。第三死代码和活代码混在一起。很多老项目改着改着一些功能看着没用其实还活着定时任务、MQ消费、回调接口、反射调用。AI最容易犯的错就是把看起来没被调用的公共方法判断成死代码然后建议删除这是老项目迁移里最危险的误判之一。我见过不止一次AI自信地建议删掉一个没有引用的方法而那个方法恰恰是被Scheduled注解驱动的定时任务入口。第四构建方式不标准。老项目的Maven/Gradle配置往往魔改严重有自定义parent、奇怪的profile、内网私服。AI默认的构建知识在这套配置面前经常失效。你让它修一个编译错误它可能直接建议你升级某个公共模块的版本——然后全项目二十多个模块一起编译失败。这四个特征决定了老项目接入AI第一步不是让它写代码而是让它先读懂你们的潜规则。跳过这一步直接让AI上手改等着的就是一堆看似合理实则破坏性的Diff。1.2 Cursor不是带AI补全的IDE而是结对编程的另一个人很多人把Cursor看成传统IDE加了个AI补全插件这低估了它的本质。我自己的理解是Cursor更像一个高度可定制的结对程序员它有记忆索引和rules、有工具终端和MCP、有上下文窗口对话和引用。你用得好不好取决于你怎么训练它而不取决于它本身有多聪明。这个定位带来两个心态转变。第一个转变你要开始写给AI看的文档了。过去写文档是为了后人维护现在写文档更是为了让AI在生成代码时遵循同样的约定。.cursor/rules文件就是给AI看的项目README它的价值不亚于一份好的架构设计文档。我后面会用一个专门的章节讲这个文件的组织方式。第二个转变代码评审的对象变了。以前Review的是代码本身现在Review的是AI生成的Diff 你给AI的指令质量。如果AI生成了一段烂代码大概率是你的上下文没给够、提示词太模糊或者索引没建好。养成这个归因习惯AI工作流才能越用越顺而不是越用越暴躁。提示不要一上来就追求让AI从0写一个模块。老项目的正确打开方式是让AI从1到1.1——理解现有实现、做小步重构、补测试、改注释。步子越小越不容易翻车。2. 迁移前的地基工程让AI能读懂一个十年老仓库2.1 目录结构和构建依赖的梳理先给AI画一张地图Cursor的索引能力再强也架不住一个满是迷宫的项目。我在做迁移准备时第一件事是确认三样东西。构建入口是否唯一。如果项目里既有Maven又有Gradle或者有多套build文件共存AI在分析时很容易精分。我见过一个项目根目录有pom.xml某个子模块里莫名冒出一个build.gradleAI分析时一会儿按Maven的逻辑猜一会儿按Gradle的逻辑猜给出的建议两头不着。先统一用一套至少在rules里明确本项目以pom.xml为准忽略其他构建文件。多模块关系是否清晰。老项目常见一个仓库N个模块模块间依赖靠本地install或者私服。建议在rules里写清楚模块间的依赖方向比如domain层不允许依赖infrastructure层controller不得直接操作DAO这类规矩。AI有了这条约束生成跨模块代码时就不容易随手封一个跨层调用。外部服务依赖名单。老项目经常藏着配置中心、缓存、MQ、定时任务这些外部依赖。AI分析代码时如果不了解它们的存在很容易对这个方法的副作用产生误判——比如一个看似纯计算的方法里其实埋了一个Redis读操作AI可能建议你把它提取成静态工具类结果破坏了缓存读取逻辑。这三样不需要你写得精美能说明白就行。我把它们整理成了一页纸的PROJECT_OVERVIEW.md放在仓库根目录并且在rules中让AI遇到不确定的架构问题先读这个文件。实测下来这比在每条对话里反复强调我们这个项目是xxx架构有效得多。2.2 代码索引与让AI记住项目的正确姿势Cursor底层的代码索引会自动扫描项目目录但老项目的目录里往往混着一堆不该进索引的东西target/、node_modules/、uploads/、third_party/。我第一次没配置忽略规则结果AI经常拿第三方源码里的风格回答问题还自以为很对。比如项目里自己封装的DateUtil不用偏偏参考某个开源库里八九年前就被废弃的写法。建议在首次进入项目时就设置好忽略列表构建产物目录target/、build/、dist/生成代码目录如generated-sources、proto生成的Java文件第三方依赖的源码包如果Maven/Gradle拉下来的源码被索引了会严重干扰检索大型测试资源src/test/resources里的大数据文件、图片、抽样数据索引构建完成后再配合代码库问答来验证AI对你项目的理解程度——直接问它XXX模块的订单状态流转是怎么实现的看它能不能准确说出核心类的位置、职责和主要调用关系。这一步的验收标准很朴素AI能准确说出项目里某个核心类的位置、职责、主要调用关系而不是给你一段放之四海而皆准的泛泛解释。2.3 JDK版本、构建工具版本与语言方言的对齐这是老项目迁移到AI工作流时最容易被忽略的技术债但对Java老项目来说几乎是决定性的。Java老项目往往停在JDK 8或11代码里全是Date、SimpleDateFormat、StringBuffer还有一堆团队自研的私有API。AI的训练数据里有大量新语法你如果不做任何约束它会默认给你生成var、List.of()、Optional.orElseThrow()这些新写法——在老项目里要么编译不过要么依赖不合规要么和现有代码风格格格不入。我在rules里直接写下项目只使用Java 8语法禁止var、禁止List.of、禁止Record时间日期一律使用项目封装的DateUtil效果立竿见影。这背后的逻辑是AI生成代码的风格是由你显式或隐式地教出来的。你给它看的项目代码全是老风格它自然会偏向老风格但如果你在对话里给它的示例太新派它也会在新老之间来回摇摆。所以请把语言语法边界当成硬性纪律写进rules里最好再附上一个本项目推荐写法 vs 禁止写法的对照表——别嫌啰嗦这个对照表能避免90%的返工。3. 最关键的一步为Cursor写一份项目说明书3.1 rules文件放什么从架构约束到潜规则的显式化在Cursor里项目的说明书主要就是.cursor/rules目录下的文件。我把它当成新入职员工的培训手册加公司红线的合体。具体我会放这几类内容。项目概况技术栈、模块结构、构建命令、入口类位置。这是AI认识项目的第一印象要保证准确。架构约束分层规则、依赖方向、禁止的循环依赖、核心业务逻辑必须写在service层。这些是硬约束AI违反它们的代价通常很大。编码规范老项目特色版强制Java版本、命名风格、日志规范、异常处理方式、返回值约定。尤其要写清楚Result包装统一异常处理这类项目特有的约定。领域潜规则金额计算禁止直接用浮点、状态机变更必须走统一方法、敏感字段脱敏规则。这些是业务红线AI越界的后果往往要上线了才能发现。AI行为约束禁止删除看起来未调用的公共方法可能被反射、定时任务、MQ消费调用、禁止把SQL重写为MyBatis-Plus链式调用老项目内统一使用XML、修改公共方法时同步搜索调用方等。我把这些rules按01-architecture.md、02-coding-standards.md、03-domain-rules.md的方式分文件组织。原因是rules文件一旦超过三个AI在不同任务里读取的优先级会出现差异分文件并按优先级命名能让它先读最关键的架构约束再读具体的编码规范。3.2 用示例驱动而不只是规则驱动纯文字规则对AI的约束力其实有限。我自己的体感是示例的约束力远大于描述。比如时间格式统一这条规则如果只写请使用统一的时间格式AI还是会自由发挥但如果你在rules里贴一段现有代码效果完全不同// 推荐项目统一使用 DateUtil.format(date, yyyy-MM-dd HH:mm:ss) // 禁止LocalDateTime.now().toString()、单独 new SimpleDateFormat()AI看到正反例以后很少再跑偏。同样道理返回值包装、异常处理、日志打点这些规则我都配了一小段正反例。这比任何措辞严谨的不得都管用——因为AI不是靠读禁令理解的它是靠模仿模式理解的。另外提醒一句rules文件本身也要纳入版本管理。我把它放在仓库的.cursor/rules目录下跟随代码提交这样每个成员clone下来拿到的是同一套项目素养不会出现你这台机器上的AI懂规则我那台机器上的AI是个野孩子这种分裂。3.3 MCP服务接入要不要给AI接内部工具Cursor支持MCP可以让AI调用外部工具获取额外上下文。对老Java项目来说最大的价值在于接上代码搜索/调用链查询工具让AI能查询这个接口有哪些实现类或谁调用了这个私服方法接上日志查询工具让AI能分析线上日志来定位问题接上数据库字典让AI生成代码时能查表结构。我的建议是先跑通基础工作流再考虑MCP。MCP的价值是锦上添花但如果项目本身的索引和rules还没理清楚接上再多的工具AI也会因为对自己的判断过于自信而出错。而且团队引入MCP是有维护成本的——你得保证服务稳定性、权限控制、数据安全。初期不接MCP靠着代码库问答全文检索人工补充上下文已经能覆盖80%的场景剩下那20%等基础扎实了再补。4. 迁移期的一天老代码上AI的实际工作流4.1 场景一理解一段没人敢动的核心逻辑我接手过一个资金计算模块方法体三百行全是if嵌套和状态位判断注释几乎为零。以前的常规操作是逐行读、画调用链、找调用方、再对照配置表猜含义整套下来一下午就没了。现在的流程换成三步。第一步在对话里选中这段代码让AI用中文逐段解释这段逻辑找出可疑的状态分支和隐藏的副作用。第二步追问这段代码在什么情况下会走到这个分支它依赖哪些外部配置——AI会结合检索到的配置类、枚举、调用方来做推断。第三步让AI把解释写成结构化文档直接沉淀成方法头的Javadoc。这个流程最大的收益不是AI替代了阅读而是AI把阅读结果结构化输出大大降低了我进入上下文的时间。我只需要验证AI的解释是否合理在关键判断处再回去看一眼源码。三个小时能压到四十分钟而且产出物文档注释是可以留存的。有一个点必须提醒AI的解释不等于事实。尤其在资金、权限、状态机这些核心领域AI自信地胡说的概率并不算低。我的做法是让AI在不确定的地方明确标注此处存疑建议人工确认并要求它给出依据引用具体类名/行号。这样我复查时有方向不会被它的语气带偏。4.2 场景二给老代码补单元测试老项目的核心痛点之一是测试覆盖率低而补测试恰恰是AI最顺手的事情之一。我这里有一套可复制的Prompt模板请为以下方法生成单元测试要求 1. 使用JUnit 4 Mockito项目现有测试框架不要引入新依赖 2. 覆盖正常路径、边界值、异常路径至少5个用例 3. 对外部依赖Redis、数据库、HTTP使用Mockito打桩 4. 测试数据使用项目已有的工厂类/测试工具类不要硬造 5. 测试命名遵循 Given_When_Then 风格保持可读性这里最容易踩的坑是AI生成的测试引用了不存在的测试工具类或者Mock了不该Mock的私有方法。我的检查顺序是先看它引用的类是否都存在再跑一遍测试看是否真的能过最后抽查两三个用例的断言是否真正覆盖了业务逻辑——而不是为了覆盖而覆盖的低质量断言比如断言一个空方法的返回值为null这种用例等于没写。补充一个实战小技巧先让AI生成测试数据工厂再让它写测试用例。老项目的测试数据构造往往又长又绕如果AI每次都在用例里内联构造数据测试会很臃肿。先让它抽出测试目录下的数据构造工具类后面的用例都基于这个工具类生成整体代码质量会提升一个档次。4.3 场景三重构一段坏味道代码老项目里最常见的重构诉求是把几百行的长方法拆成职责清晰的子方法或者把重复度极高的if-else替换成策略模式。AI在这类任务上能力很强但前提是你把边界画清楚。我会在对话框里这样写这是一个订单价格计算的核心方法重构目标 1. 把优惠计算、运费计算、税费计算拆成独立私有方法 2. 保持完全相同的外部行为不要改变任何计算结果 3. 每个子方法不超过30行加Javadoc说明输入输出 4. 重构完成后请给出一个行为等价性自查清单哪些测试用例可以验证重构前后一致这里最重要的不是让它重构而是**保持行为完全不变**。重构之后我会用现有的测试跑一遍没有测试的话先按上一小节的方式补几个关键用例再重构。顺序必须是先补测试、再重构、最后看Diff否则重构前后的行为差异会变成一笔糊涂账。还有一个我后来改掉的习惯不要让AI一次重构太多文件。一次只重构一个方法或一个类Review完确认没问题再继续。AI一次改多个文件时文件间的连贯性往往会出问题——比如公共方法签名改了某个调用方没同步改或者一处常量改了另一处还是旧的硬编码。小步快跑在老项目里永远是真理。5. 老项目迁移的坑与解题思路实测汇总5.1 坑一AI改坏了共享依赖的版本有次我让AI修复一个编译错误它直接在pom.xml里把某个公共模块的版本号从1.2.3升到了1.4.0理由是1.4.0修复了该问题。但那个公共模块是另一个组在维护的私有仓库1.4.0的接口变了全项目二十多个模块全部编译失败几个人一起查了大半天才定位到是这个善意的升级惹的祸。从那以后我在rules里加了一条硬性规定禁止修改pom.xml/gradle文件中的版本号除非人工明确指示并且把pom.xml列入AI只读文件清单。这个教训让我意识到老项目里构建文件是最脆弱的资产宁可让AI绕远路也不要让它动版本。AI看到编译错误时第一反应是升级到最新版但这个直觉在大型老项目里几乎是灾难级的。5.2 坑二AI生成的代码自带新项目味融不进老风格前面提过这个问题但值得再展开。老项目有自己的一套习惯ServiceImpl里会有一堆历史遗留的防御性判断、日志打点的固定格式、甚至变量命名的缩写风格。AI天然偏好在生成代码时合理化一切——把防御逻辑删掉、用更现代的表达重写、给变量起一个更准确的名字。结果就是功能是对的但Merge Request的Diff大得惊人Review的人看着一头雾水这个变量名原来叫userCnt你给改成userCount干什么这不影响功能但你的Diff里全这种噪声。解决方案我在实践中有三个层次写进rules禁止重命名公共方法/变量除非有编译错误或明确需求约束Diff大小每次任务时明确尽量最小化Diff只修改目标代码块不要顺手格式化其他行在对话里说明风格在任务描述里直接贴一段本项目这段代码的风格是xxx请严格模仿——AI看到具体样式后对齐速度快到惊人。5.3 坑三AI的能编译和你的能编译不是一回事Cursor的AI有时会用它认为的新API生成代码本地编译却报错。最典型的场景是Spring Boot版本过低不支持某些新注解或者JDK 8下用了String.repeat()这类只有新版本才有的方法。这类问题的本质是AI在做代码生成时对你们的项目环境的了解不一定及时。尤其是依赖版本升级后索引没更新、rules里没写JDK版本边界、IDE的语言服务没加载完AI就会拿一套通用环境的知识去生成代码。我的应对策略是每次新建会话时先确认当前项目JDK版本、Spring Boot版本、关键依赖版本生成代码后立刻让AI自查这段代码用到了哪些Java标准库API它们在你说的JDK 8下是否可用把编译和单测当成最后一道防线千万别信AI的我给你写好了。另外如果条件允许在本地搭一套和CI一致的环境给AI工作流用——同版本的JDK、Maven wrapper固定版本——能少踩一半的坑。我们团队后来统一用.sdkmanrc固定JDK版本AI的生成正确率肉眼可见地稳定了。5.4 坑四上下文爆炸AI越聊越失忆老项目的单次任务往往需要同时看十几个文件Controller、Service、Mapper XML、配置类、领域枚举。如果每条消息都把代码贴进对话上下文很快就爆了AI开始忽略之前的约束重复犯已经纠正过的错误。我的解决思路是少贴代码多指路。在对话里尽量用项目路径 类名 问题点的方式引用代码让Cursor自己通过索引去检索而不是把整段代码粘贴进去。比如项目里 com.example.order.service.impl.OrderServiceImpl 的第120行附近 checkShippingAddress 方法里有个空指针隐患 请结合 com.example.order.domain.ShippingAddress 的实现来分析。这样既省上下文又能让AI学会自主找代码。省下来的上下文额度可以让AI更从容地处理多文件联动修改。补充一个小技巧任务比较大时先让AI输出一个执行计划确认计划没问题再执行比让它闷头改完再review要稳得多。AI的计划能力和执行能力在同一个上下文窗口里是互相挤占的先计划后执行等于给它分层用脑子——第一次对话专门做规划第二次对话只做执行。6. 团队落地从一个人用到全组都会用6.1 先让AI做读代码工具再谈写代码我在团队里推AI工作流时的策略是低门槛切入第一个月不要求任何人用AI改业务代码只要求三件事——用AI理解不熟悉的模块、用AI生成Javadoc和注释、用AI写单元测试。这三件事风险极低、收益明显成员很快能感受到AI确实省时间。等大家习惯了AI是我结对的对象这个心态再逐步开放到让AI做小步重构、生成接口实现。这个循序渐进的过程本质上是在培养团队对AI输出的判断力——如果一上来就允许AI大改特改很容易出现改完就出问题然后全组反弹最后AI工具被丢进垃圾桶。老项目的逻辑是信任靠小事积累崩塌只在一瞬间。第一印象如果是AI把线上搞挂了这个坑后面很难再填回来。6.2 建立AI辅助变更的代码评审标准AI改过的代码评审标准和人工写的代码应该略有不同。我们团队最终沉淀下来的几条评审红线行为等价性对于重构类变更必须要求AI和旧代码在同样输入下输出一致最好有测试或对比验证Diff最小化不接受顺手优化——顺手改了别人的命名、顺手调整了缩进、顺手把if改成switch这些都视为噪声可回滚性AI的变更必须能被单独revert不要把AI的改动和人工的改动混在同一个commit里否则出了问题很难拆涉密与安全AI生成的代码不得包含硬编码密钥、不得过度授权涉及敏感数据的代码必须人工重点审查。这些标准并不是不信任AI而是把AI当成一个能力很强但还不懂项目潜规则的新成员给它配同样的管控流程。过了这层评审AI的产出才能真正稳定合并进主干。6.3 沉淀团队的Prompt与规则资产我把团队里好用的Prompt、rules片段、踩坑案例统一收集到一个内部文档里形成了AI协作规范。这个东西一开始只是我一个人在维护后来慢慢变成了新人入职必读的一部分——因为它沉淀的不仅是怎么用AI更是我们项目有哪些潜规则。整个文档的核心不是背标准答案而是学会描述问题。团队里最会用AI的人往往不是代码写得最好的人而是最会把业务规则和项目上下文讲清楚的人。所以我在文档里专门写了一个章节叫如何给AI一个好任务列了五个要素任务背景、目标、约束、验收标准、相关文件路径。这五个要素缺一个AI的输出质量就会掉一档。等到团队里每个人都能在五分钟内写出一条好任务AI工作流才算真正落地。我自己电脑里至今留着一个清单记录我总结出来的有效姿势和踩过的坑——老项目不敢太激进每次只改一个方法或一个类先跑测试再提Merge Request遇到这个坑AI解决不了的case宁可花半小时把上下文备齐再试一次也不要自己动手把活干了然后开骂AI。最后分享一个我个人的体会老项目接AI最成功的标志不是成员每天在群里秀AI改了多少代码而是某天你发现新人入职后第一周就能靠AI把一片旧代码讲得头头是道——那一刻你就知道这套工作流大概是真的融进项目了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进