一、先说清楚我在做什么
气象类应用平台,核心工作是汇集引接各种类型的大数据量产品。不同数据源有不同的处理规则------温度、湿度、气压、雷达回波、卫星云图,每种数据的解析逻辑、校验规则、存储策略都不一样。
但架构高度统一:Kafka 做数据管道 + PowerJob 做分布式任务调度。
- 数据量大,不能单机硬扛。Kafka 负责削峰填谷,PowerJob 负责把数据处理任务分片下发到集群执行。每个项目都是这个套路,相当于同一套骨架,换了 N套内脏。
- 今年离职的人有点多,给我的6个项目都在跑这套架构。之前每个项目都要重复写差不多的代码------Kafka Consumer、PowerJob Processor、数据解析、校验、入库。写多了就发现:90% 是重复劳动,10% 是业务差异。
那 10% 的差异(不同数据格式、不同校验规则)才是真正值钱的部分。所以也为了磨合我的ai,所以尝试让AI 帮我搞定那 90%。
二、编码阶段:AI 批量生成"Kafka + PowerJob"模板代码
1. 先给 AI 喂"项目记忆"
这是一个细碎、占用时间的过程,一开始踩坑,不会提问,宽泛得跟 AI 说"帮我写一个 Kafka 消费者处理气象数据",它给出来的代码能用,但风格跟我的项目完全不搭------包名不对、日志格式不对、异常处理方式不对。
后来我学了一招:每次开新会话,先把项目的"上下文"喂给 AI。
我建了一个 project_context.md,每次复制粘贴:
【项目技术栈】
- Spring Boot 3.2 + MyBatis-Plus 3.5
- Kafka 2.8(消费者配置:手动提交 offset,批量拉取 500 条)
- PowerJob 4.x(处理器继承 BasicProcessor,使用 Map 模式分片)
【代码规范】
- 包结构:com.xxx.consumer / processor / service / entity / dto
- 日志:统一使用 @Slf4j,打印入参和耗时
- 异常:统一抛出 BusinessException,由全局异常处理器兜底
- 返回体:统一 Result<T> 包装
【禁止项】
- 不在 Consumer 里直接写业务逻辑(全部交给 Service)
- 不在 Processor 里硬编码数据源配置
- 不 catch 异常后吞掉不打印
就这一段话,AI 生成的代码从"能跑但不像我的代码"变成了"改个包名就能用"。差别不在于会不会跟 AI 说话,在于给了 AI 多少它能用的上下文。
2. 生成 Kafka Consumer 模板
6个项目都要写 Kafka Consumer,区别只是 Topic 名称和数据类型不同。我的 Prompt 模板长这样:
你是一个资深 Java 后端工程师。
技术栈:Spring Boot 3.2 + Kafka 2.8(手动提交 offset)。
业务需求:实现一个 Kafka 消费者,监听 Topic: [填入topic名称]。
数据类型:[粘贴 JSON 示例或 DTO 定义]。
处理逻辑:收到消息后,调用 DataProcessService.process() 处理,处理成功后手动提交 offset,失败则进入重试队列。
项目规范:包路径 com.xxx.consumer,使用 @Slf4j,异常统一抛 BusinessException。
输出要求:生成 Consumer 类和对应的 DataProcessService 接口及实现类骨架。
禁止项:不要在 Consumer 里写业务逻辑,不要吞异常。
AI 一次生成三个类:XxxConsumer、XxxDataProcessService、XxxDataProcessServiceImpl。我只改 process() 方法里的具体解析规则------那是那 10% 的业务差异,AI 猜不准,得我自己写。
3. 生成 PowerJob Processor 模板
PowerJob 支持单机、广播、Map、MapReduce 四种执行模式。气象数据量大,我用的是 Map 模式------把一批数据按某个维度(比如时间片、区域)分片,下发到集群并行处理
Prompt 模板:
你是一个资深 Java 后端工程师。
技术栈:Spring Boot 3.2 + PowerJob 4.x。
业务需求:实现一个 PowerJob 处理器,处理 [数据类型] 的批量计算任务。
执行模式:Map 模式,按 [分片维度,比如日期/区域] 分片,每个分片独立处理。
处理逻辑:每个分片调用 XxxService.calculate(shardParam) 执行计算,结果汇总后写入数据库。
项目规范:包路径 com.xxx.processor,继承 BasicProcessor,使用 @Slf4j。
输出要求:生成 Processor 类和对应的 Service 类。
禁止项:不要在 Processor 里直接操作数据库,全部通过 Service。
PowerJob 的 Map/MapReduce 处理器能让开发者用寥寥数行代码就获得集群分布式计算能力。AI 把骨架搭好,我只需要填充每个分片的具体计算逻辑。
4. 批量生成单元测试
单元测试最枯燥,也让 AI 干。
为刚才生成的 XxxConsumer 和 XxxProcessor 编写单元测试。
使用 JUnit 5 + Mockito。
覆盖场景:
- 正常消费:消息解析成功,offset 提交
- 解析失败:抛出 BusinessException,offset 不提交
- 空消息:不做任何处理
- 批量消息:逐条处理,部分失败不影响整体
AI 生成的测试类覆盖了 80% 的边界情况,我只需要补充一些业务特有的断言。
实际效果 :一个新项目从零到跑通,原来要 3 天,现在 1.5 天。省下来的时间全花在那 10% 的业务逻辑上------这才是人的价值。
三、排障阶段:AI 帮我推演"数据丢了/重复了/算错了"
气象数据处理最怕三件事:数据丢了、数据重复了、数据算错了。这三类问题在 Kafka + PowerJob 架构下各有各的成因,排查起来非常耗时。
1. 数据丢失:AI 帮我排查 Kafka 消费位点问题
有一次某个项目的数据量突然少了 30%,Kafka 消费者没报错,PowerJob 任务也正常完成,但数据库里就是少了。
我把现象、配置、日志片段喂给 AI:
Kafka 消费者配置:enable.auto.commit=false,手动提交。
现象:某 Topic 消息量正常(监控显示),但数据库入库量少了 30%。
日志:无异常,Consumer 的 poll() 正常返回。
PowerJob 处理器:使用 Map 模式,10 个分片并行处理。
请列出所有可能导致数据丢失的原因,按概率排序,并给出排查步骤。
AI 给出的排查树:
数据丢失可能原因(按概率排序):
1. 【高】手动提交 offset 的时机不对 ------ 处理成功后才提交,但如果处理成功后、提交前服务重启,这批消息会重复消费(不会丢),但如果提交逻辑写在了 try 块外面,异常时没提交也没记录 → 数据"看起来"丢了
2. 【中】PowerJob Map 模式分片丢失 ------ 某个分片处理失败但没有重试,Map 任务默认不会自动重试失败的分片
3. 【中】Kafka 消费者 group.id 变化 ------ 换了 group 导致从头消费,但旧的 offset 已经过期
4. 【低】数据在 Producer 端就没发出来 ------ 检查 Producer 的 acks 配置
按这个顺序排查,最后发现是 PowerJob 某个分片处理超时,任务标记为失败但没有重试机制 。加了一个 @PowerJobRetry 配置后解决。
有个大佬曾经说过:
AI 的价值不是直接告诉你答案,而是帮你把"可能的坑"列全,避免凭经验漏掉某个方向
2. 数据重复:AI 帮我推演幂等性失效场景
另一个项目出现数据重复------同样的气象数据被处理了两次,数据库里多了重复记录。
场景:Kafka 消费一条消息,PowerJob 处理这条数据,写入数据库。
问题:同一条数据被处理了两次(ID 相同),数据库出现了重复记录。
当前设计:数据库有唯一索引,按理说重复插入会报错,但日志里没有 DuplicateKeyException。
请帮我推演:在什么情况下,唯一索引没有生效?或者重复数据是怎么绕过唯一索引的?
AI 的推演:
可能性 1:唯一索引没建对 ------ 检查索引是否包含所有业务唯一字段
可能性 2:两条数据的业务唯一字段不同 ------ 比如时间戳精度不同(毫秒 vs 秒),导致被认为是两条不同的数据
可能性 3:数据在写入前被 PowerJob 修改了 ------ 比如处理过程中给数据加了一个"批次号"字段,导致唯一键变了
可能性 4:Kafka 消费了两次,但第一次处理失败回滚,第二次成功 ------ 唯一索引在第一次回滚时不存在,第二次写入成功
最后发现是 PowerJob 处理逻辑里给数据加了一个"处理时间"字段,这个字段每次运行都不一样,导致联合唯一索引失效。去掉这个字段后问题解决。
3. 排查思路固化
每次 AI 帮我排查完一个问题,我都会把排查树 保存下来,放到项目的 docs/troubleshooting.md 里。下次遇到类似问题,先查文档,不行再问 AI。
四、验收阶段:AI 代码自查清单
AI 生成的代码快,但质量不稳定。直接上线不放心,全量 review 又太累。
我搞了一个 AI 代码自查清单,每次 AI 生成代码后,我自己对照清单过一遍:
气象数据处理专属清单:参考
| 检查维度 | 具体条目 | 为什么对气象项目重要 |
|---|---|---|
| Kafka 消费 | 手动提交 offset 是否在业务处理成功后执行 | 数据丢了就是事故 |
| Kafka 消费 | 批量消费时是否逐条处理 + 逐条提交 | 一条失败不能全回滚 |
| PowerJob | Map 分片失败是否有重试机制 | 气象数据量大,分片多,失败概率高 |
| PowerJob | 分片大小是否可配置(不硬编码) | 不同数据类型数据量不同 |
| 数据解析 | 是否处理了空值、缺失字段、格式异常 | 气象数据源多样,格式不统一 |
| 数据幂等 | 写入是否有唯一索引或去重逻辑 | 重复数据会污染分析结果 |
| 日志 | 是否打印了消息 ID、分片 ID、处理耗时 | 排查问题时全靠日志 |
| 异常处理 | 是否 catch 后打印完整堆栈 + 上下文 | 光看异常信息找不到根因 |
每次 review AI 代码时,对照清单逐项打勾。10 分钟能过完一个模块,比全量 review 省 70% 时间
把清单变成 AI 的"前置约束"
更好的做法是:在让 AI 写代码之前,就把清单里的要求写进 Prompt。
比如在生成 Kafka Consumer 的 Prompt 里加一句:
【禁止项】
- 禁止在业务处理成功前提交 offset
- 禁止 catch 异常后不打印完整堆栈
- 禁止硬编码任何配置(Topic、分片数、超时时间等全部从配置文件读取)
AI 生成的代码天然符合清单要求,返工率从 30% 降到不到 10%。
五、测试数据:Python 脚本批量生成气象模拟数据
集成测试需要数据。真实数据量大、格式复杂,每次拉取太慢。我写了一个 Python 脚本,模拟生成气象数据。
脚本核心逻辑
import random
import json
from faker import Faker
from datetime import datetime, timedelta
fake = Faker('zh_CN')
# 气象数据类型配置
DATA_TYPES = {
'temperature': {'min': -30, 'max': 45, 'unit': '℃'},
'humidity': {'min': 0, 'max': 100, 'unit': '%'},
'pressure': {'min': 950, 'max': 1060, 'unit': 'hPa'},
'wind_speed': {'min': 0, 'max': 40, 'unit': 'm/s'},
}
def generate_weather_data(station_id, data_type, timestamp):
"""生成单条气象数据"""
config = DATA_TYPES[data_type]
value = round(random.uniform(config['min'], config['max']), 2)
return {
'stationId': station_id,
'dataType': data_type,
'value': value,
'unit': config['unit'],
'timestamp': timestamp.isoformat(),
'dataId': fake.uuid4()[:8],
}
def generate_batch(station_count=100, types=['temperature', 'humidity'],
hours=24, interval_minutes=10):
"""批量生成:100个站点 × 2种数据类型 × 24小时 × 每10分钟一条"""
data = []
start_time = datetime.now() - timedelta(hours=hours)
for i in range(station_count):
station_id = f"ST{i:04d}"
for t in types:
for minute in range(0, hours * 60, interval_minutes):
ts = start_time + timedelta(minutes=minute)
data.append(generate_weather_data(station_id, t, ts))
return data
# 生成并输出为 JSON,直接推送到 Kafka 测试 Topic
if __name__ == '__main__':
batch = generate_batch()
with open('test_data.json', 'w') as f:
json.dump(batch, f, indent=2)
print(f"生成了 {len(batch)} 条测试数据")
怎么用的
-
每次改完代码,跑一遍脚本生成测试数据
-
推送到 Kafka 测试 Topic,观察消费和处理流程
-
对比数据库里的结果和预期,验证逻辑正确性
效果 :原来集成测试全靠从生产环境拉一小部分真实数据,步骤繁琐且数据量不可控。现在一键生成任意规模的数据,测试覆盖率翻倍,测试时间减半。
六、数据说话:一个人管 6 个项目
| 指标 | 用 AI 前 | 用 AI 后 |
|---|---|---|
| 新项目从零到上线 | 3 天 | 1.5 天 |
| 单元测试覆盖率 | ~50% | ~85% |
| 线上问题排查时间 | 1-2 小时 | 20-40 分钟 |
| AI 代码返工率 | ~30% | <10% |
| 同时维护项目数 | 3-4 个 | 6 个 |
6 个项目,同样的架构,不同的数据规则。AI 帮我搞定了那 90% 的重复劳动,我把精力全部花在那 10% 的业务差异上。
七、几点实在的建议
1. 先建"项目上下文"文档。 每次跟 AI 对话前把技术栈、包结构、规范、禁止项贴一遍。花 2 分钟,省 2 小时返工。
2. 把重复场景模板化。 Kafka Consumer 一个 Prompt 模板,PowerJob Processor 一个 Prompt 模板,每次只改关键字段(Topic、数据类型、分片维度)。别每次都从头写 Prompt。
3. 排障时让 AI 出"排查树"而不是"直接答案"。 "列出所有可能的原因,按概率排序"比"告诉我为什么"有用得多。
4. 建一个自查清单,每次 review 对着打勾。 10 分钟过完一个模块,比漫无目的地看代码效率高得多。
5. 把清单写进 Prompt 的"禁止项"里。 让 AI 在生成时就避开常见坑,而不是生成后再改。
6. 测试数据脚本要能一键生成、一键推送。 越简单你越愿意用,越愿意用 bug 就越少。
AI 不是银弹,但在这个场景里------同一套架构重复 6 遍------它确实是那把最趁手的工具。