MAIN_FAN.md 45 KB

矿井主通风机业务与模拟联调

当前启动、月度和 API 批次已切换为固定工作流:沿用监测预处理,Python/GLM OCR 及失败页 Qwen 补识别后,由 Qwen3.5 一次生成研判 JSON。工作流以告警准确率优先,开停、风量按冻结规则判断,性能粗略核对;仅三类均无可用数据时为 UNDETERMINED,有数据且无确凿异常为 NORMAL(未发现确凿异常)。新工作流默认只保存本地结果。下文的 Skill/沙箱说明仍适用于原有自由对话及兼容入口,不再描述批次的模型执行方式和结论口径。

批次固定首步:获取并筛选煤矿目录

批次入口先由宿主代码调用 GET /system/user/deptTree,递归提取煤矿叶节点,只保留名称末尾括号中的完整状态为“正常生产煤矿”的记录。支持中文、英文括号,保留原始 label;“非正常生产煤矿”、停产、建设及未标注状态的煤矿不会进入筛选清单。父部门即使名称中包含该状态也不作为煤矿。

该步骤使用 MAIN_FAN_AGENT_CODE 和配置的网关连接,不调用模型。每条煤矿记录保存 dept_id(原节点 id)、mine_id(原 mineId,保持字符串和前导零)、去除末尾状态后的 mine_name、production_status、原始标签、父部门、部门路径与 raw_node。mine_id 对应单矿任务输入的 mine_code。身份缺失、部门层级冲突或重复身份会明确报错,不能静默遗漏或重复执行煤矿。

通过业务管理 API 调用,无需模型参数或请求体,认证使用本服务的 BUSINESS_API_TOKEN:

curl --request POST \
  --url http://127.0.0.1:8080/api/business-agents/main_fan/mine-catalog \
  --header 'Authorization: Bearer <BUSINESS_API_TOKEN>'

成功返回 HTTP 201,包含 snapshot_id、固定阶段 mine_discovery、节点及煤矿数量、生产状态分布,以及仅包含正常生产煤矿的 mines。GET /api/business-agents/main_fan/mine-catalog 查看最近一次成功清单;GET /api/business-agents/main_fan/mine-catalog/{snapshot_id} 重读指定批次清单,均使用相同业务认证。

也可在项目根目录直接执行固定首步,不启动网页、模型、任务队列或结果推送:

.venv/bin/python scripts/refresh_main_fan_mines.py

每次成功查询生成独立快照,保存在 data/main_fan/mine_catalog/<snapshot_id>/:request.json 为查询元数据,dept-tree.json 为完整上游业务响应,all-mines.json 为全部煤矿,selected-mines.json 为筛选后冻结清单。文件不包含网关凭证。失败不会覆盖上一次成功清单;成功但没有符合条件的煤矿会明确返回0条。

此目录入口只负责煤矿发现、筛选和清单保存;逐矿判识由下述本地批次使用冻结的snapshot_id与mines执行。

单矿主通风机判识

当期切换与风量采用已确定的数据源:安全监控1010提供开停与切换,重大设备仅提供风量。批次计划和历史查询校验只接受 safety/fan_state、equipment/flow,并将 source_policy写入取数回执及详情文件;重大设备运行状态不参与切换判断。按原编号做两路风量时间对照,未确认的设备对应关系仍如实标注;窗口缺样不改用重大设备开停否定安监事件。

旧批次重新分析时按当前口径筛选历史计划,原件和缓存索引保留;覆盖统计及Agent摘要只包含本轮选中测点的日段,已有成功原件继续复用。

main_fan 在我们自己的框架内执行,陕西局网关负责对外管理和转发。默认联合研判同矿井、同组的两台主通风机,比较检测报告参数、实测性能数据,以及有真实时序输入时的切换前后稳定风量和风压。

业务 Skill 为 skills/main-fan-equivalent-capability-assessment/SKILL.md。当前模式是沙箱自主探索:Agent 自行编写文档解析、取证、计算、图表和报告生成代码,在会话沙箱中执行,根据真实输出修改方法。原七阶段、文档识别器、事实登记器和独立计算器不在默认工具集中;旧服务仅用于显式兼容脚本。

用1237已有真实原件回放固定发现和预处理,生成可直接给Agent的数据(无新接口或模型调用):

.venv/bin/python scripts/preview_main_fan_data.py \
  --capture outputs/main_fan_history_checks/20261021_094202_1237 \
  --output outputs/main_fan_prepared/1237_fixed_code

沙箱自主探索工作台

当前注册十二个入口,其中四个批次工具只接受宿主绑定的本地批次:

工具 职责
prepare_main_fan_task 绑定身份,导出原始输入、规则和交付 schema
fetch_main_fan_data 通过宿主网关取得原件、设备与运行记录
query_fan_sensor_realtime 按部门、可选类型及分页参数查询安全监控实时传感器列表
query_fan_timeseries 按测点、部门与起止时间查询历史曲线,保存完整原始及规范化数据
query_fan_equipment_realtime 查询重大设备主通风机系统的实时设备及测点数据,固定devOfSystem=30
query_fan_equipment_timeseries 按重大设备测点及时间范围取得电机、温度等历史曲线,保留原始字段
run_python 隔离执行 Agent 自己编写的代码,保存真实输出和执行记录
submit_main_fan_report 核验交付文件与执行记录、映射平台格式并归档
submit_main_fan_mine_plan 根据本矿真实实时列表提交通风井及测点计划
query_main_fan_history 按计划测点向前按天回查40天,逐段保存原件并补取失败段
fetch_main_fan_reports 正式模式经资料采集API和挂载目录复制PDF,模拟模式下载测试原件;按hash加载同矿同井成功档案
archive_main_fan_report 核验成功沙箱输出及全页覆盖声明,保存可复用的报告提取

