diff --git a/api/core/tools/builtin_tool/providers/apo_analysis/tools/trend.py b/api/core/tools/builtin_tool/providers/apo_analysis/tools/trend.py new file mode 100644 index 0000000000..4d61e8ced6 --- /dev/null +++ b/api/core/tools/builtin_tool/providers/apo_analysis/tools/trend.py @@ -0,0 +1,80 @@ +import json +import numpy as np +from scipy import stats +from collections.abc import Generator +from typing import Any, Optional + +from core.tools.builtin_tool.tool import BuiltinTool +from core.tools.entities.tool_entities import ToolInvokeMessage + + +class TrendTool(BuiltinTool): + def _invoke( + self, + user_id: str, + tool_parameters: dict[str, Any], + conversation_id: Optional[str] = None, + app_id: Optional[str] = None, + message_id: Optional[str] = None, + ) -> Generator[ToolInvokeMessage, None, None]: + metric = tool_parameters.get('metricData') + metric_data = json.loads(metric) + # threshold = float(tool_parameters.get('threshold')) + res = "ok" + for serie in metric_data['data']['timeseries']: + # for k, v in serie['chart']['chartData'].items(): + # v = float(v) + # if v > threshold: + # tmpres['data'][str(k)] = v + tmpres = self.analyze_kv_trend(serie['chart']['chartData'], window_size=5) + if tmpres.get('trend', "") != "" and tmpres.get('trend', "") != '波动': + res = "false" + + yield self.create_text_message(res) + + def analyze_kv_trend(self, data_dict, window_size=5, threshold=0.05): + + # 提取值序列 + values = np.array(list(data_dict.values())) + + # 检查数据有效性 + if len(values) < window_size: + return {"error": "数据长度不足"} + + # 计算整体趋势(使用线性回归) + x = np.arange(len(values)) + slope, intercept, r_value, p_value, std_err = stats.linregress(x, values) + + # 计算滑动窗口的局部变化 + local_trends = [] + for i in range(len(values) - window_size + 1): + window = values[i:i + window_size] + window_x = np.arange(window_size) + window_slope = stats.linregress(window_x, window)[0] + local_trends.append(window_slope) + + # 分析结果 + result = { + "overall_slope": slope, # 整体斜率 + "p_value": p_value, # 统计显著性 + "std_dev": np.std(values), # 数据标准差 + "local_trend_variability": np.std(local_trends), # 局部趋势变化的标准差 + "data_points": len(values), # 数据点数量 + } + + # 判断趋势类型 + if p_value < threshold and slope > 0: + if result["local_trend_variability"] < abs(slope) * 0.5: + result["trend"] = "持续升高" + result["description"] = "数据呈现显著的持续上升趋势" + else: + result["trend"] = "波动上升" + result["description"] = "数据整体上升但存在一定波动" + elif p_value < threshold and slope < 0: + result["trend"] = "持续下降" + result["description"] = "数据呈现显著的持续下降趋势" + else: + result["trend"] = "波动" + result["description"] = "数据呈现波动状态,无显著趋势" + + return result \ No newline at end of file diff --git a/api/core/tools/builtin_tool/providers/apo_analysis/tools/trend.yaml b/api/core/tools/builtin_tool/providers/apo_analysis/tools/trend.yaml new file mode 100644 index 0000000000..86b50e7c26 --- /dev/null +++ b/api/core/tools/builtin_tool/providers/apo_analysis/tools/trend.yaml @@ -0,0 +1,40 @@ +identity: + name: trend + author: APO + label: + en_US: trend + zh_Hans: 趋势分析 + pt_BR: trend +description: + human: + en_US: threshold judgement + zh_Hans: 基于趋势分析,分析数据是波动还是持续变化 + pt_BR: threshold judgement + llm: threshold judgement +parameters: + - name: metricData + type: string + required: true + label: + en_US: metricData + zh_Hans: metricData + pt_BR: metricData + human_description: + en_US: time series metric data + zh_Hans: 时序指标数据 + pt_BR: time series metric data + llm_description: Time series indicator data + form: llm + - name: threshold + type: string + required: false + label: + en_US: threshold + zh_Hans: threshold + pt_BR: threshold + human_description: + en_US: threshold + zh_Hans: 趋势分析阈值 + pt_BR: threshold + llm_description: threshold + form: llm \ No newline at end of file