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://localhost:8081/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. if response.status_code == 200:
  152. knowledge_meta = response.json()
  153. if isinstance(knowledge_meta, list):
  154. print(f"✅ 成功获取 {len(knowledge_meta)} 个知识元数据")
  155. return knowledge_meta
  156. else:
  157. print(f"⚠️ 知识元数据格式异常: {knowledge_meta}")
  158. return []
  159. else:
  160. print(f"❌ 获取知识元数据失败,状态码: {response.status_code}")
  161. print(f"响应内容: {response.text}")
  162. return []
  163. except Exception as e:
  164. print(f"❌ 获取知识元数据时发生错误: {str(e)}")
  165. return []
  166. def _get_input_field_for_knowledge(self, knowledge_id: str) -> str:
  167. """
  168. 根据知识ID获取对应的inputField字段名
  169. Args:
  170. knowledge_id: 知识ID
  171. Returns:
  172. inputField字段名,默认为"transactions"
  173. """
  174. for knowledge in self.available_knowledge:
  175. if knowledge.get("id") == knowledge_id:
  176. input_field = knowledge.get("inputField", "transactions")
  177. print(f"🔗 知识 {knowledge_id} 使用输入字段: {input_field}")
  178. return input_field
  179. print(f"⚠️ 未找到知识 {knowledge_id} 的输入字段,使用默认值: transactions")
  180. return "transactions" # 默认值
  181. async def calculate_metrics(self, intent_result: Dict[str, Any]) -> Dict[str, Any]:
  182. """
  183. 根据意图识别结果进行规则引擎指标计算
  184. Args:
  185. intent_result: 意图识别结果
  186. Returns:
  187. 指标计算结果
  188. """
  189. try:
  190. results = []
  191. target_configs = intent_result.get("target_configs", [])
  192. if not target_configs:
  193. return {
  194. "success": False,
  195. "message": "没有找到需要调用的配置文件",
  196. "results": []
  197. }
  198. for config_name in target_configs:
  199. if config_name in self.configs:
  200. # 使用传统的JSON配置文件方式
  201. config = self.configs[config_name]
  202. result = await self._call_rules_engine_api(config, intent_result, config_name)
  203. results.append({
  204. "config_name": config_name,
  205. "result": result
  206. })
  207. elif config_name.startswith("metric-"):
  208. # 直接使用知识ID调用API,无需配置文件
  209. result = await self._call_rules_engine_api_by_knowledge_id(config_name, intent_result)
  210. results.append({
  211. "config_name": config_name,
  212. "result": result
  213. })
  214. else:
  215. results.append({
  216. "config_name": config_name,
  217. "error": f"配置文件 {config_name} 不存在,且不是有效的知识ID"
  218. })
  219. return {
  220. "success": True,
  221. "results": results,
  222. "total_configs": len(target_configs),
  223. "successful_calculations": len([r for r in results if "result" in r])
  224. }
  225. except Exception as e:
  226. print(f"规则引擎指标计算失败: {e}")
  227. return {
  228. "success": False,
  229. "message": f"规则引擎指标计算过程中发生错误: {str(e)}",
  230. "results": []
  231. }
  232. async def _call_rules_engine_api(self, config: Dict[str, Any], intent_result: Dict[str, Any], config_name: str) -> Dict[str, Any]:
  233. """
  234. 调用规则引擎API
  235. Args:
  236. config: 配置文件
  237. intent_result: 意图识别结果
  238. Returns:
  239. API调用结果
  240. """
  241. try:
  242. # 记录API调用开始
  243. start_time = datetime.now()
  244. # 规则引擎API配置
  245. method = "POST"
  246. url = "http://localhost:8081/api/rules/executeKnowledge"
  247. # url = "http://10.192.72.11:31809/api/rules/executeKnowledge"
  248. headers = {
  249. "Accept": "*/*",
  250. "Accept-Encoding": "gzip, deflate, br",
  251. "Connection": "keep-alive",
  252. "Content-Type": "application/json",
  253. "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0"
  254. }
  255. timeout = 180 # 3分钟超时
  256. # 准备请求数据
  257. request_data = self._prepare_rules_engine_request_data(config, intent_result, config_name)
  258. # 调用API
  259. json_data = request_data.get("json", {})
  260. response = requests.post(url, headers=headers, json=json_data, timeout=timeout)
  261. # 处理响应
  262. if response.status_code == 200:
  263. try:
  264. response_data = response.json()
  265. # 记录API调用结果
  266. end_time = datetime.now()
  267. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  268. api_call_info = {
  269. "call_id": call_id,
  270. "timestamp": end_time.isoformat(),
  271. "agent": "RulesEngineMetricCalculationAgent",
  272. "api_endpoint": url,
  273. "config_name": config_name,
  274. "request": {
  275. "method": method,
  276. "url": url,
  277. "headers": headers,
  278. "json_data": json_data,
  279. "start_time": start_time.isoformat()
  280. },
  281. "response": {
  282. "status_code": response.status_code,
  283. "data": response_data,
  284. "end_time": end_time.isoformat(),
  285. "duration": (end_time - start_time).total_seconds()
  286. },
  287. "success": True
  288. }
  289. self.api_calls.append(api_call_info)
  290. # 保存API结果到文件
  291. api_results_dir = "api_results"
  292. os.makedirs(api_results_dir, exist_ok=True)
  293. filename = f"{call_id}.json"
  294. filepath = os.path.join(api_results_dir, filename)
  295. try:
  296. with open(filepath, 'w', encoding='utf-8') as f:
  297. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  298. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  299. except Exception as e:
  300. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  301. return {
  302. "success": True,
  303. "data": response_data,
  304. "status_code": response.status_code
  305. }
  306. except json.JSONDecodeError:
  307. # 记录API调用结果(JSON解析失败)
  308. end_time = datetime.now()
  309. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  310. api_call_info = {
  311. "call_id": call_id,
  312. "timestamp": end_time.isoformat(),
  313. "agent": "RulesEngineMetricCalculationAgent",
  314. "api_endpoint": url,
  315. "config_name": config_name,
  316. "request": {
  317. "method": method,
  318. "url": url,
  319. "headers": headers,
  320. "json_data": json_data,
  321. "start_time": start_time.isoformat()
  322. },
  323. "response": {
  324. "status_code": response.status_code,
  325. "data": response.text,
  326. "error": "JSON解析失败",
  327. "end_time": end_time.isoformat(),
  328. "duration": (end_time - start_time).total_seconds()
  329. },
  330. "success": False
  331. }
  332. self.api_calls.append(api_call_info)
  333. # 保存API结果到文件
  334. api_results_dir = "api_results"
  335. os.makedirs(api_results_dir, exist_ok=True)
  336. filename = f"{call_id}.json"
  337. filepath = os.path.join(api_results_dir, filename)
  338. try:
  339. with open(filepath, 'w', encoding='utf-8') as f:
  340. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  341. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  342. except Exception as e:
  343. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  344. return {
  345. "success": True,
  346. "data": response.text,
  347. "status_code": response.status_code
  348. }
  349. else:
  350. # 记录API调用结果(HTTP错误)
  351. end_time = datetime.now()
  352. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  353. api_call_info = {
  354. "call_id": call_id,
  355. "timestamp": end_time.isoformat(),
  356. "agent": "RulesEngineMetricCalculationAgent",
  357. "api_endpoint": url,
  358. "config_name": config_name,
  359. "request": {
  360. "method": method,
  361. "url": url,
  362. "headers": headers,
  363. "json_data": json_data,
  364. "start_time": start_time.isoformat()
  365. },
  366. "response": {
  367. "status_code": response.status_code,
  368. "error": response.text,
  369. "end_time": end_time.isoformat(),
  370. "duration": (end_time - start_time).total_seconds()
  371. },
  372. "success": False
  373. }
  374. self.api_calls.append(api_call_info)
  375. # 保存API结果到文件
  376. api_results_dir = "api_results"
  377. os.makedirs(api_results_dir, exist_ok=True)
  378. filename = f"{call_id}.json"
  379. filepath = os.path.join(api_results_dir, filename)
  380. try:
  381. with open(filepath, 'w', encoding='utf-8') as f:
  382. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  383. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  384. except Exception as e:
  385. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  386. return {
  387. "success": False,
  388. "message": f"规则引擎API调用失败,状态码: {response.status_code}",
  389. "response": response.text
  390. }
  391. except requests.exceptions.Timeout:
  392. # 记录API调用结果(超时)
  393. end_time = datetime.now()
  394. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  395. api_call_info = {
  396. "call_id": call_id,
  397. "timestamp": end_time.isoformat(),
  398. "agent": "RulesEngineMetricCalculationAgent",
  399. "api_endpoint": url,
  400. "config_name": config_name,
  401. "request": {
  402. "method": method,
  403. "url": url,
  404. "headers": headers,
  405. "json_data": json_data if 'json_data' in locals() else None,
  406. "start_time": start_time.isoformat()
  407. },
  408. "response": {
  409. "error": "API调用超时",
  410. "end_time": end_time.isoformat(),
  411. "duration": (end_time - start_time).total_seconds()
  412. },
  413. "success": False
  414. }
  415. self.api_calls.append(api_call_info)
  416. return {
  417. "success": False,
  418. "message": "规则引擎API调用超时"
  419. }
  420. except requests.exceptions.RequestException as e:
  421. # 记录API调用结果(请求异常)
  422. end_time = datetime.now()
  423. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  424. api_call_info = {
  425. "call_id": call_id,
  426. "timestamp": end_time.isoformat(),
  427. "agent": "RulesEngineMetricCalculationAgent",
  428. "api_endpoint": url,
  429. "config_name": config_name,
  430. "request": {
  431. "method": method,
  432. "url": url,
  433. "headers": headers,
  434. "json_data": json_data if 'json_data' in locals() else None,
  435. "start_time": start_time.isoformat()
  436. },
  437. "response": {
  438. "error": str(e),
  439. "end_time": end_time.isoformat(),
  440. "duration": (end_time - start_time).total_seconds()
  441. },
  442. "success": False
  443. }
  444. self.api_calls.append(api_call_info)
  445. return {
  446. "success": False,
  447. "message": f"规则引擎API调用异常: {str(e)}"
  448. }
  449. except Exception as e:
  450. # 记录API调用结果(其他异常)
  451. end_time = datetime.now()
  452. call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  453. api_call_info = {
  454. "call_id": call_id,
  455. "timestamp": end_time.isoformat(),
  456. "agent": "RulesEngineMetricCalculationAgent",
  457. "api_endpoint": url,
  458. "config_name": config_name,
  459. "request": {
  460. "method": method,
  461. "url": url,
  462. "headers": headers,
  463. "json_data": json_data if 'json_data' in locals() else None,
  464. "start_time": start_time.isoformat()
  465. },
  466. "response": {
  467. "error": str(e),
  468. "end_time": end_time.isoformat(),
  469. "duration": (end_time - start_time).total_seconds()
  470. },
  471. "success": False
  472. }
  473. self.api_calls.append(api_call_info)
  474. return {
  475. "success": False,
  476. "message": f"处理规则引擎API调用时发生错误: {str(e)}"
  477. }
  478. def _prepare_rules_engine_request_data(self, config: Dict[str, Any], intent_result: Dict[str, Any], config_name: str) -> Dict[str, Any]:
  479. """
  480. 准备规则引擎API请求数据
  481. Args:
  482. config: 配置文件
  483. intent_result: 意图识别结果
  484. config_name: 配置文件名
  485. Returns:
  486. 请求数据
  487. """
  488. # 从配置文件中获取id和input
  489. request_id = config.get("id", "")
  490. input_filename = config.get("input", "")
  491. # 加载对应的数据文件
  492. input_data = {}
  493. if input_filename:
  494. data_file_path = self._select_data_file(input_filename)
  495. if data_file_path:
  496. input_data = self._load_table_data(data_file_path)
  497. else:
  498. print(f"警告:找不到配置文件 {config_name} 对应的数据文件: {input_filename}")
  499. # 构造API请求体
  500. request_data = {
  501. "id": request_id,
  502. "input": input_data
  503. }
  504. return {"json": request_data}
  505. async def _call_rules_engine_api_by_knowledge_id(self, knowledge_id: str, intent_result: Dict[str, Any]) -> Dict[str, Any]:
  506. """
  507. 直接通过知识ID调用规则引擎API
  508. Args:
  509. knowledge_id: 知识ID,如 "metric-分析账户数量"
  510. intent_result: 意图识别结果(用于获取数据文件信息)
  511. Returns:
  512. API调用结果
  513. """
  514. # 记录API调用开始
  515. start_time = datetime.now()
  516. # 规则引擎API配置
  517. method = "POST"
  518. url = "http://localhost:8081/api/rules/executeKnowledge"
  519. headers = {
  520. "Accept": "*/*",
  521. "Accept-Encoding": "gzip, deflate, br",
  522. "Connection": "keep-alive",
  523. "Content-Type": "application/json",
  524. "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0"
  525. }
  526. timeout = 180 # 3分钟超时
  527. try:
  528. # 根据知识ID获取正确的输入字段名
  529. input_field_name = self._get_input_field_for_knowledge(knowledge_id)
  530. # 构造请求数据 - 直接使用默认数据文件
  531. # 从intent_result中获取数据文件名,如果没有则使用默认的农业数据
  532. input_filename = intent_result.get("data_file", "加工数据-流水分析-农业打标.json")
  533. # 加载对应的数据文件
  534. input_data = {}
  535. if input_filename:
  536. data_file_path = self._select_data_file(input_filename)
  537. if data_file_path:
  538. raw_data = self._load_table_data(data_file_path)
  539. # 使用正确的字段名包装数据
  540. input_data = {input_field_name: raw_data}
  541. else:
  542. print(f"警告:找不到数据文件: {input_filename}")
  543. input_data = {input_field_name: []}
  544. # 构造API请求体
  545. request_data = {
  546. "id": knowledge_id, # 直接使用知识ID
  547. "input": input_data
  548. }
  549. # 调用API
  550. json_data = request_data
  551. response = requests.post(url, headers=headers, json=json_data, timeout=timeout)
  552. # 处理响应(复用现有的响应处理逻辑)
  553. if response.status_code == 200:
  554. try:
  555. response_data = response.json()
  556. # 记录API调用结果
  557. end_time = datetime.now()
  558. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  559. api_call_info = {
  560. "call_id": call_id,
  561. "timestamp": end_time.isoformat(),
  562. "agent": "RulesEngineMetricCalculationAgent",
  563. "api_endpoint": url,
  564. "config_name": knowledge_id,
  565. "request": {
  566. "method": method,
  567. "url": url,
  568. "headers": headers,
  569. "json_data": json_data,
  570. "start_time": start_time.isoformat()
  571. },
  572. "response": {
  573. "status_code": response.status_code,
  574. "data": response_data,
  575. "end_time": end_time.isoformat(),
  576. "duration": (end_time - start_time).total_seconds()
  577. },
  578. "success": True
  579. }
  580. self.api_calls.append(api_call_info)
  581. # 保存API结果到文件
  582. api_results_dir = "api_results"
  583. os.makedirs(api_results_dir, exist_ok=True)
  584. filename = f"{call_id}.json"
  585. filepath = os.path.join(api_results_dir, filename)
  586. try:
  587. with open(filepath, 'w', encoding='utf-8') as f:
  588. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  589. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  590. except Exception as e:
  591. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  592. return {
  593. "success": True,
  594. "data": response_data,
  595. "status_code": response.status_code
  596. }
  597. except json.JSONDecodeError:
  598. # 记录JSON解析失败的API调用
  599. end_time = datetime.now()
  600. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  601. api_call_info = {
  602. "call_id": call_id,
  603. "timestamp": end_time.isoformat(),
  604. "agent": "RulesEngineMetricCalculationAgent",
  605. "api_endpoint": url,
  606. "config_name": knowledge_id,
  607. "request": {
  608. "method": method,
  609. "url": url,
  610. "headers": headers,
  611. "json_data": json_data,
  612. "start_time": start_time.isoformat()
  613. },
  614. "response": {
  615. "status_code": response.status_code,
  616. "data": response.text,
  617. "error": "JSON解析失败",
  618. "end_time": end_time.isoformat(),
  619. "duration": (end_time - start_time).total_seconds()
  620. },
  621. "success": False
  622. }
  623. self.api_calls.append(api_call_info)
  624. # 保存API结果到文件
  625. api_results_dir = "api_results"
  626. os.makedirs(api_results_dir, exist_ok=True)
  627. filename = f"{call_id}.json"
  628. filepath = os.path.join(api_results_dir, filename)
  629. try:
  630. with open(filepath, 'w', encoding='utf-8') as f:
  631. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  632. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  633. except Exception as e:
  634. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  635. return {
  636. "success": True,
  637. "data": response.text,
  638. "status_code": response.status_code
  639. }
  640. else:
  641. # 记录失败的API调用
  642. end_time = datetime.now()
  643. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  644. api_call_info = {
  645. "call_id": call_id,
  646. "timestamp": end_time.isoformat(),
  647. "agent": "RulesEngineMetricCalculationAgent",
  648. "api_endpoint": url,
  649. "config_name": knowledge_id,
  650. "request": {
  651. "method": method,
  652. "url": url,
  653. "headers": headers,
  654. "json_data": json_data,
  655. "start_time": start_time.isoformat()
  656. },
  657. "response": {
  658. "status_code": response.status_code,
  659. "error": response.text,
  660. "end_time": end_time.isoformat(),
  661. "duration": (end_time - start_time).total_seconds()
  662. },
  663. "success": False
  664. }
  665. self.api_calls.append(api_call_info)
  666. # 保存API结果到文件
  667. api_results_dir = "api_results"
  668. os.makedirs(api_results_dir, exist_ok=True)
  669. filename = f"{call_id}.json"
  670. filepath = os.path.join(api_results_dir, filename)
  671. try:
  672. with open(filepath, 'w', encoding='utf-8') as f:
  673. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  674. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  675. except Exception as e:
  676. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  677. return {
  678. "success": False,
  679. "message": f"规则引擎API调用失败,状态码: {response.status_code}",
  680. "response": response.text
  681. }
  682. except requests.exceptions.Timeout:
  683. # 记录API调用结果(超时)
  684. end_time = datetime.now()
  685. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  686. api_call_info = {
  687. "call_id": call_id,
  688. "timestamp": end_time.isoformat(),
  689. "agent": "RulesEngineMetricCalculationAgent",
  690. "api_endpoint": url,
  691. "config_name": knowledge_id,
  692. "request": {
  693. "method": method,
  694. "url": url,
  695. "headers": headers,
  696. "json_data": json_data if 'json_data' in locals() else None,
  697. "start_time": start_time.isoformat()
  698. },
  699. "response": {
  700. "error": "API调用超时",
  701. "end_time": end_time.isoformat(),
  702. "duration": (end_time - start_time).total_seconds()
  703. },
  704. "success": False
  705. }
  706. self.api_calls.append(api_call_info)
  707. # 保存API结果到文件
  708. api_results_dir = "api_results"
  709. os.makedirs(api_results_dir, exist_ok=True)
  710. filename = f"{call_id}.json"
  711. filepath = os.path.join(api_results_dir, filename)
  712. try:
  713. with open(filepath, 'w', encoding='utf-8') as f:
  714. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  715. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  716. except Exception as e:
  717. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  718. return {
  719. "success": False,
  720. "message": "规则引擎API调用超时"
  721. }
  722. except requests.exceptions.RequestException as e:
  723. # 记录API调用结果(请求异常)
  724. end_time = datetime.now()
  725. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  726. api_call_info = {
  727. "call_id": call_id,
  728. "timestamp": end_time.isoformat(),
  729. "agent": "RulesEngineMetricCalculationAgent",
  730. "api_endpoint": url,
  731. "config_name": knowledge_id,
  732. "request": {
  733. "method": method,
  734. "url": url,
  735. "headers": headers,
  736. "json_data": json_data if 'json_data' in locals() else None,
  737. "start_time": start_time.isoformat()
  738. },
  739. "response": {
  740. "error": str(e),
  741. "end_time": end_time.isoformat(),
  742. "duration": (end_time - start_time).total_seconds()
  743. },
  744. "success": False
  745. }
  746. self.api_calls.append(api_call_info)
  747. # 保存API结果到文件
  748. api_results_dir = "api_results"
  749. os.makedirs(api_results_dir, exist_ok=True)
  750. filename = f"{call_id}.json"
  751. filepath = os.path.join(api_results_dir, filename)
  752. try:
  753. with open(filepath, 'w', encoding='utf-8') as f:
  754. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  755. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  756. except Exception as e:
  757. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  758. return {
  759. "success": False,
  760. "message": f"规则引擎API调用异常: {str(e)}"
  761. }
  762. except Exception as e:
  763. # 记录API调用结果(其他异常)
  764. end_time = datetime.now()
  765. call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
  766. api_call_info = {
  767. "call_id": call_id,
  768. "timestamp": end_time.isoformat(),
  769. "agent": "RulesEngineMetricCalculationAgent",
  770. "api_endpoint": url,
  771. "config_name": knowledge_id,
  772. "request": {
  773. "method": method,
  774. "url": url,
  775. "headers": headers,
  776. "json_data": json_data if 'json_data' in locals() else None,
  777. "start_time": start_time.isoformat()
  778. },
  779. "response": {
  780. "error": str(e),
  781. "end_time": end_time.isoformat(),
  782. "duration": (end_time - start_time).total_seconds()
  783. },
  784. "success": False
  785. }
  786. self.api_calls.append(api_call_info)
  787. # 保存API结果到文件
  788. api_results_dir = "api_results"
  789. os.makedirs(api_results_dir, exist_ok=True)
  790. filename = f"{call_id}.json"
  791. filepath = os.path.join(api_results_dir, filename)
  792. try:
  793. with open(filepath, 'w', encoding='utf-8') as f:
  794. json.dump(api_call_info, f, ensure_ascii=False, indent=2)
  795. print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
  796. except Exception as e:
  797. print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
  798. return {
  799. "success": False,
  800. "message": f"处理规则引擎API调用时发生错误: {str(e)}"
  801. }
  802. def get_available_configs(self) -> List[str]:
  803. """获取所有可用的规则引擎配置文件名"""
  804. return list(self.configs.keys())
  805. def get_config_details(self, config_name: str) -> Optional[Dict]:
  806. """获取指定配置文件的详细信息"""
  807. return self.configs.get(config_name)