本地批次联调

井级结果中的 details.switch_analysis 必须交付状态、方法、具体事件和限制;每个候选或确认事件保留实际停启/状态变化时刻、间隔与原件依据,不能用运行占比代替事件识别。原输出目录加 --reassess 可重新分析,旧结果保存在井级 revisions/。同一批次、同一井、相同计划和时段的已取原件经hash校验后复用,不再次请求;不同月度批次重新获取当期数据。

重大设备历史已适配实际 data[].sbNodeCurve[],其中 dataTime 是采样时间,realData 是原始值;保留原始响应,额外提供规范时间、样本数和结构预览。未知结构的采样数量为 null,空数组为0,全0曲线仍是已有历史数据。井级 details.flow_analysis 必须提供状态和原始样本数,不能将已有嵌套采样误报为空数据。

报告档案采用 main-fan-agent-report-v2-page-reads,除页数声明外还核对 page_sources:每个物理页对应独立文件、实际成功的 read_file 读取及当时指纹,扫描页必须为图片。只读10页却声明26页会被拒绝;旧版缺乏读取核验的档案不再复用。合订PDF中的每份报告仍需由Agent逐份整理,读取记录不代替业务内容的正确性检查。

全局运行能力保留显式开关:CLI需同时指定 --all-producing-mines --allow-large-batch;网页或月度服务需启用 MAIN_FAN_BATCH_ALLOW_ALL=1、将 MAIN_FAN_BATCH_MAX_MINES 设为0或足够大的上限,再请求 all_producing_mines=true 或配置 MAIN_FAN_BATCH_DEPT_IDS=all。分日模式按每日矿数校验上限,每月仍使用当次筛选后的完整清单。

框架筛选正常生产煤矿后,只处理显式选择的部门。固定代码先查询安全监控与重大设备实时列表、取齐分页,按1010和30101选择开停及风量测点,校验矿井身份并保存计划。宿主按天取齐40天数据、整理开停区间、切换候选及风量窗口,并完成报告接口和hash核验,随后才调用Agent。同一矿仍复用一个main_fan会话,各井分别提交报告。Agent直接读取prepare_main_fan_task返回的prepared_data.agent_data_path,不再自主规划监测取数;井级同时导出给Agent的数据.json。

固定代码按实际类型选择安监开停和重大设备风量测点。振动、电流等不能声明为开停;请求传入类型筛选后仍须核对实际返回的类型。风机号不能当作通风井号,缺少井级证据时保留一个带“待确认”的候选主备系统。开停和风量使用相同截止时刻、按连续24小时窗口回查40天。批量传输不会消耗160个Agent步骤,每段仍独立保存原件和指纹;coverage_complete只表示请求归档覆盖;固定程序同时整理切换候选和前后稳定窗口,Agent核对有效性并作业务分析。

历史取数完成后,逐日请求、响应及完整数据经校验压缩为一个 history-evidence.zip;索引持久化后才清理本轮暂存JSON。按日记录和指纹仍可恢复,重试仅补失败段,同批次重分析复用ZIP。Agent默认只读精简的history-agent.json:矿井、查询范围、开停区间、风量概况、切换候选及前后风量和必要限制。nodeId、调试计数、质量明细、规则副本及完整窗口计算移到history-state-details.json;仅在需要时通过details_path复核。默认区间省略gaps字段;具体中断与缺测按需读取详情,详细观测段仍保留observed_parts。原始0/1状态码、一级/二级及不同系统不自动合为整机。摘要超过20个状态段或变化时保留截断标志,完整内容按details路径读取;当前本地批次按用户指定的单点法:原机以切换范围起点前1小时、新机以终点后1小时为目标,在各自一侧取最接近目标的一条。保留实际时间和原值,不求平均,不使用分钟完整率或CV门槛;原机值大于0且单位可比时计算按原编号的单点变化,缺失或原机为0时不算比例。单点变化不宣称连续稳定工况。

切换候选按同组内每个安监测点的首末净状态变化确定方向,交接时某一级短暂“开→停→开”不会再导致整组候选被跳过;一级/二级的原始变化仍保留在详情中,不自动确认整机状态。前后风量写入给Agent的数据.json的switch_candidates[].flow和comparison.before_value/after_value。日志history.prepared记录预处理版本与候选数量,便于确认镜像已更新。

用已核验的1219单矿原件生成同格式输入示例(只读原业务库,不请求模型/网关):

.venv/bin/python scripts/compact_main_fan_history.py \
  --batch-dir outputs/main_fan_batches/20261020_1219_preview

示例在 verification/agent-history/,包括Agent入口、精细区间、详细索引、一个压缩证据包及可读说明。此回放不改写此前原件和业务库;新批次自动使用压缩流程。

正式报告通过资料采集API核对矿井身份、同步类型、单矿单期采集并轮询任务,再从只读挂载目录复制到workspace。配置、目录范围及容器部署见 DOCKER.md。模拟模式仍可使用 GET /api/main-fan/reports 和 GET /api/main-fan/report-files/{hash}.pdf,原封不动返回既有测试原件,标记 is_mock 和 test_fixture_not_mine_report,不能改写为其他矿的正式报告。宿主按矿、井级内部标识、实际SHA256和提取版本保存成功档案。复用时将验证后的事实导出为当前可信输入;不同矿井、更新原件、损坏档案及未完成提取均不命中。当期时序始终重新查询。

