15 KiB
火力规则实现方案(scheme)— 详细版
本文档供后续智能体或开发人员按步骤实现代码使用。依据 requirements.md 与样例 JSON(区域防御场景设计_2026-01-14 11_49_10_带注释.json)。需求中提及但样例中未出现的字段(如 threatLevel、warTerritory、airspaceType)在代码中预留 Optional / 占位事实类字段,规则写骨架注释即可,不要阻塞主流程编译。
1. 目标与边界(实现时必须遵守)
| 项 | 说明 |
|---|---|
| 输入 | 单份超大军事场景 JSON(约 1.3MB 级),无数据库 |
| 输出 | 同一 JSON 结构;仅对红方任务下业务约定字段做补全;其它键值保持输入原样 |
| 引擎 | Drools 7.x(见 auto-solution-rule/pom.xml 的 drools.version) |
| 注释规范(Java/DRL) | 与 requirements 一致:禁止行尾注释;类/公开 API 用 /** */;字段与函数体内用 // |
| 不参与匹配 | ScenarioBase、Options;taskName、Groups;任务开始/结束时间 |
| 允许 | 红方武器不足以覆盖蓝方;红方任务部分字段匹配不上则保持空或原值 |
2. JSON 结构参考(实现时的路径依据)
根路径:MilitaryScenario(注意:样例文件在部分 key 后带有 // 注释,标准 Jackson 默认不能解析。实现时三选一:① 调用方传标准 JSON;② 服务端先 strip 行尾 //... 再解析;③ 使用 jackson-core 自定义或第三方「带注释 JSON」解析。下文路径均指去掉注释后的逻辑结构。)
2.1 顶层键(与 MilitaryScenario 同级)
实现时至少关心:
MilitaryScenario
├── RefAttributeObject # Map:key=设备 refId(字符串),value=属性对象数组
├── ForceSides # 数组:阵营
├── Equipments # 数组:装备
├── Tasks # 数组:任务(红+蓝+…)
├── Environment # 可选,默认可不进规则
├── ScenarioBase # 忽略
└── Options # 忽略
(若实际文件还有其它顶层字段,原样透传,不要删除。)
2.2 ForceSides[](阵营表)
每条典型字段:
ObjectHandle:阵营 UUID(字符串)ForceSideName:如「红方」「蓝方」「白方」
实现要点:建立 Map<String, String>:sideUuid -> sideName,以及反向查询。红方 UUID 用于与 Equipments.OwnerForceSide、task.task.sideId 等比对。
2.3 RefAttributeObject(属性字典)
- 类型:对象,子 key 为 refId(与装备里
device.refId、device.id等引用对齐)。 - 值:数组,元素字段包括但不限于:
attDef、attDefaultValue、attExplain、attName。
实现要点:不必把所有属性塞进 Drools。解析阶段可构建:
Map<String, Map<String, String>> refIdToAttDefValue:仅保留规则会用到的attDef(若未知则先存全量 按 refId 分桶的 List,但单桶过大时要按 attDef 过滤,避免 OOM)。
2.4 Equipments[](装备)
典型字段:
OwnerForceSide:所属阵营 UUIDEquipmentID:装备实例 idSupportType、Platform_type、Name等:用于类型与展示SubComponents:对象,键如weapon、sensor、platform、jammer、communication等,值为组件数组
组件项常见字段:
ObjectHandle、deviceId、soleIddevice:{ id, name, refId }ParentPlat:父平台 idplatform类下可能有positions:[经度, 纬度, 高度]
实现要点:为规则准备红方装备摘要列表(扁平结构,见第 5 节),不要 deep clone 整个 SubComponents。
2.5 Tasks[](任务)
外层常见:
id:任务 idside:字符串,如「蓝方」(以样例为准)dataType:如taskPlanetask:内层大对象
内层 task 常见:
side、sideId(阵营 UUID)type:任务类型,如interference、assault、policePatrolspeed:数值execute:数组,每项含type及多种列表字段
execute[] 内常见列表(名称以样例为准):
targetList[]:常含weaponId、targetId、ID、以及若干战术字段disturbList[]:干扰相关,可含weaponId、targetId- 其它
*List:按任务类型存在与否不同
红方识别(实现逻辑,按优先级):
task.task.sideId或外层推导的阵营 UUID 等于 红方ForceSides.ObjectHandle;或task.side/ 外层side字符串等于「红方」(需与ForceSideName一致)。
仅对识别为红方的任务执行写回;蓝方任务只读,用于生成「对手事实」。
2.6 需求字段与样例缺失
| 需求字段 | 样例中状态 | 代码策略 |
|---|---|---|
threatLevel (1–3) |
未检索到 | Java 事实类保留 Integer threatLevel,默认 null;DRL 用 threatLevel != null Guard |
warTerritory、airspaceType |
未检索到 | 事实类预留 String/Integer;阵位规则文件先写注释骨架 |
3. 总体数据流(智能体实现顺序)
flowchart TB
P1[预处理可选: 去注释]
P2[第一遍流式: 建索引]
P3[第二遍或同遍: 收集蓝方摘要 + 红方可写槽位]
P4[组装 Drools 事实]
P5[KieSession fireAllRules]
P6[应用 Rule 输出到内存补丁结构]
P7[写回 JSON: Tree 或 流式]
P1 --> P2 --> P3 --> P4 --> P5 --> P6 --> P7
4. OOM 与解析策略(必须写进实现)
4.1 禁止
- 使用
ObjectMapper.readTree(整个 InputStream)默认把 1.3MB+ 全树常驻且复制多份。 insertAll(全部 Equipment)、insertAll(全部 Task)进入 KieSession。- 无界
String拼接整文件多次。
4.2 推荐
- Jackson
JsonParser+JsonToken顺序扫描;仅当currentName属于目标段时深入读取。 - 分块构建索引:
RefAttributeObject、ForceSides、Equipments各用Map/ 紧凑 DTO 列表;数字与字符串优先,避免嵌套Map过深。 - Tasks:流式读数组,每元素解析为「任务摘要对象」或仅红方保留完整
task子树的 JsonNode 引用(若采用 DOM 则只保留红方子树,蓝方只保留摘要)。 - 写回:
- 方案 A(推荐起步):第一遍用流式解析 + 若内存允许用
JsonNode仅替换Tasks下红方节点(需评估内存); - 方案 B:两遍文件:第一遍偏移量/路径索引,第二遍
JsonGenerator复制并覆盖红方字段。
- 方案 A(推荐起步):第一遍用流式解析 + 若内存允许用
智能体实现时可先 方案 A + 设置 Jackson 流式配置,在压测后再切方案 B。
4.3 Drools 工作内存
- 单次
fireAllRules前插入事实数建议:O(蓝方任务数 + 红方候选装备数 + 红方待填槽位数),每项为小对象(< 1KB 量级为宜)。 - 规则执行完后
dispose()KieSession,避免泄漏。
5. Java 侧建议类型(包名可按项目调整)
建议包:com.solution.rule.firepower(或沿用 com.solution.rule 下子包),避免与旧 WarplaneHandler 混在同一责任链。
5.1 索引与上下文(非 Drools Fact,解析阶段使用)
| 类名(建议) | 职责 |
|---|---|
ScenarioIndexes |
持有 sideIdToName、redSideId、blueSideId(可多蓝多红时扩展为 Set)、refAttributes 精简索引 |
EquipmentSummary |
单条红方可用装备:equipmentId、ownerSideId、platformType、weaponComponentIds(List<String>)、可选 positionLonLatAlt |
BlueTaskFact |
单条蓝方任务摘要:taskId、taskType、speed、sideId、从 execute 抽出的 打击/干扰目标 id 列表、航迹摘要(见下) |
TrackSummary |
可选:routeId 或关键点 List<double[]>(经纬高),从蓝方编队/平台关联推导(若样例中路径复杂,第一版可只填 speed + 单点位置) |
RedTaskFillSlot |
描述一处待填写位置:taskId、executeIndex、listName(如 targetList)、itemIndex、指向 Map 或 JsonNode 的可变引用(或用 Consumer 写回) |
5.2 Drools 事实(插入 KieSession)
| 类名(建议) | 说明 |
|---|---|
OpponentContext |
当前正在处理的蓝方任务/目标封装(可多条规则共享) |
RedInventory |
红方可用武器/装备 id 及剩余数量(数量规则 3.1 用) |
MatchResult |
规则填写结果:selectedWeaponId、targetId、reasonCode(便于日志) |
ThreatContext |
预留 Integer threatLevel |
PositionContext |
预留防区/作战区相关字段 |
事实类使用 可修改 JavaBean(Drools 7 常用),在规则中 modify() 或 通过全局服务写回 RedTaskFillSlot(若用全局服务,需 KieSession.setGlobal(...))。
5.3 规则与 Java 交互方式(二选一,文档推荐前者)
- 纯规则修改 Fact:
MatchResult填好后,Java 在fireAllRules后遍历 Fact 应用到 JSON。 - 全局写回器:
globals.put("fillService", bean),drl 中调用fillService.apply(...)(需在 drl 声明import与global)。
智能体选一种即可,全项目统一。
6. Drools 规则文件组织
目录:auto-solution-rule/src/main/resources/rules/(以实际 DroolsConfig 的 classpath*:rules/*.* 为准)。
| 文件 | package 建议 | 内容 |
|---|---|---|
fire-package.drl |
rules.fire |
仅 package、import、中文块注释说明修改须知 |
fire-task-type.drl |
同上 | task.type:干扰 vs 打击 vs 巡逻等分支;salience 最高或单独 agenda-group task-type |
fire-equipment-match.drl |
同上 | 装备类型、数量 ≥ 蓝方、weaponId/targetId 绑定;引用 RedInventory |
fire-position.drl |
同上 | 阵位:预留条件,注释写「待 warTerritory/airspaceType 路径确认」 |
fire-track.drl |
同上 | 航迹:高度、速度、航向、经纬高;注释说明可调参数 |
fire-fallback.drl |
同上 | 无匹配时的默认策略或显式「不填写」 |
删除或覆盖无效的 fire-rule.drl 占位内容,保证 KieBuilder 能 buildAll() 成功。
Salience 建议(数值越大越先执行,按项目再调):
- 任务类型分支:100
- 装备匹配:80
- 阵位:60
- 航迹:40
- 兜底:-10
agenda-group(可选):task-type → equipment → position → track,Java 中按序 getAgenda().getAgendaGroup("xxx").setFocus()。
7. 规则与需求章节映射(DRL 注释必须写清)
| requirements 章节 | DRL 落点 | 注释必须说明 |
|---|---|---|
| 3.1 装备匹配 | fire-equipment-match.drl |
依据哪些 Fact 字段;如何改「优先级」 |
| 3.2 阵位 | fire-position.drl |
红方防区/作战区判定条件(占位) |
| 3.3 航迹 | fire-track.drl |
最短距离/绕后等可选策略的切换方式 |
| 3.4 任务类型(干扰↔反干扰) | fire-task-type.drl |
与 3.1 的差异 |
| 3.5 贴合实际、不考虑时间 | 各文件 | 不写时间条件 |
8. 解析算法伪代码(供智能体翻译为 Java)
function process(inputStream) -> OutputStream:
bytesOrReader = optionalStripJsonComments(inputStream) // 若需要
indexes = new ScenarioIndexes()
blueFacts = new ArrayList<BlueTaskFact>()
redSlots = new ArrayList<RedTaskFillSlot>()
redEquipSummaries = new ArrayList<EquipmentSummary>()
parser = JsonFactory.createParser(bytesOrReader)
while parser.nextToken() != END_OBJECT:
if field == "RefAttributeObject":
indexes.refAttributes = parseRefAttributeObjectStream(parser)
else if field == "ForceSides":
indexes.parseForceSides(parser) // 设置 redSideId / blueSideId
else if field == "Equipments":
for each equipment object in stream:
if owner == indexes.redSideId:
redEquipSummaries.add(summarize(equipment))
else if field == "Tasks":
for each task object in stream:
if isRedTask(task, indexes):
redSlots.addAll(collectFillSlots(task)) // 只记录需规则填的槽位
else if isBlueTask(task, indexes):
blueFacts.add(summarizeBlue(task))
session = kieBase.newKieSession()
try:
session.insert(new RedInventory(redEquipSummaries))
for b : blueFacts: session.insert(b)
for slot : redSlots: session.insert(slot)
// globals if needed
session.fireAllRules()
applyFactsToJson(modelOrPatches)
finally:
session.dispose()
return serialize(modelOrPatches)
collectFillSlots:遍历 task.execute[*] 下各 *List,对 weaponId/targetId 为空且业务约定需要填的项注册 RedTaskFillSlot(第一版可只处理 targetList)。
9. Spring 接口层建议
- Controller(可放在
auto-solution-admin或独立 API 模块):POST /api/firepower/plan(路径自定)Content-Type: application/json- 方法参数:
HttpServletRequest.getInputStream()或InputStreamResource,不要@RequestBody String若可避免。
- Service:
FirepowerRuleService#apply(InputStream in, OutputStream out),异常包装为业务码,不要吞掉栈。
10. 与现有模块的衔接(避免冲突)
| 文件/类 | 动作 |
|---|---|
DroolsConfig |
保持;新增 drl 放入 rules/ |
JsonStreamParser |
重写或新建 MilitaryScenarioStreamParser,与注释中假数据结构脱钩 |
TaskJsonDTO 等 |
与样例不一致时:以样例为准 新建 firepower 包 DTO,或 JsonNode |
WarplaneHandler |
不要强行合并;新链路独立 Bean |
11. 测试与验收(智能体应补充用例)
- 单元测试:
MilitaryScenarioStreamParser对小样本 JSON(截取Tasks一条 +ForceSides+ 一条Equipments)解析结果符合预期索引。 - 规则测试:使用 Drools
KieSessionTest或 JUnit 手动insert事实,断言MatchResult。 - 集成测试:完整样例文件跑通不 OOM(JVM
-Xmx限制下观察);输出 JSON 除红方任务外字节级或键序尽量一致(键序若难一致,至少结构等价)。
12. 实现检查清单(按顺序勾选)
- 确定 JSON 注释处理策略并实现
strip或约束调用方。 - 实现
ScenarioIndexes+ 流式解析RefAttributeObject、ForceSides、Equipments。 - 实现
Tasks遍历 + 红/蓝识别 +RedTaskFillSlot收集。 - 定义 Drools 事实类 +
kie-module可编译的fire-*.drl。 - 实现
FirepowerRuleService:newKieSession→insert→fireAllRules→ 应用结果。 - 实现写回:JsonNode 或流式生成。
- Controller + 集成测试 + 日志(规则命中原因)。
13. 修订记录
| 日期 | 说明 |
|---|---|
| 2026-03-26 | 初稿 |
| 2026-03-26 | 详细版:路径说明、类设计、伪代码、DRL 分层、检查清单、测试要求 |