rules_engine_metric_calculation_agent.py 36 KB

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