配置 MAIN_FAN_BATCH_CRON=0 2 1 * *、MAIN_FAN_BATCH_SPREAD_DAYS=20 后,北京时间每月1日02:00冻结当月清单,均分为20份,每天02:00只投递一份,余数分到前几天。MAIN_FAN_BATCH_DEPT_IDS=all、MAIN_FAN_BATCH_ALLOW_ALL=True、MAIN_FAN_BATCH_MAX_MINES=0 覆盖全部正常生产煤矿。建议 MAIN_FAN_BATCH_RUN_ON_STARTUP=False,重启仅续跑已投递的中断份额;停机漏掉的份额按顺序每天一份顺延,不集中补跑。未配置分日天数或设为1时保留每月整批方式。计划、恢复、失败处理和保护上限详见部署说明。

如另需服务启动就跑前N矿,设 MAIN_FAN_BATCH_RUN_ON_STARTUP=True、MAIN_FAN_BATCH_STARTUP_MAX_MINES=2。每次重启都会额外触发独立启动批次。可设置 MAIN_FAN_BATCH_STARTUP_EXCLUDE_DEPT_IDS=[1045,1106],只对独立启动批次先排除这些部门,再按数量上限选矿,未配置时不排除;不改变月度计划范围。

独立脚本默认最多两个矿、回查40天,使用独立业务库和checkpoint,关闭结果平台与自动推送。保留现有模型、网关配置:

.venv/bin/python scripts/run_main_fan_batch.py \
  --dept-id 1219 \
  --mock-pdf '/实际路径/通风机性能测定报告.pdf' \
  --output outputs/main_fan_batches/local-preview

重复 --dept-id 可选择第二个矿;--snapshot-id 使用已有冻结清单,默认重新获取部门树;--cutoff '2026-10-20 15:00:00' 指定北京时间回放。再次指定原输出目录可恢复未完成任务,沿用原清单和截止时刻。大批次必须显式添加 --allow-large-batch,联调不使用该选项。

文件夹中包含 index.html、batch.json、冻结清单、每矿发现记录、每井的 报告.md、结果.json、待审阅报文.json、来源与覆盖.json、推送记录.json,以及工作区、查询原件和Python执行记录。正式批次先保存本地结果,再按 RESULT_PLATFORM_ENABLED 总开关决定是否进入持久化推送队列;失败重试不重新调用Agent。上述隔离预览脚本始终关闭推送。

已归档的单候选系统可单独运行本地开发核验,不需要模型或网关:

.venv/bin/python scripts/verify_main_fan_batch.py \
  --batch-dir outputs/main_fan_batches/20261020_1219_preview

核验先校对请求、响应及数据的SHA256,再统计正常开停标签、时间冲突和候选变化,以及实际嵌套风量的原始/去重样本、空段、0值及采样间隔,输出 verification/本地数据核验.html、Markdown和JSON。此脚本只适用于每矿一个已保存候选系统,多井需另行逐井核验;它不提交Agent结果,也不代替业务判识。2026-10-20真实联调仅涉及1219一个矿:280/280分段成功;风量1124条全0,安全监控存在两组配对变化候选。旧AI初稿的风量遗漏已作废标记;补充Agent复核因模型服务403待权限恢复。正式交付先查看本地核验报告。

可选网页入口需启用 MAIN_FAN_LOCAL_BATCH_ENABLED=1,配置 MAIN_FAN_MOCK_REPORT_PDF 和网关。POST /api/business-agents/main_fan/batches 接受 dept_ids(默认最多两个)及可选 snapshot_id/cutoff/lookback_days/user_name;GET /api/business-agents/main_fan/batches/{batch_id} 查询状态和输出目录,均使用 BUSINESS_API_TOKEN。服务关闭时取消任务并保存中断状态。

月度入口使用相同本地队列,在批次开关开启且配置 MAIN_FAN_BATCH_CRON 后装载。按月份及矿井范围生成幂等键,重复触发复用原计划或原整批结果;分日模式每份有独立批次标识,已完成时不重跑。新计划只由月度触发器创建,日调度和启动恢复只处理已有计划。独立模拟PDF服务可运行 scripts/mock_main_fan_reports.py --pdf '/实际路径/通风机性能测定报告.pdf',仅监听 127.0.0.1:8768;批次脚本通过进程内ASGI HTTP调用同一接口。

query_fan_timeseries 固定代理 GET /aqjk/alarmcurve/getCurveByNodeId。模型传 workflow_id、node_id、dept_id、start_time、end_time,宿主使用 SHANXI_GATEWAY_URL/TOKEN 和本业务的 MAIN_FAN_AGENT_CODE 发请求;不把凭证交给模型。时间支持带时区的 ISO 格式或 YYYY-MM-DD HH:MM:SS,统一转为 Asia/Shanghai,默认单次最多24小时、200000个采样点,分别由 MAIN_FAN_SERIES_MAX_HOURS、MAIN_FAN_SERIES_MAX_SAMPLES 配置。可重复分段查询,不静默截断或降采样。

例如先准备实际矿井任务,再调用:

{
  "workflow_id": "准备工具返回的实际ID",
  "node_id": "61082101917301KG1010016D09",
  "dept_id": "1117",
  "start_time": "2026-10-19 11:00:00",
  "end_time": "2026-10-19 11:11:00"
}

该编号来自对方提供的朱盖塔矿“主通1一级”接口样例,不预设为其他矿井或整机状态。工具返回记录数、实际时间范围、重复/倒序/窗口外/空值计数、少量预览及完整文件路径;所有收到的采样按原顺序保留。每次查询分别存档请求、上游原始业务响应、规范化数据,加入本轮指纹和报告证据来源。模型用返回的 python_paths.data 在沙箱读取完整 JSON;切换识别及工况计算仍由模型自编代码完成。空数据明确为0条,失败返回 ok=false 及可恢复反馈。配置的网关需支持这个真实曲线接口,本地旧模拟网关的批量资料路由不等同于该接口。

四个真实接口分别接入,均使用配置的网关地址、凭证和 MAIN_FAN_AGENT_CODE:

