run_main_fan_document.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #!/usr/bin/env python3
  2. """默认验证真实 Agent 的沙箱文档解析与报告交付;旧服务须显式选择。"""
  3. import argparse
  4. import asyncio
  5. import hashlib
  6. import json
  7. import os
  8. from pathlib import Path
  9. import shutil
  10. import sys
  11. import uuid
  12. ROOT = Path(__file__).resolve().parents[1]
  13. sys.path.insert(0, str(ROOT))
  14. async def run(args, output):
  15. from agents.workspace import session_root
  16. from db import chat_store
  17. from runtime.environment import RuntimeEnvironment
  18. from extensions.main_fan.service import analyze
  19. from runtime.execution import execute
  20. source = args.document.resolve()
  21. source_hash = hashlib.sha256(source.read_bytes()).hexdigest()
  22. async with RuntimeEnvironment(prewarm=False, billing_retry=False):
  23. user = "main-fan-live-document"
  24. session = chat_store.create_session(user, "full", "原件自动识别实测")
  25. root = session_root(user, session["id"])
  26. target = root / "workspace" / "uploads" / source.name
  27. target.parent.mkdir(parents=True, exist_ok=True)
  28. shutil.copyfile(source, target)
  29. def progress(value):
  30. print(json.dumps(value, ensure_ascii=False), flush=True)
  31. data = {"mine_code": args.mine_code, "mine_name": args.mine_name,
  32. "fan_name": args.fan_name, "fan_id": args.fan_name,
  33. "document_cache_policy": args.cache_policy,
  34. "materials": [{"path": "/workspace/uploads/"+source.name}]}
  35. if args.input_json:
  36. raw = json.loads(args.input_json.read_text(encoding='utf-8'))
  37. data = {**raw, **data, 'materials': [*raw.get('materials', []), *data['materials']]}
  38. data['fan_id'] = args.fan_id or raw.get('fan_id', args.fan_name)
  39. elif args.fan_id:
  40. data['fan_id'] = args.fan_id
  41. if args.agent:
  42. execution = await execute(agent_name="main_fan", user_name=user, session_id=session["id"],
  43. message="请读取业务 Skill,在沙箱自行编写文档解析、计算和报告生成代码,核对后提交真实脚本输出。完整输入已注入任务配置。",
  44. graph_config={"configurable": {"business_task_input": data,
  45. "document_audit_dir": str(output / "document")}})
  46. if execution.status != "success" or not execution.structured_output:
  47. raise RuntimeError("实际智能体执行失败:"+execution.error)
  48. result = execution.structured_output
  49. audit = result.get('assessment', {}).get('exploration', {}).get('python_runs', [])
  50. if not audit or result['assessment'].get('mode') != 'sandbox_exploration':
  51. raise RuntimeError('没有本轮成功沙箱交付记录,不能把旧固定服务作为自主探索实测')
  52. else:
  53. result = await analyze(data, user, session["id"], document_audit_dir=output / "document", document_progress=progress)
  54. audit = result["analysis"]["document_audits"]
  55. if not audit:
  56. raise RuntimeError("没有完整自动识别记录,详情见文档调用原始响应")
  57. if any(a.get("transcript_seed_loaded") or a.get("cache_used") for a in audit) and args.cache_policy != "auto":
  58. raise RuntimeError("刷新实测不可使用已有缓存或转录")
  59. if hashlib.sha256(source.read_bytes()).hexdigest() != source_hash:
  60. raise RuntimeError("原件在实测过程中发生变化")
  61. summary = {"mode": "live_agent_sandbox" if args.agent else "legacy_model_document_recognition",
  62. "source": str(source), "source_sha256": source_hash,
  63. "session_id": session['id'], "workspace": str(root / 'workspace'),
  64. "transcript_seed_loaded": False, "cache_policy": args.cache_policy,
  65. "mine_code_note": "本地测试编码,未假定陕西局正式编码", "result": result}
  66. (output / "result.json").write_text(json.dumps(summary, ensure_ascii=False, indent=2)+"\n", encoding="utf-8")
  67. print("真实模型研判完成:", output / "result.json", flush=True)
  68. if args.agent:
  69. print('成功沙箱交付', len(audit), '结论', result['platform_payload']['judgment']['resultCode'], flush=True)
  70. else:
  71. print("完成页数",sum(len(a["pages"]) for a in audit),"模型调用",sum(len(a["calls"]) for a in audit),
  72. "计算复核",len(result["analysis"]["calculations"]), flush=True)
  73. def main():
  74. parser = argparse.ArgumentParser()
  75. parser.add_argument("--document", type=Path, required=True)
  76. parser.add_argument("--mine-code", default="live-test-unassigned")
  77. parser.add_argument("--mine-name", required=True, help="任务目标矿井身份,不作为文档模型的预填数据")
  78. parser.add_argument("--fan-name", required=True)
  79. parser.add_argument("--fan-id", help="可选的明确设备ID,默认沿用输入JSON中的fan_id")
  80. parser.add_argument("--output", type=Path)
  81. parser.add_argument("--input-json", type=Path, help="可选的原始任务JSON,提供时序等明确数据;不注入文档转录结果")
  82. parser.add_argument("--cache-policy", choices=["refresh", "off", "auto"], default="refresh")
  83. parser.add_argument("--vision-model", help="仅旧固定服务:覆盖视觉模型;自主模式由主Agent直接看图")
  84. parser.add_argument("--agent", action="store_true", default=True, help="默认通过真实 Agent 的沙箱自主执行")
  85. parser.add_argument("--legacy-service", action="store_false", dest="agent", help="显式验证旧固定服务,不验证沙箱自主探索")
  86. args = parser.parse_args()
  87. output = (args.output or ROOT/"data"/"main_fan_live"/uuid.uuid4().hex[:12]).resolve()
  88. output.mkdir(parents=True, exist_ok=True)
  89. if (output/"business.sqlite").exists():
  90. raise ValueError("实测目录已有数据库,请使用新目录保留独立识别记录")
  91. # 沿用项目模型凭证,仅隔离运行数据与网关;不加载任何测试转录 JSON。
  92. os.environ.update({"DEEP_AGENT_ENV_PRIORITY": "process", "DB_DIALECT": "sqlite",
  93. "DB_SQLITE_PATH": str(output/"business.sqlite"), "CHECKPOINTER": "sqlite",
  94. "CHECKPOINT_DB_PATH": str(output/"checkpoints.sqlite"), "SHANXI_GATEWAY_ENABLED": "0",
  95. "MAIN_FAN_ALLOW_MANUAL_CACHE": "0", "RESULT_PLATFORM_ENABLED": "0", "MAIN_FAN_AUTO_PUBLISH": "0",
  96. "MAIN_FAN_TARGETS_FILE": "", "LOG_LEVEL": "WARNING"})
  97. if args.vision_model:
  98. os.environ["MAIN_FAN_VISION_MODEL"] = args.vision_model
  99. try:
  100. asyncio.run(run(args, output))
  101. except Exception as exc:
  102. (output/"failure.json").write_text(json.dumps({"type":type(exc).__name__,"message":str(exc),
  103. "transcript_seed_loaded":False},ensure_ascii=False,indent=2),encoding="utf-8")
  104. raise
  105. if __name__ == "__main__":
  106. main()