diff --git a/skills/csv-data-analysis/SKILL.md b/skills/csv-data-analysis/SKILL.md
new file mode 100644
index 000000000..50ad00f73
--- /dev/null
+++ b/skills/csv-data-analysis/SKILL.md
@@ -0,0 +1,106 @@
+---
+name: csv-data-analysis
+description: This skill should be used when users need to analyze CSV files, understand data patterns, generate statistical summaries, or create data visualizations. Trigger keywords include "分析CSV", "数据分析", "CSV分析", "数据统计", "生成图表", "数据可视化".
+---
+
+# 智能 CSV 数据深度分析工具
+
+CSV数据分析工具是一个基于 AI 与前端可视化技术(ECharts + Tailwind CSS)的深度自动化数据探索工具。它能够快速提取统计特征、分类信息、相关性以及时序趋势,并由大模型注入深度业务洞察,生成高度美观和可交互的网页分析报告。
+
+## 核心工作流(LLM 必读)
+
+作为 AI 助手,在用户上传 CSV 并要求分析时,你需要严格按照以下两步执行:
+
+### 第一步:提取数据特征 (执行脚本)
+
+使用 `execute_skill_script_file` 工具运行 `csv_analyzer.py`,将 CSV 文件路径传入。
+
+**工具调用参数示例:**
+```json
+{
+ "skill_name": "csv-data-analysis",
+ "script_file_name": "csv_analyzer.py",
+ "args": {"input_file": "/path/to/data.csv"}
+}
+```
+
+**脚本返回说明:**
+脚本会返回一大段 `text` 内容,其中包含两个部分:
+1. **【统计摘要】**:供你阅读并理解数据集的基本情况、分布、相关性和分类构成。
+2. **【CHART_DATA_JSON】**:位于 `###CHART_DATA_JSON_START###` 和 `###CHART_DATA_JSON_END###` 之间的纯 JSON 字符串。这是用于渲染交互式图表的原生数据。
+
+### 第二步:生成洞察与展示报告 (注入模板)
+
+阅读第一步获得的"统计摘要",思考数据背后的业务意义或规律。然后使用 `html_interpreter` 工具,加载模板并注入数据。
+
+**关键规则(必须遵守):**
+
+1. **必须设置 `template_path`** 为 `csv-data-analysis/templates/report_template.html`。模板中已内置完整的 ECharts 渲染 JavaScript 代码和所有章节标题、页脚文本,你只需要通过 `data` 参数填充 9 个内容占位符即可。**绝对不要自己编写或修改任何 JavaScript 图表渲染代码。**
+
+2. **`CHART_DATA_JSON`** 必须**完整且原封不动**地复制自脚本输出中 `###CHART_DATA_JSON_START###` 和 `###CHART_DATA_JSON_END###` 之间的纯 JSON 字符串。不要自行编造,不需要做任何转义处理。
+
+3. **`*_INSIGHTS`、`EXEC_SUMMARY` 和 `CONCLUSIONS`** 必须使用 HTML 格式(如 `
`, `
`, `- `, ``, `
`)来确保排版美观。这些内容由你基于统计摘要撰写深度业务洞察。
+
+4. **输出语言必须与用户输入语言一致。**
+
+5. **只传 9 个占位符,不要多也不要少。** 模板已将所有章节标题(Distribution Analysis、Correlation Analysis 等)、洞察框标题(Insights)和页脚文本硬编码在 HTML 中,你无需传递这些。
+
+**`html_interpreter` 调用示例:**
+```json
+{
+ "template_path": "csv-data-analysis/templates/report_template.html",
+ "data": {
+ "REPORT_TITLE": "销售数据集深度分析报告",
+ "REPORT_SUBTITLE": "多维度数据特征与业务洞见挖掘",
+ "EXEC_SUMMARY": "本数据集共包含 1000 行 5 列,数据完整性良好。核心洞察如下:
",
+ "DISTRIBUTION_INSIGHTS": "从数值分布图可以看出,指标 A 呈现出明显的右偏态分布,建议...
",
+ "CORRELATION_INSIGHTS": "变量间的热力图揭示了强烈的正相关关系,特别是...,这意味着...
",
+ "CATEGORICAL_INSIGHTS": "分类占比显示,'城市'字段中北京与上海占据了 50% 以上的份额。
",
+ "TIME_SERIES_INSIGHTS": "从时序趋势中可以看出,数据在年末存在显著的季节性拉升现象。
",
+ "CONCLUSIONS": "综合以上多维度分析,数据呈现出明确的结构性特征与规律。
建议
- 建议定期检查缺失值比例...
- 重点关注高增长细分市场...
",
+ "CHART_DATA_JSON": "此处粘贴脚本输出中 ###CHART_DATA_JSON_START### 到 ###CHART_DATA_JSON_END### 之间的完整 JSON 字符串"
+ }
+}
+```
+
+> **严禁事项:**
+> - 禁止在 `data` 中添加任何 JavaScript 代码
+> - 禁止省略 `template_path` 参数(不设置 template_path 会导致图表无法渲染!)
+> - 禁止对 `CHART_DATA_JSON` 做任何修改、截断或二次编码
+> - 禁止返回静态 PNG 图片,本工具已全面升级为 ECharts 动态前端渲染
+> - 禁止传递不存在的占位符(模板只有以下 9 个占位符,传递其他名称会被忽略)
+
+## 占位符清单(共 9 个)
+
+模板中的全部占位符如下(通过 `data` 参数传递):
+
+| 占位符 | 类型 | 必填 | 说明 |
+|---|---|---|---|
+| `REPORT_TITLE` | 文本 | 是 | 报告标题,如"销售数据集深度分析报告" |
+| `REPORT_SUBTITLE` | 文本 | 是 | 报告副标题,如"多维度数据特征与业务洞见挖掘" |
+| `EXEC_SUMMARY` | HTML | 是 | 执行摘要(你撰写的深度总结),使用 ``, `
`, `- ` 等标签 |
+| `DISTRIBUTION_INSIGHTS` | HTML | 是 | 数值分布洞察正文 |
+| `CORRELATION_INSIGHTS` | HTML | 是 | 相关性分析洞察正文 |
+| `CATEGORICAL_INSIGHTS` | HTML | 是 | 分类变量洞察正文 |
+| `TIME_SERIES_INSIGHTS` | HTML | 是 | 时间序列洞察正文 |
+| `CONCLUSIONS` | HTML | 是 | 结论与建议正文(包含建议内容,直接写在此字段中) |
+| `CHART_DATA_JSON` | JSON字符串 | 是 | 脚本输出的原始 JSON(驱动图表渲染),必须从脚本输出原封不动复制 |
+
+> **注意:** 模板中的所有章节标题(如 "Distribution Analysis"、"Correlation Analysis"、"Conclusions & Recommendations" 等)、洞察框标题("Insights")和页脚文本已硬编码在 HTML 中,无需通过占位符传递。
+
+## 为什么选择本工具?
+
+1. **极速与轻量**:告别缓慢的 Python 绘图和大量 PNG 生成,只传输核心 JSON 数据。
+2. **现代交互式排版**:全面接入 Tailwind CSS 响应式布局和 Apache ECharts 丝滑动画交互。
+3. **深度业务洞见**:通过将机器的数据提炼和 LLM 的逻辑推理分离,能产出极具含金量的数据分析报告。
+
+## 文件结构
+
+```
+csv-data-analysis/
+├── SKILL.md # 你当前正在阅读的技能指南
+├── scripts/
+│ └── csv_analyzer.py # Python 分析引擎(轻量级、无图形依赖)
+└── templates/
+ └── report_template.html # 响应式 ECharts 报表模板(内含完整渲染逻辑与硬编码标题)
+```
diff --git a/skills/csv-data-analysis/references/reference.md b/skills/csv-data-analysis/references/reference.md
new file mode 100644
index 000000000..498af42f7
--- /dev/null
+++ b/skills/csv-data-analysis/references/reference.md
@@ -0,0 +1,15 @@
+# Reference Documentation
+
+This file contains detailed reference material for the skill.
+
+## API Reference
+
+[TODO: Add detailed API documentation here]
+
+## Schema Definitions
+
+[TODO: Add schema definitions if applicable]
+
+## Detailed Workflows
+
+[TODO: Add detailed workflow descriptions]
diff --git a/skills/csv-data-analysis/scripts/csv_analyzer.py b/skills/csv-data-analysis/scripts/csv_analyzer.py
new file mode 100644
index 000000000..d8923b7fa
--- /dev/null
+++ b/skills/csv-data-analysis/scripts/csv_analyzer.py
@@ -0,0 +1,328 @@
+import pandas as pd
+import numpy as np
+import os
+import json
+import warnings
+import sys
+
+warnings.filterwarnings("ignore")
+
+
+def log(*args, **kwargs):
+ """将日志输出到 stderr,避免污染 stdout 的 JSON 输出"""
+ print(*args, file=sys.stderr, **kwargs)
+
+
+def analyze_csv(file_path):
+ """
+ 分析CSV文件,提取用于 ECharts 渲染的数据结构和用于 LLM 分析的统计摘要。
+ 输出包含: overview, distributions, correlations, categories, time_series,
+ scatter (散点图), stats_table (统计表格)
+ """
+ try:
+ log(f"正在读取文件: {file_path}")
+ df = pd.read_csv(file_path)
+
+ # ==========================================
+ # 1. 基础概览数据
+ # ==========================================
+ total_cells = int(df.shape[0] * df.shape[1])
+ missing_cells = int(df.isnull().sum().sum())
+ missing_pct = (
+ round((missing_cells / total_cells) * 100, 2) if total_cells > 0 else 0
+ )
+
+ overview = {
+ "rows": int(df.shape[0]),
+ "cols": int(df.shape[1]),
+ "missing_cells": missing_cells,
+ "missing_pct": missing_pct,
+ }
+
+ # ==========================================
+ # 2. 数值列分析 (直方图分布 & 相关性)
+ # ==========================================
+ numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()
+ distributions = {}
+ correlations = {"cols": numeric_cols, "data": []}
+ numeric_summary = {}
+
+ if numeric_cols:
+ # 取最多前 8 个数值列画分布图
+ for col in numeric_cols[:8]:
+ s = df[col].dropna()
+ if len(s) > 0:
+ # 使用 numpy 计算直方图 (10个 bin)
+ hist, bin_edges = np.histogram(s, bins=10)
+ bins = [
+ f"{bin_edges[i]:.1f}~{bin_edges[i + 1]:.1f}"
+ for i in range(len(hist))
+ ]
+ distributions[col] = {
+ "bins": bins,
+ "counts": [int(x) for x in hist],
+ }
+ numeric_summary[col] = {
+ "min": float(s.min()),
+ "max": float(s.max()),
+ "mean": float(s.mean()),
+ "median": float(s.median()),
+ "std": float(s.std()),
+ "q25": float(s.quantile(0.25)),
+ "q75": float(s.quantile(0.75)),
+ }
+
+ # 相关性矩阵 (取全部数值列)
+ if len(numeric_cols) > 1:
+ corr_df = df[numeric_cols].corr(method="pearson").fillna(0).round(2) # type: ignore[call-overload]
+ for i, col1 in enumerate(numeric_cols):
+ for j, col2 in enumerate(numeric_cols):
+ correlations["data"].append([i, j, float(corr_df.iloc[i, j])])
+
+ # ==========================================
+ # 3. 分类列分析 (饼图/柱状图)
+ # ==========================================
+ categorical_cols = df.select_dtypes(
+ include=["object", "category"]
+ ).columns.tolist()
+ categories = {}
+ cat_summary = {}
+
+ if categorical_cols:
+ # 取最多前 6 个分类列
+ for col in categorical_cols[:6]:
+ if df[col].nunique() <= 50:
+ val_counts = df[col].value_counts().head(10)
+ if len(val_counts) > 0:
+ categories[col] = {
+ "labels": [str(x) for x in val_counts.index.tolist()],
+ "values": [int(x) for x in val_counts.values],
+ }
+ top1 = val_counts.index[0]
+ top1_count = val_counts.values[0]
+ cat_summary[col] = (
+ f"唯一值数量: {df[col].nunique()},最常见: {top1} (出现 {top1_count} 次)"
+ )
+
+ # ==========================================
+ # 4. 时间序列分析
+ # ==========================================
+ time_series = {"name": "", "dates": [], "values": []}
+
+ if numeric_cols:
+ date_col = None
+ for col in df.columns:
+ if df[col].dtype == "object":
+ try:
+ pd.to_datetime(df[col].dropna().head(100))
+ date_col = col
+ break
+ except Exception:
+ pass
+
+ if date_col:
+ num_col = numeric_cols[0]
+ df_ts = df.copy()
+ df_ts[date_col] = pd.to_datetime(df_ts[date_col], errors="coerce")
+ df_ts = df_ts.dropna(subset=[date_col, num_col])
+
+ if not df_ts.empty:
+ df_ts = df_ts.set_index(date_col)
+ try:
+ monthly = df_ts[num_col].resample("M").mean().dropna()
+ if len(monthly) < 3:
+ monthly = df_ts[num_col].resample("D").mean().dropna()
+ monthly = monthly.tail(100)
+
+ time_series["name"] = num_col
+ time_series["dates"] = [
+ x.strftime("%Y-%m-%d") for x in monthly.index
+ ]
+ time_series["values"] = [
+ round(float(x), 2) for x in monthly.values
+ ]
+ except Exception as e:
+ log(f"时间序列处理失败: {e}")
+
+ # ==========================================
+ # 5. 散点图数据 (前两个数值列)
+ # ==========================================
+ scatter = {}
+ if len(numeric_cols) >= 2:
+ col_x, col_y = numeric_cols[0], numeric_cols[1]
+ df_scatter = df[[col_x, col_y]].dropna()
+ # 限制最多 500 个点,避免数据过大
+ if len(df_scatter) > 500:
+ df_scatter = df_scatter.sample(500, random_state=42)
+ scatter = {
+ "x_name": col_x,
+ "y_name": col_y,
+ "x": [round(float(v), 4) for v in df_scatter[col_x].tolist()],
+ "y": [round(float(v), 4) for v in df_scatter[col_y].tolist()],
+ }
+
+ # ==========================================
+ # 6. 统计汇总表格
+ # ==========================================
+ stats_table = {"headers": [], "rows": []}
+ if numeric_summary:
+ stats_table["headers"] = [
+ "变量",
+ "最小值",
+ "Q25",
+ "中位数",
+ "均值",
+ "Q75",
+ "最大值",
+ "标准差",
+ ]
+ for col, s in numeric_summary.items():
+ stats_table["rows"].append(
+ [
+ col,
+ round(s["min"], 2),
+ round(s["q25"], 2),
+ round(s["median"], 2),
+ round(s["mean"], 2),
+ round(s["q75"], 2),
+ round(s["max"], 2),
+ round(s["std"], 2),
+ ]
+ )
+
+ # ==========================================
+ # 构建给 ECharts 渲染的完整 JSON 数据结构
+ # ==========================================
+ chart_data = {
+ "overview": overview,
+ "numeric_cols": numeric_cols,
+ "distributions": distributions,
+ "correlations": correlations,
+ "categories": categories,
+ "time_series": time_series,
+ "scatter": scatter,
+ "stats_table": stats_table,
+ }
+
+ chart_data_json_str = json.dumps(chart_data, ensure_ascii=False)
+
+ # ==========================================
+ # 构建给 LLM 深度分析阅读的文本摘要
+ # ==========================================
+ summary_lines = [
+ "==================================================",
+ "【数据概览】",
+ f"- 数据集尺寸: {overview['rows']} 行 × {overview['cols']} 列",
+ f"- 缺失值情况: 共有 {overview['missing_cells']} 个单元格缺失,整体数据完整率 {100 - overview['missing_pct']}%",
+ f"- 数值型列 ({len(numeric_cols)}): {', '.join(numeric_cols[:10])}",
+ f"- 分类型列 ({len(categorical_cols)}): {', '.join(categorical_cols[:10])}",
+ "",
+ "【数值型特征统计 (Top 8)】",
+ ]
+ for col, s in numeric_summary.items():
+ summary_lines.append(
+ f"- {col}: min={s['min']:.2f}, Q25={s['q25']:.2f}, median={s['median']:.2f}, "
+ f"mean={s['mean']:.2f}, Q75={s['q75']:.2f}, max={s['max']:.2f}, std={s['std']:.2f}"
+ )
+
+ summary_lines.append("")
+ summary_lines.append("【分类型特征摘要 (Top 6)】")
+ for col, stats in cat_summary.items():
+ summary_lines.append(f"- {col}: {stats}")
+
+ summary_lines.append("")
+ summary_lines.append("【核心相关性】")
+ if correlations["data"]:
+ strong_corrs = []
+ for item in correlations["data"]:
+ i, j, val = item
+ if i < j and abs(val) >= 0.5:
+ strong_corrs.append(
+ f"{numeric_cols[i]} 与 {numeric_cols[j]} (相关系数: {val})"
+ )
+ if strong_corrs:
+ summary_lines.extend([f"- {c}" for c in strong_corrs])
+ else:
+ summary_lines.append("- 没有发现强相关的数值变量组合(|r| >= 0.5)。")
+
+ if scatter:
+ summary_lines.append("")
+ summary_lines.append(
+ f"【散点图】已生成 {scatter['x_name']} vs {scatter['y_name']} 的散点图数据"
+ )
+
+ summary_lines.append("==================================================")
+ summary_lines.append(
+ "请作为数据分析专家,基于以上【统计摘要】为用户撰写深度的数据分析见解(Insights)。"
+ )
+ summary_lines.append(
+ "并且,在使用 html_interpreter 时,请将下方 JSON_START 和 JSON_END 标记之间的纯 JSON 字符串完整传递给变量 CHART_DATA_JSON。"
+ )
+ summary_lines.append("###CHART_DATA_JSON_START###")
+ summary_lines.append(chart_data_json_str)
+ summary_lines.append("###CHART_DATA_JSON_END###")
+
+ final_text = "\n".join(summary_lines)
+
+ # 输出标准 chunks
+ print(
+ json.dumps(
+ {"chunks": [{"output_type": "text", "content": final_text}]},
+ ensure_ascii=False,
+ )
+ )
+
+ except Exception as e:
+ import traceback
+
+ err_msg = f"分析过程中出现错误: {str(e)}\n{traceback.format_exc()}"
+ print(
+ json.dumps(
+ {"chunks": [{"output_type": "text", "content": err_msg}]},
+ ensure_ascii=False,
+ )
+ )
+
+
+def main():
+ if len(sys.argv) < 2:
+ result = {
+ "chunks": [
+ {
+ "output_type": "text",
+ "content": '使用方法: python csv_analyzer.py \'{"input_file": "data.csv"}\'',
+ }
+ ]
+ }
+ print(json.dumps(result, ensure_ascii=False))
+ sys.exit(1)
+
+ try:
+ args = json.loads(sys.argv[1])
+ csv_file = (
+ args.get("input_file") or args.get("file_path") or args.get("csv_file", "")
+ )
+ except (ValueError, TypeError):
+ csv_file = sys.argv[1]
+
+ if not csv_file or not os.path.exists(csv_file):
+ result = {
+ "chunks": [{"output_type": "text", "content": f"文件不存在: {csv_file}"}]
+ }
+ print(json.dumps(result, ensure_ascii=False))
+ sys.exit(1)
+
+ if not csv_file.lower().endswith(".csv"):
+ result = {
+ "chunks": [
+ {"output_type": "text", "content": f"文件不是CSV格式: {csv_file}"}
+ ]
+ }
+ print(json.dumps(result, ensure_ascii=False))
+ sys.exit(1)
+
+ analyze_csv(csv_file)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/skills/csv-data-analysis/scripts/example.py b/skills/csv-data-analysis/scripts/example.py
new file mode 100755
index 000000000..c0985cb10
--- /dev/null
+++ b/skills/csv-data-analysis/scripts/example.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+"""
+Example script for the skill.
+
+This script can be called by Claude to perform deterministic operations.
+Replace this with your actual skill logic.
+"""
+
+import sys
+import json
+
+def main():
+ """Main entry point."""
+ if len(sys.argv) < 2:
+ print("Usage: python3 example.py ")
+ sys.exit(1)
+
+ input_data = sys.argv[1]
+ # TODO: Add your skill logic here
+ result = {"status": "success", "input": input_data}
+ print(json.dumps(result, indent=2))
+
+if __name__ == "__main__":
+ main()
diff --git a/skills/csv-data-analysis/templates/report_template.html b/skills/csv-data-analysis/templates/report_template.html
new file mode 100644
index 000000000..bf3ed0914
--- /dev/null
+++ b/skills/csv-data-analysis/templates/report_template.html
@@ -0,0 +1,534 @@
+
+
+
+
+
+ {{REPORT_TITLE}}
+
+
+
+
+
+
+
+
+
+
+
{{REPORT_TITLE}}
+
{{REPORT_SUBTITLE}}
+
+
+
+
+
+
+
+
+
+
+ Executive Summary
+
+
+
{{EXEC_SUMMARY}}
+
+
+
+
+
+
+
+
+
+
{{DISTRIBUTION_INSIGHTS}}
+
+
+
+
+
+
+
+
+
+
{{CORRELATION_INSIGHTS}}
+
+
+
+
+
+
+
+
+
+
+
{{CATEGORICAL_INSIGHTS}}
+
+
+
+
+
+
+
+
+
+
{{TIME_SERIES_INSIGHTS}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Conclusions & Recommendations
+
+
+
{{CONCLUSIONS}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+