☰
如何把 Java 仓库改造成 AI Native?用 AGENTS.md 与 Spring Modulith 落地
2026/9/29 12:16:16 网站建设 项目流程

1. 存量 Java 仓库为什么一接 Agent 就翻车

先说结论:Agent 改不动你的老仓库,大概率不是模型不行,而是仓库结构从来没为「非人类读者」设计过。我见过太多 Spring Boot 项目,包结构长这样:controller、service、mapper、entity四个大平层,每个下面几百个类。人类看目录能靠命名和经验脑补出业务关系,Agent 看目录只能看到一堆按技术角色堆叠的文件,它不知道「工单」和「支付」是两个独立业务域,也不知道改工单超时逻辑时不该顺手动权限代码。

这就是 AI Native 改造要解决的核心问题:把隐性的工程约束,从架构师脑子里、从 Code Review 评论里,搬到 Agent 能读到的文件里。本文聚焦存量 Java 仓库向 AI Native 演进,用 AGENTS.md 声明模块边界与代理协作规则,结合 Spring Modulith 与六边形架构拆分领域模块,交付可复制的 AGENTS.md 骨架、模块目录结构和验证动作。适合正在用 Claude Code、Cursor 等工具改老项目的 Java 团队,也适合想提前把仓库结构理顺的后端工程师。

改造分三层落地:物理边界(Spring Modulith + 六边形目录)、规则宪法(AGENTS.md)、验证闭环(模块依赖校验 + 回归测试)。下面按可跟做的顺序展开。

2. 前置准备:TaoToken 接入与仓库现状盘点

Agent 要能稳定改代码,前提是它有一个稳定的模型调用入口。我这边习惯用 TaoToken 做统一接入,官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api 。它把模型对话、Coding Plan、API Keys 管理放在一个控制台里,省得在多个工具间来回切配置。

动手改造前,先做两件事。

第一件,拿到可用的 Key。登录控制台后进 API Keys 页面创建,注意权限范围按项目隔离,别一个 Key 打通所有环境。创建后本地用环境变量存,不要写进仓库:

export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

第二件,盘点仓库现状。跑一条命令看包结构分布:

find src/main/java -type d -maxdepth 4 | sort

如果输出里出现controller/service/mapper/entity这种技术分层,且每个目录下类数量超过 50,基本可以判定这个仓库对 Agent 不友好。记录下三个数字:总类数、跨层调用最多的 Service、被引用最多的 Entity。这三个数字后面用来对比改造效果。

注意:改造期间不要停业务开发。建议拉一个ai-native-refactor分支,模块迁移分批合入,每批都保证mvn verify通过。

3. 可复制配置:AGENTS.md 骨架与模块目录结构

3.1 AGENTS.md 骨架

在仓库根目录建AGENTS.md,内容按「地图而非手册」的原则写。下面这份骨架可以直接改项目名用:

# AGENTS.md ## 项目概述 企业工单管理系统。Spring Boot 3.2 + Java 21 + Spring Modulith。 核心模块:ticket(工单)、approval(审批)、notification(通知)。 ## 架构约束(违反必挂) - Controller 禁止直接调用 Repository。 路径:Controller → Application Service → Domain Port → Infrastructure - 禁止跨模块直接引用内部类。模块间通信只能通过 Domain Event。 - 任何数据库 Schema 修改必须先读 docs/db-schema.md。 ## 禁止模式 - 禁止在 Service 里拼接 SQL 字符串 - 禁止吞异常(catch + log 然后 return null) - 禁止用 new 创建 Domain Entity,统一走 Factory 方法 ## 关键文件索引 - 架构文档:docs/architecture.md - 领域模型:docs/domain-model.md - 已知问题与陷阱:docs/known-issues.md ## 本地验证 - 单模块测试:`mvn test -pl ticket-module` - 全部测试 + Modulith 校验:`mvn verify` - 代码风格:`mvn checkstyle:check` ## 提交流程(强制) 1. `mvn verify` 全部通过 2. `git diff --stat` 确认改动范围 3. 如有跨模块改动,在 PR 描述中说明理由

三个设计点值得强调。前 10 行建立心智模型,Agent 读完就知道有几个模块、技术栈、顶层约束。禁止项比建议项更重要,Agent 不缺生成能力,缺的是「哪些不该生成」。用链接做渐进式披露,AGENTS.md 别膨胀到几千行,详细文档放单独文件。

3.2 模块目录结构

把技术分层改成业务域分层,每个域内部再套六边形分层:

src/main/java/com/company/ticket/ ├── api/ # REST 接口 + DTO ├── application/ # 用例编排 ├── domain/ # 领域模型 + Port 接口 └── infrastructure/ # 数据库 + 外部服务实现 src/main/java/com/company/approval/ ├── api/ ├── application/ ├── domain/ └── infrastructure

Domain 层定义 Port 接口,让 Agent 必须通过接口调用:

// domain/TicketRepository.java —— 契约,Agent 必须遵守 public interface TicketRepository { Ticket save(Ticket ticket); Optional<Ticket> findById(TicketId id); List<Ticket> findPendingByAssignee(UserId assignee); } // infrastructure/MySqlTicketRepository.java —— 实现细节 @Repository class MySqlTicketRepository implements TicketRepository { // MyBatis / JDBC 实现 }

这样 Agent 说「换个查询条件」,它大概率改findPendingByAssignee的实现,不会在 Service 里裸写 SQL。边界制造了正确的惯性。

3.3 模块依赖校验

在测试目录加一个 Modulith 校验类,让 CI 守住边界:

@SpringBootTest class ModularityTest { @Test void verifyModuleStructure(ApplicationModules modules) { modules.verify(); } }

Agent 一旦在 ticket 模块里直接引用 approval 的内部实现,verify()会在 CI 上炸掉。相比口头规范,物理约束对 Agent 更有效——它不是「被建议不要改」,而是「改了就跑不通」。

4. 验证请求:跑通模块校验与代理回归测试

配置写完,先验证 Agent 是否真的按约定改代码。分两步。

第一步,本地跑模块校验:

mvn verify -Dtest=ModularityTest

预期输出BUILD SUCCESS。如果报Module 'ticket' depends on non-exposed type,说明有跨模块内部引用,按报错路径去改。

第二步,做一次代理回归测试。给 Agent 一个明确任务,比如「在 ticket 模块加审批超时自动关闭功能」,然后观察三件事:

# 看改动范围是否落在 ticket 目录内 git diff --stat # 看是否走了 Domain Port 而非直接访问实现 git diff src/main/java/com/company/ticket/domain/ # 跑单模块测试 mvn test -pl ticket-module

实测下来,改造前 Agent 改一个需求平均碰 4 个文件、跨 2 个模块;改造后基本落在 1 到 2 个文件、单模块内。如果 Agent 还是跑错门,检查 AGENTS.md 的「关键文件索引」是否写清楚了模块路径。

第三步,把验证命令写进 AGENTS.md 的「本地验证」段,让 Agent 自己形成「改代码 → 跑测试 → 看结果 → 修正」的循环。没有这个回路,Agent 写的代码永远要人再跑一遍,生产力初衷就反了。

5. 本篇常见错排查

报错一:ApplicationModules.verify()找不到符号。检查spring-modulith-starter-test依赖是否引入,版本要和 Spring Boot 对齐。Maven 里加:

<dependency> <groupId>org.springframework.modulith</groupId> <artifactId>spring-modulith-starter-test</artifactId> <scope>test</scope> </dependency>

报错二:模块间事件不触发。@ApplicationModuleListener默认异步,测试里要加@Awaitility或改成同步配置。别在 Domain 层直接 new 事件发布器,走 Spring 注入。

报错三:Agent 无视 AGENTS.md 继续跨模块改。先确认文件名大小写和位置,必须是仓库根目录的AGENTS.md。再确认约束写成了「禁止」而非「建议」,负面约束利用率最高。最后看 CI 是否真的挂了modulith-verify,没有 Gate 的规则等于没有规则。

报错四:迁移后老代码编译不过。分批迁移,每批只动一个业务域,用 IDE 的 Move Class 重构而非手动剪切,保证 import 自动更新。迁移完立刻跑mvn verify,别攒着一起改。

报错五:Agent 反复改同一个文件。多半是 AGENTS.md 里「关键文件索引」指向了过期文档,Agent 读了矛盾信息。定期清理docs/下的过期内容,保持索引和实际文件一致。

6. 把工程约束翻译给 AI:下一步怎么走

改造到这一步,仓库已经有了物理边界、规则宪法和验证闭环。接下来可以补两块:仓库记忆和自动化管道。

仓库记忆很轻,建一个.ai/memory/目录,放三份文件:decisions.md记架构决策和替代方案,known-issues.md记已知坑和 workaround,failed-attempts.md记失败尝试。Agent 动手前读一遍,避免团队踩过的坑被 AI 再踩一次。AI 最需要继承的不是代码,是团队的踩坑经验。

自动化管道方面,把mvn verify挂进 CI,再加一层 checkstyle Gate。Agent 提交的代码违反模块边界或风格,CI 直接打回,它必须自行修复。这一步做完,Agent 的编程循环才算真正闭合。

如果你还在选模型接入方式,可以先用模型对话快速验证 AGENTS.md 的约束是否被正确理解,地址是 https://taotoken.net/api 。长期跑编码和 Agent 任务的话,Coding Plan 更适合,具体在 https://taotoken.net/api 的控制台里看。接入文档和 API Keys 管理都在 https://taotoken.net/api ,配置细节以文档为准。

最后说个真实感受:改造仓库这件事,本质是把隐性的工程决策变成显性的结构化信息。过去这些决策藏在架构师脑子里、藏在 Code Review 评论里,AI 来了以后得搬到文件里。不是因为 AI 比人笨,恰恰相反,它能读的文件量远超人类,但它不会脑补你省略掉的意图。Java 工程师的核心能力,正在从「写什么代码」转向「定义 Agent 在什么边界内、用什么规则、基于什么知识来写代码」。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询