Agent工具 上游GET路径 参数
query_fan_sensor_realtime /aqjk/node/getNodeRealtimeDetails dept_id、page_num、page_size、可选sensor_type_list;宿主生成索引键值对数组
query_fan_timeseries /aqjk/alarmcurve/getCurveByNodeId dept_id、node_id、start_time、end_time;上游nodeIds复数
query_fan_equipment_realtime /zdsb/sbnode/selectSbNodeList dept_id、page_num、page_size;宿主固定devOfSystem=30
query_fan_equipment_timeseries /zdsb/sbnode/selectSbNodeCurve dept_id、node_id、start_time、end_time;上游nodeId单数

四个工具均需先准备本轮workflow_id。实时列表工具一次一页,默认page_num=1、page_size=100;每页请求上限由 MAIN_FAN_REALTIME_MAX_PAGE_SIZE 控制,默认1000。可传 sensor_type_list=["0005","0013","1001","1010","0001,0011,0043","0002"] 原样复现给定筛选;未传时不添加类型筛选。识别到rows/total时返回row_count、total、has_more、next_page,未识别的结构明确标记未知,不伪装成空列表。超过预览预算时省略preview,完整数据仍保留。

实时列表与重大设备曲线的完整data_path JSON在payload下保留上游业务响应;不猜测重大设备的风量、温度、单位或采样字段。Agent用Python读取真实字段后决定解析方法。重大设备实时列表示例为dept_id="1219";其曲线示例为dept_id="1237"、node_id="6108310185903000MN30102100000000000064"、start_time="2026-10-20 06:20:49"、end_time="2026-10-20 09:20:49"。这些示例部门不自动绑定为同矿,重大设备编码也不直接用于安全监控曲线。是否存在主通风机风量测点须看实际返回中的测点、单位及设备关联,接口接入本身不证明存在风量。

每次查询均归档请求、完整响应和数据文件,准备工具返回sensor_queries/equipment_queries/timeseries_queries;全部文件支持来源哈希核验及报告引用。只使用实时/时序入口的任务无需强制调用批量fetch_main_fan_data。请求失败返回可恢复错误,不以空数据代替失败。

文档文本提取、页面渲染和字段整理使用 Agent 自编 Python;扫描件由它渲染 PNG 后通过通用 read_file 看图。中间事实结构由 Agent 自行设计,不再登记到固定 DocumentFacts。标准库、numpy、pypdfium2、Pillow 和 cv2 已可使用;沙箱不联网、不注入服务端凭证、不运行时安装依赖。业务要求、单位和阈值写在 Skill 与本轮冻结的 rules.json。

macOS 使用 sandbox-exec,Linux 需要 bubblewrap;缺少沙箱时报不可执行,不回退为宿主裸执行。默认单次最长120秒、单会话最多40次。配置项为 AGENT_PYTHON_MAX_SECONDS、AGENT_PYTHON_MEMORY_MB(仅Linux地址空间)、AGENT_PYTHON_MAX_RUNS。

Agent 用代码生成 Markdown、AgentAssessment JSON 及需要的附件,声明 output_paths 并带 workflow_id 执行。提交时必须关联本轮成功 run_id,报告、JSON、附件的哈希必须仍与声明输出一致。宿主只核验身份、原件与可信输入指纹、来源归属、文件格式及执行记录,不重新 OCR、不复算窗口或核心指标、不改写结论和正文。业务结论和平台摘要来自 Agent 的 JSON;算法与文字正确性由 Agent 按 Skill 核对,执行成功本身不证明结论正确。

原始输入、规则版本、实际操作和最终结果保存在 main_fan_workflows、main_fan_analyses。派生文件在会话 /workspace/,宿主另存受保护的代码快照和执行凭据。工作台显示实际操作,不预设七阶段;探索步骤预算默认480,由 AGENT_EXPLORATION_RECURSION_LIMIT 控制。详细交付格式见 Skill 下的 references/workbench.md。

2026-10-19 改造验证

563 项离线回归通过,包含实际 macOS 沙箱中的 PDF 渲染、库加载、文件/网络隔离、执行失败反馈、输出哈希、来源归属,以及真实 Agent 图的写代码/执行/提交与协调委派。网关取数连接保留,默认测试 API 使用完整 Agent。

真实 qwen3.5-35b-a3b 扫描件实测中,Agent 自行渲染并查看原页、编写解析/切换分析/报告脚本,得到合成样例的6分钟切换间隔、3800→3610 m³/min稳定风量与5%差异。测试程序随后直接提交其未修改的脚本输出,宿主归档及平台映射通过;这一步不是模型自行完成提交。

最后模型调用被提供方 429 insufficient_quota / Allocated quota exceeded 中断,文本PDF最终用例与扫描PDF的完整自动提交尚未完成验收。扫描件报告仍发现电动机型号字段吞入下一行、Measured误标为折算两处质量问题;已补强Skill自检,因配额不足未复测。不得将上述记录表述为真实业务准确性已经验收。

机器可读记录位于 data/main_fan_live/20261019_sandbox_verification.json,含测试范围、已验证指标、已知问题及恢复配额后的复测命令。测试使用独立SQLite和checkpoint、合成PDF与时序,未连接真实取数网关或推送正式结果。

网页报告输出

最终答复是主通风机与备用风机一致性整体报告,重点对比两台风机测定报告中同叶片角度、同频率的绘图数据表,计算风压、功率和效率差异,逐工况给出指标、阈值和结论,无需重新画曲线。风量点不同只在共同实测范围内插值对齐,不按原表行号比较,禁止外推。型号、额定功率和电动机配置作为基础核对,不能代替性能通过;角度或频率未知时不判同工况一致。

