早上9点,疾控中心信息科的老师发来消息:"领导催着要应急管理的系统化方案,下周演示,你们能不能做?"换成以前,从需求调研到演示环境,排期少说一周。但这回我只排了一天,而且把核心工作交给了两个AI工具:Hermes负责任务拆解、需求设计和数据建模,Cursor负责把设计翻译成代码。做完之后我特意复盘了一遍,发现这个"一天交付"不是运气,而是一套新工作流带来的必然结果。
先说明这个项目到底做了什么:疾控应急管理系统,覆盖突发事件上报、应急物资台账与调拨、应急队伍调度、处置流程跟踪,外加一个指挥大屏展示和一套基础权限管理。系统本身不是高并发高复杂度的互联网产品,但业务流程琐碎、状态流转多、报表口径多,这正是AI Agent最擅长处理的场景。这篇文章把Hermes和Cursor的分工、提示词怎么设计、代码怎么落地、联调时哪些环节最坑,完整写出来,供想做类似项目的团队参考。
1. 为什么选Hermes + Cursor,而不是传统协作方式
1.1 疾控应急需求的真实痛点
疾控行业的应急管理系统,需求来源往往很"原始"。信息科老师给你的不是PRD,而是几句话:"现在发生突发公共卫生事件都是打电话、发Excel,领导要看实时进展,物资调拨也要能查。"真正开始梳理的时候会发现,这里边牵扯的角色很杂:一线报告人员、应急办审核人员、物资管理员、应急队伍队长、中心领导。每个角色关心的数据维度都不一样。
传统开发流程在这种场景下有天然短板。需求靠口头加Excel传递,等开发把原型做出来,业务人员才反应过来"哦,我要的不是这个"。一版一版改,时间全耗在需求确认上。而且疾控应急有个特点:流程不能随便设计,必须跟上实际的应急预案口径,比如事件分级、响应时间节点、物资分类编码,这些都不是拍脑袋能定的。
所以我这次刻意把流程倒过来:先让AI Agent把"模糊需求"逼成"结构化需求",再让人做业务口径把关,最后才交给代码生成工具去写。这套顺序是项目和传统方式最不一样的地方。
1.2 Hermes和Cursor的分工逻辑
很多团队用AI编程的姿势是:打开Cursor,让AI直接生成整个项目。我试过,结果是一堆看似能跑但逻辑残缺的代码,尤其是表结构设计前后矛盾,改起来比重写还费劲。原因很简单:代码生成工具擅长"在明确任务下执行",不擅长"帮你把需求想清楚"。需求都没收敛,代码只会越写越乱。
Hermes在这里承担的是需求Agent的角色。我给它喂原始诉求,它会基于公开行业知识库补全出功能清单、角色权限、状态流转、数据实体。它不是人类业务专家,但它能把"该设计什么东西"这件事穷举得比较完整。我再基于对疾控业务的理解,把里面不符合实际口径的东西删掉或修正。这一步做完,数据库表、接口清单、页面清单基本就稳定了。
Cursor承担的是编码执行的角色。设计定稿之后,把功能描述、表结构、接口约定喂给Cursor,让它生成代码。因为输入已经很明确,它输出的代码质量远高于"从零直接写"。说白了,Hermes做的是"想清楚做什么",Cursor做的是"快速做完"。
1.3 一天的排期长什么样
很多人听到"1天做完"第一反应是通宵。实际排下来,我基本是正常上下班,晚上7点前收工。节奏如下:
| 时间段 | 任务 | 使用工具 |
|---|---|---|
| 08:30-10:30 | 需求梳理、功能清单、数据建模 | Hermes |
| 10:30-12:00 | 项目初始化、用户权限模块 | Cursor |
| 13:30-16:30 | 事件、物资、队伍、大屏四大模块 | Cursor |
| 16:30-18:00 | 联调自测、修复Bug | Cursor + 人工Review |
| 18:00-19:00 | 造演示数据、跑通演示流程 | 人工 |
这个排期能成立的前提是,上午的设计阶段真的想清楚了,而不是花一上午讨论"这个按钮放左边还是右边"。AI的价值之一就是帮你快速跳过无意义的纠结。
技术栈选择上也说下我的考虑:后端用Spring Boot 3 + MyBatis-Plus + MySQL 8,前端用Vue3 + Element Plus + ECharts。为什么不用Python系?因为疾控行业的信息科后续大概率要自己维护,Java体系在国内最普及,交接成本最低。而且Cursor对Spring Boot的生态理解足够深,生成出来的代码风格统一,接手的人不会觉得陌生。
2. 用Hermes做需求梳理与数据建模的完整过程
2.1 第一轮对话:把口头需求变成功能清单
我一开始没有指望Hermes一步到位。第一轮对话我做的事情很简单:给它一个角色设定和一段原始诉求,然后让它穷举。
你现在是一名有十年经验的疾控信息系统产品经理。我们需要开发一套疾控应急管理系统,使用方包括一线报告人员、应急办、物资管理员、应急队伍、中心领导。请基于疾控中心实际的突发公共卫生事件应急业务,先输出完整的功能清单,包括:事件管理、物资管理、应急队伍管理、指挥大屏、系统管理,每个模块下列出核心功能点,并说明每个功能点的使用角色。
Hermes第一轮输出大概有8000多字,把业务框架搭得很全。它列出的功能模块远远超出我原始的诉求,例如事件管理里补充了"事件分级动态调整""事件关联报告""结案审核归档",物资里补充了"安全库存预警""批次效期管理",队伍里补充了"值班排班""出勤记录"。这些其实是行业里已经有的标准做法,但如果你不是这个业务背景的人,很容易漏。
这一步的产出是一份功能清单。我不关心格式漂不漂亮,只关心一件事:还有哪些功能是业务方会问"这个有没有"的。
2.2 第二轮对话:从功能清单到数据库表结构
功能清单确认后,我继续让Hermes做数据建模:
基于以上功能清单,请设计MySQL数据库表结构。要求:
- 每张表给出表名、字段名、类型、注释、主键策略;
- 标注表之间的外键关系;
- 事件、用户、物资、队伍之间如果有关联,需要给出关联表设计;
- 考虑到应急管理系统需要审计追溯,操作日志、状态变更记录不能缺失。
它给出的核心表大致如下(节选关键字段):
CREATE TABLE event_info ( id BIGINT PRIMARY KEY AUTO_INCREMENT, event_code VARCHAR(32) NOT NULL COMMENT '事件编号', event_name VARCHAR(200) NOT NULL COMMENT '事件名称', event_type VARCHAR(50) COMMENT '事件类型编码', event_level VARCHAR(10) COMMENT '事件等级:一般/较大/重大/特别重大', address VARCHAR(255) COMMENT '事发地址', report_user_id BIGINT COMMENT '报告人ID', report_time DATETIME COMMENT '报告时间', status TINYINT COMMENT '0草稿 1待审核 2处置中 3已结案 4已退回', description TEXT COMMENT '事件描述', UNIQUE KEY uk_event_code (event_code) );这版设计覆盖了主要实体:事件、事件处置记录、物资信息、出入库流水、调拨单、队伍、队员、系统用户、角色、菜单、操作日志。但我看过之后发现几个问题:一是事件和调拨单、事件和队伍派单之间没有关联表,这会导致"这个事件动了哪些物资、派了哪支队伍"查不到;二是缺少事件附件表,实际业务里现场照片、检测报告都是要留档的;三是没有考虑物资批次效期,疾控物资是有失效日期的。
我又让Hermes补了一轮,加了三张表:event_material_rel事件物资关联表、event_team_rel事件队伍关联表、attach_file附件表。到这一步,数据模型才算真正能落地。
2.3 人工把关清单:哪些不能全信AI
这是我最想强调的部分。AI建模速度快,但它不知道你所在地区的实际业务口径,以下几个地方必须人工过一遍:
| 检查点 | AI容易出的问题 | 人工把关方式 |
|---|---|---|
| 权限模型 | 只设计了菜单权限,漏了按钮权限 | 逐角色确认"谁能新增、谁能审核、谁能结案" |
| 状态流转 | 状态枚举随意定义,没有闭环 | 对照应急预案确认事件必须经过哪些状态 |
| 字段字典 | 事件类型、物资分类乱编 | 替换成本地实际使用的编码体系 |
| 删除策略 | 喜欢物理删除,破坏审计链 | 要求业务表一律逻辑删除 |
| 必填校验 | 很多字段漏掉NOT NULL | 核对上报页面必须填哪些项 |
做完这轮把关,设计阶段才算结束。后面编码快不快,完全取决于这一步做得细不细。
2.4 部署方式备注
Hermes我是在Windows本机用Docker Desktop跑起来的,没有用远程API。本地部署的好处是文档、SQL这些中间产物可以直接落盘,不用来回复制,隐私上也更踏实。配置要求不算高,8G内存的机器能流畅对话。实际使用中我发现,对话上下文越长越容易偏离主题,所以建议一个大型任务拆成几次独立会话,每次会话聚焦一个产出物,比如"本次会话只做数据建模"。
3. Cursor编码落地:核心模块的实战细节
3.1 项目骨架和基建怎么搭
设计稿定下来之后,Cursor的工作从搭建骨架开始。我先让它生成整个工程的基础结构,包括pom依赖、application.yml、统一返回对象R、全局异常处理器、MyBatis-Plus分页配置、JWT登录拦截器。
给Cursor的指令要非常具体,比如:
创建一个Spring Boot 3项目,要求:
- 引入spring-boot-starter-web、mybatis-plus-boot-starter、mysql-connector-j、lombok、jjwt、hutool;
- 写一个统一的返回结果类R,包含code、msg、data;
- 写一个全局异常处理器,处理业务异常和参数校验异常;
- yml配置数据库连接和mybatis-plus的逻辑删除、驼峰映射。
Cursor生成的代码质量在这个阶段是最稳定的,因为都是标准模板。真正需要人工介入的是"代码组织方式"。AI默认会生成一个几百行的Service类,把所有方法堆在一起。我会让它拆成EventService、MaterialService、TeamService、DashboardService,每个Service只做自己领域的逻辑。这个拆分越早做,后面越省事。
3.2 应急事件上报模块的编码
事件模块是整个系统的核心,包含上报、审核、处置、结案、退回五个动作。我让Cursor按状态机思路实现,而不是随手写if-else。
核心状态流转如下:草稿 -> 待审核 -> 处置中 -> 已结案;待审核可以被退回成草稿。删除只允许草稿状态执行。这个约束看起来简单,但如果散落在各个方法里,很容易漏。
我让Cursor生成的核心Service片段:
@Transactional public void updateStatus(Long id, Byte targetStatus, Long operatorId) { EventInfo event = getById(id); if (event == null) { throw new BizException("事件不存在"); } // 状态流转校验:当前状态是否允许变更到目标状态 if (!StatusFlow.canTransit(event.getStatus(), targetStatus)) { throw new BizException("非法状态流转: " + event.getStatus() + " -> " + targetStatus); } event.setStatus(targetStatus); updateById(event); // 写入状态变更记录,用于审计 EventStatusLog log = new EventStatusLog(); log.setEventId(id); log.setFromStatus(event.getStatus()); log.setToStatus(targetStatus); log.setOperatorId(operatorId); log.setOperateTime(LocalDateTime.now()); eventStatusLogMapper.insert(log); }这里有个值得注意的点:Cursor默认生成的状态校验就是简单的if判断,比如if (!"1".equals(status))。我要求它抽取一个StatusFlow.canTransit方法,把所有合法流转定义在同一个类里。这样以后要调整流程,只改一处,不会出现"这里能退、那里不能退"的诡异情况。
3.3 物资库存和调拨:并发控制不能省
疾控应急系统的并发量不大,但不代表可以裸扣库存。调拨、出库、盘点几个操作同时发生时,库存数据会出现偏差。我要求Cursor在扣减库存时使用乐观锁,用一条SQL完成"扣减并校验库存充足":
@Transactional public void outbound(MaterialIoRecord record) { // 先扣库存,受影响行数为0说明库存不足或物料不存在 int rows = materialInfoMapper.deductStock( record.getMaterialId(), record.getQuantity() ); if (rows == 0) { throw new BizException("库存不足,扣减失败"); } // 再写入库流水 materialIoRecordMapper.insert(record); }对应的Mapper方法:
@Update("UPDATE material_info SET stock = stock - #{quantity}, update_time = NOW() " + "WHERE id = #{materialId} AND stock >= #{quantity}") int deductStock(@Param("materialId") Long materialId, @Param("quantity") Integer quantity);注意这里用了stock >= #{quantity}条件,加上受影响行数判断,天然避免了负数库存。调拨单逻辑类似,但要同时处理调出仓扣减和调入仓增加,两个操作必须在同一个事务里。我给Cursor的要求是"调拨单创建时同时生成两条出入库流水,调出为出库,调入为入库,任何一步失败全部回滚"。这个约束是物资模块的底线,不能妥协。
3.4 大屏统计和权限控制
指挥大屏是这个项目的门面,领导最先看的就是它。大屏需要展示的内容包括:待处置事件数、近7日事件趋势、物资预警清单、应急队伍在岗状态。我用一个DashboardController聚合四个统计接口。
-- 近7日事件趋势 SELECT DATE_FORMAT(report_time, '%Y-%m-%d') AS day, COUNT(*) AS cnt FROM event_info WHERE report_time >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) GROUP BY DATE_FORMAT(report_time, '%Y-%m-%d') ORDER BY day;这种统计SQL对数据库压力不大,MySQL处理几万行数据毫无压力。但要注意给report_time和status建索引,否则数据量上来后大屏响应会变慢。这是AI容易忽略的地方,它生成的Mapper可能不带索引建议,需要人工在Review时补上。
权限控制方面,Cursor可以生成基于注解的接口权限校验,前端配合按钮级指令。但这里有个隐蔽的问题,后面联调时会详细说:AI生成的菜单表和接口注解里的权限标识经常对不上。
4. 联调阶段踩到的坑和验收清单
4.1 坑一:事件编号并发重复
第一次联调时,我快速点击两次"上报",结果第二条数据直接插入失败,数据库报唯一索引冲突。排查过程很快:看日志发现报错指向uk_event_code,再往前翻单号生成逻辑,发现Cursor用new Date().getTime()加3位随机数生成单号。理论上毫秒级时间戳一般不会重复,但两台机器时间一致或者单线程快速调用时,随机数还是可能碰撞。
修复分两层:一是单号规则加上业务前缀、时间戳精确到毫秒、随机数扩大到5位;二是保留数据库唯一索引作为最终兜底。这种问题靠AI自己是发现不了的,它生成代码时看不到"数据库里有唯一索引"这个约束,必须人工在Review时盯住。
4.2 坑二:菜单权限标识和接口注解不一致
这个坑排查了将近40分钟。现象是:给管理员账号分配了"事件审核"菜单权限,登录后打开审核页面,点击"通过"按钮却提示无权限。数据库菜单表里权限标识是event:audit,接口上的注解也是event:audit,看起来没问题。最后把SQL日志打开,发现前端按钮调用的接口路径是/api/event/approve,而这个接口上的注解写的是event:approve。菜单权限标识和接口权限标识不一致,自然被拦截器拦下来。
修复方法就是统一命名。我让Cursor全局搜索所有@RequiresPermission注解,列出一个菜单权限表和注解对照表,逐个核对。这个工作不复杂,但很烦琐。经验是:权限标识这种元数据,从设计阶段就要定好命名规范,否则AI在不同位置生成的标识很容易漂移。
4.3 其他值得注意的小问题
时间格式化是另一个常见问题。Spring Boot默认的Jackson配置会把LocalDateTime序列化成数组或时间戳,前端拿到根本没法直接用。Cursor生成的代码不会主动处理这个问题,我手动加了一个全局Jackson配置,统一输出yyyy-MM-dd HH:mm:ss。
还有事务注解丢失的问题。AI生成Service方法时,有时会忘记加@Transactional。我Review时发现物资调拨方法里,扣减库存和写流水两个操作没有放在一个事务里,如果流水写入失败,库存就凭空少了。排查方法是全局搜索所有涉及多表写入的Service方法,逐个确认事务注解。
联调阶段我整理了一份验收清单,适合所有AI辅助开发的项目:
| 检查项 | 检查方式 | 状态 |
|---|---|---|
| 事务完整性 | 搜索所有多表写入方法,检查@Transactional | 通过 |
| 唯一性约束 | 检查业务唯一字段是否建唯一索引 | 通过 |
| 权限标识 | 菜单权限和接口注解逐项对照 | 通过 |
| SQL性能 | 检查大屏统计SQL走索引 | 通过 |
| 时间格式 | 前后端联调确认显示正常 | 通过 |
| 逻辑删除 | 确认所有业务表继承逻辑删除字段 | 通过 |
5. 这套工作流的边界和后续演进
5.1 什么样的项目适合"1天AI交付"
这次做完之后,我仔细想过适用范围。任何工作流都有边界,不能拿锤子看什么都是钉子。
适合做"1天AI交付"的项目特征比较明显:以CRUD为主、业务流程标准、数据量不大、演示级交付可接受、业务口径相对固定。疾控应急管理系统恰好都满足:事件、物资、队伍都是标准实体,没有复杂的推荐算法,没有高并发交易,领导要的是流程跑通和数据可视化。
不适合的场景我列了个表:
| 不适合场景 | 原因 |
|---|---|
| 高并发交易系统 | AI生成的代码缺少压测和性能调优经验 |
| 强合规审计系统 | 审计要求、加密算法、留痕规则需要专人把关 |
| 复杂算法模块 | AI只能模仿常见算法,精细调参仍需专家 |
| 硬件对接系统 | 设备协议、串口通信、离线容错需要专业开发 |
5.2 疾控应急系统还能往哪个方向演进
当前版本是Web端管理系统,单机部署,满足演示和基本使用没问题。后续如果有生产环境真实使用,有几个方向必然要补。
第一是GIS地图展示。突发公共卫生事件天然带空间属性,领导看的是"哪个区、哪个街道、周围什么情况"。前端用Leaflet或MapBox接入地图,事件上报时记录坐标,大屏上按点位展示。这个功能的前后端代码都可以借助AI生成,但地图底图和坐标系转换需要人工把关。
第二是通知推送。系统目前靠站内消息提醒,真实场景下一线人员不可能一直盯着系统。对接企业微信或短信平台,事件升级、物资预警时自动推送,这个需求很实际。
第三是数据交换。疾控体系上下级单位之间需要上报数据,系统要预留标准数据交换接口。这不是简单加几个接口的事,涉及数据字段映射、传输加密、幂等控制,建议在一个正式版本中专项处理,不适合在"1天交付"里硬塞。
5.3 这次实践给我留下最深的一点体会
这次用Hermes + Cursor完成整个项目,最大的收获不是"一天交付"这个速度,而是工作方式的转变。上午用Hermes把需求、表结构、字段口径全部敲定,下午用Cursor高速编码,人干的活就剩下两件:做决策、做验收。
以前我会担心AI写出来的东西能不能用,现在我的心态是:AI代码一定会有问题,所以更要主动设计验收机制,而不是靠它自己保证质量。真正决定项目上限的,还是你对自己所在业务的理解有多深。AI擅长穷举和生成,但"什么该做、什么不该做、做到什么程度",最后还是得由人来拍板。