🤖系列:Java工程师转 AI Agent 3 个月学习计划
👤作者:宸丶一|28 岁 Java 程序员
🎯今日目标:从项目想法收敛出一个边界清楚的 Agent MVP,并验证它是否真的可用
💬个人格言:代码改不改变世界我不知道,但先让我准时下班。
前言:Day 29,本来只做设计,最后把 MVP 跑起来了
Day 28,我刚把后续路线校准清楚:长期目标仍然是Java / Spring AI 企业 Agent 实战;短期先用 Python 做一个最小闭环,再理解、重构、逐步把主导权拿回来。
所以 Day 29 的原计划其实是:选 MVP、写边界、写验收、准备 Vibe Coding 上下文。
但今天时间比较充裕,我没有停在“规划完成”,而是把第一版离线 Python CLI 直接做出来并完成了两轮验收。
这次做的不是网页,不是聊天界面,也不是“万能 Java Agent”,而是一个小到可以验证、又足够接近真实开发场景的工具:
Java 单元测试草稿助手:输入一个 Java 文件和方法名,输出 JUnit 5 + Mockito 测试草稿。
最后的验收评分是92 分。不过,比 92 分更值得记录的是:我亲自经历了一次“需求收敛 → AI 生成 → 真实验证 → 发现缺陷 → 补负向测试”的工程闭环。
学习目标
- 把“做 Java 代码助手”收敛为一个可验证的 MVP
- 理解 CLI 为什么是合适的第一步
- 使用 Vibe Coding 生成真实可运行的第一版
- 用成功与失败路径验证工程边界
- 为后续 Java / Spring AI 重构保留清晰模块边界
一、先对齐主计划:Python MVP 不是终点
当前主线仍然没有变:我最终要走的是 Java / Spring AI 方向的企业 Agent 实战。
Python MVP 的定位,是一个更快进入真实问题的入口:
因此,今天不是为了“用 AI 快速拼个 Demo”,而是为后面真正的工程化学习准备一个可运行参照物。
我最终选择的 MVP 是:为指定 Java 方法生成单元测试草稿。
它比“做一个万能代码助手”更适合作为第一步,因为它的输入、输出和验收都比较明确:
| 项目 | MVP 定义 |
|---|---|
| 目标用户 | 想快速获得测试思路与测试骨架的 Java 开发者 |
| 输入 | 一个本地.java文件 + 一个或多个方法名 |
| 处理 | 校验文件 → 定位方法 → 识别构造函数 → 生成草稿 → 校验结构 |
| 输出 | JUnit 5 + Mockito 测试草稿 |
| 成功标准 | 生成草稿或落盘成功,返回 exit0 |
| 失败策略 | 非 Java 文件、文件不存在、方法不存在时立即失败,不重试 |
二、CLI 不是“模拟软件”,而是最轻量的真实产品入口
我一开始把 Python CLI 理解成“控制台可运行的 Demo”,后来进一步理解:它不是模拟软件,而是一个真实的软件形态,只是交互入口是命令行而不是网页和按钮。
例如:
# 生成草稿到 stdoutpython-magent_cli fixtures/Calc.javaadddiv# 直接写到指定输出目录python-magent_cli--outputgenerated fixtures/Calc.javaadddiv背后的链路是:
用户参数 ↓ 文件与扩展名校验 ↓ Java 方法定位 ↓ 构造函数依赖识别 ↓ JUnit 测试草稿生成 ↓ 基础 Java 结构校验 ↓ stdout / 安全文件输出这很像一个离线、确定性的简版 Dify 工作流:每个步骤都像一个职责明确的节点。
后面如果接入 LLM 或 Spring AI,重点可以增强“测试计划”和“测试草稿生成”节点;但文件校验、输出保护、错误处理、结果验证这些工程骨架不应该被替代。
三、我给 AI 的提示词:只公开约束,不公开完整上下文
这次我没有直接把完整原始 Prompt 放出来。一方面里面有学习上下文和个人协作表达;另一方面,真正值得复用的不是某一句“魔法提示词”,而是它包含的约束结构。
下面是脱敏后的 Prompt 骨架:
实现一个离线 Python CLI: - 输入:指定 Java 文件与方法名 - 输出:JUnit 5 + Mockito 单元测试草稿 - 不接网络或 LLM API - 不扫描整个仓库 - 不修改输入文件 - 输入非法或方法不存在时立即失败,不重试 - 至少验证:成功生成、方法不存在、非 Java 文件拒绝第一轮生成的记录显示,初始构建过程大约用了9 分钟。当然,真正的项目时间不只包括“AI 生成”:后面还有阅读、验收、发现问题、修复、再验收。
这也是我今天最大的感受:
Vibe Coding 让“第一版”来得很快,但不能替代“证明第一版正确”。
四、第一轮验收:能跑,不代表能交付
第一版 CLI 很快就跑通了三条核心路径:
| 路径 | 结果 |
|---|---|
合法.java文件 + 存在方法 | 成功生成草稿,exit0 |
| 方法不存在 | 明确报错,exit3,无半成品输出 |
非.java文件 | 明确拒绝,exit2,无测试输出 |
但是验收时发现两个不能忽略的问题:
问题 1:package和import顺序错了
生成的 Java 文件一开始类似:
import...;packagecom.example.demo;Java 的正确顺序必须是:
packagecom.example.demo;import...;这个问题说明“输出看起来像 Java”,不代表它已经满足 Java 编译单元的基本规则。
问题 2:默认假设被测类有无参构造函数
示例类实际只有:
publicCalc(intseed)但草稿里却直接生成:
subject=newCalc();所以第二轮修复明确要求:识别构造函数参数;原生类型生成占位值,引用类型生成@Mock字段。
例如修复后会生成类似:
@MockprivatePricingGatewaypricingGateway;@MockprivateOrderRepositoryorderRepository;@BeforeEachvoidsetUp(){Stringregion="todo-value";subject=newOrderService(pricingGateway,orderRepository,region);}另外还补了--output:目录不存在时可以创建,但目标文件已经存在时必须拒绝覆盖,避免误改他人的测试文件。
五、最有价值的插曲:测试绿了,校验器却漏检了
第二轮验收后,我本来以为package → import问题已经结束。
但继续核查时发现:生成器虽然已经修好,结构校验器却仍可能把下面这种非法内容当成合法:
importjava.util.List;packagedemo;原因不是 Java 知识不够,而是校验器的实现只看到了第一个import,就停止继续寻找后面是否还有package。
于是,验证不能只保留“正确示例通过”,还要加入反例:
| 校验样例 | 期望结果 |
|---|---|
package → import | 通过 |
import → package | 拒绝 |
两个package声明 | 拒绝 |
这次让我真正理解了一句话:
正向测试证明“能做”;负向测试证明“不会悄悄放过不该做的事”。
对后面的 Agent 项目也是一样:不能只测试工具调用成功,还要测试非法输入、权限拒绝、覆盖文件、部分失败和不安全输出。
六、Vibe Coding 里的“括号打架”
今天还有一个让我觉得很有意思的小插曲。
在 Vibe Coding 的过程中,AI 为了修正文案和代码表达,出现了一句类似:
“引号打架,改一下写法。”
我第一反应是:哈哈,这不就是“括号打架”吗?
上图已经做了脱敏处理:移除了原始对话顶部信息,只保留与本次学习有关的技术反馈片段。
这件小事其实很真实。做 Agent / Vibe Coding 时,很多“奇怪报错”不是业务逻辑打架,而是:
- Markdown 代码块和普通文本混在一起;
- Python 字符串、Shell 引号、Java 字符串多层嵌套;
- Windows 路径反斜杠与转义规则碰撞;
- 注释里的引号、模板里的占位符互相干扰。
看起来只是“括号打架”,实际提醒我:给 AI 的上下文和约束,也是一种工程输入。输入不清楚,输出就容易在边缘处出问题。
七、最终验证结果
最终实际执行:
python tests/verify.py python-mcompileall-qagent_cli tests结果:四条端到端路径全部通过,Python 语法检查通过。
| 验证项 | 最终结果 |
|---|---|
| 合法 Java 文件 + 存在方法 | exit0,生成测试草稿 |
| 方法不存在 | exit3,stderr 说明缺失方法,stdout 无半成品 |
| 非 Java 文件 | exit2,拒绝处理 |
--output输出目录 | 生成目标文件;目标已存在时 exit5拒绝覆盖 |
| 源文件保护 | 输入文件哈希前后一致,未被修改 |
| Java 基础结构 | package/import 顺序、重复 package、括号平衡均有检查 |
这里也要诚实说明当前 MVP 的边界:
- 当前环境没有
javac,没有做真实编译级验证; - 示例依赖不是完整业务项目;
- 生成的是可审阅、可继续补全的测试草稿,不是承诺一次就能在真实项目中
mvn test通过的最终测试。
八、今日收获
知识层面
- 理解 CLI 是真实产品入口,不是模拟工具;
- 理解 Agent 工作流可以先用确定性规则跑通,再引入 LLM;
- 明确 Python MVP 与 Java / Spring AI 重构的衔接方式。
工程层面
- MVP 的重点不是“功能多”,而是边界清楚、可验证;
- 输出文件必须有隔离与拒绝覆盖策略;
- fail-fast 不是一句口号,需要落实到错误码、stdout/stderr 和测试路径;
- 测试既要有正向样例,也要有负向样例。
学习方式层面
今天我没有手写完整业务代码,但并不是把任务交给 AI 就结束了。
我真正做的是:确定范围、限制 AI 行为、提出验收、检查结果、发现漏洞、要求修复、再验证。
Vibe Coding 用来加速实现,不用来跳过学习。
九、留给读者的 4 个问题
1. 你会把“生成了代码”当作完成,还是把“通过可解释的验收”当作完成?
提示:可以从成功路径、失败路径、不变量和真实运行结果几个角度思考。
2. 一个 MVP 最该先砍掉什么功能?
提示:不一定是“最难的功能”,也可能是让输入、输出和验收边界突然变模糊的功能。
3. 为什么要为“本来不该出现的错误”写测试?
提示:想想import → package这种反例。如果没有它,测试全绿是否真的能证明规则被守住?
4. 未来把这个 Python CLI 重构为 Java / Spring AI 时,哪些模块不该被 LLM 替代?
提示:可以关注输入校验、文件权限、输出隔离、审计、错误码和结果验证。
十、明日计划
今天时间充裕,提前完成了原本 Day 30 的“最小实现 + 基础验收”。但学习 Day 不跳过,明天仍然是Day 30,主题调整为:理解与重构准备。
- 沿着
cli → parser → generator → verify阅读真实调用链; - 解释每个模块的输入、输出和失败行为;
- 区分哪些边界要在 Java / Spring AI 版保持稳定;
- 设计显式的
TestPlan,把“解析”“测试规划”“草稿生成”进一步拆开; - 为后续接入 LLM 制定最小增量路线,不急着扩功能。
📝小小腾老师评分
维度 得分 评价 MVP 需求与范围收敛 19/20 输入、输出、非目标与安全边界明确 CLI 工作流实现 20/20 控制台到文件输出形成真实闭环 验收与错误处理 20/20 四条路径、退出码、拒绝覆盖和输入保护均已验证 Vibe Coding 使用方式 18/20 能快速生成,也能根据验收持续修复 工程理解与复盘 15/20 已掌握结构校验与负向测试;AST 与真实 Java 编译仍待深化 总分:92 / 100(优秀)
老师说:今天最大的成果不是“AI 帮你写了一个 CLI”,而是你完成了一次标准工程闭环:需求收敛 → 实现 → 验收 → 缺陷修复 → 负向测试防回归。后面我们会把这条 Python 工作流读懂、拆开,再逐步迁移到你真正的 Java / Spring AI 主线。