性能表默认阈值为风压平均偏差≤5%、最大偏差≤10%、功率最大偏差≤10%、效率最大差≤5个百分点;每台同工况至少4个有效测定点,共同风量范围覆盖双方各自范围至少80%。数据条件满足且指标均不超限才通过,超限列明差异,不足标记无法判断。具体计算和记录要求见Skill的references/performance-tables.md,阈值取本轮冻结规则,不由Agent临时决定。

综合核心项为报告性能表格一致性、切换间隔和前后监测风量差。核心项证据充分且通过才为NORMAL;有效性能指标或监测指标一般超限为WARNING;达到另行配置且证据有效的严重线才为ABNORMAL;关键对照不足为UNDETERMINED。监测证据不足时仍保留已完成的报告性能对比结论。基础铭牌一致、历史检测合格和任务执行成功均不能代替本次性能通过。

报告使用 m³/min、Pa、kW 和 Hz,效率差用百分点,保持原始值与换算依据。当前本地批次的开停、切换和监测风量直接采用prepared_data.agent_data_path(导出为给Agent的数据.json)中的states、switch_candidates.flow/comparison及notes,不重新取数、定位切换、选择风量点或计算稳定窗口。候选time_range不作准确切换耗时,零值保留,缺失或编号对应限制照实呈现;仅摘要截断时读取剩余整理明细。模拟数据明确标注来源。

规则和阈值配置位于 examples/main_fan/equivalence_rules.json,可通过 MAIN_FAN_RULES_FILE 替换。初始配置来自需求中的建议值,不表述为法规限值。执行状态与综合判定状态分开:部分项目有结果时报告只陈述这些结果,Agent 应在交付 JSON 中明确未评估项目和证据限制。

自主模式的提取事实与计算细节保存在 assessment.agent_result.details,来源引用在 assessment.evidence,代码执行记录在 assessment.exploration;不再由固定算法生成 analysis。网页工具详情默认折叠,文件来源保留显示;最终正文恢复 Agent 实际提交的原件。

单机报告版本的历史实测记录位于 data/main_fan_live/20261014_report_style_5eda22f9/;该版本当时只分析1号,当前默认流程已改为双机。显式设置 paired_assessment=false 仅用于旧单机接口兼容。

双机版本网页实测记录:data/main_fan_live/20261014_pair_verified_20a71196/。实际请求为“审核众源煤业主通风机及备用是否一致”,从原件模拟网关下载26页PDF和两张系统截图,16次实际视觉模型调用(含一次图注分类回读),未使用旧缓存或人工转录。两台各44行数据,88行公式检查;30、40、50Hz均形成共同风量区间的数据比较。截图识别出另一矿井的设备与风速,未混入本矿井报告。正文约2500字符(含Markdown表格,不计SVG编码),只含有数据的参数、性能和实际资料差异章节。

文档识别对风量原文单位、轴功率含义和表图工况分类进行一致性检查,疑似记录自动放大回读原页;仍缺明确单位或轴功率依据的行退出计算,原值不按公式反算修正。缓存升级至v4,旧识别记录不自动复用。

历史服务的资料与实测记录

下列原件核验和历史实测基于此前固定服务,不代表本次自主探索改造已完成模型联调或测试。

当前目录有一份 26 页扫描 PDF,风机数据截图/ 子目录内有两张裁切截图。原件模拟网关递归建立文件索引。PDF 包含陕西众源煤业集团有限公司的 1、2 号主通风机报告,编号分别以 0003、0004 结尾;检验日期为 2022-03-18、2022-03-17,报告所载建议下次日期为 2025-03-17、2025-03-16。

截图属于神木市瓷窑塔矿业有限公司,不能与上述报告合并。只转录完整可见行:设备 00000540 为“地面主通二号二级/开”,00000541、00000542 为“一号一级/停”“一号二级/停”;开停截图未提供采集时间。测点 2000000TJFJ010038 为“一号风机风速”,值 0 m/s、状态正常,时间 2026-10-13 10:13:00;下方温度行不完整,未转录。

reviewed_sample.json 是旧离线联调夹具,保存人工核验转录、原文件 SHA256 和 PDF 物理页码;生产自动识别和原件实测不加载它。mock-ci、mock-zy 是模拟编码,实际矿井编码未知。

1 号报告物理页 8 的现场运行表工况静压为 523.57 Pa、效率 64.77%;物理页 11 曲线图注为 511.73 Pa、63.30%。自动识别把图注与数据表分开保存,保留两处差异供复核。旧离线夹具只覆盖身份和各 7 行 30 Hz 现场数据。

规则边界

输入 实际处理
矿井编码或名称冲突 排除记录;不模糊合并公司名称
名称、编号、位置线索 同矿井风机号形成 candidate;PLC1、一级/二级不作风机号
人工确认关联 须提供 point_code、fan_id、confirmed_by、reason;冲突仍阻断
重复、断线、缺时、过期、未来时间、未知单位 保留发现,排除当前计算
单点风速 不直接换算风量;缺断面与平均风速时说明缺件
“风压”、电输入功率 不冒充风机静压增量或轴功率
当前效率 唯一、已确认关联、有效且同步的 Q、静压、轴功率才计算
历史报告 同矿井且对应目标风机时复核同一行,不混用现场和折算值
建议检验日期已过 提示核查更新报告,不直接认定当前不合格或违法
开停快照 不根据单台/单级停机推断全矿停风或备用能力

静压效率:eta = Q[m3/s] × p_static[Pa] / (1000 × P_shaft[kW]) × 100%。支持显式 m3/min→m3/s、kPa→Pa、W→kW 换算。不把静压功率/电输入功率误称为风机轴功率效率。

时效默认 600 秒,同步窗口 120 秒,分别配置 MAIN_FAN_FRESHNESS_SECONDS、MAIN_FAN_SYNC_SECONDS;它们是数据筛查参数,不是工程安全限值。无时区时间按 Asia/Shanghai 解释。evaluation_time 可指定回放时刻并保存在输入;默认当前时间。

