记录我用AI工具实际解决的问题,记录尝试的过程,每个案例都是真实经历。
一、开发调试
作为开发人员,日常工作中最多的问题就是排查和解决Bug。AI工具在这方面的帮助超出我的预期。
1.1 解决BUG
案例1:Jar冲突导致Word导出失败
问题描述:执行Word模板填充功能时,使用EasyPoi库导出Word文档失败,抛出 NoSuchMethodError异常。
错误日志:
1 | Exception in thread "main" java.lang.NoSuchMethodError: org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth.getW()Ljava/math/BigInteger; |
提示词:程序启动报错 [Copy 10+] , 请修复。
AI分析错误日志,定位是Apache POI版本冲突问题,查看pom.xml中相关依赖版本,锁定 openxmlformats库版本不兼容,排除冲突依赖,统一定义版本
当天发了个朋友圈:
1 | 一个jar 冲突 的 bug 自己研究一小时,没解决。 |


1.2 代码审查
案例:Review代码指出问题
场景:开发完成代码后,让AI进行代码审查,发现潜在问题。
提示词:review vxlink-bill-server 项目下的 feature-workingday 分支代码
<think>现在我已经获取了完整的代码差异,可以进行代码审查了。让我分析一下这个分支的变更内容。
</think>现在我来对代码进行详细的 review:
📋 Code Review: feature-workingday 分支
一、概述
该分支主要实现了工作日服务功能,包括:
- 新增
WorkDayService接口及其实现- 新增 Redis 缓存枚举
RedisKeyPrefixEnum- 提供获取当月/下月第一个工作日的功能
- 使用 Redis 缓存优化查询性能
二、变更文件清单
文件 变更类型 说明 RedisKeyPrefixEnum.java新增 Redis 缓存 Key 前缀枚举 WorkDayService.java新增 工作日服务接口 WorkDayServiceImpl.java新增 工作日服务实现
三、代码质量分析
✅ 做得好的地方
- 接口设计清晰 -
WorkDayService接口职责单一,只提供两个方法- 使用缓存优化 - 实现了 Redis 缓存逻辑,减少 RPC 调用
- 使用函数式编程 - 使用
Supplier封装查询逻辑,代码简洁- 日志记录完善 - 有适当的 debug/info 日志
⚠️ 需要改进的问题
1. 缓存逻辑存在 Bug
1
2
3 // 第 55-56 行
String cachedValue = null != redisTemplate.opsForValue().get(key)
? redisTemplate.opsForValue().get(key).toString() : null;问题:对同一个 key 调用了两次
opsForValue().get(key),应该只调用一次然后判断结果。
1
2
3 // 建议修改为:
Object cachedObj = redisTemplate.opsForValue().get(key);
String cachedValue = cachedObj != null ? cachedObj.toString() : null;2. 日期处理逻辑有误
1
2 // getCurrentMonthFirstWorkDay() 方法
Date nextWorkDay = calendarRpc.getNextWorkDay(now);
- 方法名是获取"当月第一个工作日",但调用的是
getNextWorkDay(now)- 这实际上是获取下一个工作日,而非当月第一个工作日
3. 缓存 Key 缺少月份区分(潜在问题)
1
2 // 下月工作日缓存 Key
String nextMonthWorkdayKey = RedisKeyPrefixEnum.WORK_DAY.key("nextMonthWorkingday") + ":" + DateUtil.format(now, >DateFormatEnum.DASH_yyyy_MM.getCode());
- 当前只使用当前月份作为 key 的一部分
- 但下月第一个工作日应该跨月时需要考虑缓存失效问题
- 例如:4月28日缓存的"下月第一个工作日"应该是5月1日,但到5月1日时缓存仍然有效
4. Redis 缓存有效期设置不合理
1 redisTemplate.opsForValue().set(key, workDay, 24, TimeUnit.HOURS);
- 注释说"24 小时",但代码实际设置的是
24 * 30 = 720 小时(因为第一个参数是值,第二个是数量)- 应该明确是
24小时还是更长的有效期5. 缺少空值处理
- 如果 RPC 调用返回 null 或抛出异常,没有对应的容错处理
6. 不必要的导入
1 import org.springframework.test.context.TestConstructor;这个测试框架的导入不应该出现在生产代码中。
四、安全与规范检查
检查项 状态 说明 敏感信息 ✅ 通过 无敏感信息硬编码 空指针风险 ⚠️ 需注意 RPC 返回值未做空检查 日志规范 ⚠️ 需注意 info 日志过于频繁,适合改为 debug 异常处理 ❌ 缺失 缺少 try-catch 保护
五、建议修复优先级
优先级 问题 修复建议 🔴 高 缓存重复查询 优化为单次查询 🔴 高 缓存有效期单位 确认 24 小时语义 🟡 中 日期逻辑错误 确认业务需求,修正方法调用 🟡 中 缺少异常处理 添加 try-catch 和降级逻辑 🟢 低 删除无用导入 移除 TestConstructor 六、总结
该分支实现了基础的工作日查询功能,整体代码结构清晰,但在缓存实现细节和业务逻辑准确性上存在几个需要修复的问题。建议在合并前修复上述高优先级问题,以确保功能正确和性能最优。
1.3 生成单元测试
案例:生成测试用例
场景:写完业务代码,需要补充单元测试。或者要改动一个功能,先生成单元测试,然后让AI改动,改动后运行测试用例,确保功能正常后,再补充新增代码的单元测试。
案例:生成单元测试
场景:写完业务代码,需要补充单元测试。或者要改动一个功能,先生成单元测试,然后在让AI改动,改动后运行测试用例,确保功能正常后,在补充新增代码的单元测试。
提示词:com.vxlink.repay.ext.util.IdCardExtractor#extract 帮我生成单元测试。
后续会让AI填充测试数据,运行测试验证。
二、编码辅助
2.1 写SQL
案例:查询缺失数据的资产包
业务需求:查询资产包表,关键字段为空的记录。
提示词:请帮我写SQL,查询资产包表 [Copy 10+ 资产包表的DDL]中,关键字段为空的记录。关键字如下
转让签约日期、债转通知公告日期、成交金额、基准日债权总额、基准日债权本金、债转协议名称、债转协议编号
<think>用户想查询资产包表中关键字段为空的记录。关键字段包括:
- 转让签约日期 (transfer_signing_date)
- 债转通知公告日期 (debt_transfer_notice_time)
- 成交金额 (transaction_price)
- 基准日债权总额 (compute_total_amt)
- 基准日债权本金 (compute_total_principal_amt)
- 债转协议名称 (asset_agreement_name)
- 债转协议编号 (asset_agreement_code)
这是一个简单的查询任务,我可以直接写出SQL语句。用户说的是"关键字段为空的记录",应该是指这些字段中任意一个为空,或者可能需要同时满足多个为空。
我先写一个查询这些字段为空的SQL,使用 OR 条件连接,这样只要任意一个关键字段为空就会被查询出来。
</think>根据您提供的表结构和关键字段,我为您编写查询这些字段为空的记录:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 SELECT
id,
asset_code,
asset_name,
project_name,
transfer_signing_date,
debt_transfer_notice_time,
transaction_price,
compute_total_amt,
compute_total_principal_amt,
asset_agreement_name,
asset_agreement_code,
asset_status,
created_date
FROM pm_asset
WHERE is_deleted = 0
AND (
transfer_signing_date IS NULL
OR debt_transfer_notice_time IS NULL
OR transaction_price IS NULL
OR compute_total_amt IS NULL
OR compute_total_principal_amt IS NULL
OR asset_agreement_name IS NULL
OR asset_agreement_code IS NULL
)
ORDER BY created_date DESC;
说明:
- 使用
is_deleted = 0过滤掉已删除的记录- 使用
OR连接,只要任意一个关键字段为空就会被查询出来- 如需查询所有关键字段都为空的记录,将
OR改为AND需要我帮您执行这个查询吗?
如果你让他执行 ,他会反问你连接信息。当然到这一步,我么就不要再执行了。

