rules_engine_metric_calculation_agent.py 36 KB

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