status=completed 表示初步筛查完成;judgment_scope=preliminary_screening,工程状态保持 review_required 或 insufficient_data,不自动生成红橙黄蓝等级。没有任何本矿井可用资料时为 needs_materials。结果保存 main_fan_analyses,发布时恢复数据库原件;模型不能改写工具数值后推送。队列工具使用服务端输入,不能自行增加人工绑定。

历史规范仅作为原报告事实保留。当前规程基准核对了应急管理部第 17 号令、2026-02-01 施行的《煤矿安全规程》第 177–179 条。连续运转、备用、改造/换叶片后测定、反风能力需要配置、试验或过程记录;样例不足以核验,不用历史条款数值做当前自动执法判定。规则核对日期:2026-10-14。

使用真实模型识别原件

.venv/bin/python scripts/run_main_fan_document.py \
  --document '/Users/gaoshutao/Project/煤科/陕西局代码/测试数据/通风机性能测定报告.pdf' \
  --mine-name '陕西众源煤业集团有限公司' --fan-name '1号通风机' --agent

默认 document_cache_policy=refresh,创建独立 SQLite 与 checkpoint,调用实际 main_fan LangGraph 和业务工具。矿井名称只用于任务身份筛查,不作为识别模型的预填答案。不导入人工转录,不使用已有识别缓存,不调用真实陕西局网关。原件复制到本会话附件目录,并验证运行前后的 SHA256 一致。

结果保存在新的 data/main_fan_live/<id>/result.json。--agent 使用自主模式,Agent 自行选择证据范围,脚本、事实、选页审计及模型原始响应留在本会话 workspace/exploration/<workflow_id>/,受保护的代码快照留在同会话 python_runs/。不加 --agent 才直接调用历史固定服务,其 document/<附件标识>/facts.json、audit.json 和 call-*.json 保存自动提取与逐页调用记录。--output 可指定新目录,已有实测数据库不覆盖。

2026-10-14 在本机配置的 deepseek-flash 上完成真实模型验证:

输入与记录目录 实际识别 业务执行
原始 通风机性能测定报告.pdf → data/main_fan_live/20261014_scan_verified/ 26 页全部走视觉、13 次实际识别调用;2 份报告、88 行性能数据、2 条数字图注 实际 main_fan 图;目标 1 号风机 44 行公式复核,最大效率偏差 0.0071 个百分点
合成带文本层 PDF → data/main_fan_live/20261014_native_verified/ 1 页走文本、1 次实际识别调用,未发送图片 实际 main_fan 图;合成数据复核 60%

原件 SHA256 为 46eb24ec6c0f23907b4dc6f67af00f7907fa15d7acbf04ce13d142a247cfc92a,扫描识别调用用量合计 76,071 tokens。两种实测均为 cache_used=false、transcript_seed_loaded=false,数据库缓存方法为 automatic_extraction;缓存是在本次完整识别后才写入的。文本 PDF 是独立软件测试输入,不是把原扫描报告转录后冒充可解析 PDF。混合 PDF 另有逐页路由回归测试。

抽查原件物理页 3、8、11、16、21、24 的身份、日期、运行工况和图注。保留 1 号表格 523.57 Pa/64.77% 与图注 511.73 Pa/63.30% 的原件差异;这属于资料复核,不能用历史“合格”结论证明当前设备状态。完整事实未逐字人工验收。全量 381 项测试、结构自检、依赖锁及打包白名单校验通过。

离线模拟全链路

.venv/bin/python scripts/demo_main_fan.py \
  --data-dir '/Users/gaoshutao/Project/煤科/陕西局代码/测试数据'

该兼容脚本用两个临时本地端口启动取数网关和独立结果接收平台,在新的 data/main_fan_demo/<id>/ 创建业务 SQLite、checkpoint、接收平台 SQLite 和 result.json,不读取/修改本机 .env。会话附件进入框架 data/workspaces/,不改变原测试目录。脚本显式调用历史固定服务,经持久化队列、HTTP下载和独立结果推送进行离线联调;不调用外部模型或真实陕西局服务,也不验证自主探索能力。

默认三场景:original 原截图与异矿报告,report 原报告历史复核,synthetic 合成量及合成确认(60 m3/s、500 Pa、50 kW→60%)。随后验证本地业务 stop/start,检查网关没有收到注册、上传或结果推送请求。第三种来源标注 synthetic。可用 --scenario original|report|synthetic 单独运行;--output 指定新目录,已有演示库不覆盖。

原 PDF 按真实哈希核验,离线识别用人工转录缓存。这验证业务与计算,不能替代视觉模型识别质量验收。

单独启动模拟网关

.venv/bin/python scripts/mock_shaanxi_gateway.py \
  --data-dir '/Users/gaoshutao/Project/煤科/陕西局代码/测试数据' --port 8766 --raw-files

默认仅监听 127.0.0.1。--raw-files 按当前测试目录直接建立 PDF/图片原件索引,不加载人工转录 JSON;文档中的事实由业务智能体实际识别。启动脚本另外加载下述两份明确合成的时序JSON及其风机身份,不从人工转录夹具填充报告或监测值。原件变动后需重启网关刷新索引。不加该参数则沿用旧离线夹具。业务配置示例:

SHANXI_GATEWAY_ENABLED=1
SHANXI_GATEWAY_URL=http://127.0.0.1:8766
SHANXI_GATEWAY_TOKEN=mock-internal-token
SHANXI_FILE_BASE_URL=http://127.0.0.1:8766
MAIN_FAN_AGENT_CODE=mock-main-fan
MAIN_FAN_DEVICES_PATH=/mock-platform/main-fan/devices
MAIN_FAN_POINTS_PATH=/mock-platform/main-fan/points
MAIN_FAN_REPORTS_PATH=/mock-platform/main-fan/reports
MAIN_FAN_SERIES_PATH=/mock-platform/main-fan/series
MAIN_FAN_OPERATION_LOG_PATH=/mock-platform/main-fan/states

