This commit is contained in:
2026-04-19 16:29:59 +08:00
22 changed files with 2060 additions and 916 deletions

View File

@@ -19,6 +19,7 @@ from utils.data_loader import load_and_profile_data
from utils.llm_helper import LLMHelper
from utils.code_executor import CodeExecutor
from utils.script_generator import generate_reusable_script
from utils.data_privacy import build_safe_profile, build_local_profile, sanitize_execution_feedback
from config.llm_config import LLMConfig
from prompts import data_analysis_system_prompt, final_report_system_prompt, data_analysis_followup_prompt
@@ -61,7 +62,8 @@ class DataAnalysisAgent:
self.current_round = 0
self.session_output_dir = None
self.executor = None
self.data_profile = "" # 存储数据画像
self.data_profile = "" # 存储数据画像(完整版,本地使用)
self.data_profile_safe = "" # 存储安全画像发给LLM
self.data_files = [] # 存储数据文件列表
self.user_requirement = "" # 存储用户需求
@@ -120,6 +122,8 @@ class DataAnalysisAgent:
figures_to_collect = yaml_data.get("figures_to_collect", [])
collected_figures = []
# 使用seen_paths集合来去重防止重复收集
seen_paths = set()
for figure_info in figures_to_collect:
figure_number = figure_info.get("figure_number", "未知")
@@ -138,10 +142,6 @@ class DataAnalysisAgent:
print(f" [NOTE] 描述: {description}")
print(f" [SEARCH] 分析: {analysis}")
# 使用seen_paths集合来去重防止重复收集
seen_paths = set()
# 验证文件是否存在
# 只有文件真正存在时才加入列表,防止报告出现裂图
if file_path and os.path.exists(file_path):
@@ -266,26 +266,29 @@ class DataAnalysisAgent:
# 设置会话目录变量到执行环境中
self.executor.set_variable("session_output_dir", self.session_output_dir)
# 设用工具生成数据画像
data_profile = ""
# 生成数据画像分级安全级发给LLM完整级留本地
data_profile_safe = ""
data_profile_local = ""
if files:
print("[SEARCH] 正在生成数据画像...")
try:
data_profile = load_and_profile_data(files)
print("[OK] 数据画像生成完毕")
data_profile_safe = build_safe_profile(files)
data_profile_local = build_local_profile(files)
print("[OK] 数据画像生成完毕(安全级 + 本地级)")
except Exception as e:
print(f"[WARN] 数据画像生成失败: {e}")
# 保存到实例变量供最终报告使用
self.data_profile = data_profile
# 安全画像发给LLM完整画像留给最终报告生成
self.data_profile = data_profile_local # 本地完整版用于最终报告
self.data_profile_safe = data_profile_safe # 安全版用于LLM对话
# 构建初始prompt
# 构建初始prompt只发送安全级画像给LLM
initial_prompt = f"""用户需求: {user_input}"""
if files:
initial_prompt += f"\n数据文件: {', '.join(files)}"
if data_profile:
initial_prompt += f"\n\n{data_profile}\n\n请根据上述【数据画像】中的统计信息(如高频值、缺失率、数据范围)来制定分析策略。如果发现明显的高频问题或异常分布,请优先进行深度分析。"
if data_profile_safe:
initial_prompt += f"\n\n{data_profile_safe}\n\n请根据上述【数据结构概览】中的列名、数据类型和特征描述来制定分析策略。先通过代码探索数据的实际分布,再进行深度分析。"
print(f"[START] 开始数据分析任务")
print(f"[NOTE] 用户需求: {user_input}")
@@ -385,8 +388,10 @@ class DataAnalysisAgent:
# 根据动作类型添加不同的反馈
if process_result["action"] == "generate_code":
feedback = process_result.get("feedback", "")
# 对执行反馈进行脱敏移除真实数据值后再发给LLM
safe_feedback = sanitize_execution_feedback(feedback)
self.conversation_history.append(
{"role": "user", "content": f"代码执行反馈:\n{feedback}"}
{"role": "user", "content": f"代码执行反馈:\n{safe_feedback}"}
)
# 记录分析结果
@@ -522,8 +527,6 @@ class DataAnalysisAgent:
print("[OK] 最终报告生成完成")
print("[OK] 最终报告生成完成")
except Exception as e:
print(f"[ERROR] 生成最终报告时出错: {str(e)}")
final_report_content = f"报告生成失败: {str(e)}"