2.2 变量命名
案例:摆脱命名困难症
痛点:经常为一个变量名纠结半天,真正做到了见名知意。
解决: AI 生成的代码命名非常规范。像xxxPO再也没有了(非驼峰命名,idea下划线提示,但这玩意也不能在团队间规约,因为很多人这么写)
再也不用忍受这样的命名了。

2.3 写正则表达式
案例:提取身份证号
场景:从文本中提取所有身份证号。
提示词: 我需要从一下备注 [Copy 10+ 银行流水表中的备注] 中尽可能的提取身份证号。帮我写一个用于提取用户姓名、身份证号的的方法,用Java实现。
三、脚本工具
3.1 启动服务
案例:vxlink-core-web 前端服务启动失败
问题描述:前端启动失败,不知道原因,也不关心原因
提示词:启动服务
3.2 打开本地应用
案例:一键启动开发环境
场景:每天早上需要打开多个应用(IDE、数据库工具、终端、浏览器)。
解决:让AI帮我写一个打开所有应用的脚本。
1 |
|
commond 中这么写
1 | cat cs-devtools.md |
案例:我想听歌
1 | cat cs-music.md |
注意 opencode 不会自动发现commond 但是 claude code 默认会自动发现,除非明确禁止。我认为commond应该是命令不开启的,只维护自己的明确的指令,防止注意力分散。
3.3 Git批量操作
案例:批量推送项目更新
场景:需要同时更新14个git仓库。需要每一个项目都新建一个分支,都添加一个 Agent.md 文件,然后推送到远程仓库。在发起合并请求的PR。
结果:
- 成功推送:14个项目 ✅
- 已更新:2个项目 ⏭️
- 有冲突:1个项目 ⚠️(需要手动合并)
1 | 成功推送的项目 ✅ |
3.4 写Shell脚本
案例:写爬虫
1 | @/Users/chenshang/Work/ShellScript/Crawler/PingAn/Controller/ArchiveController.sh |
1 | <think>用户想让我修复这个脚本,从第89行的result中提取URL并下载文件。 |
这里 result 已经包含了下载结果,包括 udmpFileUrl。现在需要:
- 从result中提取udmpFileUrl
- 使用这个URL下载文件
让我看看现有的batchFilesDownload函数做了什么,以及是否有其他下载相关的函数。
我需要先搜索相关文件来了解现有的函数。
</think>
我来帮你分析并修复这个脚本。首先让我了解一下相关的服务函数。
<think>让我看看PersonalLoanArchive.sh中的batchFilesDownload函数。
</think>
<think>让我看看batchFilesDownload函数的完整实现,以及是否有其他下载相关的函数。
</think>
<think>我明白了。batchFilesDownload 函数调用API获取文件信息,返回的结果中包含 udmpFileUrl。但是现在看起来,API返回的是一个包含文件URL的结果,而不是直接下载文件。
用户的需求是:从result中提取udmpFileUrl,然后用这个URL下载文件。
让我修复ArchiveController.sh的代码。从第87行开始,需要:
- 提取udmpFileUrl
- 用curl下载文件
看代码,当前逻辑:
1 | local result=$(batchFilesDownload "${projectId}" "${fileManageDtoList}") |
result返回的是:
1 | {"returnStatus":"S","returnCode":"000","errorSeqNo":null,"returnMessage":"交易成功","data":{"fileSeq":null,"fileName":"bhzx147-20260420230837.zip","uploadTime":null,"udmpDocId":"...","udmpFileUrl":"https://..."}} |
需要提取 data.udmpFileUrl 并下载。
让我修复第87-110行的代码。
</think>
明白了!batchFilesDownload 函数返回的是包含 udmpFileUrl 的JSON响应,需要提取这个URL再下载文件。让我修复脚本:
<think>好,我已经修复了代码。主要改动:
- 检查返回码是否为 “000”(成功)
- 从result中提取
udmpFileUrl和fileName - 使用 curl 下载文件到指定目录
- 保留了原有的异常检查逻辑
让我确认一下修改是否正确。
</think>
<think>代码已经修改完成了。让我给用户总结一下修改内容。
</think>
已修复!主要改动如下:
修改内容(第85-131行):
- 检查返回码 - 先验证API返回的
returnCode是否为000 - 提取URL - 从JSON中提取
udmpFileUrl和fileName - 下载文件 - 使用
curl -L从提取的URL下载文件到指定目录 - 保留重试逻辑 - 如果下载的文件是JSON(异常),会重试一次
关键代码:
1 | # 提取文件URL |
注意:代码第111行还有一个 exit 需要删除吗?看起来它可能会导致只处理一个合同就退出。让我检查一下:
<think>第132行有一个 exit,这会导致只处理一个合同就退出整个脚本。这个exit看起来应该删除,否则只会下载一个合同的文件。
</think>
我发现第132行有个 exit,这会导致只处理一个合同就退出整个循环!需要删除它:
<think>完成!已经删除了exit,现在循环可以正常处理所有合同了。
</think>
已修复完成!总结一下改动:
| 修改点 | 说明 |
|---|---|
| 第91-95行 | 新增返回码检查,确保API调用成功 |
| 第97-102行 | 提取 udmpFileUrl 和 fileName |
| 第104-107行 | 使用 curl 下载文件 |
| 第132行 | 删除 exit - 原来会跳过后续合同!现在可以正常遍历所有合同了 |
脚本现在会:
- 调用API获取文件信息
- 从返回的JSON中提取URL
- 使用curl下载zip文件
- 检查文件是否正常(如果是JSON说明出错,会重试)
- 正常完成后记录到
has_archive.csv
1 |  |
提示词:com.vxlink.registration.ext.service.caseInfo.impl.TcCaseInfoExtServiceImpl#updateCreditSubmitStatus
这段代码在干什么
1 |
提示词:com.vxlink.registration.ext.service.caseInfo.impl.TcCaseInfoExtServiceImpl#updateCreditSubmitStatus
这段代码的业务逻辑是什么?
1 |
提示词:com.vxlink.registration.ext.service.caseInfo.impl.TcCaseInfoExtServiceImpl#updateCreditSubmitStatus
这段代码的业务逻辑使用mermaid画成流程图
1 |
提示词:/flow com.vxlink.registration.ext.service.caseInfo.impl.TcCaseInfoExtServiceImpl#updateCreditSubmitStatus
1 |
提示词:/flow com.vxlink.registration.ext.service.caseInfo.impl.TcCaseInfoExtServiceImpl#updateCreditSubmitStatus
重点整理 countAssetBaseInfo 逻辑
1 |
|
vxlink-registration-server/vxlink-registration-server-> ext/src/main/java/com/vxlink/registration/ext/plugin/logic/TaCaseInfoLogicPluginEx.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
**计算逻辑(第58-68行)**:
```java
LocalDate currentDate = LocalDate.now();
results.forEach(result -> {
//权利转移日/交易基准日
Date overdueDate = result.getBaseTime();
if (overdueDate == null) {
return;
}
LocalDate localDate = overdueDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
long days = ChronoUnit.DAYS.between(localDate, currentDate);
Integer overdueDay = result.getOverdueDay();
long age = (days + overdueDay) / 30;
result.setOverdueDayNow(days + overdueDay + "(M" + age + ")");
});计算公式:
实时逾期天数 = (当前日期 - 权利转移日/交易基准日) + 封包日逾期天数
baseTime: 权利转移日/交易基准日overdueDay: 封包日逾期天数- 最终结果格式:
days + overdueDay + "(M" + age + ")"(如:120(M4))其中
age(账龄)= 逾期天数 / 30补充说明:这个计算逻辑是在查询后通过Plugin插件机制实时计算的,并不是存储在数据库中的固定值。
六、从零开发应用
提示词:这个需要经过多轮对话实现。
部门AI员工应用

七、创意娱乐
7.1 生成音乐
工作之余,想用AI生成一些背景音乐。
案例:生成舒缓的背景音乐
使用的工具:豆包、Gemini
过程:描述想要的风格(轻音乐、钢琴曲、缓解压力),AI生成音乐。
7.2 生成歌曲
八、帮我制定团队规约
参考 Ai Coding Rules 规约