这些路径、凭证只属于模拟服务。取数身份在网关中预先授权,应用无需运行时注册。真实路径、字段和取数编码需同事提供,没有预设陕西局存在 /mock-platform/ 接口。

结果接收另起 .venv/bin/python scripts/mock_result_platform.py(8767端口),配置 RESULT_PLATFORM_ENABLED/URL/TOKEN 后独立推送。正式结果格式、四种编码及推送查询接口见 独立结果平台。

开停与风量模拟时序(10分钟、10%规则)

新增 examples/main_fan/mock_switch_states.json 和 examples/main_fan/mock_airflow_series.json,统一声明 schema_version=1、data_kind=synthetic、矿井身份、时区、采样间隔和 series。每条曲线有 fan_id、samples=[{"observed_at":"带时区时间","value":数值}]。开停曲线是整机级,state_scope=whole_fan,0为停、1为开;风量曲线另有 sensor_id、unit=m3/min 和显式的 mapping_confirmed。两台设备绑定 mock-zy 下的 mock-report-fan-1、mock-report-fan-2。

默认回放2026-10-14 09:20至11:00,每60秒一条,每类数据两台各101点。1号10:00停机,2号10:06启动,双停过渡6分钟。1号切换前风量均值3800 m³/min,2号切换后3610 m³/min,差异5%;停机零值和启动过渡也保留在原始曲线中。

网关代理 /mock-platform/main-fan/states 返回整机状态记录,/mock-platform/main-fan/series 返回两条风量序列;智能体从状态变化识别切换,不使用预写的切换结论。原始JSON可查看 http://127.0.0.1:8766/mock/main-fan/curves/switch-states 和 /mock/main-fan/curves/airflow。更换样例目录使用 --operating-data-dir。

两项规则独立计算:原机停机至另一台启动的非负间隔 ≤10分钟;|切换后稳定均值-切换前稳定均值| / 切换前稳定均值 ×100% ≤10%。等于边界也通过;涨幅、降幅均按绝对差异判断。先启动再停机时另外记录重叠时长,停机等待间隔计0。前窗口取首次切换动作前5分钟之外的30分钟,后窗口取切换完成后5分钟之外的30分钟,默认有效样本完整率≥90%、变异系数≤5%。切换前风量为0不形成比例结论。

整机未知、冲突或连续状态记录缺测超过两个采样间隔时,不跨缺口推断停启时间;未来样本不能补足窗口。没有可比风量时仍能单独保留已证明的切换间隔;只有切换时刻而无停机、启动时刻的旧记录,不自动判定间隔合格。两项通过只表示本次切换与风量规则通过,不替代整体同等能力判识。上述10分钟/10%为本次用户指定业务规则,规则版本随配置归档。

本地网页测试可打开 http://127.0.0.1:8080/,在新会话选择“矿井主通风机研判智能体”,只需发送“审核众源煤业1号主通风机”。无需填写矿井编码、工具名或网关/缓存参数,也无需手动上传:业务工具从模拟网关取得目录和文件鉴权,直连下载原 PDF,实际调用视觉模型重新识别。网页聊天的结果保存在当前应用 SQLite;平台推送另由业务任务 API 或网关事件任务触发。

简短请求与目标身份目录

prepare_main_fan_task 支持目标文字或 {"target":"众源煤业1号主通风机"};业务任务 API 的 input 同样只需一个 target 字段。target 也可以是已配置的风机标识。完整 MainFanInput 协议仍兼容。

{"input":{"target":"众源煤业1号主通风机"},"publish":false}

服务端设置示例:

MAIN_FAN_TARGETS_FILE=examples/main_fan/mock_targets.json
MAIN_FAN_DEFAULT_DOCUMENT_CACHE_POLICY=refresh

目标目录保存矿井名称、经明确配置的别名、矿井编码、风机名称及标识;不包含报告日期、监测数值或人工转录。当前测试目录配置众源煤业 1、2 号风机。自然语言前后缀和“一号/1号/1#”可归一化,但不会模糊搜索公司名称或根据文件内容猜平台编码。未唯一匹配时先询问业务对象,未确定身份前不会取数或分析。

简短请求未带本地材料且网关启用时自动 use_gateway=true,默认刷新原件识别。明确提供的附件和显式 use_gateway/document_cache_policy 会保留;关闭全局网关不会暗中启用 Mock。完整协议输入维持原默认值,队列以服务端已验证输入为准,模型不能通过改写目标或人工绑定改变任务。

测试目标目录明确绑定 http://127.0.0.1:8766;真实环境需配置正式身份目录并更新其网关绑定,不能把 Mock 编码用于真实网关。新增矿井在目录里增加身份与别名即可,不需要修改业务 prompt。地址和凭证仍由服务配置决定,用户一句话不能切换网关环境。

2026-10-14 已在运行中的网页仅发送“审核众源煤业1号主通风机”验证完整链路,无附件、无技术参数:自动网关取数和直连下载,实际识别 26 页、13 次文档模型调用,对目标风机复核 44 行;cache_used=false、transcript_seed_loaded=false。实测记录位于 data/main_fan_live/20261014_short_request/,网页会话为 0a159bbb91dc43c39f9296f35c0fa821。目标文字、单 target 对象及模型偶尔返回的 JSON 字符串都可解析;全量 411 项测试通过。

