用自然语言分析数据 —— 一个生产级 LLM Agent 项目
上传 CSV / Excel,用大白话提问,看 AI Agent 实时拆解、计算、出图、写结论。
🌐 Live Demo · 📊 进度看板 · 🚀 部署指南
让 不会写 SQL / Python 的业务用户 也能做数据分析。
把 Excel 丢进去,用自然语言提问,Agent 自主决定每一步要调用什么工具(看数据 → 计算 → 出图 → 给结论),全过程实时流式展示,让用户能看到 AI 的每一个动作。
用户: 哪个区域销售额最高?
Agent: [Database] 正在读取数据结构... ✓
[Calculator] 正在按区域汇总销售额... ✓
[BarChart] 正在生成图表... ✓
华东区域销售额最高,达 **44,700** 元,
比第二名华北(31,500)高出 42%。
[📊 柱状图已渲染]
[📄 下载 .html 报告]
每一步可见、每一个数字可追溯。导出的 HTML 报告离线可双击打开,内嵌图表 SVG,普通用户友好。
面试现场可以直接照着 docs/demo-script.md 跑一遍:选择内置「销售数据」demo,提问「哪个区域销售额最高?请生成柱状图」,再让 Agent 生成简短报告。
| 数据集即刻可用 | Agent 步骤可追溯 | 报告可离线交付 |
|---|---|---|
![]() |
![]() |
![]() |
一眼能看到的产品闭环:
- 不是 Chat UI 套壳:Agent 会展示
inspect_data → run_analysis → create_chart → generate_report的完整执行轨迹。 - 不是编答案:二级 LLM 只负责生成 SQLite SQL,数字由
better-sqlite3在:memory:数据库里真实计算。 - 不是 demo-only:Prisma/Postgres 持久化、Auth.js 登录、owner check、HTML 报告导出都已经接上。
- 🤖 多步 Agent 推理 — 自动调用
inspect_data→run_analysis→create_chart→generate_report - 🌊 全程流式 — 文字 / 工具步骤 / 图表 / 报告通过 SSE 实时推送
- 🧠 支持 DeepSeek V4 thinking mode —
reasoning_content字段按协议回 echo - 🗃️ 真 SQL 执行 — LLM 生成 SQLite SQL → better-sqlite3
:memory:执行,支持 GROUP BY / 窗口函数 / CTE - 💾 Prisma 7 + Postgres 持久化 — driver adapter 架构(
@prisma/adapter-pg,无 Rust binary),6 表、5 次 migration 进 git,刷新不丢数据 - 🔐 生产级鉴权 — Auth.js v5 + bcrypt(12) + JWT;Credentials / Google / GitHub 三 provider;邮箱验证 + 登录失败滑动窗口(15min/5 次)+ enumeration 防御;
proxy.ts路由级保护、owner 校验防越权 - 📊 4 种图表类型 — bar / line / pie / scatter,基于 Recharts,主题色自动跟随
- 📄 HTML 报告导出 — 内嵌 SVG 图表,离线可双击打开,无外部依赖
- 🌗 明 / 暗主题 — 14 个语义化 CSS 变量,组件零硬编码颜色
- 🔄 每数据集独立历史 — 切换数据集互不污染上下文 + sticky-to-bottom 滚动
- 🌐 Provider 抽象 — DeepSeek / OpenAI / Claude 通过环境变量切换
- 🛡️ 三层 SQL 安全 — 只允 SELECT/WITH 开头 + 禁 DDL/DML 关键字 +
:memory:per-query - ✨ 动态提问建议 — LLM 根据 dataset schema 生成自然中文示例问题(替代硬编码模板)
- ✂️ Token 控制 — tool result 截断 + 滑动窗口(最近 40 条消息),长对话不爆上下文
- 🎯 一键试用 — 内置 2 个 demo 数据集,新用户零门槛体验
- 🔁 瞬时失败重试 — 限流 / 5xx / 网络抖动指数退避重试,4xx 参数错立即抛(不浪费 token)
- 📈 可观测性 — 每轮 Agent 记录 LLM/工具 耗时 + token + 失败率,结构化
[agent-metrics]日志 - ⚡ 二次 LLM 缓存 — 同
(datasetId, intent)复用生成的 SQL,LRU 100 条 - 🔎 数据集搜索 + 上传进度条 — 侧栏按名过滤、上传百分比进度 +「解析中」阶段
- 🧪 测试 + CI — vitest 79 例(解析 / SQL 沙箱 / registry / 缓存 / 重试 / 指标)+ GitHub Actions(tsc + lint + test)
| 层 | 选型 | 理由 |
|---|---|---|
| 框架 | Next.js 16 (App Router, Turbopack) | 全栈一体,API Route 不用单独搭后端 |
| 语言 | TypeScript strict | 类型在 SSE / tool / LLM 协议间流转,必须 strict |
| LLM | DeepSeek V4 (OpenAI 兼容) | 中文好、价格低、支持 Tool Use 与 thinking mode |
| 流式 | 原生 SSE + ReadableStream | 单向流足够;WebSocket 是双向通信,本场景过度设计 |
| 持久化 | Prisma 7 + Postgres(Supabase 仅作宿主) | driver adapter 架构(@prisma/adapter-pg,无 Rust binary);6 表、5 次 migration 进 git;连接配置在 prisma.config.ts |
| 鉴权 | Auth.js v5 + bcryptjs + Resend | Credentials / Google / GitHub 三 provider + JWT + 邮箱验证 + 登录 rate limit + proxy.ts 路由保护 |
| 图表 | Recharts | React 原生 + SVG 输出(可抓取嵌入报告) |
| 样式 | Tailwind v4 + CSS variables | @theme inline 让 token 体系天然落地 |
| 主题 | next-themes | SSR 安全、不闪 |
| Markdown | react-markdown + remark-gfm | 14 个元素 custom map,贴合对话紧凑场景 |
| 解析 | papaparse + exceljs | 服务端解析;exceljs 替代 xlsx 解 CVE |
| SQL 执行 | better-sqlite3 :memory: |
替代 node:vm 沙箱;真 SQL 引擎 + 三层防御 |
| 报告 | marked + inline CSS | 离线可读 + 内嵌 SVG 图表 |
Agent 主循环是整个项目的心脏(lib/agent.ts,约 250 行):
sequenceDiagram
actor U as 用户
participant FE as React (useAgent)
participant API as /api/agent (SSE)
participant Agent as runAgent
participant LLM as DeepSeek V4
participant Tool as 工具执行器
U->>FE: 上传 CSV + 提问
FE->>API: POST { datasetId, message, previousMessages }
API->>Agent: runAgent({ ..., onEvent })
loop step < MAX_STEPS
Agent->>LLM: chatCompletionStream(messages, tools)
LLM-->>Agent: chunks (content / reasoning / tool_calls)
Agent-->>FE: SSE answer_delta (流式文本)
alt 有 tool_calls
Agent-->>FE: SSE tool_start
Agent->>Tool: execute (inspect / analysis / chart / report)
Tool-->>FE: SSE chart / report (via ctx.emit)
Tool-->>Agent: result JSON
Agent-->>FE: SSE tool_done
else 无 tool_calls (结束)
Agent-->>FE: SSE done (本轮新增 messages)
end
end
- Node.js 20+(生产环境跑 24.x)
- DeepSeek API Key — platform.deepseek.com 注册有免费额度
git clone https://github.com/vaezc/data-analysis-agent.git
cd data-analysis-agent
npm install
# 配置环境变量(分两个文件)
cp .env.local.example .env.local
# .env 放数据库连接(Prisma CLI 只认 .env)
cat > .env <<EOF
DATABASE_URL="postgresql://...:6543/postgres?pgbouncer=true&connection_limit=1"
DIRECT_URL="postgresql://...:5432/postgres"
EOF
# .env.local 放 LLM key、AUTH_SECRET 等
# 生成 AUTH_SECRET: openssl rand -base64 32
# 初始化数据库表结构
npx prisma migrate deploy # 生产/CI 用 deploy;本地开发用 prisma migrate dev
# 启动
npm run dev浏览器打开 http://localhost:3000
- 上传
scripts/sample.csv(项目自带的小销售数据) - 输入 "哪个区域销售额最高?"
- 看 Agent 一步步推理
# 1. push 到自己的 GitHub 仓库
# 2. Vercel 导入项目
# 3. 添加环境变量(Production scope):
# LLM_PROVIDER = deepseek
# LLM_API_KEY = sk-xxx
# LLM_MODEL = deepseek-v4-flash
# DATABASE_URL = postgresql://...:6543/postgres?pgbouncer=true&connection_limit=1
# DIRECT_URL = postgresql://...:5432/postgres
# AUTH_SECRET = <openssl rand -base64 32>
# AUTH_URL = https://<your-domain>.vercel.app
# AUTH_TRUST_HOST = true # Vercel preview / 自定义域名必加
# 4. Deploy(build = "prisma generate && next build",构建不连库)
# 注:migration 不在 build 里跑。新增 migration 时部署前先手动
# npm run db:migrate:deploy(详见 DEPLOY.md §4)data-analysis-agent/
├── app/
│ ├── api/
│ │ ├── agent/route.ts # SSE Agent 端点
│ │ ├── upload/route.ts # 文件上传 + 解析
│ │ ├── datasets/
│ │ │ ├── route.ts # GET 列表
│ │ │ └── [id]/
│ │ │ ├── route.ts # DELETE
│ │ │ └── suggestions/route.ts # GET LLM 生成的提问建议
│ │ └── messages/route.ts # GET 历史 / DELETE 清空
│ ├── page.tsx # 主对话界面 + sidebar
│ └── globals.css # 14 个语义 CSS token
├── lib/
│ ├── agent.ts # ★ Agent 主循环
│ ├── llm.ts # Provider 抽象
│ ├── prisma.ts # Prisma client 单例(HMR-safe)
│ ├── db/
│ │ ├── datasets.ts # 数据集 CRUD + owner check
│ │ └── messages.ts # 对话持久化 + 滑动窗口 + 配对删除
│ ├── auth/
│ │ ├── email.ts # Resend 邮箱验证发送
│ │ └── rate-limit.ts # 登录失败 rate limit
│ ├── suggestions.ts # LLM 生成自然中文提问建议
│ └── tools/
│ ├── registry.ts # ★ 自注册中心:defineTool + executeTool + getToolList
│ ├── index.ts # 副作用 import 触发各工具自注册 + re-export
│ ├── inspect-data.ts # 工具 1:schema + handler + UI 描述同文件
│ ├── run-analysis.ts # 工具 2:含 uiDescriptionFrom 动态文案 + 截断
│ ├── create-chart.ts # 工具 3:zod superRefine 兜 pie / 长度校验
│ ├── generate-report.ts # 工具 4
│ └── sqlite-runner.ts # ★ better-sqlite3 SQL 沙箱
├── prisma/
│ ├── schema.prisma # 6 表 schema
│ └── migrations/ # 5 次 migration 进 git
├── auth.ts # Auth.js v5 完整配置
├── auth.config.ts # edge-safe 部分(给 proxy.ts 用)
├── proxy.ts # Next.js 16 路由保护(旧名 middleware.ts)
├── hooks/
│ └── use-agent.ts # SSE 消费 + per-dataset 历史
├── components/chat/
│ ├── ChatPanel.tsx # 输入区 + sticky-to-bottom 滚动
│ ├── MessageBubble.tsx
│ ├── ChartRenderer.tsx
│ ├── ReportCard.tsx # HTML 导出 + 内嵌 SVG
│ └── StepList.tsx
└── types/index.ts # 全局类型(StreamEvent / ChatMessage)
| 想了解什么 | 看哪里 |
|---|---|
| Agent 主循环 + 三种 delta 累积 | lib/agent.ts |
| SSE 流式协议 + UTF-8 安全 | hooks/use-agent.ts |
| 工具自注册 registry(借鉴 Hermes Agent) | lib/tools/registry.ts |
| Tool result 截断(控 token) | lib/tools/run-analysis.ts |
| HTML 报告内嵌 SVG 图表 | components/chat/ReportCard.tsx |
| Sticky-to-bottom 滚动 | components/chat/ChatPanel.tsx |
| Prisma 数据访问层 + owner check | lib/db/datasets.ts · lib/db/messages.ts |
PROGRESS.md— 项目蓝图 + 局限登记册 + 优化项 backlogDEPLOY.md— Vercel 端到端部署 checklist(13 项环境变量)CLAUDE.md— 开发规范与约束
- Phase 1 — Agent 主循环、工具系统、SSE 流式
- Phase 2 — Recharts 图表、明暗主题、流式 answer、多轮上下文
- Phase 3 — HTML 报告 + Supabase 持久化 + Vercel 上线
- 安全 / 性能 polish
- xlsx → exceljs(解 CVE)
- node:vm → better-sqlite3 真 SQL 执行(解 vm 不安全 + 不支持 async)
- 滑动窗口 + tool result 截断(控 LLM token)
- UX polish
- 错误条 dismiss、数据集删除、New Chat、HistorySkeleton
- Demo 数据集 + 一键试用按钮
- LLM 生成的动态提问建议
- Vision 多模态架构 — 后端协议层 ready,前端 UI 待 vision-capable LLM 启用
- 工具系统重构 — 自注册 registry(借鉴 Nous Research Hermes Agent)+ zod 校验,新增工具只需 1 个文件
- 鉴权完整化 — 登录失败 rate limit(DB 滑动窗口)+ 邮箱验证(Resend + 24h TTL)+ OAuth(Google / GitHub)
- Prisma 6 → 7 升级 — WASM driver adapter,包体积 14MB → 1.6MB,cold start 加速
- E2B 沙箱 — 替代 better-sqlite3 跑真 Python(需付费 API key)
- 二次 LLM 调用缓存 — 同 intent 复用,省 token
- 多 Excel sheet 支持 — 当前只读第一个
- 可观测性 — 耗时、token、失败率监控
完整登记见 PROGRESS.md。
MIT
Built with Claude Code.



