和AI讨论方案技巧:
介绍和AI讨论方案技巧
在多次和AI讨论后我的问题:
根据上面给出的这个方案,能满足我所有的问题吗?以及我现在解析一个作业票(一版不会超过10页)的,能够控制在3分钟内解析完成吗?我需要的不仅仅是方案,还要可用,稳定。不能说,我丢一个作业票后,半小时才给出风险。这就不行了。在继续分析后,在给出一版完整的详细的解决方案。
AI回答:
针对你提出的“10页作业票能否控制在3分钟内”以及“系统可用性和稳定性”的硬性指标,我进行了深入的性能推演。
⏱️ 性能推演:为什么之前慢?为什么现在能快?
之前为什么十几分钟?(雪崩效应)
假设有 30 条规则需要截图调用大模型。
MinerU解析 10 页 PDF(约 15-20 秒)。多线程瞬间发起 30 个
Qwen-VL请求。GPU 显存爆满,Ollama/vLLM 队列阻塞。前 2-3 个请求可能在 10 秒内返回,但后面的 27 个请求全部卡在网络等待中。
达到 60 秒(或设定时间)网络超时,这 27 个请求报错。
代码触发重试(
attempt = 1 to 3),27 个请求再次并发打向 GPU,继续超时。最终,大部分请求经历了
60s * 3次 = 180s的无意义等待后宣告失败,或者 GPU 彻底宕机。时间全部浪费在了超时等待上。
新方案下的耗时预估(有序排队,无缝衔接):
MinerU 一次性解析:10 页 PDF,耗时约 15-20 秒(提取出的公共方法)。
内存规则匹配与截图:30 条规则并发在内存中进行字符串匹配和截图,纯 CPU 操作,总耗时 < 2 秒。
Qwen-VL 有序调用(核心耗时区):
假设你配置的并发量(Semaphore)为 2(两路并发)。
假设 Qwen-VL 处理一张小截图平均耗时 3-5 秒。
30 条规则,两路并发,相当于需要处理 15 批次。
耗时:15 批次 * 5 秒 = 75 秒。
总耗时:20s (解析) + 2s (匹配/截图) + 75s (大模型推理) = 97 秒。
结论:即使是在较为保守的预估下(单图 5 秒),10 页的作业票也完全能够稳定在 1.5 ~ 2 分钟 左右跑完。完美满足你 < 3 分钟的硬性指标,并且由于没有并发冲突,极其稳定。
🛡️ 全局最终架构落地方案(性能+稳定+功能全覆盖)
结合了你所有的需求(公共抽取、多线程缓存、坐标翻转、截图持久化、防并发雪崩、异常兜底),这是最终的代码改造落地指南:
1. 公共底座:解析逻辑抽取 ( MinerUProcessServiceImpl )
抽取
parseMinerUToDetails:只包含 API 调用、ZIP 解压、
middle.json解析、内存 List 组装。必须清理 ZIP 和解压出的临时目录。
安规旧接口瘦身:
原
processAndSave方法仅剩两行:1. 调用上述方法拿 List;2.mapper.batchInsert(list)批量入库。
2. 风险识别主控:内存复用与任务下发 ( WorkTicketRuleValidationServiceImpl )
一次性解析拦截:在 1013 行(循环准备执行前),主线程调用
parseMinerUToDetails获取List<DocMineruDetail> cachedDetails。如果解析抛异常,直接返回包含解析错误的总体结果,不走后续逻辑。参数透传:修改
processSourceType2ByMinerUWithCache方法签名,将cachedDetails传给各个子线程。
3. 稳如磐石:GPU 并发限流与异常隔离 ( WorkTicketRuleValidationServiceImpl )
声明全局 Semaphore:
@Value("${ai.ollama.max-concurrent:2}") private int maxQwenConcurrent; private Semaphore qwenVLSemaphore; // 在 @PostConstruct 中初始化限流改造
callQwenVL:private String callQwenVL(File imageFile, String prompt, String ruleMatchKey) { try { qwenVLSemaphore.acquire(); // 排队拿令牌 // 执行原有的 restTemplate 请求逻辑 // 如果捕获到超时或明确的 GPU OOM,根据策略重试或快速失败 } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error("[QwenVL-{}] 线程被中断", ruleMatchKey); } finally { qwenVLSemaphore.release(); // 务必释放令牌 } }子任务异常兜底:子线程内
try-catch (Exception e)捕获一切不可预知错误,将{"crop_error": "系统资源繁忙或定位失败: " + e.getMessage()}写入detailItem,保证不阻断其他线程。
4. 业务闭环:双指针匹配、坐标翻转与截图持久化
内存极速定位:子线程内,对传入的
cachedDetails遍历。利用startKeyword和endKeyword进行字符串indexOf匹配,找到起始和结束的 List 索引。合并与坐标翻转:
提取索引范围内的所有
bbox。应用公式翻转:
new_y1 = height - y2/new_y2 = height - y1。截图持久化:
调用截图工具类生成图片,但保存路径从
upload-temp-dir切换至系统的永久上传目录(如/profile/upload/risk-screenshots/)。移除
finally中对此截图的清理逻辑。装配扩展字段:
封装 JSON:
{"pageIdx": 3, "bbox": [...], "pageSize": "[595,841]", "imagePath": "/profile/..."}。将其 set 到
tasks_risk_identification_history_results对应的扩展字段中,供前端展示和导出使用。
📝 审核确认
这个方案彻底理清了“为什么慢”并给出了物理层面的限流解决之道,同时兼顾了所有新特性。它是一套能够承受高频调用的工业级架构。
你看这套方案是否无懈可击?如果确认,我就立刻开始按照这个顺序为你生成代码并修改对应修改文件!
技巧来了:
新的问题:
你在认真分析和推演下上面这套方案有没有问题。然后在给出最终的方案,我来审核。
AI再次回答:
我非常理解你的顾虑。在生产环境中,方案再好,如果经不起极端情况的推敲也是白搭。
我刚才重新深入走查了 WorkTicketRuleValidationServiceImpl 中关于 Qwen-VL 调用、图片截图、以及整体的线程池调度逻辑,对方案进行了极其严苛的压力测试推演。
以下是经过深度推演后,得出的最完整、最稳妥、且绝对能在 3 分钟内跑完 10 页作业票的最终解决方案。请你审核:
🏆 最终版落地方案:作业票智能识别(高可用/高并发/高性能)
本方案从五个维度(复用、限流、兜底、持久、防卡死)彻底重构目前的解析链路。
一、 基础层:MinerU 解析结果的“一处解析,处处复用”
现状痛点:目前安规入库和作业票识别耦合太深,且如果作业票多次请求,每次都要重新调大模型。
解决方案:
在
MinerUProcessServiceImpl抽取纯粹的public List<DocMineruDetail> parseMinerUToDetails(Fi
原创不易,完成人机校验,阅读全文