用网关内部 Bearer 和 X-Agent-Code: mock-main-fan 向 POST /mock/tasks 发送 {"scenario":"original","taskId":"local-001"},产生 main_fan.judgment 事件。须业务端已注册并订阅;单独启动模式使用你配置的真实语言模型,演示脚本才是离线编排器。

管理模拟:GET /openapi/agent/manage?agentCode=mock-main-fan&action=stop&token=mock-platform-manage-token,action 支持 start/stop/restart/status/logs。停止关闭 SSE,重连返回 403;本业务执行和推送暂停,启动后恢复订阅。对方真实网关的指标/日志口径仍按双方约定。

历史固定服务的 PDF 识别实现(自主模式不调用)

独立 PDFium 进程逐页判别,不按文件名选择识别方式:

页面 处理
可读、完整的文本层 直接提取文本,由 MAIN_FAN_TEXT_MODEL 整理结构;不发送图片
空文本、损坏字符、零散水印或大图配少量文字 渲染为 PNG,由 MAIN_FAN_VISION_MODEL 读取原页
曲线图页 走视觉;仅录印出的工况数字,不猜曲线像素
文本与扫描页混合 分别按每页路由,合并到同一文档事实

默认最多 32 页,扫描页最长边 2200px,截图最长边 1700px;同一路由每批 2 页。文字模型默认沿用主模型,视觉模型必须明确配置且支持图像。以下设置可独立指定模型、接口和凭证;留空的接口/凭证沿用项目设置:

MAIN_FAN_VISION_MODEL=deepseek-flash
MAIN_FAN_TEXT_MODEL=deepseek-flash
MAIN_FAN_VISION_BASE_URL=
MAIN_FAN_VISION_API_KEY=
MAIN_FAN_TEXT_BASE_URL=
MAIN_FAN_TEXT_API_KEY=
MAIN_FAN_DOCUMENT_TIMEOUT=180
MAIN_FAN_DOCUMENT_BATCH_PAGES=2
MAIN_FAN_DOCUMENT_MAX_TOKENS=20000
MAIN_FAN_MAX_DOCUMENT_PAGES=32
MAIN_FAN_ALLOW_MANUAL_CACHE=0

DeepSeek 的文档识别显式关闭思考,使用 JSON 输出模式。视觉与文本分别计入 main_fan_ocr、main_fan_document_text,不作为主回答流输出,也不重复计费;部署时配置对应模型单价,提供方没有 usage 时标记 estimate。

提取结果校验 schema、PDF 物理页、日期标签及单位,按报告编号累积。JSON/schema 结构异常会重新读取同批原页一次,仍失败则报缺件;截断输出直接报错,避免把不完整结果缓存为成功。数据行或图注的数值与其印出的效率相差超过 0.5 个百分点时,扫描页增加原图放大区域,再读一次;公式只触发复读,不反算覆盖数字,仍不一致则保留原值并提示核验。每次复读同样记录实际模型响应与用量。

旧服务缓存版本为 main-fan-facts-v4,支持 document_cache_policy=auto|refresh|off;自主工作台只保留本轮识别,不读写共享缓存。不同页出现真实字段冲突时清除该字段并保留候选值与页码;当前自主模式由 Agent 修改自己的提取代码和派生事实后重新执行,代码快照和交付文件哈希留作追溯。制造年月不能替代检验日期,缺 Q/静压/轴功率的行不进入公式复核。

证据方法区分 text_extraction、model_extraction,保留源文件 SHA256、原文和物理页码。自动识别仍需核对原页,公式正确不证明 OCR 数字正确。业务结果以 SQLite 原件为准,Agent 的代码、派生输出和报告都有各自记录;当前自主模式的平台编码来自 Agent 脚本交付,不由宿主重新计算。

旧人工夹具的显式导入

离线调试需要时可以导入已核验的转录:

.venv/bin/python scripts/import_main_fan_facts.py \
  --document '/Users/gaoshutao/Project/煤科/陕西局代码/测试数据/通风机性能测定报告.pdf' \
  --facts examples/main_fan/reviewed_sample.json

该命令写当前配置的本地库,验证哈希、物理页码和原文,不修改原件。自动识别默认拒绝该缓存;旧 demo_main_fan.py 才显式开启人工缓存。其他人工转录使用 DocumentFacts JSON 和 --sha256 原文档哈希。

JSON 适配在 extensions/main_fan/data_source.py,目前接受 items、data.items 或 data 数组;字段使用业务 schema 的 snake_case/明确声明的 camelCase。真实响应不同需增加明确映射。报告目录只需文件 ID、版本和下载路径,由我们取鉴权、直连下载、存文件和索引;模拟网关拒绝拿内部凭证直接下载。

代码与验证

  • algorithms/main_fan/:事实 schema、确定性关联/筛查/计算、隔离 PDF 渲染。
  • extensions/main_fan/:工具、网关 JSON 适配、文档提取、结果和提示词。
  • db/main_fan_store.py:文档缓存、分析原件;business_files 存队列下载索引。
  • mock_gateway/main_fan.py:取数鉴权、JSON代理和文件系统;旧协议接口仅保留兼容测试。
  • extensions/result_platform/:独立结果平台的地址、鉴权、回执校验及客户端。
  • mock_result_platform/:独立结果接收服务,SQLite存档、幂等及冲突检测。
  • tests/test_result_platform.py:四种编码契约、实际规则映射、取数/结果解耦、重试、导出及所有权校验。
  • tests/test_main_fan.py:原始数据边界、量纲/身份/时效/同步、真实图、PDF 渲染、原件及模拟网关。
  • tests/test_main_fan_documents.py:文本/扫描/混合路由、真实调用协议、缓存隔离、字段冲突与截断处理;其中 PDF 是合成测试输入,不是原报告转录。

运行 .venv/bin/python -m pytest 和隔离存储配置下的 scripts/selfcheck.py,无需真实网关或模型。