rules_engine_metric_calculation_agent.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. """
  2. 规则引擎指标计算Agent (Rules Engine Metric Calculation Agent)
  3. ===========================================================
  4. 此Agent负责根据意图识别结果执行规则引擎模式的指标计算任务。
  5. 核心功能:
  6. 1. 配置文件加载:读取和解析规则引擎指标计算配置文件
  7. 2. API调用管理:根据配置文件调用规则引擎API
  8. 3. 结果处理:处理API返回的数据,提取关键指标
  9. 4. 错误处理:处理API调用失败、网络异常等错误情况
  10. 5. 结果验证:验证计算结果的合理性和完整性
  11. 工作流程:
  12. 1. 接收意图识别结果和用户参数
  13. 2. 加载对应的规则引擎指标计算配置文件
  14. 3. 构造API请求参数(id和input)
  15. 4. 调用远程规则引擎服务
  16. 5. 解析和验证返回结果
  17. 6. 返回结构化的计算结果
  18. 技术实现:
  19. - 支持动态加载JSON配置文件
  20. - 使用requests库进行HTTP API调用
  21. - 集成LangChain用于复杂计算逻辑(可选)
  22. - 完善的错误处理和超时机制
  23. - 支持多种计算方法(标准、高级、自定义)
  24. 配置文件结构:
  25. - id: 规则引擎执行ID
  26. - input: 数据文件路径
  27. - description: 规则描述
  28. API接口:
  29. POST http://localhost:8081/api/rules/executeKnowledge
  30. 请求体:
  31. {
  32. "id": "知识ID",
  33. "input": {
  34. "动态字段名": [...] // 根据知识的inputField字段动态确定,如"transactions"或"resultTag"
  35. }
  36. }
  37. 作者: Big Agent Team
  38. 版本: 1.0.0
  39. 创建时间: 2024-12-19
  40. """
  41. import os
  42. import json
  43. import requests
  44. from datetime import datetime
  45. from typing import Dict, List, Any, Optional
  46. from langchain_openai import ChatOpenAI
  47. from langchain_core.prompts import ChatPromptTemplate
  48. import re
  49. class RulesEngineMetricCalculationAgent:
  50. """规则引擎指标计算Agent"""
  51. def __init__(self, api_key: str, base_url: str = "https://api.deepseek.com"):
  52. """
  53. 初始化规则引擎指标计算Agent
  54. Args:
  55. api_key: DeepSeek API密钥
  56. base_url: DeepSeek API基础URL
  57. """
  58. self.llm = ChatOpenAI(
  59. model="deepseek-chat",
  60. api_key=api_key,
  61. base_url=base_url,
  62. temperature=0.1
  63. )
  64. # 加载配置文件
  65. self.configs = self._load_configs()
  66. # 获取可用的知识元数据
  67. self.available_knowledge = self._load_available_knowledge()
  68. # 加载数据文件映射
  69. self.data_files = self._load_data_files()
  70. # 初始化API调用跟踪
  71. self.api_calls = []
  72. def _load_data_files(self) -> Dict[str, str]:
  73. """加载数据文件映射"""
  74. data_files = {}
  75. data_dir = "data_files"
  76. if os.path.exists(data_dir):
  77. for file in os.listdir(data_dir):
  78. if file.endswith('.json'):
  79. try:
  80. # 提取文件名,用于匹配配置文件
  81. key = file.replace('.json', '')
  82. data_files[key] = os.path.join(data_dir, file)
  83. except Exception as e:
  84. print(f"处理数据文件 {file} 失败: {e}")
  85. return data_files
  86. def _select_data_file(self, input_filename: str) -> Optional[str]:
  87. """
  88. 根据输入文件名选择对应的数据文件
  89. Args:
  90. input_filename: 配置文件中的input字段值
  91. Returns:
  92. 数据文件路径,如果找不到则返回None
  93. """
  94. # input字段直接指定数据文件名
  95. if input_filename in self.data_files:
  96. return self.data_files[input_filename]
  97. # 如果找不到精确匹配,尝试模糊匹配
  98. for key, file_path in self.data_files.items():
  99. if input_filename in key or key in input_filename:
  100. return file_path
  101. return None
  102. def _load_table_data(self, data_file_path: str) -> List[Dict[str, Any]]:
  103. """加载数据文件中的JSON数据"""
  104. try:
  105. with open(data_file_path, 'r', encoding='utf-8') as f:
  106. data = json.load(f)
  107. if isinstance(data, list):
  108. return data
  109. elif isinstance(data, dict):
  110. # 如果是字典,尝试提取其中的数组数据
  111. for key, value in data.items():
  112. if isinstance(value, list):
  113. return value
  114. return []
  115. else:
  116. return []
  117. except Exception as e:
  118. print(f"加载数据文件 {data_file_path} 失败: {e}")
  119. return []
  120. def _load_configs(self) -> Dict[str, Dict]:
  121. """加载所有规则引擎配置文件"""
  122. configs = {}
  123. json_dir = "json_files"
  124. if os.path.exists(json_dir):
  125. for file in os.listdir(json_dir):
  126. if file.endswith('.json') and '规则引擎' in file:
  127. try:
  128. with open(os.path.join(json_dir, file), 'r', encoding='utf-8') as f:
  129. config = json.load(f)
  130. key = file.replace('.json', '')
  131. configs[key] = config
  132. except Exception as e:
  133. print(f"加载规则引擎配置文件 {file} 失败: {e}")
  134. return configs
  135. def _load_available_knowledge(self) -> List[Dict[str, Any]]:
  136. """
  137. 从规则引擎获取可用的知识元数据
  138. Returns:
  139. 知识元数据列表,包含id、description和inputField
  140. """
  141. try:
  142. url = "http://10.192.72.11:31809/api/rules/getKnowledgeMeta"
  143. headers = {
  144. "Accept": "*/*",
  145. "Accept-Encoding": "gzip, deflate, br",
  146. "Connection": "keep-alive",
  147. "Content-Type": "application/json",
  148. "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0"
  149. }
  150. response = requests.post(url, headers=headers, json={}, timeout=30)
  151. print(f"访问知识接口:{response}")
  152. if response.status_code == 200:
  153. knowledge_meta = response.json()
  154. if isinstance(knowledge_meta, list):
  155. print(f"✅ 成功获取 {len(knowledge_meta)} 个知识元数据")
  156. return knowledge_meta
  157. else:
  158. print(f"⚠️ 知识元数据格式异常: {knowledge_meta}")
  159. return []
  160. else:
  161. print(f"❌ 获取知识元数据失败,状态码: {response.status_code}")
  162. print(f"响应内容: {response.text}")
  163. return []
  164. except Exception as e:
  165. print(f"❌ 获取知识元数据时发生错误: {str(e)}")
  166. return []
  167. def _get_input_field_for_knowledge(self, knowledge_id: str) -> str:
  168. """
  169. 根据知识ID获取对应的inputField字段名
  170. Args:
  171. knowledge_id: 知识ID
  172. Returns:
  173. inputField字段名,默认为"transactions"
  174. """
  175. for knowledge in self.available_knowledge:
  176. if knowledge.get("id") == knowledge_id:
  177. input_field = knowledge.get("inputField", "transactions")
  178. print(f"🔗 知识 {knowledge_id} 使用输入字段: {input_field}")
  179. return input_field
  180. print(f"⚠️ 未找到知识 {knowledge_id} 的输入字段,使用默认值: transactions")
  181. return "transactions" # 默认值
  182. async def calculate_metrics(self, intent_result: Dict[str, Any]) -> Dict[str, Any]:
  183. """
  184. 根据意图识别结果进行规则引擎指标计算
  185. Args:
  186. intent_result: 意图识别结果
  187. Returns:
  188. 指标计算结果
  189. """
  190. try:
  191. results = []
  192. target_configs = intent_result.get("target_configs", [])
  193. if not target_configs:
  194. return {
  195. "success": False,
  196. "message": "没有找到需要调用的配置文件",
  197. "results": []
  198. }
  199. for config_name in target_configs:
  200. if config_name in self.configs:
  201. # 使用传统的JSON配置文件方式
  202. config = self.configs[config_name]
  203. result = await self._call_rules_engine_api(config, intent_result, config_name)
  204. results.append({
  205. "config_name": config_name,
  206. "result": result
  207. })
  208. elif config_name.startswith("metric-"):
  209. # 直接使用知识ID调用API,无需配置文件
  210. result = await self._call_rules_engine_api_by_knowledge_id(config_name, intent_result)
  211. results.append({
  212. "config_name": config_name,
  213. "result": result
  214. })
  215. else:
  216. results.append({
  217. "config_name": config_name,
  218. "error": f"配置文件 {config_name} 不存在,且不是有效的知识ID"
  219. })
  220. return {
  221. "success": True,
  222. "results": results,
  223. "total_configs": len(target_configs),
  224. "successful_calculations": len([r for r in results if "result" in r])
  225. }
  226. except Exception as e:
  227. print(f"规则引擎指标计算失败: {e}")
  228. return {
  229. "success": False,
  230. "message": f"规则引擎指标计算过程中发生错误: {str(e)}",
  231. "results": []
  232. }
  233. async def _call_rules_engine_api(self, config: Dict[str, Any], intent_result: Dict[str, Any], config_name: str) -> Dict[str, Any]:
  234. """
  235. 调用规则引擎API
  236. Args:
  237. config: 配置文件
  238. intent_result: 意图识别结果
  239. Returns:
  240. API调用结果
  241. """
  242. try:
  243. # 记录API调用开始
  244. start_time = datetime.now()
  245. # 规则引擎API配置
  246. method = "POST"
  247. url = "http://10.192.72.11:31809/api/rules/executeKnowledge"
  248. # url = "http://10.192.72.11:31809/api/rules/executeKnowledge"
  249. headers = {
  250. "Accept": "*/*",
  251. "Accept-Encoding": "gzip, deflate, br",
  252. "Connection": "keep-alive",
  253. "Content-Type": "application/json",
  254. "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0"
  255. }
  256. timeout = 180 # 3分钟超时
  257. # 准备请求数据
  258. request_data = self._prepare_rules_engine_request_data(config, intent_result, config_name)
  259. # 调用API
  260. json_data = request_data.get("json", {})
  261. response = requests.post(url, headers=headers, json=json_data, timeout=timeout)
  262. # 处理响应
  263. if response.status_code == 200:
  264. try:
  265. response_data = response.json()
  266. # 记录API调用结果
  267. end_time = datetime.now()
  268. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  269. api_call_info = {
  270. "call_id": call_id,
  271. "timestamp": end_time.isoformat(),
  272. "agent": "RulesEngineMetricCalculationAgent",
  273. "api_endpoint": url,
  274. "config_name": config_name,
  275. "request": {
  276. "method": method,
  277. "url": url,
  278. "headers": headers,
  279. "json_data": json_data,
  280. "start_time": start_time.isoformat()
  281. },
  282. "response": {
  283. "status_code": response.status_code,
  284. "data": response_data,
  285. "end_time": end_time.isoformat(),
  286. "duration": (end_time - start_time).total_seconds()
  287. },
  288. "success": True
  289. }
  290. self.api_calls.append(api_call_info)
  291. # 保存API结果到文件
  292. api_results_dir = "api_results"
  293. os.makedirs(api_results_dir, exist_ok=True)
  294. filename = f"{call_id}.json"
  295. filepath = os.path.join(api_results_dir, filename)
  296. try:
  297. with open(filepath, 'w', encoding='utf-8') as f:
  298. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  299. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  300. except Exception as e:
  301. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  302. return {
  303. "success": True,
  304. "data": response_data,
  305. "status_code": response.status_code
  306. }
  307. except json.JSONDecodeError:
  308. # 记录API调用结果(JSON解析失败)
  309. end_time = datetime.now()
  310. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  311. api_call_info = {
  312. "call_id": call_id,
  313. "timestamp": end_time.isoformat(),
  314. "agent": "RulesEngineMetricCalculationAgent",
  315. "api_endpoint": url,
  316. "config_name": config_name,
  317. "request": {
  318. "method": method,
  319. "url": url,
  320. "headers": headers,
  321. "json_data": json_data,
  322. "start_time": start_time.isoformat()
  323. },
  324. "response": {
  325. "status_code": response.status_code,
  326. "data": response.text,
  327. "error": "JSON解析失败",
  328. "end_time": end_time.isoformat(),
  329. "duration": (end_time - start_time).total_seconds()
  330. },
  331. "success": False
  332. }
  333. self.api_calls.append(api_call_info)
  334. # 保存API结果到文件
  335. api_results_dir = "api_results"
  336. os.makedirs(api_results_dir, exist_ok=True)
  337. filename = f"{call_id}.json"
  338. filepath = os.path.join(api_results_dir, filename)
  339. try:
  340. with open(filepath, 'w', encoding='utf-8') as f:
  341. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  342. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  343. except Exception as e:
  344. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  345. return {
  346. "success": True,
  347. "data": response.text,
  348. "status_code": response.status_code
  349. }
  350. else:
  351. # 记录API调用结果(HTTP错误)
  352. end_time = datetime.now()
  353. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  354. api_call_info = {
  355. "call_id": call_id,
  356. "timestamp": end_time.isoformat(),
  357. "agent": "RulesEngineMetricCalculationAgent",
  358. "api_endpoint": url,
  359. "config_name": config_name,
  360. "request": {
  361. "method": method,
  362. "url": url,
  363. "headers": headers,
  364. "json_data": json_data,
  365. "start_time": start_time.isoformat()
  366. },
  367. "response": {
  368. "status_code": response.status_code,
  369. "error": response.text,
  370. "end_time": end_time.isoformat(),
  371. "duration": (end_time - start_time).total_seconds()
  372. },
  373. "success": False
  374. }
  375. self.api_calls.append(api_call_info)
  376. # 保存API结果到文件
  377. api_results_dir = "api_results"
  378. os.makedirs(api_results_dir, exist_ok=True)
  379. filename = f"{call_id}.json"
  380. filepath = os.path.join(api_results_dir, filename)
  381. try:
  382. with open(filepath, 'w', encoding='utf-8') as f:
  383. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  384. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  385. except Exception as e:
  386. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  387. return {
  388. "success": False,
  389. "message": f"规则引擎API调用失败,状态码: {response.status_code}",
  390. "response": response.text
  391. }
  392. except requests.exceptions.Timeout:
  393. # 记录API调用结果(超时)
  394. end_time = datetime.now()
  395. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  396. api_call_info = {
  397. "call_id": call_id,
  398. "timestamp": end_time.isoformat(),
  399. "agent": "RulesEngineMetricCalculationAgent",
  400. "api_endpoint": url,
  401. "config_name": config_name,
  402. "request": {
  403. "method": method,
  404. "url": url,
  405. "headers": headers,
  406. "json_data": json_data if 'json_data' in locals() else None,
  407. "start_time": start_time.isoformat()
  408. },
  409. "response": {
  410. "error": "API调用超时",
  411. "end_time": end_time.isoformat(),
  412. "duration": (end_time - start_time).total_seconds()
  413. },
  414. "success": False
  415. }
  416. self.api_calls.append(api_call_info)
  417. return {
  418. "success": False,
  419. "message": "规则引擎API调用超时"
  420. }
  421. except requests.exceptions.RequestException as e:
  422. # 记录API调用结果(请求异常)
  423. end_time = datetime.now()
  424. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  425. api_call_info = {
  426. "call_id": call_id,
  427. "timestamp": end_time.isoformat(),
  428. "agent": "RulesEngineMetricCalculationAgent",
  429. "api_endpoint": url,
  430. "config_name": config_name,
  431. "request": {
  432. "method": method,
  433. "url": url,
  434. "headers": headers,
  435. "json_data": json_data if 'json_data' in locals() else None,
  436. "start_time": start_time.isoformat()
  437. },
  438. "response": {
  439. "error": str(e),
  440. "end_time": end_time.isoformat(),
  441. "duration": (end_time - start_time).total_seconds()
  442. },
  443. "success": False
  444. }
  445. self.api_calls.append(api_call_info)
  446. return {
  447. "success": False,
  448. "message": f"规则引擎API调用异常: {str(e)}"
  449. }
  450. except Exception as e:
  451. # 记录API调用结果(其他异常)
  452. end_time = datetime.now()
  453. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  454. api_call_info = {
  455. "call_id": call_id,
  456. "timestamp": end_time.isoformat(),
  457. "agent": "RulesEngineMetricCalculationAgent",
  458. "api_endpoint": url,
  459. "config_name": config_name,
  460. "request": {
  461. "method": method,
  462. "url": url,
  463. "headers": headers,
  464. "json_data": json_data if 'json_data' in locals() else None,
  465. "start_time": start_time.isoformat()
  466. },
  467. "response": {
  468. "error": str(e),
  469. "end_time": end_time.isoformat(),
  470. "duration": (end_time - start_time).total_seconds()
  471. },
  472. "success": False
  473. }
  474. self.api_calls.append(api_call_info)
  475. return {
  476. "success": False,
  477. "message": f"处理规则引擎API调用时发生错误: {str(e)}"
  478. }
  479. def _prepare_rules_engine_request_data(self, config: Dict[str, Any], intent_result: Dict[str, Any], config_name: str) -> Dict[str, Any]:
  480. """
  481. 准备规则引擎API请求数据
  482. Args:
  483. config: 配置文件
  484. intent_result: 意图识别结果
  485. config_name: 配置文件名
  486. Returns:
  487. 请求数据
  488. """
  489. # 从配置文件中获取id和input
  490. request_id = config.get("id", "")
  491. input_filename = config.get("input", "")
  492. # 加载对应的数据文件
  493. input_data = {}
  494. if input_filename:
  495. data_file_path = self._select_data_file(input_filename)
  496. if data_file_path:
  497. input_data = self._load_table_data(data_file_path)
  498. else:
  499. print(f"警告:找不到配置文件 {config_name} 对应的数据文件: {input_filename}")
  500. # 构造API请求体
  501. request_data = {
  502. "id": request_id,
  503. "input": input_data
  504. }
  505. return {"json": request_data}
  506. async def _call_rules_engine_api_by_knowledge_id(self, knowledge_id: str, intent_result: Dict[str, Any]) -> Dict[str, Any]:
  507. """
  508. 直接通过知识ID调用规则引擎API
  509. Args:
  510. knowledge_id: 知识ID,如 "metric-分析账户数量"
  511. intent_result: 意图识别结果(用于获取数据文件信息)
  512. Returns:
  513. API调用结果
  514. """
  515. # 记录API调用开始
  516. start_time = datetime.now()
  517. # 规则引擎API配置
  518. method = "POST"
  519. url = "http://10.192.72.11:31809/api/rules/executeKnowledge"
  520. headers = {
  521. "Accept": "*/*",
  522. "Accept-Encoding": "gzip, deflate, br",
  523. "Connection": "keep-alive",
  524. "Content-Type": "application/json",
  525. "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0"
  526. }
  527. timeout = 180 # 3分钟超时
  528. try:
  529. # 根据知识ID获取正确的输入字段名
  530. input_field_name = self._get_input_field_for_knowledge(knowledge_id)
  531. # 构造请求数据 - 直接使用默认数据文件
  532. # 从intent_result中获取数据文件名,如果没有则使用默认的农业数据
  533. input_filename = intent_result.get("data_file", "加工数据-流水分析-农业打标.json")
  534. # 加载对应的数据文件
  535. input_data = {}
  536. if input_filename:
  537. data_file_path = self._select_data_file(input_filename)
  538. if data_file_path:
  539. raw_data = self._load_table_data(data_file_path)
  540. # 使用正确的字段名包装数据
  541. input_data = {input_field_name: raw_data}
  542. else:
  543. print(f"警告:找不到数据文件: {input_filename}")
  544. input_data = {input_field_name: []}
  545. # 构造API请求体
  546. request_data = {
  547. "id": knowledge_id, # 直接使用知识ID
  548. "input": input_data
  549. }
  550. # 调用API
  551. json_data = request_data
  552. response = requests.post(url, headers=headers, json=json_data, timeout=timeout)
  553. # 处理响应(复用现有的响应处理逻辑)
  554. if response.status_code == 200:
  555. try:
  556. response_data = response.json()
  557. # 记录API调用结果
  558. end_time = datetime.now()
  559. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  560. api_call_info = {
  561. "call_id": call_id,
  562. "timestamp": end_time.isoformat(),
  563. "agent": "RulesEngineMetricCalculationAgent",
  564. "api_endpoint": url,
  565. "config_name": knowledge_id,
  566. "request": {
  567. "method": method,
  568. "url": url,
  569. "headers": headers,
  570. "json_data": json_data,
  571. "start_time": start_time.isoformat()
  572. },
  573. "response": {
  574. "status_code": response.status_code,
  575. "data": response_data,
  576. "end_time": end_time.isoformat(),
  577. "duration": (end_time - start_time).total_seconds()
  578. },
  579. "success": True
  580. }
  581. self.api_calls.append(api_call_info)
  582. # 保存API结果到文件
  583. api_results_dir = "api_results"
  584. os.makedirs(api_results_dir, exist_ok=True)
  585. filename = f"{call_id}.json"
  586. filepath = os.path.join(api_results_dir, filename)
  587. try:
  588. with open(filepath, 'w', encoding='utf-8') as f:
  589. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  590. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  591. except Exception as e:
  592. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  593. return {
  594. "success": True,
  595. "data": response_data,
  596. "status_code": response.status_code
  597. }
  598. except json.JSONDecodeError:
  599. # 记录JSON解析失败的API调用
  600. end_time = datetime.now()
  601. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  602. api_call_info = {
  603. "call_id": call_id,
  604. "timestamp": end_time.isoformat(),
  605. "agent": "RulesEngineMetricCalculationAgent",
  606. "api_endpoint": url,
  607. "config_name": knowledge_id,
  608. "request": {
  609. "method": method,
  610. "url": url,
  611. "headers": headers,
  612. "json_data": json_data,
  613. "start_time": start_time.isoformat()
  614. },
  615. "response": {
  616. "status_code": response.status_code,
  617. "data": response.text,
  618. "error": "JSON解析失败",
  619. "end_time": end_time.isoformat(),
  620. "duration": (end_time - start_time).total_seconds()
  621. },
  622. "success": False
  623. }
  624. self.api_calls.append(api_call_info)
  625. # 保存API结果到文件
  626. api_results_dir = "api_results"
  627. os.makedirs(api_results_dir, exist_ok=True)
  628. filename = f"{call_id}.json"
  629. filepath = os.path.join(api_results_dir, filename)
  630. try:
  631. with open(filepath, 'w', encoding='utf-8') as f:
  632. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  633. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  634. except Exception as e:
  635. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  636. return {
  637. "success": True,
  638. "data": response.text,
  639. "status_code": response.status_code
  640. }
  641. else:
  642. # 记录失败的API调用
  643. end_time = datetime.now()
  644. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  645. api_call_info = {
  646. "call_id": call_id,
  647. "timestamp": end_time.isoformat(),
  648. "agent": "RulesEngineMetricCalculationAgent",
  649. "api_endpoint": url,
  650. "config_name": knowledge_id,
  651. "request": {
  652. "method": method,
  653. "url": url,
  654. "headers": headers,
  655. "json_data": json_data,
  656. "start_time": start_time.isoformat()
  657. },
  658. "response": {
  659. "status_code": response.status_code,
  660. "error": response.text,
  661. "end_time": end_time.isoformat(),
  662. "duration": (end_time - start_time).total_seconds()
  663. },
  664. "success": False
  665. }
  666. self.api_calls.append(api_call_info)
  667. # 保存API结果到文件
  668. api_results_dir = "api_results"
  669. os.makedirs(api_results_dir, exist_ok=True)
  670. filename = f"{call_id}.json"
  671. filepath = os.path.join(api_results_dir, filename)
  672. try:
  673. with open(filepath, 'w', encoding='utf-8') as f:
  674. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  675. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  676. except Exception as e:
  677. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  678. return {
  679. "success": False,
  680. "message": f"规则引擎API调用失败,状态码: {response.status_code}",
  681. "response": response.text
  682. }
  683. except requests.exceptions.Timeout:
  684. # 记录API调用结果(超时)
  685. end_time = datetime.now()
  686. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  687. api_call_info = {
  688. "call_id": call_id,
  689. "timestamp": end_time.isoformat(),
  690. "agent": "RulesEngineMetricCalculationAgent",
  691. "api_endpoint": url,
  692. "config_name": knowledge_id,
  693. "request": {
  694. "method": method,
  695. "url": url,
  696. "headers": headers,
  697. "json_data": json_data if 'json_data' in locals() else None,
  698. "start_time": start_time.isoformat()
  699. },
  700. "response": {
  701. "error": "API调用超时",
  702. "end_time": end_time.isoformat(),
  703. "duration": (end_time - start_time).total_seconds()
  704. },
  705. "success": False
  706. }
  707. self.api_calls.append(api_call_info)
  708. # 保存API结果到文件
  709. api_results_dir = "api_results"
  710. os.makedirs(api_results_dir, exist_ok=True)
  711. filename = f"{call_id}.json"
  712. filepath = os.path.join(api_results_dir, filename)
  713. try:
  714. with open(filepath, 'w', encoding='utf-8') as f:
  715. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  716. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  717. except Exception as e:
  718. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  719. return {
  720. "success": False,
  721. "message": "规则引擎API调用超时"
  722. }
  723. except requests.exceptions.RequestException as e:
  724. # 记录API调用结果(请求异常)
  725. end_time = datetime.now()
  726. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  727. api_call_info = {
  728. "call_id": call_id,
  729. "timestamp": end_time.isoformat(),
  730. "agent": "RulesEngineMetricCalculationAgent",
  731. "api_endpoint": url,
  732. "config_name": knowledge_id,
  733. "request": {
  734. "method": method,
  735. "url": url,
  736. "headers": headers,
  737. "json_data": json_data if 'json_data' in locals() else None,
  738. "start_time": start_time.isoformat()
  739. },
  740. "response": {
  741. "error": str(e),
  742. "end_time": end_time.isoformat(),
  743. "duration": (end_time - start_time).total_seconds()
  744. },
  745. "success": False
  746. }
  747. self.api_calls.append(api_call_info)
  748. # 保存API结果到文件
  749. api_results_dir = "api_results"
  750. os.makedirs(api_results_dir, exist_ok=True)
  751. filename = f"{call_id}.json"
  752. filepath = os.path.join(api_results_dir, filename)
  753. try:
  754. with open(filepath, 'w', encoding='utf-8') as f:
  755. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  756. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  757. except Exception as e:
  758. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  759. return {
  760. "success": False,
  761. "message": f"规则引擎API调用异常: {str(e)}"
  762. }
  763. except Exception as e:
  764. # 记录API调用结果(其他异常)
  765. end_time = datetime.now()
  766. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  767. api_call_info = {
  768. "call_id": call_id,
  769. "timestamp": end_time.isoformat(),
  770. "agent": "RulesEngineMetricCalculationAgent",
  771. "api_endpoint": url,
  772. "config_name": knowledge_id,
  773. "request": {
  774. "method": method,
  775. "url": url,
  776. "headers": headers,
  777. "json_data": json_data if 'json_data' in locals() else None,
  778. "start_time": start_time.isoformat()
  779. },
  780. "response": {
  781. "error": str(e),
  782. "end_time": end_time.isoformat(),
  783. "duration": (end_time - start_time).total_seconds()
  784. },
  785. "success": False
  786. }
  787. self.api_calls.append(api_call_info)
  788. # 保存API结果到文件
  789. api_results_dir = "api_results"
  790. os.makedirs(api_results_dir, exist_ok=True)
  791. filename = f"{call_id}.json"
  792. filepath = os.path.join(api_results_dir, filename)
  793. try:
  794. with open(filepath, 'w', encoding='utf-8') as f:
  795. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  796. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  797. except Exception as e:
  798. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  799. return {
  800. "success": False,
  801. "message": f"处理规则引擎API调用时发生错误: {str(e)}"
  802. }
  803. def get_available_configs(self) -> List[str]:
  804. """获取所有可用的规则引擎配置文件名"""
  805. return list(self.configs.keys())
  806. def get_config_details(self, config_name: str) -> Optional[Dict]:
  807. """获取指定配置文件的详细信息"""
  808. return self.configs.get(config_name)