{ "cells": [ { "cell_type": "markdown", "id": "1e898f6e", "metadata": {}, "source": [ "# 智能数据分析师(Agent Data Analyst)\n", "\n", "## 项目简介\n", "\n", "本项目基于 **Hello-Agents 1.x** 框架构建了一个「智能数据分析师」Agent。用户只需用自然语言提出数据分析需求,Agent 即可自主完成 **数据加载 → 数据质量诊断 → 统计分析 → 数据清洗 → 可视化图表生成 → 业务洞察总结** 的完整分析流程,让不会编程的业务人员也能一键获得专业的数据分析报告。\n", "\n", "**核心特性:**\n", "- 🗣️ 自然语言交互:零代码完成数据分析\n", "- 🔧 Function Calling:Agent 自主规划并调用 4 个专业数据分析工具\n", "- 📊 自动可视化:根据分析意图自动选择合适图表类型\n", "- 💡 业务洞察:不止给数字,更给出可执行的业务建议\n", "\n", "## 作者信息\n", "- 姓名:孟凡超\n", "- GitHub:BeiXiao-929\n", "- 日期:2026-9-3\n", "\n", "## 项目结构\n", "\n", "```\n", "BeiXiao-929-AI-Powered-Data-Analyst-Agent/\n", "├── main.ipynb # 本文件:项目主程序\n", "├── README.md # 项目说明文档\n", "├── requirements.txt # 依赖清单\n", "├── data/\n", "│ └── sample_sales.csv # 示例数据(100条记录,含缺失值/重复行)\n", "└── outputs/ # 图表与分析结果输出目录\n", "```\n", "\n", "## 环境说明\n", "\n", "本项目依赖 **hello-agents ≥ 1.0.0**(新版 API:`Tool` / `ToolRegistry` / `ToolResponse`)。若按旧版教程使用 `BaseTool`/`agent.add_tool()` 会报 `ImportError`。\n" ] }, { "cell_type": "markdown", "id": "5199eae9", "metadata": {}, "source": [ "## 第2部分:环境配置\n", "\n", "### 2.1 安装依赖(首次运行执行一次)\n", "\n", "```bash\n", "pip install -r requirements.txt\n", "# 或:pip install \"hello-agents>=1.0.0\" pandas matplotlib python-dotenv\n", "```\n", "\n", "### 2.2 配置密钥(重要)\n", "\n", "新版 `HelloAgentsLLM` 从 **`LLM_API_KEY`**(不是 `ZHIPU_API_KEY`)读取密钥。\n", "本项目使用 `api.env` 文件,请在项目根目录的 `api.env` 中确认/补齐三个变量:\n", "\n", "```bash\n", "LLM_MODEL_ID=glm-4-flash\n", "LLM_API_KEY=你的智谱API密钥 # ← 注意键名,旧模板常误写为 ZHIPU_API_KEY\n", "LLM_BASE_URL=https://open.bigmodel.cn/api/paas/v4\n", "```\n" ] }, { "cell_type": "code", "execution_count": 8, "id": "b6016049", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "环境配置完成 ✅\n", "当前模型: glm-4-flash | 密钥已配置: True\n" ] } ], "source": [ "# 若未安装依赖,可取消下面一行的注释后执行(已安装则跳过)\n", "# %pip install -q -r requirements.txt\n", "\n", "# 导入必要的库\n", "from hello_agents import SimpleAgent, HelloAgentsLLM\n", "from hello_agents.tools import Tool, ToolParameter, ToolResponse, ToolRegistry, ToolErrorCode\n", "import os\n", "import json\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "from datetime import datetime\n", "from dotenv import load_dotenv\n", "\n", "# 解决 matplotlib 中文乱码\n", "plt.rcParams[\"font.sans-serif\"] = [\"SimHei\", \"Microsoft YaHei\"]\n", "plt.rcParams[\"axes.unicode_minus\"] = False\n", "\n", "# 加载环境变量(兼容 .env 与 api.env 两种命名)\n", "load_dotenv()\n", "load_dotenv(\"api.env\")\n", "\n", "DATA_PATH = \"data/sample_sales.csv\"\n", "print(\"环境配置完成 ✅\")\n", "print(f\"当前模型: {os.getenv('LLM_MODEL_ID')} | 密钥已配置: {bool(os.getenv('LLM_API_KEY'))}\")" ] }, { "cell_type": "markdown", "id": "a38de8d4", "metadata": {}, "source": [ "## 第3部分:工具定义\n", "\n", "适配 hello-agents 1.x 新版 API 定义 4 个数据分析工具(继承 `Tool`,返回 `ToolResponse`,用 `get_parameters()` 声明结构化参数):\n", "\n", "| 工具 | 名称 | 参数 | 功能 |\n", "|------|------|------|------|\n", "| `CSVLoaderTool` | `csv_loader` | file_path | 加载数据集,返回规模、字段、样例、缺失值、重复行诊断 |\n", "| `DataStatsTool` | `data_stats` | file_path, column | 数值列描述性统计 + 类别列分布统计 |\n", "| `DataCleanTool` | `data_cleaner` | file_path | 缺失值填充、去重,保存清洗后数据并返回报告 |\n", "| `DataVizTool` | `data_visualizer` | file_path, chart_type, x_column, y_column | 柱状/折线/饼图/直方图/散点图,保存到 outputs/ |\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "e466e0d4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✅ 工具 'csv_loader' 已注册。\n", "✅ 工具 'data_stats' 已注册。\n", "✅ 工具 'data_cleaner' 已注册。\n", "✅ 工具 'data_visualizer' 已注册。\n", "工具注册完成 ✅ 共 4 个:['csv_loader', 'data_stats', 'data_cleaner', 'data_visualizer']\n" ] } ], "source": [ "class CSVLoaderTool(Tool):\n", " \"\"\"数据加载工具:读取CSV并返回数据全貌与质量诊断\"\"\"\n", "\n", " def __init__(self):\n", " super().__init__(\n", " name=\"csv_loader\",\n", " description=(\n", " \"加载CSV数据集并返回数据概览,包括:数据规模、字段及类型、前5行样例、\"\n", " \"各列缺失值数量、重复行数量。数据分析的第一步应调用本工具。\"\n", " ),\n", " )\n", "\n", " def run(self, parameters: dict) -> ToolResponse:\n", " path = str(parameters.get(\"file_path\", \"\")).strip().strip(\"'\\\"\")\n", " if not os.path.exists(path):\n", " return ToolResponse.error(code=ToolErrorCode.INVALID_PARAM,\n", " message=f\"文件 {path} 不存在,请检查路径\")\n", " try:\n", " df = pd.read_csv(path)\n", " except Exception as e:\n", " return ToolResponse.error(code=ToolErrorCode.INVALID_FORMAT,\n", " message=f\"读取文件失败: {e}\")\n", " missing = df.isnull().sum()\n", " missing = missing[missing > 0]\n", " info = {\n", " \"文件路径\": path,\n", " \"数据规模\": f\"{df.shape[0]} 行 x {df.shape[1]} 列\",\n", " \"字段及类型\": {col: str(dtype) for col, dtype in df.dtypes.items()},\n", " \"前5行样例\": df.head().to_dict(orient=\"records\"),\n", " \"缺失值统计\": {k: int(v) for k, v in missing.items()} if len(missing) else \"无缺失值\",\n", " \"重复行数量\": int(df.duplicated().sum()),\n", " }\n", " text = json.dumps(info, ensure_ascii=False, indent=2, default=str)\n", " return ToolResponse.success(text=text, data=info)\n", "\n", " def get_parameters(self):\n", " return [\n", " ToolParameter(name=\"file_path\", type=\"string\",\n", " description=\"CSV文件路径,例如 data/sample_sales.csv\", required=True),\n", " ]\n", "\n", "\n", "class DataStatsTool(Tool):\n", " \"\"\"统计分析工具:数值列描述性统计 + 类别列分布\"\"\"\n", "\n", " def __init__(self):\n", " super().__init__(\n", " name=\"data_stats\",\n", " description=(\n", " \"对数据集做统计分析:自动输出所有数值列的 count/mean/std/min/25%/50%/75%/max,\"\n", " \"以及低基数类别列的取值分布(Top5)。如需只看某一列,可传入 column 参数。\"\n", " ),\n", " )\n", "\n", " def run(self, parameters: dict) -> ToolResponse:\n", " path = str(parameters.get(\"file_path\", \"\")).strip().strip(\"'\\\"\")\n", " if not os.path.exists(path):\n", " return ToolResponse.error(code=ToolErrorCode.INVALID_PARAM,\n", " message=f\"文件 {path} 不存在\")\n", " df = pd.read_csv(path)\n", " result = {\"文件\": path}\n", "\n", " column = parameters.get(\"column\")\n", " if column and column in df.columns:\n", " series = df[column]\n", " if pd.api.types.is_numeric_dtype(series):\n", " result[\"列统计\"] = series.describe().round(2).to_dict()\n", " else:\n", " vc = series.value_counts(dropna=False).head(10)\n", " result[\"取值分布\"] = {str(k): int(v) for k, v in vc.items()}\n", " return ToolResponse.success(\n", " text=json.dumps(result, ensure_ascii=False, indent=2, default=str), data=result)\n", "\n", " numeric_cols = df.select_dtypes(include=\"number\").columns.tolist()\n", " if numeric_cols:\n", " result[\"数值列统计\"] = df[numeric_cols].describe().round(2).to_dict()\n", " cat_cols = df.select_dtypes(exclude=\"number\").columns.tolist()\n", " cat_dist = {}\n", " for col in cat_cols:\n", " vc = df[col].value_counts().head(5)\n", " if len(vc) <= 10:\n", " cat_dist[col] = {str(k): int(v) for k, v in vc.items()}\n", " if cat_dist:\n", " result[\"类别列分布(Top5)\"] = cat_dist\n", " return ToolResponse.success(\n", " text=json.dumps(result, ensure_ascii=False, indent=2, default=str), data=result)\n", "\n", " def get_parameters(self):\n", " return [\n", " ToolParameter(name=\"file_path\", type=\"string\",\n", " description=\"CSV文件路径,例如 data/sample_sales.csv\", required=True),\n", " ToolParameter(name=\"column\", type=\"string\",\n", " description=\"要重点分析的列名(可选,省略则分析全表)\",\n", " required=False, default=\"\"),\n", " ]\n", "\n", "\n", "class DataCleanTool(Tool):\n", " \"\"\"数据清洗工具:缺失值填充 + 去重,保存清洗结果并返回报告\"\"\"\n", "\n", " def __init__(self):\n", " super().__init__(\n", " name=\"data_cleaner\",\n", " description=(\n", " \"清洗数据集:数值列缺失值用中位数填充、类别列缺失值用众数填充、删除重复行。\"\n", " \"清洗后的数据保存到 outputs/ 目录,返回清洗报告。\"\n", " ),\n", " )\n", "\n", " def run(self, parameters: dict) -> ToolResponse:\n", " path = str(parameters.get(\"file_path\", \"\")).strip().strip(\"'\\\"\")\n", " if not os.path.exists(path):\n", " return ToolResponse.error(code=ToolErrorCode.INVALID_PARAM,\n", " message=f\"文件 {path} 不存在\")\n", " df = pd.read_csv(path)\n", " report = {\"原始规模\": f\"{df.shape[0]} 行 x {df.shape[1]} 列\"}\n", "\n", " # 1. 缺失值处理\n", " missing_before = df.isnull().sum()\n", " missing_before = missing_before[missing_before > 0]\n", " fill_detail = {}\n", " for col in missing_before.index:\n", " if pd.api.types.is_numeric_dtype(df[col]):\n", " fill_value = df[col].median()\n", " strategy = \"中位数\"\n", " else:\n", " fill_value = df[col].mode().iloc[0] if not df[col].mode().empty else \"未知\"\n", " strategy = \"众数\"\n", " df[col] = df[col].fillna(fill_value)\n", " fill_detail[col] = f\"{int(missing_before[col])} 个缺失值已用{strategy}({fill_value})填充\"\n", " report[\"缺失值处理\"] = fill_detail if fill_detail else \"无缺失值\"\n", "\n", " # 2. 去重\n", " dup_count = int(df.duplicated().sum())\n", " if dup_count:\n", " df = df.drop_duplicates().reset_index(drop=True)\n", " report[\"重复行处理\"] = f\"删除 {dup_count} 条重复行\"\n", "\n", " # 3. 保存\n", " os.makedirs(\"outputs\", exist_ok=True)\n", " cleaned_path = f\"outputs/cleaned_{os.path.basename(path)}\"\n", " df.to_csv(cleaned_path, index=False, encoding=\"utf-8-sig\")\n", " report[\"清洗后规模\"] = f\"{df.shape[0]} 行 x {df.shape[1]} 列\"\n", " report[\"清洗后文件\"] = cleaned_path\n", " return ToolResponse.success(\n", " text=json.dumps(report, ensure_ascii=False, indent=2, default=str), data=report)\n", "\n", " def get_parameters(self):\n", " return [\n", " ToolParameter(name=\"file_path\", type=\"string\",\n", " description=\"待清洗的CSV文件路径\", required=True),\n", " ]\n", "\n", "\n", "class DataVizTool(Tool):\n", " \"\"\"可视化工具:根据分析意图生成图表并保存到 outputs/\"\"\"\n", "\n", " def __init__(self):\n", " super().__init__(\n", " name=\"data_visualizer\",\n", " description=(\n", " \"生成数据可视化图表。chart_type 支持:bar(柱状图-对比各类别)、\"\n", " \"line(折线图-展示趋势)、pie(饼图-展示占比)、hist(直方图-展示分布)、\"\n", " \"scatter(散点图-看两列关系)。\"\n", " \"bar/pie 省略 y_column 时按计数统计;hist 只需 x_column 传数值列;\"\n", " \"scatter/line 需要 x_column 与 y_column。\"\n", " ),\n", " )\n", "\n", " def run(self, parameters: dict) -> ToolResponse:\n", " path = str(parameters.get(\"file_path\", \"\")).strip().strip(\"'\\\"\")\n", " chart_type = str(parameters.get(\"chart_type\", \"\")).lower()\n", " x_col = parameters.get(\"x_column\") or \"\"\n", " y_col = parameters.get(\"y_column\") or \"\"\n", " if not os.path.exists(path):\n", " return ToolResponse.error(code=ToolErrorCode.INVALID_PARAM, message=f\"文件 {path} 不存在\")\n", " df = pd.read_csv(path)\n", "\n", " # 数值化容错:空字符串会被读成 object,转数值并丢弃无效行\n", " if y_col and y_col in df.columns:\n", " df[y_col] = pd.to_numeric(df[y_col], errors=\"coerce\")\n", " df = df.dropna(subset=[c for c in [x_col, y_col] if c and c in df.columns])\n", "\n", " plt.figure(figsize=(10, 6))\n", " try:\n", " if chart_type == \"bar\":\n", " if y_col:\n", " data = df.groupby(x_col)[y_col].sum().sort_values(ascending=False)\n", " plt.bar(data.index.astype(str), data.values, color=\"#3498db\")\n", " plt.ylabel(y_col)\n", " else:\n", " data = df[x_col].value_counts()\n", " plt.bar(data.index.astype(str), data.values, color=\"#3498db\")\n", " plt.ylabel(\"数量\")\n", " plt.title(f\"{x_col} 分组统计(柱状图)\")\n", " elif chart_type == \"line\":\n", " df = df.sort_values(x_col) if x_col in df.columns else df\n", " plt.plot(df[x_col].astype(str), df[y_col], marker=\"o\", color=\"#e74c3c\")\n", " plt.title(f\"{y_col} 随 {x_col} 变化趋势(折线图)\")\n", " plt.ylabel(y_col)\n", " elif chart_type == \"pie\":\n", " data = df.groupby(x_col)[y_col].sum() if y_col else df[x_col].value_counts()\n", " plt.pie(data.values, labels=data.index.astype(str), autopct=\"%1.1f%%\")\n", " plt.title(f\"{x_col} 占比(饼图)\")\n", " elif chart_type == \"hist\":\n", " col = x_col if x_col in df.columns else y_col\n", " plt.hist(pd.to_numeric(df[col], errors=\"coerce\").dropna(), bins=15,\n", " color=\"#2ecc71\", edgecolor=\"white\")\n", " plt.title(f\"{col} 分布(直方图)\")\n", " plt.xlabel(col)\n", " elif chart_type == \"scatter\":\n", " plt.scatter(df[x_col], df[y_col], alpha=0.6, color=\"#9b59b6\")\n", " plt.xlabel(x_col)\n", " plt.ylabel(y_col)\n", " plt.title(f\"{x_col} 与 {y_col} 的关系(散点图)\")\n", " else:\n", " plt.close()\n", " return ToolResponse.error(code=ToolErrorCode.INVALID_PARAM,\n", " message=f\"不支持的图表类型 {chart_type},支持 bar/line/pie/hist/scatter\")\n", " except Exception as e:\n", " plt.close()\n", " return ToolResponse.error(code=ToolErrorCode.EXECUTION_ERROR,\n", " message=f\"绘图失败: {e},请检查列名是否正确\")\n", " os.makedirs(\"outputs\", exist_ok=True)\n", " filename = f\"outputs/{chart_type}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png\"\n", " plt.xticks(rotation=30)\n", " plt.tight_layout()\n", " plt.savefig(filename, dpi=110, bbox_inches=\"tight\")\n", " plt.close()\n", " text = f\"图表已生成并保存至:{filename}({chart_type} 图,x={x_col}, y={y_col or '(计数)'})\"\n", " return ToolResponse.success(text=text, data={\"chart_path\": filename, \"chart_type\": chart_type})\n", "\n", " def get_parameters(self):\n", " return [\n", " ToolParameter(name=\"file_path\", type=\"string\",\n", " description=\"CSV文件路径\", required=True),\n", " ToolParameter(name=\"chart_type\", type=\"string\",\n", " description=\"图表类型:bar/line/pie/hist/scatter\", required=True),\n", " ToolParameter(name=\"x_column\", type=\"string\",\n", " description=\"x轴/分类列名(hist 时为数值列)\", required=False, default=\"\"),\n", " ToolParameter(name=\"y_column\", type=\"string\",\n", " description=\"y轴数值列名(bar/pie 省略则计数)\", required=False, default=\"\"),\n", " ]\n", "\n", "\n", "# 创建工具注册表并注册全部工具(1.x 新版 API:registry → tool_registry 传给 Agent)\n", "tool_registry = ToolRegistry()\n", "for tool_cls in [CSVLoaderTool, DataStatsTool, DataCleanTool, DataVizTool]:\n", " tool_registry.register_tool(tool_cls())\n", "print(f\"工具注册完成 ✅ 共 {len(tool_registry.list_tools())} 个:{tool_registry.list_tools()}\")" ] }, { "cell_type": "markdown", "id": "0e3beeee", "metadata": {}, "source": [ "## 第4部分:智能体构建\n", "\n", "创建 LLM 与 `SimpleAgent`,通过 `tool_registry` 挂载工具(注意:**不是** `agent.add_tool()`)。同时传入精简 `Config`,关闭框架默认自动注册的 Task/TodoWrite/DevLog/Skill 等无关内置工具,让智能体专注数据分析场景。" ] }, { "cell_type": "code", "execution_count": 10, "id": "f1358a6e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "智能体「智能数据分析师」构建完成 ✅ 工具调用已启用: True\n", "可用工具: ['csv_loader', 'data_stats', 'data_cleaner', 'data_visualizer']\n" ] } ], "source": [ "# 创建LLM(自动读取 LLM_MODEL_ID / LLM_API_KEY / LLM_BASE_URL)\n", "llm = HelloAgentsLLM()\n", "\n", "from hello_agents import Config\n", "\n", "# 精简配置:关闭无关内置组件,只保留本项目4个数据分析工具\n", "config = Config(\n", " skills_enabled=False, # 关闭 Skills 自动注册\n", " subagent_enabled=False, # 关闭 Task 子代理工具\n", " todowrite_enabled=False, # 关闭 TodoWrite\n", " devlog_enabled=False, # 关闭 DevLog\n", " trace_enabled=False, # 关闭 trace 落盘\n", " session_enabled=False, # 关闭会话持久化\n", ")\n", "\n", "# 系统提示词:定义智能数据分析师的角色、流程与输出规范\n", "SYSTEM_PROMPT = \"\"\"你是一位拥有10年经验的资深智能数据分析师,专注于电商/零售销售数据分析。\n", "\n", "## 你的工作流程(ReAct范式:推理-行动-观察循环)\n", "1. **了解数据**:任何分析开始前,先调用 csv_loader 了解数据全貌与质量\n", "2. **统计分析**:调用 data_stats 获取关键指标的描述性统计\n", "3. **数据清洗**:若发现缺失值或重复行,调用 data_cleaner 清洗,后续分析基于清洗后的数据\n", "4. **可视化**:调用 data_visualizer 生成图表辅助说明\n", " - 对比不同类别 → bar 柱状图(x_column=类别列, y_column=销售额列)\n", " - 展示趋势 → line 折线图\n", " - 展示占比 → pie 饼图\n", " - 展示分布 → hist 直方图\n", "5. **总结洞察**:基于以上所有观察结果,输出结构化分析结论\n", "\n", "## 输出规范\n", "最终回答必须包含以下部分(使用Markdown):\n", "### 📊 数据概况\n", "### 🔍 关键发现(至少3条,附具体数字支撑)\n", "### 📈 可视化图表(说明图表保存路径及读图结论)\n", "### 💡 业务建议(可执行、有优先级)\n", "\"\"\"\n", "\n", "# 创建智能体(1.x 新版 API:传入 tool_registry 启用 Function Calling)\n", "agent = SimpleAgent(\n", " name=\"智能数据分析师\",\n", " llm=llm,\n", " system_prompt=SYSTEM_PROMPT,\n", " config=config,\n", " tool_registry=tool_registry, # ← 新版 API 关键:工具经注册表传入\n", " max_tool_iterations=8, # 允许更多轮工具调用以完成完整分析流水线\n", ")\n", "\n", "print(f\"智能体「{agent.name}」构建完成 ✅ 工具调用已启用: {agent.enable_tool_calling}\")\n", "print(f\"可用工具: {agent.tool_registry.list_tools()}\")" ] }, { "cell_type": "markdown", "id": "0a300970", "metadata": {}, "source": [ "## 第5部分:功能演示\n", "\n", "> 说明:以下两个示例会真实调用大模型与 4 个工具,需要网络与 API 额度。首次运行请耐心等待(每个示例约 10~60 秒)。" ] }, { "cell_type": "markdown", "id": "5e7e276a", "metadata": {}, "source": [ "### 示例1:基础功能 —— 数据概况速览" ] }, { "cell_type": "code", "execution_count": 11, "id": "0bdfaa89", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=== 示例1:基础功能(数据概况速览) ===\n", "### 📊 数据概况\n", "数据集 `data/sample_sales.csv` 包含 100 行 x 10 列的数据,字段包括订单号、订单日期、地区、渠道、产品、类别、单价、数量、销售额和客户满意度。数据类型涵盖了字符串、浮点数和整数。前5行样例数据如下:\n", "\n", "| 订单号 | 订单日期 | 地区 | 渠道 | 产品 | 类别 | 单价 | 数量 | 销售额 | 客户满意度 |\n", "| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n", "| ORD20250045 | 2025-03-09 | 华北 | 线上商城 | 智能手机 | 数码电子 | 3999.0 | 1 | 3556.09 | 4.1 |\n", "| ORD20250046 | 2025-06-26 | 华东 | 线上商城 | 电饭煲 | 家用电器 | 399.0 | 18 | 7520.18 | 4.7 |\n", "| ORD20250067 | 2025-05-10 | 华南 | 线下门店 | 按摩仪 | 个护健康 | 899.0 | 15 | 16527.88 | 4.1 |\n", "| ORD20250029 | 2025-01-20 | 华北 | 线下门店 | 笔记本电脑 | 数码电子 | 5999.0 | 9 | 60056.66 | 4.7 |\n", "| ORD20250058 | 2025-03-25 | 华北 | 线下门店 | 智能手机 | 数码电子 | 3999.0 | 10 | 41992.21 | 4.1 |\n", "\n", "数据质量问题方面,存在一些缺失值和重复行。具体来说,地区列有1个缺失值,销售额列有2个缺失值,客户满意度列有6个缺失值,同时有3个重复行。\n" ] } ], "source": [ "print(\"=== 示例1:基础功能(数据概况速览) ===\")\n", "result = agent.run(\n", " \"请帮我全面了解 data/sample_sales.csv 这个数据集:\"\n", " \"数据规模多大?包含哪些字段?数据质量有没有问题?\"\n", ")\n", "print(result)" ] }, { "cell_type": "markdown", "id": "169fa9d2", "metadata": {}, "source": [ "### 示例2:复杂场景 —— 完整分析流水线\n", "\n", "要求 Agent 自主完成「清洗 → 区域销售对比分析 → 可视化 → 业务洞察」的端到端分析。" ] }, { "cell_type": "code", "execution_count": 12, "id": "fa968c0f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=== 示例2:复杂场景(端到端完整分析) ===\n", "### 🔍 关键发现(至少3条,附具体数字支撑)\n", "1. **销售额分布**:销售额的中位数为 8240.90,说明大部分订单的销售额集中在这一水平。销售额的均值为 21187.03,但标准差高达 26943.65,表明销售额的波动性较大。\n", "2. **客户满意度**:客户满意度的平均值为 4.07,标准差为 0.56,说明客户满意度整体较高,但仍有提升空间。\n", "3. **区域销售表现**:华南地区的订单数量最多,达到 32 个,销售额也最高;华东地区和华北地区紧随其后。\n", "\n", "### 📈 可视化图表(说明图表保存路径及读图结论)\n", "- **图表保存路径**:outputs/bar_20260903_152531.png\n", "- **读图结论**:从柱状图中可以看出,华南地区的销售额最高,其次是华东地区和华北地区。这可能与华南地区的人口密度和消费能力较高有关。\n", "\n", "### 💡 业务建议(可执行、有优先级)\n", "1. **提升客户满意度**:分析客户满意度较低的订单,找出原因并采取措施提升客户体验。\n", "2. **优化销售策略**:针对销售额较高的区域,加大营销力度,同时关注销售额较低的区域的潜在需求。\n", "3. **产品多样化**:根据不同区域的消费习惯,开发更多符合当地市场需求的产品。\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABEIAAAKICAYAAAB0YV+RAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAQ6wAAEOsBUJTofAAAT+9JREFUeJzt3QeYVOX5B+wXRECavaAQG5aI2MFu7CV2jX97SVAhdrHEggUbVsQWRWOLNRpjrzFqNHaMXaOiooCIWBBEUIH5ruf9vplvgaXpws7uue/rGnfnnNkzZ2cP4zm/ed7nbVIqlUoJAAAAoACa1vcOAAAAAMwpghAAAACgMAQhAAAAQGEIQgAAAIDCEIQAAAAAhSEIAQAAAApDEAIAAAAUhiAEAAAAKAxBCAAAAFAYghAAAACgMAQhAMAcM2HChMnuv/LKK2n06NEz9bM//fRTnezD9Lbz4osvpgEDBtTJczz++OPps88+S3Vt/PjxtS4fNmxYfs5x48bVuv79999Pb7/99kw9x//+97907rnnpi+++GKy5WPGjEmDBw9O3333XZoTpvW7AsAvIQgBAOaIN998M62wwgrp2WefzfeHDx+e1l133XTFFVfM8GfjArxjx47pqquu+sX70b179/Tb3/42jR07dqp1L730Ujr00EPTG2+8Md1tnHfeeWnnnXeeZqjyww8/pC222CI99dRTqa6USqV05JFHpt12263W9Y899lh+zm+++WaqdRMnTkybb755Ovzww2fquSI0OfHEE9PXX3892fJbb701Lb300umJJ55IkyZNqjV0efrpp9OKK674s24RjNW0zTbbpJNPPnmm9hkAZlazmX4kANAgjBo1Kn3++ef5wrKanHPOOWnkyJFp+eWXz/fbt2+fQ4mLLroo/f73v0+LLbbYNH/2oYceSl999VXaYIMNJlu+2WabpU8++aTWn4kL+dh+Td9++236xz/+kfbbb7/UunXrqX7m4IMPTg8//PAMKx7WXnvtdPrpp6fdd9893XHHHalZs8lPqVq0aJG/tmrVKtWVCEHuv//+9Mgjj9S6vvz7NG/efKp1c801V36N47X+8ssv00ILLTTd5yr/PlNuq02bNvlrhCHHHntsrqB54IEH0vzzz195TIQj7733Xrrpppsme57nn38+de7cObVr126q5xs6dGg66KCDpqoYuuSSS3IY0qRJk3TWWWdNd58BYGYJQgCgkbn99tvTH//4x1xBUC1iqMWdd96ZevfunRZeeOHK8ggTbrvtthxYPPjgg9P8+WuuuSb17NkzrbzyylNVisSyww47bLLlu+66a67KmFJUn0Q4EaFMiMBoiSWWSPPMM89kYUZUjIR4DWN4xg477JD3v2zjjTdOf/vb33JVyL777pt/h5riwr0uXXfddTlwieBhySWXrPUxTZs2naoK5J///Gf+3SIIieqbe++9N/8tyr/XAgsskNZcc808rOZ3v/tduvrqq1OXLl0q25pym+WAJ8KMqNSICpS4xZCc+eabL68rv47xGnXo0CF/HwHYHnvskZfdc889U+177FPNny1bZZVV0pNPPpn3fdVVV51mNQwAzApBCAA0Mssuu2wOAqpFXJD/4Q9/yAFIVBHUtOiii+YqhQMPPDCdcsop6cwzz6x1SM0LL7yQbr755nw/LryPOOKItP3226e55547X2zHsI+aYvmUF/FRUXLhhRemCy64IF+0R7gRIUoMX4lqinj8nnvumbcdF94hAoMIVOadd96p9it+/owzzkiLLLJImp2igqNXr145iKktBImqlKjciDAjxP5HEBOvefw+LVu2zEFIVLnELSpvyr9XBD5//etf898hfscdd9wx/fe//53mvpQrRGJ7Cy64YK7UOemkkyarHJkyzCjvU1TjxLCocjgSNtlkk1w5Ujbl3yxEBdFf/vKXXK2z9dZbp7Zt287S6wcAUxKEAEAjU/6UvlpE+BDDIqJqojy0oqaoBon1MfQhKjzi8TUvpuNC+5BDDskX8P/+979z9cHee+89S5UXcdG///775+FCe+21V95ODDOJ0GjDDTfMj4khMVGZEBfjq6222kxtd070r4gqlnXWWWeaf9MImCLsKPc1KVfcRLVHzX4h8bpefvnludnplOL1jgqXeJ74nSJkChGYxHajiiYeE5Ud5aEs5WEsMQQp+r3Ea1kOSabc/6hSitc9KpVCPFeEG/GzNU3r7xmVN7H/8TNHH330TL92AFAbQQgAzEZxsRg9O6KHQlwgxgX5xx9/XGv/jpiho3xBWVtgUL4AjR4M8Zi4YB80aFDuw1AelhBiyEN88j+9PhDxPDEsJLZTs2dDXPhG5UQsi0/5hwwZkj/JX2655SrDImbFo48+mofDxPCRGBoxLTEkIy6CoydEhCJx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AACAwhCEAAAAAIUhCAEAAAAKQxACAAAAFIYgBAAAACgMQQgAAABQGIIQAAAAoDAEIQAAAEBhCEIAAACAwhCEAAAAAIUhCAEAAAAKQxACAAAAFIYgBAAAACgMQQgAAABQGIIQAAAAoDAEIQAAAEBhCEIAAACAwhCEAAAAAIUhCAEAAAAKQxACAAAAFIYgBAAAACgMQQgAAABQGIIQAAAAoDAEIQAAAEBhCEIAAACAwhCEAAAAAIUhCAEAAAAKQxACAAAAFIYgBAAAACgMQQgAAABQGIIQAAAAoDAEIQAAAEBhCEIAAACAwhCEAAAAAIUhCAEAAAAKQxACAAAAFIYgBAAAACgMQQgAAABQGFURhPz000/poIMOSgceeGDldvXVV0/2mCeeeCJtueWWacMNN0y33377VNuo7/UAAABA9auKIOS1115L9957b1p55ZUrt44dO1bWv/DCC2nbbbdNG2+8cerRo0e+PfLII1WzHgAAAGgYmqUq8OKLL6Z11103HXXUUbWuP/PMM9Puu++eTjrppHz/888/T+eee27aeuutq2I9AAAA0DA0rZYgZJlllkk33nhjuuOOO9KoUaMmW//MM8+kXXbZpXJ/8803T88991yaNGlSVayvzejRo9PQoUMrt+HDh/+i1wgAAABoJBUhzz//fPryyy/TZpttlkODnj17pocffjitvfbaacyYMfm20korVR6/8MIL574i8TPzzDNPva5fZJFFav2d+vXrl/r06TMbXi0AAACgwVaETJw4Me2///7p7bffTnfddVeuDonqi/IwlPHjx+evrVu3rvxM+fv42fpePy29evVKQ4YMqdxeeumln/0aAQAAAI2kImSuueZKp5xyymTLDjjggFwdUiqVKqHD119/ndq3b5+/HzduXP7arl271KRJk3pdPy2xbnrrAQAAgAJWhMTwkoceemiyZRE0NGvWLAchrVq1Sssvv3waOHBgZf2bb76ZFl100RyS1Pd6AAAAoOGo9yAkGqPuuuuu6aOPPsr3J0yYkC699NK06aabpqZN/9/dixlb+vfvn4epRDhyxRVX5Olsy+p7PQAAANAw1PvQmE6dOqVDDjkkN0Zdf/3107vvvpt++OGH9Pjjj1cec+yxx6YHHnggde7cObVp0yaNHDlysp4b9b0eAAAAaBjqPQgJF110Ua4KeeGFF/LXuMWQlLLotRHr7r333vTtt9/mZqoLLLBA1awHAAAAGoaqCELCeuutl2/T0rx587TbbrtV7XoAAACg+tV7jxAAAACAOUUQAgAAABSGIAQAAAAoDEEIAAAAUBiCEAAAAKAwBCEAAABAYQhCAAAAgMIQhAAAAACFIQgBAAAACkMQAgAAABSGIAQAAAAoDEEIAAAAUBiCEAAAAKAwBCEAAABAYQhCAAAAgMIQhAAAAACFIQgBAAAACkMQAgAAABSGIAQAAAAoDEEIAAAAUBiCEAAAAKAwBCEAAABAYQhCAAAAgMIQhAAAAACFIQgBAAAACkMQAgAAABSGIAQAAAAoDEEIAAAAUBiCEAAAAKAwBCEAAABAYQhCAAAAgMIQhAAAAACFIQgBAAAACkMQAgAAABSGIAQAAAAoDEEIAAAAUBiCEAAAAKAwBCEAAABAYQhCAAAAgMIQhAAAAACFIQgBAAAACkMQAgAAABSGIAQAAAAoDEEIAAAAUBiCEAAAAKAwBCEAAABAYdRJEDJw4MA0evToyZY99thj6fDDD6+LzQMAAABUTxBywgknpPfff3+yZYsvvni67bbb6mLzAAAAANU9NGbkyJFp3nnnnV2bBwAAAJhlzdLPNHHixLTsssvm70eMGJF22GGH1Lx583y/VCqlYcOGpcsvv/znbh4AAACgeoKQpk2bVoKO3r17pwMOOCB16tSpsm755Zev3AcAAABo0EFIkyZN0nbbbZe/79+/f9pggw3SWmutVZf7BgAAAFB9PULOPvvstNxyy9XFpgAAAACqryKkprXXXrsuNgMAAABQ/UHIoEGD0pFHHpmn0I1GqWXRJ+Shhx6qi6cAAAAAqI4g5Oijj04TJkxIZ511VmrRokVlebt27epi8wAAAADVE4QMHTo0/e1vf8sVIAAAAACNulnqJptsku6999662BQAAABAdVeEbL/99mn//fdP77zzTtpyyy1T27ZtK0NjNtpoo7p4CgAAAIDqCEKuvfba1LRp0/Tkk0/mW9kKK6wgCAEAAAAaVxBy880318VmAAAAAKq/RwgAAABAYSpCoj/Is88+O9XymEXmoYceqounAAAAAKiOIKRHjx5p5513zt+PHTs2Pf300+mee+5JBx10UF1sHgAAAKB6gpD11ltvsvt77713Wn/99dM//vGPSkAyK+6444602WabpQUXXLCy7IcffshT9I4bNy7PUrPAAgtM9jP1vR4AAAAoSBBSm1133TUdd9xxs/xzd999d9p9993Tq6++WglCRo0alX7zm9+kn376KS2yyCLp1FNPTS+++GJabLHFqmI9AAAAUKBmqREKPPDAA5VbDIs5+OCD0+KLLz5L2xkxYkQeZhNT8dZ05pln5q///e9/01NPPZXWWWed1Lt376pZDwAAABQoCLnsssvSYYcdVrkdffTRaciQIenqq6+epe1ET5EYSjP//PNPtvyuu+5Khx56aGrZsmW+HyFLDFOplvW1GT16dBo6dGjlNnz48Fl6LQAAAIAqHRpz8803/+JtXHPNNem9995Lt912Ww4eyn788cf06aefpq5du1aWderUKX355Zfp22+/TfPMM0+9rp933nlr/X369euX+vTp84tfFwAAAKDKKkLKJk2alKsfJkyYMEs/99FHH6U//elP6dZbb02tW7eeqrKiVCqlhRdeuLKs/Jjvv/++3tdPS69evXJVTPn20ksvzdJrAgAAAFRxEHLOOeektm3bpo4dO+ag4JhjjsnNRWcmPNlvv/3S8ccfn9Zcc82p1s8111z568SJE///nf7/eog0b9683tdPS7t27VKHDh0qt/bt28/wtQAAAAAaQBBy7bXX5j4hMbzljTfeyMNbYvaXCEdm5JZbbkkDBw5MX3zxRTr22GPzLSotLr744jxEJvqFRMDywQcfVH4mKiyiX0dMYVvf6wEAAICCBSHRI6R///5pr732Sl26dEm77LJLDkci5JiRzp07p7POOivPMBPT0catSZMmeerccv+N7bffPt1+++2Vn7n//vvzzC3xuGpYDwAAABSoWWooDyGpbLhZs9xbY0bWWGONfKvp3HPPzcNlVltttXz/yCOPTBtssEEOSyIgifU1Q5b6Xg8AAAAUKAjZc889c3PQCD9WXnnlNGjQoHTUUUfl5T/HDjvskOabb77K/W7duqV//etfuXIkZmq58sor04477lg16wEAAICGoUlpZso2ZsIZZ5yR+vbtm8aPH58DkT/+8Y/poosuSnPPPXddbL7Bi9l0opFs9BeJ5qkNRdcBg+p7F2iEXu7RKVUbxzpFOdaD452iHOsAFMfQWbjmrrNZY0499dQ0ZsyYPBXu2LFj06WXXioEAQAAABrf0JhIXu65555cDVLTQgstlA444IC6eAoAAACA6ghCorFpTC8bM8DUtNRSSwlCAAAAgMYVhMRMKvvuu2/6/e9/XxebAwAAAKjeIOSYY45J22yzTXryySdTu3btKstjutmTTjqpLp4CAAAAoDqCkBNOOCEtueSSqVWrVmnChAmV5RMnTqyLzQMAAABUTxCy+uqrp06dOqVDDz20LjYHAAAAUL1BSMuWLdPRRx+d/va3v002NCaqRK644oq6eAoAAACA6ghCVl111XTGGWdMtXzhhReui80DAAAAVE8Qsscee9TFZgAAAACqPwgplUrplltuSa+99lqlWWo0Sh05cmS6/fbb6+IpAAAAAKojCDn77LPT1VdfnRZccMEcgHTu3DndeeedqXfv3nWxeQAAAIDqCUIefPDBHIREo9TTTjst3XbbbTkM+fTTT+ti8wAAAADVNTSmSZMmeRrdN954I9/fbbfd0hZbbFEXmwcAAAConiBkm222Sd27d0/PPfdcWmGFFdL555+fxo4dm1q1alUXmwcAAAConiDk5JNPTpMmTUrjx49Pffv2TTvvvHP67rvv0nXXXVcXmwcAAAConiCkWbNmqU+fPvn75ZdfPo0YMSI3TY3lAAAAANWi6ezYaPQLqRmCXHPNNemLL76YHU8FAAAAUL9ByJRef/319P3338+JpwIAAACo3yAEAAAAoBoIQgAAAIDCEIQAAAAAhSEIAQAAAApDEAIAAAAUxhwJQlZeeeXUqlWrOfFUAAAAANPULM0BPXv2nBNPAwAAADD7K0ImTpyYrrzyyjR27Ng0YsSIdMABB6T99tsvDR8+vC42DwAAAFA9Qcjpp5+eLr/88lQqldKJJ56YPv744xyIHHbYYXWxeQAAAIDqGRrz2GOPpQEDBqQ2bdqkhx9+OD333HOpRYsWaY011qiLzQMAAABUT0VI06ZNU7NmzdLgwYPz90svvXT65ptvUsuWLeti8wAAAADVUxGy1VZb5Z4gEXxsu+22eVjMcccdlzbddNO62DwAAABA9QQhvXv3Tm3btk3jx49Phx9+eBo2bFhacsklU9++feti8wAAAADVE4TEsJhjjjmmcr9du3Z5FhkAAACARtcjBAAAAKAwQcjEiRPTmWeemVZZZZV0xhlnpJtvvjnts88+6bvvvquLzQMAAABUTxDSr1+/dP311+e+IKNHj05rr712+uijj9Lxxx9fF5sHAAAAqJ4g5O6770433HBD2nHHHfP95ZZbLvcIuf/+++ti8wAAAADVE4TMM888Uy379ttvU5s2bepi8wAAAADVE4TsscceqWfPnumFF15II0aMyBUicX/PPfesi80DAAAAVM/0uQceeGAaOXJkuuCCC9KoUaPSPffck4OQE088sS42DwAAAFA9QUiTJk3SSSedlG/ffPNNmm+++fIyAAAAgEYXhNQ0//zz1/UmAQAAAKqnRwgAAABAQyAIAQAAAArjZw2NGTZsWOrbt+8MH7f44ovnviEAAAAADTYIKZVKacKECTN83MSJE3/O5gEAAACqJwjp0KFDuuqqq+p+bwAAAABmIz1CAAAAgMIQhAAAAACFIQgBAAAACuNn9QiprXnqLbfckl577bVKE9VolDpy5Mh0++2318VTAAAAAFRHEHL22Wenq6++Oi244II5AOncuXO68847U+/eveti8wAAAADVE4Q8+OCDOQhp165dOu2009Jtt92Ww5BPP/20LjYPAAAAUF1DY5o0aZJWX3319MYbb+T7u+22W9piiy3qYvMAAAAA1ROEbLPNNql79+7pueeeSyussEI6//zz09ixY1OrVq3qYvMAAAAA1ROEnHzyyWnSpElp/PjxqW/fvmnnnXdO3333XbruuuvqYvMAAAAA1ROENGvWLPXp0yd/v/zyy6cRI0bkpqmxHAAAAKBaNJ0dG41+IUIQAAAAoFEGIVH9ceWVV+a+IFENcsABB6T99tsvDR8+vC42DwAAAFA9Qcjpp5+eLr/88jxbzIknnpg+/vjjHIgcdthhdbF5AAAAgDpRJ008HnvssTRgwIDUpk2b9PDDD+fZY1q0aJHWWGONutg8AAAAQPVUhDRt2jT3BBk8eHD+fumll07ffPNNatmyZV1sHgAAAKB6KkK22mqr3BMkgo9tt902D4s57rjj0qabbloXmwcAAAConiCkd+/eqW3btmn8+PHp8MMPT8OGDUtLLrlk6tu3b11sHgAAAKB6gpAYFnPMMcdU7rdr1y7PIjM7TJo0KQ+/qdb1AAAAQPWqmiv6M844Iy266KJpnnnmSdttt91UU+/2798/LbDAArnyJIbdxAw11bQeAAAAqH5VEYRcd9116c4770zPPvtsGjRoUBo1alTq1atXZf0dd9yRTjnllHT77benV155Jd111115lppqWQ8AAAA0DFURhET48ec//zl16tQpLbHEEumAAw5I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M9C6dev89euvv65c4I4bNy5/jUqRaYl1U64vV5TQeMUxEtVC0Ng51ikKxzpF4ninKBzrjddSSy01U48za8wMtGrVKi2//PJp4MCBlWVvvvlmWnTRRSshCQAAANAwCEJmQswY079//zy8JVqqXHHFFXk6XQAAAKBhMTRmJhx77LHpgQceSJ07d05t2rTJ446iFwSUxTCo0047bbrDpaAxcKxTFI51isTxTlE41inTLHUm/fjjj+nee+9N3377bdpll13SAgssMLM/CgAAAFQJQQgAAABQGHqEAAAAAIUhCAEAAAAKQxACAAAAFIYgBAAAACgMQQgAAABQGIIQmEO+/PLLdM0113i9AYAG5+2330733Xdffe8GQJ0QhMBsNmnSpDRgwIC01lprpWHDhqVSqeQ1p9H79NNP63sXYLZ47733vLIUyujRo9Nxxx2XdtxxxzR+/Pj63h2oc1999VX+wJJiEYRAHXvttdfS0ksvncaMGZP+/e9/p65du6ZXXnklvfTSS+n0009PEyZM8JrTKLz11lvp9ttvn2zZoEGD0jbbbJO23XZboR+NzosvvphWX3319Pnnn1eWjRs3Lp1zzjmTLYOG7MYbb0ybbrpp/iDnuuuuyx/kLLzwwrkiZLfddnMeQ6NzwAEHpD59+ky27N577033339/ve0Ts58gBOrYyiuvnH788cf0m9/8JgcfcRJx9dVXpx9++CHtueeeab/99vOa0yg8+OCDqW/fvvn77777Lp144olp7bXXTuuvv36+YGzSpEl97yL8Yt9++20+zqOaL47v7bffPp100kmV9bfccku66KKLvNI0Guuuu27lg5xnnnkmPf300+n444/PH/TEuquuuqq+dxF+sccffzw9+uij+fvzzjsvXXvttZWKvwgBe/XqlY9/Gi9BCNShsWPHptNOOy1/bdq0aXryySfT8ssvn1PmjTfeOH9/5513ptdff93rToO3xBJL5LDjpptuSiussEIaMmRIeuONN1Lv3r1Tq1at6nv3oM5ceuml6dZbb83fX3DBBemOO+5IAwcOzKH3hRdemPr165cWW2wxrziNYljjqaeempo3b5423HDDdP311+cQcP/9909//OMfc0VUVEDFeQ40ZHEufvjhh6effvoprbTSSumggw5KRx99dF4X1a5zzTVXOuOMM+p7N5mNBCFQByZOnJhPFtZYY418AfjCCy/kT04uu+yytOqqq+bS6bgfgci+++6bU2Zo6OJEOE4kLr/88nTXXXflT1QiHKk55jZKS6Ehm3feeXNFyAknnJC+//779Ktf/Sodc8wx6YgjjsihyJJLLpkvEqEhi+G8EYBsueWWaaeddsrN3eP9O479DTbYIFf6RfgX5zXzzTdfOv/88+t7l+EXOfLII1OzZs3yMR2iivvll19Ot912W+6JE/8GWrZs6VVuxAQh8As99NBDaZVVVslfn3jiiXTyySfnC8Q4eY77Dz/8cHr11VfTP/7xj/z4OKmIN9ryfWhoPvvsszzEKz45mX/++XPwF6FHVIWMGDEil5RGiWkME4uqKGjoIuhYfPHF07nnnpvv/+lPf0pDhw7NlSB/+ctf6nv34GeLao9LLrkkrbjiirn3x3//+9+0xx575OXR4D0aSMYQggi633///Xzh2L9//xwCfvLJJ155Gqw4li+++OJc9TFy5Mh8PhPf77PPPul3v/tdHuJO4yYIgTq4KIxwI4a8xJtq9+7d0+9///v0t7/9Ld19991p2WWXTV988UUeKrPLLrvkUCTCkmOPPTb3DYGGJMbTRsDRsWPHHHYstNBCeXjMVlttlTp16pQOPPDAPK48PkmMceVxwgwNXRzj0SQyhsHExV9U/sWF4TzzzJMWXHDB+t49mGXxQU1UgcSxHQH2I488koe8fPDBB3kobwwFi+ao0f9mkUUWSR999FEORdZbb7202mqrpc022yx/ag4N2TrrrJMrnOK8PBx88MH5HCcq/Wj8BCEwi6KaI5LiCDdCXPjFLBlRJhpNxNZcc80cjMRYw7/+9a95qrmYei6a68XjNtpoo9yNPcYearBHNYugLo7Z559/vrIsSqSjEerZZ5+d+yPECXIYPnx4nlXggQceyN3X77vvvlwlEp80xqxJMXwMqtlhhx1Wa3XHu+++mxukRpl0vMeXL/6i+XXMEFauEin78MMPU48ePXLPHKg2UckUx24cx/G+HSIAad++ferZs2f+NDwaX8e5zN57751nvCuf70QVYAzxjWqRo446Kr/PR+ANDU1UP1155ZW5EioqP6LXWQxhj3Pz+ACnXCVS04ABA3IVII2HIARmIE4Ctthii1zuH+JEOS7qyheAoTzFXIytPeSQQ/LUodFoKfonRAOmmFYx3mA7dOiQTy5iaroIQSIwiYoSqAYRXMQngR9//HG+H8O33nnnndS5c+fKY1q3bp2WW265ygVfu3bt8rja+FRlu+22S7vvvntl2Fesj/4hMfVilJzGxSFUi0MPPTTdcMMN+fsYAhAVTl26dJnsMfEeHjPFxIlyTBcdJ8sxDLJ88RdBX5wYR4PJsvh/Q8wUJgihmsSHMmeddVY+luOcJj7UiQbuZaNGjcrnJjHsKyr84kIweihEv4RokBrv488991weHhP34/iOPjnxmPL5EVSjmNkrQo+aIvC7+eab02OPPZaP+wjC41gOm2yySa54isbvNUVVVHzYQyNSAqZr5MiRpQUXXLB07bXXlv73v/+VFl544dKwYcOmety///3vUrNmzUpvvPFG6b333it17dq1tPPOO+fvO3XqVFp++eVLa621VunZZ5/Nj580aVJefuGFF/oLUBXimPzNb35T2nfffUvjx48vrbDCCqUHHnhgmo9deeWVS02aNCl17949/zsJQ4YMKbVq1ap05513Vh77ySeflK644opS//7959jvAjNyxhlnlJZaaql8rMcxfPTRR9f6uCnf7+PnVltttdLEiRPz/T/84Q+l//u//8vfjxkzpnTUUUeVFlhggdKIESP8EagK8X4cx/qGG25Y+vbbbyd7H6/pnHPOKXXo0KE0duzY0oMPPlhadtllS8cdd1zp1VdfLTVv3ry03HLLlXbbbbfS4MGDK/824v8BL7zwwhz/nWBK+++//2Tv46+//nppo402Kq244opTncsMHz58suM//l0sssgipTvuuCPf//jjj0utW7fOx3545pln8r+HE044wQvfiAhCoBYXX3xx6aSTTqrcv+qqq0qLLbZYaf31188XdGWPPfZYacsttyz9+OOP+X6cTG+yySalcePGlR5++OHS119/nd+UF1100dLcc89dGjp0aOVnDzvssNIyyyxT+vTTT/0NqDePPPJIvoj76aef8v233norH6u77LJLPuEti2N32223Lb388suVZTfddFM+zuOC8Prrr88nDuH000/PJ93x7wCqRYR0e+65Z+mVV17J93/44Yd8YhvH+q9+9ascYpRFuBHv+7X5/vvv8+OvvvrqfP/zzz8vzT///KXtt9++tPjii5f22muv/FxQ31577bXSxhtvnN+7471+oYUWKn322Wf5/T7Oc+IDm/J7f4jvI+A+5ZRTSh988EHpzTffLL3//vulHXfcMYd7v/71rysBYPz7WXvttUtbbbVV5RwI6lN8iBPn1l9++WXpkEMOyR9cXnrppZMd49MzYMCA0pJLLlk5d4l/Bx07dixtvfXWpSWWWKJ04403ThUe0rAJQqAWBxxwQGn33Xev3I//8cen4507d66cBITnn3++FIVVH330Ub4fnwC2a9eudNddd+XAJN6EI1CJE+wITOIkvCxOHOLNGurTDTfckIO6mg488MDSXHPNNdkn4RMmTMiVHtddd91U24jjPv4dPProo5ULxTZt2lQuFKEaRJgXx2lc3JXdfvvtedktt9wy2WPjwjECjdrE8b3OOuvkTw9HjRqVl/3nP/8pHXHEET4ZpypEhV7Pnj1zqBGVp/fcc09efuKJJ5Y233zzHGjE+Uh8Wn7ZZZdN9rP//Oc/S/PMM0+u+jjooINK7du3L/3lL3/Jx3r8v6Lmh0FxDhOBCFSDeA+OYz7OvSMI+eqrr6Z6TM1z+Cndf//9+f8HUfVXPk/v06dP6YILLih99913s3XfqR96hEAtfvrpp/T1119X7kezyGiaNGjQoMp0cTFOPBqJRePUpZZaqjI2vDwjTEwl+swzz+Smkm3atMn9QL7//vvcYDLMPffcZhugKo71OCZjyucQswL885//zLNhPPXUU3lZ9AmJMeXLLLNM2nrrrafaRqxv0aJF2nDDDfP2omfCuHHj8swyUC3i2Azl9/b4MChmxmjbtm2eHjR88803eax4vOfHDGBT+u6779Jvf/vb9Ktf/Sr3VzjllFPy8vXXXz/3C4l+IlCfDa6jeW/08/j1r3+dZ6mLPk3HHHNM7nETvcr+9a9/5d4ecexfccUVuW9IHPdlm2++eb5FM9Volh0zx8S/hXnnnTf3g4oZZspixqTmzZvX028L/794D4/z8jj3iBmRdt5550oPqBANf/fdd9/cCLg2MdNdTJMejYPj39DgwYPzefqpp56az+mjPxqNUD0FMFDVYghM/POIoS9R7h89Qu69995cQt2lS5fSpptumitEHnroofz4GGP+4osv5u/j05EY8nLWWWfV828BM3byySfnYz0ql6J8tFu3bqVevXrlctI47qMyKj5dif4e5fLSp59+erJtxCcmUX5dPv7j05TaKkegPj355JP5WI9qjihvjt4H0bcphsrEcLC99947V3nEJ+nlar3//ve/lSEzUfkUQwl23XXX/G9h4MCBuVeIIWBUi3j/PfbYYyfrTxOVHFHuX+51FsMY11133cr6+OT88MMPn2w7MRwm/k089dRTc3T/YVbFcN4YlhiVT3FuXq7mjmrXli1b5iFe/fr1y0NbTj311NLo0aOn2kacr0Q1d/T6CzFcOP6t0PgJQqCWE4ko64+T3RgKEye85VLqGFsbb7KXXHJJZUxsDAeIRqjRhKxm74RoslRbU1WoJjFkK471OGGIIV7R3DeO7RgKE2WmxxxzTKURaqyLx8c48+iLUBbjxKMvCFSz888/P/dwil4Hf/3rX3MPp/J79DXXXFPaZ599crPr8sXjkUcemf9dRLl0iJ+J9/mawYfx4lSrGAIQwxOj+WmEezGsJT60iWM2Ar3od3DfffflECQCwHfeeWeyn+/Ro0dp1VVXne5QAqhv0eumb9+++dw93rMPPfTQyrpVVlklv4fHe3u818ewxilFk9T4/0LN4ZHe14tDEAJTiE7p8cb5zTff5AQ5Phkv+9e//pUrQ0KkzDvssEM+uYiTjbhwLIsTh3gDjpNrqFZxsRef+kWFx0477ZQrnso+/PDDHPiVTxQiEImA8Pjjj6/0Raj576LcJweqVXwKHp8IXn755bmpabnSI8Z+R1VTnEjHe3e8b8eFYTSIjE/GoSGKRtYxo0u5OXCE2OUZMaKCNWa5iw9sotov3utjfU1x4Rihd1RFQUMQlRxnnnlm6d133y1ts802pdVXXz33O4seTiHe06P5afR/isaoJitAEAJTiDfQ+KQkxNd55503T7MV4gQ5wpEoqW7btm0uQa05FV1NMf0cVLNoJBYXhfEpyaBBg3IoEifP4e233y61aNGidNppp1UuCuMx0FBFpV4c1xFaR7PICPdCfEoeVX0HH3xwPnGOZnuPP/54fe8u/GLR9Ld8nMdw3fjEvCwCjnK1X/y/IIYG/P3vf5/s553H0JDEsPSoYoqwI4a7RGVHVDatueaa+fs4v49mv/HBT4SAvXv3ru9dpp41if/Ud58SqFaTJk1K22+/fW6I161bt3T99dengw46KDfJe+CBB1KnTp3qexehzkRzvGjye+CBB+ZGv7vvvntuLPnggw+mzTbbzCtNo/GPf/wjv4dfd911uQH2fvvtl55++ul0xhlnpJNOOinNNddc9b2L8It9/PHHadVVV02vvPJKPt5ffvnl3CS15jnOjTfemBumbrzxxumxxx5LH3zwQWrZsqVXnwZl6NChabXVVstNUi+88MLc3LfcAH655ZZLF110UfrDH/5QeXw0VY3bAgssUI97TX0zawxM7x9I06b5InDChAk5CLn44ovzm+mnn36amjVr5rWjUbngggvy7DARgOyyyy7pT3/6Uz6ZiBMJaEzi+I7ZNGJGgC5duuQT6C233DK/twtBaCyWXnrpPAtSr1690pAhQ9Jiiy1WWffss8/mWY5ito0IAa+99tp0//33C0FokDp06JCDv2uuuSYHf507d87hyEILLZQ/zIyAO2ZuLIuZ8YQguJKD6Yjpcnv37p2nEz3ttNPSIYcckgOQgQMHpqOPPjrdfffdXj8ahW+//Tadf/756bLLLstTyL3//vtp/vnnT61atcpTx2233Xamj6NRmDhxYrrpppvye3ucLL/wwgtppZVWysf8Kquskg4++ODUtWvX+t5NqBNxARhVrIcffngO+yIQiZD7ww8/TJdeemlad911K4+NQBAaqpgKPcSxHdWsEY6E1VdfPU/7HFNIx4eaUKYiBKYhqkA233zzNN988+UT5COOOKJSBdK3b9+cLI8dO9brR6PQs2fP9Pzzz+dbhCERgoQoJY2TiI8++qi+dxHqxA033JCHwFxxxRXp0UcfzSFIiIvFCLjfe+89rzSNRps2bfI5Sxzbffr0SZtsskkORCIArBmCQGMRH1bG+XuI8/ddd9017bXXXmmttdaq712jyugRAtMxZsyYSsIMjZljnaL46aefclWIPggURbQDjE/CY6jjPffck8MRaKyWXXbZXAnVvXv3SnV3LGvSpEl97xpVRkUITIcQhKJwrFMUc889txCEQokLwPPOOy998cUXhjjSqI0cOTIf49H8tywmNhCCUBsVIQAA0Mj98MMPqUWLFvW9GwBVQRACAAAAFIahMQAAAEBhCEIAAACAwhCEAAAAAIUhCAEAAAAKQxACAAAAFIYgBAAAACgMQQgAAABQGIIQAAAAoDAEIQAAAEBhCEIAAACAwhCEAAAAAKko/h8Fj85Q/balIgAAAABJRU5ErkJggg==", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "print(\"=== 示例2:复杂场景(端到端完整分析) ===\")\n", "result = agent.run(\n", " \"请对 data/sample_sales.csv 做一次完整的销售分析:\"\n", " \"先检查并清洗数据质量问题,然后对比各区域的销售表现,\"\n", " \"生成一张区域销售额柱状图,再分析客户满意度情况,\"\n", " \"最后总结关键发现并给出下半年的业务建议。\"\n", ")\n", "print(result)\n", "\n", "# 查看最新生成的柱状图\n", "import glob\n", "from IPython.display import Image, display\n", "charts = sorted(glob.glob(\"outputs/bar_*.png\"))\n", "if charts:\n", " display(Image(filename=charts[-1]))" ] }, { "cell_type": "markdown", "id": "51e85ee3", "metadata": {}, "source": [ "## 第6部分:性能评估\n", "\n", "从两个维度评估项目质量:\n", "\n", "1. **工具层自动化测试**:直接实例化 4 个工具,验证正常/异常输入均正确返回\n", "2. **Agent 层定性评估**:从准确性、完整性、格式规范性等维度人工打分" ] }, { "cell_type": "code", "execution_count": 13, "id": "698a00e3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "用例 结果 说明\n", "----------------------------------------------------------------\n", "加载-正常路径 ✅ ToolResponse(status=