viz_agent.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. """
  2. 数据可视化 Agent:用 Python 代码对 DataFrame 做统计分析和绑图。
  3. """
  4. import os
  5. import sys
  6. import traceback
  7. import warnings
  8. from io import StringIO
  9. from contextlib import redirect_stdout
  10. # 确保父目录可导入(支持直接运行 python agents/viz_agent.py)
  11. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  12. import pandas as pd
  13. import matplotlib.pyplot as plt
  14. import seaborn as sns
  15. import numpy as np
  16. from langchain.tools import tool
  17. from langchain.agents import create_agent
  18. from config import llm, engine
  19. warnings.filterwarnings("ignore")
  20. # ============================================================
  21. # 1. 中文字体配置
  22. # ============================================================
  23. plt.rcParams["font.sans-serif"] = ["SimHei", "PingFang SC", "DejaVu Sans"]
  24. plt.rcParams["axes.unicode_minus"] = False
  25. # ============================================================
  26. # 2. 延迟加载 DataFrame(避免 import 时就连库)
  27. # ============================================================
  28. _dataframes = None
  29. def load_dataframes():
  30. """从数据库加载 DataFrame。首次调用后缓存,后续直接返回缓存。"""
  31. global _dataframes
  32. if _dataframes is None:
  33. _dataframes = {
  34. "employees_df": pd.read_sql("SELECT * FROM employees", engine),
  35. "products_df": pd.read_sql("SELECT * FROM products", engine),
  36. "orders_df": pd.read_sql("SELECT * FROM orders", engine),
  37. }
  38. return _dataframes
  39. # ============================================================
  40. # 3. 代码执行沙箱
  41. # ============================================================
  42. @tool
  43. def execute_python_code(code: str) -> str:
  44. """
  45. 执行 Python 代码进行数据分析和可视化。
  46. 可用变量:
  47. - employees_df: 员工表 DataFrame(字段:id, name, department, salary, hire_date)
  48. - products_df: 产品表 DataFrame(字段:id, product_name, category, price, stock)
  49. - orders_df: 订单表 DataFrame(字段:id, employee_id, product_id, quantity, order_date)
  50. - pd: pandas 库
  51. - plt: matplotlib.pyplot
  52. - sns: seaborn
  53. - np: numpy
  54. 使用示例:
  55. result = employees_df.groupby('department')['salary'].mean()
  56. print(result)
  57. """
  58. dfs = load_dataframes()
  59. sandbox = {
  60. **dfs,
  61. "pd": pd,
  62. "plt": plt,
  63. "sns": sns,
  64. "np": np,
  65. }
  66. exec_locals = {}
  67. output_buffer = StringIO()
  68. try:
  69. with redirect_stdout(output_buffer):
  70. exec(code, sandbox, exec_locals)
  71. result = output_buffer.getvalue()
  72. if not result.strip():
  73. result = "✅ 代码执行成功(无文本输出,可能已生成图表)"
  74. return f"执行成功:\n{result}"
  75. except Exception as e:
  76. return f"❌ 执行出错:{e}\n\n{traceback.format_exc()}"
  77. # ============================================================
  78. # 4. Agent System Prompt
  79. # ============================================================
  80. VISUALIZATION_PROMPT = """你是一名资深数据分析师,精通 Python、Pandas 和 Matplotlib 数据可视化。
  81. ## 可用数据
  82. 1. employees_df — 员工表(字段:id, name, department, salary, hire_date)
  83. 2. products_df — 产品表(字段:id, product_name, category, price, stock)
  84. 3. orders_df — 订单表(字段:id, employee_id, product_id, quantity, order_date)
  85. ## 工作流程
  86. 1. 理解用户的分析需求
  87. 2. 用 execute_python_code 工具编写并执行 Python 代码
  88. 3. 先做数据探索(head、describe、info),再做深入分析
  89. 4. 用中文解释分析结果,给出业务洞察
  90. ## 代码规范
  91. - 绑图前设置中文字体:plt.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC', 'DejaVu Sans']
  92. - 设置 plt.rcParams['axes.unicode_minus'] = False
  93. - 图表尺寸统一用 plt.figure(figsize=(10, 6))
  94. - 必须添加标题、坐标轴标签,让图表自解释
  95. - 用 print() 输出关键统计量,不要只画图不说话
  96. - 图表标题用英文(避免渲染问题),但用中文向用户解释结果
  97. ## 注意事项
  98. - 每次只执行一段完整的代码,不要拆成多段
  99. - 先探索数据结构,再做分析——不要上来就画图
  100. - 结果要有业务洞察,不只是"最大值是 XXX"
  101. """
  102. # ============================================================
  103. # 5. 创建 Agent
  104. # ============================================================
  105. visualization_agent = create_agent(
  106. model=llm,
  107. tools=[execute_python_code],
  108. system_prompt=VISUALIZATION_PROMPT,
  109. )
  110. if __name__ == "__main__":
  111. dfs = load_dataframes()
  112. print("✅ 数据加载完成")
  113. for name, df in dfs.items():
  114. print(f" {name}:{len(df)} 行 × {len(df.columns)} 列")
  115. print("\n✅ 数据可视化 Agent 创建完成")